mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
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
537 lines
12 KiB
C
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);
|
|
}
|