📄 nu_file.c
字号:
parent_is_locked = NO;
parent_obj = NULL;
pobj = NULL;
/* We'll need to know this in a few places. */
if(flag & (PO_WRONLY|PO_RDWR))
open_for_write = YES;
else
open_for_write = NO;
fs_user->p_errno = 0;
/* Get the drive number */
if (!pc_parsedrive( &driveno, name))
{
fs_user->p_errno = PENOENT;
goto errex1;
}
if ( (fd = pc_allocfile()) < 0 ) /* Grab a file */
{
fs_user->p_errno = PEMFILE;
goto errex1;
}
/* Get the FILE. This will never fail */
pfile = pc_fd2file(fd, NO);
/* Paranoia. Set the obj to null until we have one */
pfile->pobj = NULL;
PC_DRIVE_ENTER(driveno, NO) /* Register drive in use */
/* Get out the filename and d:parent */
if (!pc_parsepath(path,filename,fileext,name))
{
fs_user->p_errno = PENOENT;
goto errex;
}
/* Find the parent */
parent_obj = pc_fndnode(path);
if (!parent_obj || !pc_isadir(parent_obj) || pc_isavol(parent_obj))
{
fs_user->p_errno = PENOENT;
goto errex;
}
PC_INODE_ENTER(parent_obj->finode, YES)
parent_is_locked = YES;
pobj = pc_get_inode(NULL, parent_obj,(UTEXT*)filename,(UTEXT*)fileext);
if (pobj)
{
/* If we goto exit: we want them linked so we can clean up */
pfile->pobj = pobj; /* Link the file to the object */
/* check the sharing conditions */
if (pobj->finode->opencount != 1)
{
/* The file is already open by someone. Lets see if we are
compatible */
sharing_error = NO;
/* 1. We don't want to share with anyone */
if (flag & PO_NOSHAREANY)
sharing_error = YES;
/* 2. Someone else doesn't want to share */
if (pobj->finode->openflags & OF_EXCLUSIVE)
sharing_error = YES;
/* 3. We want exclusive write but already open for write */
if ( open_for_write && (flag & PO_NOSHAREWRITE) &&
(pobj->finode->openflags & OF_WRITE))
sharing_error = YES;
/* 4. We want open for write but it's already open for
exclusive */
if ( (open_for_write) &&
(pobj->finode->openflags & OF_WRITEEXCLUSIVE))
sharing_error = YES;
/* 5. Open for trunc when already open */
if (flag & PO_TRUNC)
sharing_error = YES;
if (sharing_error)
{
fs_user->p_errno = PESHARE;
goto errex;
}
}
if( pc_isadir(pobj) || pc_isavol(pobj) )
{
fs_user->p_errno = PEACCES; /* is a directory */
goto errex;
}
if ( (flag & (PO_EXCL|PO_CREAT)) == (PO_EXCL|PO_CREAT) )
{
fs_user->p_errno = PEEXIST; /* Exclusive fail */
goto errex;
}
if(open_for_write && (pobj->finode->fattribute & ARDONLY) )
{
fs_user->p_errno = PEACCES; /* read only file */
goto errex;
}
if (flag & PO_TRUNC)
{
cluster = pobj->finode->fcluster;
ltemp = pobj->finode->fsize;
pobj->finode->fcluster = 0;
pobj->finode->fsize = 0L;
if (pc_update_inode(pobj))
{
/* And clear up the space */
PC_FAT_ENTER(pobj->pdrive->driveno)
pc_freechain(pobj->pdrive,cluster);
pc_flushfat(pobj->pdrive->driveno);
PC_FAT_EXIT(pobj->pdrive->driveno)
}
else
{
pobj->finode->fcluster = cluster;
pobj->finode->fsize = ltemp;
fs_user->p_errno = PEACCES;
goto errex;
}
}
}
else /* File not found */
{
if (!(flag & PO_CREAT))
{
fs_user->p_errno = PENOENT; /* File does not exist */
goto errex;
}
/* Do not allow create if write bits not set */
if(!open_for_write)
{
fs_user->p_errno = PEACCES; /* read only file */
goto errex;
}
/* Create for read only if write perm not allowed */
pobj = pc_mknode( parent_obj, filename, fileext, (UTINY) ((mode == PS_IREAD) ? ARDONLY : 0));
if (!pobj)
{
fs_user->p_errno = PENOSPC;
goto errex;
}
else
pfile->pobj = pobj; /* Link the file to the object */
}
/* Set the file sharing flags in the shared finode structure */
/* clear flags if we just opened it . */
if (pobj->finode->opencount == 1)
pobj->finode->openflags = 0;
if (open_for_write)
{
pobj->finode->openflags |= OF_WRITE;
if (flag & PO_NOSHAREWRITE)
pobj->finode->openflags |= OF_WRITEEXCLUSIVE;
}
if (flag & PO_NOSHAREANY)
pobj->finode->openflags |= OF_EXCLUSIVE;
pfile->flag = flag; /* Access flags */
pfile->fptr = 0L; /* File pointer */
/* Set the cluster and block file pointers */
_synch_file_ptrs(pfile);
fs_user->p_errno = 0;
if (parent_obj)
{
if (parent_is_locked)
PC_INODE_EXIT(parent_obj->finode)
pc_freeobj(parent_obj);
}
PC_DRIVE_EXIT(driveno)
/* Restore the kernel state */
PC_FS_EXIT()
return(fd);
errex:
pc_freefile(fd);
if (parent_obj)
{
if (parent_is_locked)
PC_INODE_EXIT(parent_obj->finode)
pc_freeobj(parent_obj);
}
PC_DRIVE_EXIT(driveno)
errex1:
/* Restore the kernel state */
PC_FS_EXIT()
return(-1);
}
/****************************************************************************
PO_READ - Read from a file.
Description
Attempt to read count bytes from the current file pointer of file at fd
and put them in buf. The file pointer is updated.
Returns
Returns the number of bytes read or -1 on error.
If the return value is ((UCOUNT) ~0) (UCOUNT) -1 fs_user->p_errno will be set
with one of the following:
PENBADF - File descriptor invalid
PENOSPC - File IO error
*****************************************************************************/
COUNT NU_Read(PCFD fd, UTINY *buf, UCOUNT count) /*__fn__*/
{
PC_FILE *pfile;
UCOUNT block_in_cluster;
UCOUNT byte_offset_in_block;
UCOUNT n_bytes;
UCOUNT next_cluster;
UCOUNT n_clusters;
ULONG block_to_read;
DDRIVE *pdrive;
ULONG saved_ptr;
ULONG saved_ptr_block;
UCOUNT saved_ptr_cluster;
UCOUNT n_left;
UCOUNT n_to_read;
UCOUNT utemp;
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;
}
/* return 0 bytes read if bad arguments */
if (!count || !buf)
{
ret_val = 0;
goto return_error;
}
if (pfile->fptr >= pfile->pobj->finode->fsize) /* Dont read if done */
{
ret_val = 0;
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);
saved_ptr = pfile->fptr;
saved_ptr_block = pfile->fptr_block;
saved_ptr_cluster = pfile->fptr_cluster;
/* Truncate the read count if we need to */
if ( (pfile->fptr + count) >= pfile->pobj->finode->fsize)
count = (UCOUNT) (pfile->pobj->finode->fsize - pfile->fptr);
n_left = count;
while (n_left)
{
block_in_cluster = (UCOUNT) (pfile->fptr & pdrive->byte_into_cl_mask);
block_in_cluster >>= 9;
block_to_read = pfile->fptr_block + block_in_cluster;
/* how many clusters are left */
n_to_read = (UCOUNT) ( (n_left + 511) >> 9 );
n_clusters =(UCOUNT) ((n_to_read+pdrive->secpalloc-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) )
{
byte_offset_in_block = (UCOUNT) (pfile->fptr & 0x1ffL);
/* READ */
PC_DRIVE_IO_ENTER(pdrive->driveno)
if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_read, local_buf, 1, YES) )
{
PC_DRIVE_IO_EXIT(pdrive->driveno)
goto ret_bad_f;
}
PC_DRIVE_IO_EXIT(pdrive->driveno)
/* Copy source data to the local buffer */
n_bytes = (UCOUNT) (512 - byte_offset_in_block);
if (n_bytes > n_left)
n_bytes = n_left;
copybuff(buf, &local_buf[byte_offset_in_block], n_bytes);
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
{
pfile->fptr_cluster = next_cluster;
pfile->fptr_block = pc_cl2sector(pdrive, next_cluster);
} /* if (--nclusters) {} else {}; */
} /* if (!(pfile->fptr & pdrive->byte_into_cl_mask)) */
} /* if ( (pfile->fptr & 0x1ff) || (n_left < 512) ) */
else
{
/* Read as many blocks as possible */
/* How many blocks in the current chain */
n_to_read = (UCOUNT) (n_clusters << pdrive->log2_secpalloc);
/* subtract out any leading blocks */
n_to_read -= block_in_cluster;
/* How many blocks yet to read */
utemp = (UCOUNT) (n_left >> 9);
/* take the smallest of the two */
if (n_to_read > utemp)
n_to_read = utemp;
if (n_to_read)
{
/* If we get here we need to read contiguous blocks */
block_to_read = pfile->fptr_block + block_in_cluster;
/* READ */
PC_DRIVE_IO_ENTER(pdrive->driveno)
if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, block_to_read, buf, n_to_read,YES))
{
PC_DRIVE_IO_EXIT(pdrive->driveno)
goto ret_bad_f;
}
PC_DRIVE_IO_EXIT(pdrive->driveno)
n_bytes = (UCOUNT) (n_to_read << 9);
buf += n_bytes;
n_left -= n_bytes;
pfile->fptr += n_bytes;
/* if we advanced to a cluster boundary advance the
cluster pointer */
/* utemp ==s how many clusters we read */
utemp =(UCOUNT) ((n_to_read+block_in_cluster) >> pdrive->log2_secpalloc);
if (utemp == n_clusters)
{
pfile->fptr_cluster = next_cluster;
}
else
{
/* advance the pointer as many as we read */
pfile->fptr_cluster += utemp;
}
pfile->fptr_block = pc_cl2sector(pdrive, pfile->fptr_cluster);
}
}
} /* while n_left */
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)
PC_DRIVE_EXIT(pdrive->driveno)
ret_val = (UCOUNT) ~0;
return_error:
/* Restore the kernel state */
PC_FS_EXIT()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -