📄 nu_file.c
字号:
/* Assume success until something fails */
ret_val = YES;
/* Get the FILE. We don't want it if an error has occured */
pfile = pc_fd2file(fd, NO);
/* Make sure we have write privilages */
if ( (!pfile) || !((pfile->flag & PO_WRONLY) || (pfile->flag & PO_RDWR)))
{
fs_user->p_errno = PEBADF;
ret_val = NO;
goto return_error;
}
pdrive = pfile->pobj->pdrive;
PC_DRIVE_ENTER(pdrive->driveno, NO) /* Register drive in use */
/* Grab exclusive access to the file */
PC_INODE_ENTER(pfile->pobj->finode, YES)
/* Can only truncate a file that you hold exclusively */
if (pfile->pobj->finode->opencount > 1)
{
ret_val = NO;
fs_user->p_errno = PESHARE;
goto errex;
}
/* Set the cluster and block file pointers if not already set */
_synch_file_ptrs(pfile);
/* Call the internal seek routine that we share with NU_Seek. Seek to
offset from the origin of zero. */
offset = _po_lseek(pfile, offset, PSEEK_SET);
if (offset == -1 || ((ULONG)offset >= pfile->pobj->finode->fsize))
{
ret_val = NO;
}
else
{
/* Are we on a cluster boundary ? */
if (!(offset & pdrive->byte_into_cl_mask))
{
/* Free the current cluster and beyond since we're on a cluster boundary. */
first_cluster_to_release = pfile->fptr_cluster;
/* Find the previous cluster so we can terminate the chain */
PC_FAT_ENTER(pdrive->driveno) /* claim the fat for alloc */
clno = pfile->pobj->finode->fcluster;
last_cluster_in_chain = clno;
while (clno != first_cluster_to_release)
{
last_cluster_in_chain = clno;
clno = pc_clnext(pdrive , clno);
if (clno == 0)
{
PC_FAT_EXIT(pdrive->driveno)
ret_val = NO;
fs_user->p_errno = PENOSPC;
goto errex;
}
}
PC_FAT_EXIT(pdrive->driveno)
/* Set ptr_cluster to last in chain so read&write will work right */
pfile->fptr_cluster = last_cluster_in_chain;
if (last_cluster_in_chain)
pfile->fptr_block = pc_cl2sector(pdrive, last_cluster_in_chain);
else
pfile->fptr_block = 0;
pfile->at_eof = YES;
}
else /* Simple case. we aren't on a cluster boundary. Just free*/
{ /* The chain beyond us and terminate the list */
PC_FAT_ENTER(pdrive->driveno) /* claim the fat */
last_cluster_in_chain = pfile->fptr_cluster;
first_cluster_to_release = pc_clnext(pdrive, pfile->fptr_cluster);
PC_FAT_EXIT(pdrive->driveno)
pfile->at_eof = YES;
}
/* Now update the directory entry. */
pfile->pobj->finode->fsize = offset;
if (!offset) /* If the file goes to zero size unlink the chain */
{
pfile->pobj->finode->fcluster = 0;
pfile->fptr_cluster = 0;
pfile->fptr_block = 0;
pfile->fptr = 0;
pfile->at_eof = NO;
/* We're freeing the whole chain so we don't mark last_cluster in chain */
last_cluster_in_chain = 0;
}
if (!pc_update_inode(pfile->pobj))
{
ret_val = NO;
fs_user->p_errno = PENOSPC;
goto errex;
}
/* Terminate the chain and free the lost chain part */
PC_FAT_ENTER(pfile->pobj->pdrive->driveno)
/* Free the rest of the chain */
if (first_cluster_to_release)
{
/* Release the chain */
pc_freechain(pfile->pobj->pdrive, first_cluster_to_release);
}
/* Null terminate the chain */
if (last_cluster_in_chain)
{
if (!pc_pfaxx(pdrive, last_cluster_in_chain, 0xffff))
{
ret_val = NO;
fs_user->p_errno = PENOSPC;
}
}
if (!pc_flushfat(pfile->pobj->pdrive->driveno))
{
ret_val = NO;
fs_user->p_errno = PENOSPC;
}
PC_FAT_EXIT(pfile->pobj->pdrive->driveno)
}
errex:
PC_INODE_EXIT(pfile->pobj->finode)
PC_DRIVE_EXIT(pdrive->driveno)
return_error: /* No only errors return through here. Everything does. */
/* Restore the kernel state */
PC_FS_EXIT()
return(ret_val);
}
/**************************************************************************
_PO_LSEEK - Move file pointer (internal)
Description
Behaves as NU_Seek but takes a file instead of a file descriptor.
Attempting to seek beyond end of file puts the file pointer one
byte past eof.
All setting up such as drive_enter and drobj_enter should have been done
before calling here.
Called By:
NU_Seek and NU_Truncate.
Returns
Returns the new offset or -1 on error.
If the return value is -1 fs_user->p_errno will be set with one of the following:
PENBADF - File descriptor invalid
PEINVAL - Seek to negative file pointer attempted.
History
NAME DATE REMARKS
S. Murrill 11/14/96 Changed _po_lseek() so that a seek to end of
file works correctly when the file ends at the
end of a cluster (SPR216)
*****************************************************************************/
LONG _po_lseek(PC_FILE *pfile, LONG offset, COUNT origin) /*__fn__*/
{
LONG file_pointer;
DDRIVE *pdrive;
BOOL past_file;
COUNT log2_bytespcluster;
ULONG ltemp;
ULONG ltemp2;
UCOUNT n_clusters_to_seek;
UCOUNT n_clusters;
UCOUNT first_cluster;
LONG ret_val;
ULONG alloced_size;
fs_user->p_errno = 0;
pdrive = pfile->pobj->pdrive;
/* If file is zero size'd. were there */
if (!(pfile->pobj->finode->fsize))
{
ret_val = 0L;
goto errex;
}
if (origin == PSEEK_SET) /* offset from begining of file */
file_pointer = offset;
else if (origin == PSEEK_CUR) /* offset from current file pointer */
{
file_pointer = (LONG) pfile->fptr;
file_pointer += offset;
}
else if (origin == PSEEK_END) /* offset from end of file */
{
file_pointer = (LONG) pfile->pobj->finode->fsize;
file_pointer += offset;
}
else /* Illegal origin */
{
fs_user->p_errno = PEINVAL;
ret_val = -1L;
goto errex;
}
if (file_pointer < 0L)
{
fs_user->p_errno = PEINVAL;
ret_val = -1L;
goto errex;
}
if (file_pointer > (LONG) pfile->pobj->finode->fsize)
{
file_pointer = (LONG) pfile->pobj->finode->fsize;
past_file = YES;
}
else
past_file = NO;
log2_bytespcluster = (COUNT) (pdrive->log2_secpalloc + 9);
/* How many clusters do we need to seek */
/* use the current cluster as the starting point if we can */
if (file_pointer >= (LONG)pfile->fptr)
{
first_cluster = pfile->fptr_cluster;
ltemp = file_pointer >> log2_bytespcluster;
ltemp2 = pfile->fptr >> log2_bytespcluster;
n_clusters_to_seek = (UCOUNT) (ltemp - ltemp2);
}
else
{
/* seek from the beginning */
first_cluster = pfile->pobj->finode->fcluster;
ltemp = file_pointer >> log2_bytespcluster;
n_clusters_to_seek = (UCOUNT) ltemp;
}
while (n_clusters_to_seek)
{
PC_FAT_ENTER(pdrive->driveno)
n_clusters = pc_get_chain(pdrive, first_cluster,
&first_cluster, n_clusters_to_seek);
PC_FAT_EXIT(pdrive->driveno)
if (!n_clusters)
{
fs_user->p_errno = PEINVAL;
ret_val = -1L;
goto errex;
}
n_clusters_to_seek -= n_clusters;
}
pfile->fptr_cluster = first_cluster;
pfile->fptr_block = pc_cl2sector(pdrive, first_cluster);
pfile->fptr= file_pointer;
/* If seeking to the end of file see if we are beyond the allocated size of
the file. If we are we set the at_eof flag so we know to try to move the
cluster pointer in case another file instance extends the file */
if (past_file)
{
/* Round the file size up to its cluster size by adding in clustersize-1
and masking off the low bits */
alloced_size = (pfile->pobj->finode->fsize + pdrive->byte_into_cl_mask) &
~(pdrive->byte_into_cl_mask);
/* If the file pointer is beyond the space allocated to the file note it
since we may need to adjust this file's cluster and block pointers
later if someone else extends the file behind our back */
if (pfile->fptr >= alloced_size)
pfile->at_eof = YES;
else
pfile->at_eof = NO;
}
else
pfile->at_eof = NO;
ret_val = pfile->fptr;
errex:
/* No only errors return through here. Everything does. */
return(ret_val);
}
/* Internal version of NU_Flush() called by NU_Flush and NU_Close */
BOOL _po_flush(PC_FILE *pfile) /*__fn__*/
{
BOOL ret_val;
/* Start by assuming success */
ret_val = YES;
fs_user->p_errno = 0;
/* Convert to native and overwrite the existing inode*/
if (!pc_update_inode(pfile->pobj))
{
ret_val = NO;
fs_user->p_errno = PENOSPC;
}
else
{
/* Flush the file allocation table */
PC_FAT_ENTER(pfile->pobj->pdrive->driveno)
if (!pc_flushfat(pfile->pobj->pdrive->driveno))
{
ret_val = NO;
fs_user->p_errno = PENOSPC;
}
PC_FAT_EXIT(pfile->pobj->pdrive->driveno)
}
return(ret_val);
}
/****************************************************************************
PO_FLUSH - Flush a file.
Description
Flush the file updating the disk.
Returns
Returns YES if all went well otherwise it returns NO and fs_user->p_errno is set to
one of these values
PENBADF - Invalid file descriptor
PENOSPC - IO error occured
****************************************************************************/
BOOL NU_Flush(PCFD fd) /*__fn__*/
{
PC_FILE *pfile;
BOOL ret_val;
PC_FS_ENTER() /* Must be last line in declarations */
CHECK_USER(BOOL, 0) /* Check if a valid user if multitasking */
/* Start by assuming success */
ret_val = YES;
fs_user->p_errno = 0;
/* Get the FILE. Take it even if an error has occured */
if ( (pfile = pc_fd2file(fd, YES)) == NULL)
{
fs_user->p_errno = PEBADF;
ret_val = NO;
goto return_error;
}
PC_DRIVE_ENTER(pfile->pobj->pdrive->driveno, NO) /* Register drive in use */
if (pfile->flag & ( PO_RDWR | PO_WRONLY ) )
{
/* Claim exclusive access on flush */
PC_INODE_ENTER(pfile->pobj->finode, YES)
if (!_po_flush(pfile))
ret_val = NO;
PC_INODE_EXIT(pfile->pobj->finode)
}
PC_DRIVE_EXIT(pfile->pobj->pdrive->driveno)
return_error: /* Not only errors return through here. Everything does. */
/* Restore the kernel state */
PC_FS_EXIT()
return(ret_val);
}
/****************************************************************************
PO_CLOSE - Close a file.
Description
Close the file updating the disk and freeing all core associated with FD.
Returns
Returns 0 if all went well otherwise it returns -1 and fs_user->p_errno is set to
one of these values
PENBADF - Invalid file descriptor
PENOSPC - IO error occured
****************************************************************************/
INT NU_Close(PCFD fd) /*__fn__*/
{
PC_FILE *pfile;
INT ret_val;
COUNT driveno;
PC_FS_ENTER() /* Must be last line in declarations */
CHECK_USER(INT, -1) /* Check if a valid user if multitasking */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -