1
0
mirror of https://github.com/adtools/clib2.git synced 2025-12-08 14:59:05 +00:00
Files
amiga-clib2/library/stdio_fdhookentry.c
Olaf Barthel ee556fcb35 - Moved a few __delete_semaphore() calls into conditional compilation
sections where they should have been in the first place.


git-svn-id: file:///Users/olsen/Code/migration-svn-zu-git/logical-line-staging/clib2/trunk@14869 87f5fb63-7c3d-0410-a384-fd976d0f7a62
2005-03-09 12:06:10 +00:00

537 lines
12 KiB
C

/*
* $Id: stdio_fdhookentry.c,v 1.19 2005-03-09 12:06:10 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2005 by Olaf Barthel <olsen@sourcery.han.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of Olaf Barthel nor the names of contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _STDLIB_MEM_DEBUG_H
#include "stdlib_mem_debug.h"
#endif /* _STDLIB_MEM_DEBUG_H */
/****************************************************************************/
#ifndef _STDIO_HEADERS_H
#include "stdio_headers.h"
#endif /* _STDIO_HEADERS_H */
#ifndef _UNISTD_HEADERS_H
#include "unistd_headers.h"
#endif /* _UNISTD_HEADERS_H */
/****************************************************************************/
#include <strings.h>
#include <limits.h>
/****************************************************************************/
int
__fd_hook_entry(
struct fd * fd,
struct file_action_message * fam)
{
D_S(struct FileInfoBlock,fib);
BOOL fib_is_valid = FALSE;
struct FileHandle * fh;
off_t current_position;
off_t new_position;
int new_mode;
char * buffer = NULL;
int result = -1;
BPTR file;
ENTER();
assert( fam != NULL && fd != NULL );
assert( __is_valid_fd(fd) );
__fd_lock(fd);
file = fd->fd_DefaultFile;
if(file == ZERO)
{
SHOWMSG("file is closed");
fam->fam_Error = EBADF;
goto out;
}
switch(fam->fam_Action)
{
case file_action_read:
SHOWMSG("file_action_read");
assert( fam->fam_Data != NULL );
assert( fam->fam_Size > 0 );
D(("read %ld bytes from position %ld to 0x%08lx",fam->fam_Size,Seek(file,0,OFFSET_CURRENT),fam->fam_Data));
PROFILE_OFF();
result = Read(file,fam->fam_Data,fam->fam_Size);
PROFILE_ON();
if(result < 0)
{
D(("read failed ioerr=%ld",IoErr()));
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
if(FLAG_IS_SET(fd->fd_Flags,FDF_CACHE_POSITION))
fd->fd_Position += result;
break;
case file_action_write:
SHOWMSG("file_action_write");
assert( fam->fam_Data != NULL );
assert( fam->fam_Size > 0 );
if(FLAG_IS_SET(fd->fd_Flags,FDF_APPEND))
{
SHOWMSG("appending data");
PROFILE_OFF();
if(Seek(file,0,OFFSET_END) >= 0)
{
if(FLAG_IS_SET(fd->fd_Flags,FDF_CACHE_POSITION))
fd->fd_Position = Seek(file,0,OFFSET_CURRENT);
}
PROFILE_ON();
}
D(("write %ld bytes to position %ld from 0x%08lx",fam->fam_Size,Seek(file,0,OFFSET_CURRENT),fam->fam_Data));
PROFILE_OFF();
result = Write(file,fam->fam_Data,fam->fam_Size);
PROFILE_ON();
if(result < 0)
{
D(("write failed ioerr=%ld",IoErr()));
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
if(FLAG_IS_SET(fd->fd_Flags,FDF_CACHE_POSITION))
fd->fd_Position += result;
break;
case file_action_close:
SHOWMSG("file_action_close");
/* If this is an alias, just remove it. */
if(__fd_is_aliased(fd))
{
__remove_fd_alias(fd);
}
else
{
/* The following is almost guaranteed not to fail. */
result = 0;
/* Are we disallowed to close this file? */
if(FLAG_IS_SET(fd->fd_Flags,FDF_NO_CLOSE))
{
/* OK, so we cannot close it. But we might be obliged to
reset a console into buffered mode. */
if(FLAG_IS_SET(fd->fd_Flags,FDF_NON_BLOCKING) && FLAG_IS_SET(fd->fd_Flags,FDF_IS_INTERACTIVE))
SetMode(file,DOSFALSE);
}
else
{
BOOL name_and_path_valid = FALSE;
D_S(struct FileInfoBlock,fib);
BPTR parent_dir;
memset(fib,0,sizeof(*fib));
/* Call a cleanup function, such as the one which
* releases locked records.
*/
if(fd->fd_Cleanup != NULL)
(*fd->fd_Cleanup)(fd);
PROFILE_OFF();
parent_dir = __safe_parent_of_file_handle(file);
if(parent_dir != ZERO)
{
if(__safe_examine_file_handle(file,fib))
name_and_path_valid = TRUE;
}
if(CANNOT Close(file))
{
fam->fam_Error = __translate_io_error_to_errno(IoErr());
result = -1;
}
PROFILE_ON();
fd->fd_DefaultFile = ZERO;
#if defined(UNIX_PATH_SEMANTICS)
{
DECLARE_UTILITYBASE();
assert( UtilityBase != NULL );
/* Now that we have closed this file, know where it is and what its
* name would be, check if we tried to unlink it earlier. If we did,
* we'll try to finish the job here and now.
*/
if(name_and_path_valid)
{
struct UnlinkNode * node;
struct UnlinkNode * uln_next;
struct UnlinkNode * uln;
BOOL file_deleted = FALSE;
assert( __unlink_list.mlh_Head != NULL );
/* Check all files to be unlinked when this program exits. */
for(uln = (struct UnlinkNode *)__unlink_list.mlh_Head ;
(uln_next = (struct UnlinkNode *)uln->uln_MinNode.mln_Succ) != NULL ;
uln = uln_next)
{
node = NULL;
/* If the file name matches, check if the path matches, too. */
if(Stricmp(FilePart(uln->uln_Name),fib->fib_FileName) == SAME)
{
BPTR old_dir;
BPTR node_lock;
BPTR path_lock = ZERO;
PROFILE_OFF();
/* Try to get a lock on the file first, then move on to
* the directory it is stored in.
*/
old_dir = CurrentDir(uln->uln_Lock);
node_lock = Lock(uln->uln_Name,SHARED_LOCK);
if(node_lock != ZERO)
{
path_lock = ParentDir(node_lock);
UnLock(node_lock);
}
CurrentDir(old_dir);
/* If we found the file's parent directory, check if it matches
* the parent directory of the file we just closed.
*/
if(path_lock != ZERO)
{
if(SameLock(path_lock,parent_dir) == LOCK_SAME)
node = uln;
UnLock(path_lock);
}
PROFILE_ON();
}
/* If we found that this file was set up for deletion,
* delete it here and now.
*/
if(node != NULL)
{
if(NOT file_deleted)
{
BPTR old_dir;
PROFILE_OFF();
old_dir = CurrentDir(parent_dir);
if(DeleteFile(fib->fib_FileName))
{
file_deleted = TRUE;
name_and_path_valid = FALSE;
}
CurrentDir(old_dir);
PROFILE_ON();
}
if(file_deleted)
{
Remove((struct Node *)node);
free(node);
}
}
}
}
}
#endif /* UNIX_PATH_SEMANTICS */
if(FLAG_IS_SET(fd->fd_Flags,FDF_CREATED) && name_and_path_valid)
{
ULONG flags;
BPTR old_dir;
PROFILE_OFF();
old_dir = CurrentDir(parent_dir);
flags = fib->fib_Protection ^ (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE);
CLEAR_FLAG(flags,FIBF_EXECUTE);
CLEAR_FLAG(flags,FIBF_OTR_EXECUTE);
CLEAR_FLAG(flags,FIBF_GRP_EXECUTE);
SetProtection(fib->fib_FileName,(LONG)(flags ^ (FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE)));
CurrentDir(old_dir);
PROFILE_ON();
}
PROFILE_OFF();
UnLock(parent_dir);
PROFILE_ON();
}
}
__fd_unlock(fd);
#if defined(__THREAD_SAFE)
{
/* Free the lock semaphore now. */
__delete_semaphore(fd->fd_Lock);
}
#endif /* __THREAD_SAFE */
/* And that's the last for this file descriptor. */
memset(fd,0,sizeof(*fd));
break;
case file_action_seek:
SHOWMSG("file_action_seek");
if(fam->fam_Mode == SEEK_CUR)
new_mode = OFFSET_CURRENT;
else if (fam->fam_Mode == SEEK_SET)
new_mode = OFFSET_BEGINNING;
else
new_mode = OFFSET_END;
D(("seek to offset %ld, new_mode %ld; current position = %ld",fam->fam_Offset,new_mode,Seek(file,0,OFFSET_CURRENT)));
if(FLAG_IS_SET(fd->fd_Flags,FDF_CACHE_POSITION))
{
current_position = fd->fd_Position;
}
else
{
PROFILE_OFF();
current_position = Seek(file,0,OFFSET_CURRENT);
PROFILE_ON();
if(current_position < 0)
{
fam->fam_Error = EBADF;
goto out;
}
}
new_position = current_position;
switch(new_mode)
{
case OFFSET_CURRENT:
new_position += fam->fam_Offset;
break;
case OFFSET_BEGINNING:
new_position = fam->fam_Offset;
break;
case OFFSET_END:
if(__safe_examine_file_handle(file,fib))
{
new_position = fib->fib_Size + fam->fam_Offset;
fib_is_valid = TRUE;
}
break;
}
if(new_position != current_position)
{
LONG position;
PROFILE_OFF();
position = Seek(file,fam->fam_Offset,new_mode);
PROFILE_ON();
if(position < 0)
{
D(("seek failed, fam->fam_Mode=%ld (%ld), offset=%ld, ioerr=%ld",new_mode,fam->fam_Mode,fam->fam_Offset,IoErr()));
fam->fam_Error = __translate_io_error_to_errno(IoErr());
#if defined(UNIX_PATH_SEMANTICS)
{
if(NOT fib_is_valid && CANNOT __safe_examine_file_handle(file,fib))
{
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
if(new_position <= fib->fib_Size)
{
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
if(__grow_file_size(fd,new_position - fib->fib_Size) < 0)
{
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
}
#else
{
goto out;
}
#endif /* UNIX_PATH_SEMANTICS */
}
if(FLAG_IS_SET(fd->fd_Flags,FDF_CACHE_POSITION))
fd->fd_Position = new_position;
}
result = new_position;
break;
case file_action_set_blocking:
SHOWMSG("file_action_set_blocking");
PROFILE_OFF();
if(FLAG_IS_SET(fd->fd_Flags,FDF_IS_INTERACTIVE))
{
LONG mode;
SHOWMSG("changing the mode");
if(fam->fam_Arg != 0)
mode = DOSFALSE; /* buffered mode */
else
mode = DOSTRUE; /* single character mode */
if(CANNOT SetMode(file,mode))
{
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
result = 0;
}
else
{
SHOWMSG("can't do anything here");
fam->fam_Error = EBADF;
}
PROFILE_ON();
break;
case file_action_examine:
SHOWMSG("file_action_examine");
if(CANNOT __safe_examine_file_handle(file,fam->fam_FileInfo))
{
SHOWMSG("couldn't examine the file");
fam->fam_Error = __translate_io_error_to_errno(IoErr());
goto out;
}
fh = BADDR(file);
fam->fam_FileSystem = fh->fh_Type;
result = 0;
break;
default:
SHOWVALUE(fam->fam_Action);
fam->fam_Error = EBADF;
break;
}
out:
__fd_unlock(fd);
if(buffer != NULL)
free(buffer);
SHOWVALUE(result);
RETURN(result);
return(result);
}