📄 nu_file.c
字号:
return(ret_val);
}
/***************************************************************************
PO_WRITE - Write to a file.
Description
Attempt to write count bytes from buf to the current file pointer of file
at fd. The file pointer is updated.
Returns
Returns the number of bytes written 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 or open read only
PENOSPC - Write failed. Presumably because of no space
****************************************************************************/
COUNT NU_Write(PCFD fd, UTINY *buf, UCOUNT count) /*__fn__*/
{
PC_FILE *pfile;
DDRIVE *pdrive;
UCOUNT block_in_cluster;
UCOUNT byte_offset_in_block;
UCOUNT next_cluster;
ULONG saved_ptr;
ULONG saved_ptr_block;
UCOUNT saved_ptr_cluster;
ULONG ltemp;
UCOUNT n_bytes;
UCOUNT n_to_write;
UCOUNT n_left;
UCOUNT n_blocks_left;
UCOUNT n_clusters;
ULONG alloced_size;
ULONG block_to_write;
char local_buf[512];
UCOUNT ret_val;
PC_FS_ENTER() /* Must be last line in declarations */
CHECK_USER(UCOUNT, 0) /* Check if a valid user if multitasking */
fs_user->p_errno = 0;
/* Get the FILE. Second argument is ignored */
if ( (pfile = pc_fd2file(fd, NO)) == NULL)
{
fs_user->p_errno = PEBADF;
ret_val = (UCOUNT) ~0;
goto return_error;
}
if (!((pfile->flag & PO_WRONLY) || (pfile->flag & PO_RDWR)))
{
fs_user->p_errno = PEBADF;
ret_val = (UCOUNT) ~0;
goto return_error;
}
/* Return 0 (none written) on bad args */
if (!count || !buf)
{
ret_val = 0;
goto return_error;
}
pdrive = pfile->pobj->pdrive;
PC_DRIVE_ENTER(pdrive->driveno, NO) /* Register drive in use (non excl) */
/* Only one process may write at a time */
PC_INODE_ENTER(pfile->pobj->finode, YES)
/* if the file is zero sized make sure the current cluster pointer
is invalid */
if (!pfile->pobj->finode->fsize)
pfile->fptr_cluster = 0;
/* Set the cluster and block file pointers if not already set */
_synch_file_ptrs(pfile);
saved_ptr = pfile->fptr;
saved_ptr_block = pfile->fptr_block;
saved_ptr_cluster = pfile->fptr_cluster;
/* calculate initial values */
n_left = count;
/* 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);
while (n_left)
{
block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
block_in_cluster >>= 9;
if (pfile->fptr >= alloced_size)
{
/* Extending the file */
n_blocks_left = (UCOUNT) ((n_left + 511) >> 9);
/* how many clusters are left-
* assume 1 for the current cluster.
* subtract out the blocks in the current
* round up by adding secpalloc-1 and then
* divide by sectors per cluster
| n_clusters = 1 +
| (n_blocks_left-
| (pdrive->secpalloc-block_in_cluster)
| + pdrive->secpalloc-1) >> pdrive->log2_secpalloc;
==>
*/
n_clusters = ( UCOUNT) (1 +
((n_blocks_left + block_in_cluster -1) >> pdrive->log2_secpalloc));
/* Call pc_alloc_chain to build a chain up to n_cluster clusters
long. Return the first cluster in pfile->fptr_cluster and
return the # of clusters in the chain. If pfile->fptr_cluster
is non zero link the current cluster to the new one */
PC_FAT_ENTER(pdrive->driveno)
n_clusters = pc_alloc_chain(pdrive, &(pfile->fptr_cluster), n_clusters);
PC_FAT_EXIT(pdrive->driveno)
if (!n_clusters)
goto ret_bad_f;
/* Calculate the last cluster in this chain. */
next_cluster = (UCOUNT) (pfile->fptr_cluster + n_clusters -1);
/* link the chain to the directory object if just starting */
if (!pfile->pobj->finode->fcluster)
pfile->pobj->finode->fcluster = pfile->fptr_cluster;
/* calculate the new block pointer */
pfile->fptr_block = pc_cl2sector(pdrive, pfile->fptr_cluster);
/* calculate amount of space used by the file */
ltemp = n_clusters << pdrive->log2_secpalloc; ltemp <<= 9;
alloced_size += ltemp;
}
else /* Not extending the file. (writing inside the file) */
{
n_blocks_left = (UCOUNT) ((n_left + 511) >> 9);
/* how many clusters are left-
* assume 1 for the current cluster.
* subtract out the blocks in the current
* round up by adding secpalloc-1 and then
* divide by sectors per cluster
| n_clusters = 1 +
| (n_blocks_left-
| (pdrive->secpalloc-block_in_cluster)
| + pdrive->secpalloc-1) >> pdrive->log2_secpalloc;
==>
*/
n_clusters = (UCOUNT) (1 +
((n_blocks_left + block_in_cluster -1) >> pdrive->log2_secpalloc));
/* how many contiguous clusters can we get ? <= n_clusters */
PC_FAT_ENTER(pdrive->driveno)
n_clusters = pc_get_chain(pdrive, pfile->fptr_cluster,
&next_cluster, n_clusters);
PC_FAT_EXIT(pdrive->driveno)
if (!n_clusters)
goto ret_bad_f;
}
/* Are we inside a block */
if ( (pfile->fptr & 0x1ffL) || (n_left < 512) )
{
block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
block_in_cluster >>= 9;
block_to_write = pfile->fptr_block + block_in_cluster;
byte_offset_in_block = (UCOUNT) (pfile->fptr & 0x1ffL);
/* Copy source data to the local buffer */
n_bytes = (UCOUNT) (512 - byte_offset_in_block);
if (n_bytes > n_left)
n_bytes = n_left;
/* Read */
PC_DRIVE_IO_ENTER(pdrive->driveno)
if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_write, local_buf, 1, YES) )
{
PC_DRIVE_IO_EXIT(pdrive->driveno)
goto ret_bad_f;
}
copybuff(&local_buf[byte_offset_in_block], buf, n_bytes);
/* Write */
if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_write, local_buf, 1, NO) )
{
PC_DRIVE_IO_EXIT(pdrive->driveno)
goto ret_bad_f;
}
PC_DRIVE_IO_EXIT(pdrive->driveno)
buf += n_bytes;
n_left -= n_bytes;
pfile->fptr += n_bytes;
/* Are we on a cluster boundary ? */
if (!(pfile->fptr & pdrive->byte_into_cl_mask))
{
if (--n_clusters) /* If contiguous */
{
pfile->fptr_block += pdrive->secpalloc;
pfile->fptr_cluster += 1;
}
else
{
/* NOTE: Put the next cluster into the pointer. If we had
alloced a chain this value is the last cluster in
the chain and does not concur with the byte file pointer.
This is not a problem since the cluster pointer is known
to be off at this point any (fptr>=alloced_size) */
pfile->fptr_cluster = next_cluster;
pfile->fptr_block = pc_cl2sector(pdrive, next_cluster);
} /* if (--nclusters) {} else {}; */
} /* if (!(pfile->fptr & byte_into_cl_mask)) */
} /* if ( (pfile->fptr & 0x1ff) || (n_left < 512) ) */
if (n_clusters && (n_left>511))
{
/* If we get here we need to write contiguous blocks */
block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
block_in_cluster >>= 9;
block_to_write = pfile->fptr_block + block_in_cluster;
/* how many do we write ? */
n_blocks_left = (UCOUNT) (n_left >> 9);
n_to_write = (UCOUNT) ((n_clusters << pdrive->log2_secpalloc) - block_in_cluster);
if (n_to_write > n_blocks_left)
{
n_to_write = n_blocks_left;
/* If we are not writing to the end of the chain we may not
advance the cluster pointer to the beginning of the next
chain. We add in block_in_cluster so we account for the
partial cluster we've already seen */
next_cluster = (UCOUNT) (pfile->fptr_cluster +
((n_to_write+block_in_cluster) >> pdrive->log2_secpalloc));
}
PC_DRIVE_IO_ENTER(pdrive->driveno)
if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_write, buf, n_to_write, NO))
{
PC_DRIVE_IO_EXIT(pdrive->driveno)
goto ret_bad_f;
}
PC_DRIVE_IO_EXIT(pdrive->driveno)
n_bytes = (UCOUNT) (n_to_write << 9);
buf += n_bytes; n_left -= n_bytes;
pfile->fptr += n_bytes;
/* See note above */
pfile->fptr_cluster = next_cluster;
pfile->fptr_block = pc_cl2sector(pdrive, next_cluster);
}
} /* while n_left */
if (pfile->fptr > pfile->pobj->finode->fsize)
pfile->pobj->finode->fsize = pfile->fptr;
/* 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;
PC_INODE_EXIT(pfile->pobj->finode)
PC_DRIVE_EXIT(pdrive->driveno)
/* Restore the kernel state */
PC_FS_EXIT()
return(count);
ret_bad_f:
/* Restore pointers and return */
pfile->fptr = saved_ptr;
pfile->fptr_block = saved_ptr_block;
pfile->fptr_cluster = saved_ptr_cluster;
fs_user->p_errno = PENOSPC;
PC_INODE_EXIT(pfile->pobj->finode) /* Release excl use of finode */
PC_DRIVE_EXIT(pdrive->driveno) /* Release non-excl use of drive */
ret_val = (UCOUNT) ~0;
return_error:
/* Restore the kernel state */
PC_FS_EXIT()
return(ret_val);
}
/**************************************************************************
PO_LSEEK - Move file pointer
Description
Move the file pointer offset bytes from the origin described by
origin. The file pointer is set according to the following rules.
Origin Rule
PSEEK_SET offset from begining of file
PSEEK_CUR offset from current file pointer
PSEEK_END offset from end of file
Attempting to seek beyond end of file puts the file pointer one
byte past eof.
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.
*****************************************************************************/
LONG NU_Seek(PCFD fd, LONG offset, COUNT origin) /*__fn__*/
{
PC_FILE *pfile;
DDRIVE *pdrive;
LONG ret_val;
PC_FS_ENTER() /* Must be last line in declarations */
CHECK_USER(LONG, -1) /* Check if a valid user if multitasking */
fs_user->p_errno = 0;
/* Get the FILE. We don't want it if an error has occured */
pfile = pc_fd2file(fd, NO);
if (!pfile)
{
fs_user->p_errno = PEBADF;
ret_val = -1L;
goto return_error;
}
pdrive = pfile->pobj->pdrive;
PC_DRIVE_ENTER(pdrive->driveno, NO) /* Register drive in use */
/* Grab exclusive access to the drobj */
PC_INODE_ENTER(pfile->pobj->finode, YES)
/* 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_Truncate */
ret_val = _po_lseek(pfile, offset, origin);
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);
}
/**************************************************************************
NU_Truncate - Truncate an open file.
Description
Move the file pointer offset bytes from the beginning of the file
and truncate the file beyond that point by adjusting the file size
and freeing the cluster chain past the file pointer.
Returns
Returns YES if successful otherwise NO
If the return value is NO fs_user->p_errno will be set with one of the
following:
PENBADF - File descriptor invalid or open read only
PENOSPC - IO error
PEINVAL - Invalid offset
PESHARE - Can not truncate a file open by more than one handle.
---------
BobB 2/18/99 Changed name of po_truncate to NU_Truncate
*****************************************************************************/
BOOL NU_Truncate(PCFD fd, LONG offset) /*__fn__*/
{
PC_FILE *pfile;
DDRIVE *pdrive;
BOOL ret_val;
UCOUNT first_cluster_to_release;
UCOUNT last_cluster_in_chain;
UCOUNT clno;
PC_FS_ENTER() /* Must be last line in declarations */
CHECK_USER(BOOL, 0) /* Check if a valid user if multitasking */
fs_user->p_errno = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -