twl_wrapsdk/build/libraries/fatfs/ARM7/apirealt.c
Shirait 4fe5688d29 add SD driver and FATFS library (tentative)
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/twl_wrapsdk/trunk@96 4ee2a332-4b2b-5046-8439-1ba90f034370
2007-05-30 10:22:28 +00:00

1091 lines
39 KiB
C

/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright EBS Inc. 1987-2003
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIREALT.C - Contains user level real time and special user level
file and FAT manipuation code.
The following routines are included:
pc_custer_size - Return the number of bytes per cluster for a drive
po_extend_file - Extend a file by with contiguous clusters.
po_chsize - Truncate or extend an open file.
pc_get_file_extents - Get the list of block segments that make up a file
pc_raw_read - Read blocks directly from a disk
pc_raw_write - Write blocks directly to a disk
pc_get_free_list - Get a list free cluster segments on the drive
*/
#include <rtfs.h>
/* PC_CLUSTER_SIZE - Return the number of bytes per cluster for a drive
Description
This function will return the cluster size mounted device
named in the argument.
Returns
The cluster size or zero if the device is not mounted.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID- Drive name is invalid
*****************************************************************************/
int pc_cluster_size(byte *drive) /*__apifn__*/
{
int driveno;
int ret_val;
DDRIVE *pdrive;
CHECK_MEM(int, 0) /* Make sure memory is initted */
rtfs_set_errno(0); /* pc_cluster_size: clear error status */
/* Get the drive and make sure it is mounted */
driveno = check_drive_name_mount(drive);
if (driveno < 0)
{
/* errno was set by check_drive */
return(0);
}
pdrive = pc_drno2dr(driveno);
ret_val = pdrive->bytespcluster;
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(ret_val);
}
/****************************************************************************
Name:
po_extend_file - Extend a file by with contiguous clusters.
Summary:
BOOLEAN po_extend_file(PCFD fd, dword_bytes, dword_*new_bytes, dword start_cluster,
int method)
Description
Given a file descriptor, n_bytes bytes and method, extend the file and
update the file size.
If the file can be extended by n_bytes contiguous bytes it will be done.
Otherwise if there is no contiguos region left on the disk that can
contain n_bytes the routine DOES NOT extend the file but does return
the length of the next largest contiguous region that is avaliable.
With this scheme an application can request to extend the file by a
given contiguous amount. If that is not possible the routine will return
the largest contiguous region available, the application can then decide
if it wishes to use this region. Please read the notes below for an
important discussion about the limitations of this routine.
The special method PC_FIXED_FIT may be used to extend the file beginning
at a specific cluster. With this method, start_cluster must be provided.
It is used as the starting point for the allocation. With this method it
is possible to precisely assign locations on the disk to file section.
This may be used for example to create interleaved files where several
files share a disk segment with interleaving clusters.
Method may be one of the following:
PC_FIRST_FIT - The first chain in which the extension will fit
PC_BEST_FIT - The smallest chain in which the extension will fit
PC_WORST_FIT - The largest chain in which the extension will fit
PC_FIXED_FIT - Extend n_clusters from start cluster
Please note the following issues and limitations.
. PC_FIRST_FIT is significantly faster than the others
. If the current end of file is not on a cluster boundary
then the region to be tested will start at the cluster
immediatley following the last cluster in the file and the
routine will allocate from the segment that starts with
that cluster or it will return the number of contiguous
bytes available starting at that cluster.
. If possible you should allocate space in contiguouos regions
that are a multiple of the drive s cluster size.
. If the PC_FIXED_FIT option is selected a start cluster must
must be supplied, n_bytes must be an even multiple of cluster
size and the file to extend must be either zero
sized or the end of file must be on a cluster boundary.
Returns
FALSE if an error occured.
TRUE if an error did not occur.
Returns n_bytes in *new_bytes if the file was extended. Otherwise it
returns the largest contiguous chain of bytes available in *new_bytes.
If it n_bytes is not returned the files was not extended.
errno is set to one of these values
0 - No error
PEBADF - Invalid file descriptor
PEACCES - File is read only
PEINVALIDPARMS - Invalid or inconsistent arguments
An ERTFS system error
*****************************************************************************/
BOOLEAN po_extend_file(PCFD fd, dword n_bytes, dword *new_bytes, dword start_cluster, int method) /* __apifn__ */
{
BOOLEAN ret_val;
CLUSTERTYPE clno;
dword n_alloced;
dword ltemp;
CLUSTERTYPE n_clusters;
CLUSTERTYPE largest_chain;
CLUSTERTYPE first_cluster;
CLUSTERTYPE last_cluster_in_chain;
CLUSTERTYPE i;
dword alloced_size;
dword new_alloced_size;
dword new_file_size;
dword range_check;
dword clusters_in_chain;
PC_FILE *pfile;
DDRIVE *pdr;
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
if (!n_bytes)
{
ret_val = TRUE;
*new_bytes = 0;
goto return_error;
}
rtfs_set_errno(0); /* po_extend_file: clear error status */
/* Assume error to start */
ret_val = FALSE;
/* Get the file structure and semaphore lock the drive */
pfile = pc_fd2file(fd, PO_WRONLY|PO_RDWR);
/* Make sure we have write privileges. Make sure we got a count */
if (!pfile)
{ /* fd2file set errno */
goto return_error;
}
first_cluster = 0;
/* From here on we exit through alloc_done so we will unlock these resources */
pdr = pfile->pobj->pdrive;
/* Make sure our file pointer is ok */
if (!_synch_file_ptrs(pfile))
{ /* synch file pointer set errno */
goto alloc_done;
}
new_file_size = pfile->pobj->finode->fsize + n_bytes;
/* Fail if it exceeds MAX_FILE_SIZE or it wraps 32 bit offset max */
if (new_file_size > RTFS_MAX_FILE_SIZE || new_file_size < pfile->pobj->finode->fsize)
{
rtfs_set_errno(PETOOLARGE); /* po_extend_file: new size too large */
goto alloc_done;
}
new_alloced_size = (new_file_size + pdr->byte_into_cl_mask) &
~(pdr->byte_into_cl_mask);
if (new_alloced_size < new_file_size)
new_alloced_size = 0xffffffff;
/* 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 + pdr->byte_into_cl_mask) &
~(pdr->byte_into_cl_mask);
if (alloced_size < pfile->pobj->finode->fsize)
alloced_size = 0xffffffff;
if (method == PC_FIXED_FIT)
{
/* Check for errors. If the old size was not on a cluster
boundary or the new size is not on a cluster boundary
or now start cluster was provided then its an error
for the FIXED_FIT option
*/
if ( ( new_alloced_size != new_file_size) ||
(alloced_size != pfile->pobj->finode->fsize) ||
!start_cluster)
{
/* If using fixed fit and not on a cluster boundary
it is an error */
rtfs_set_errno(PEINVALIDPARMS); /* po_extend_file: fixed fit and not on a cluster boundary */
goto alloc_done;
}
}
n_clusters = pc_chain_length(pdr, new_file_size) -
pc_chain_length(pdr, pfile->pobj->finode->fsize);
if (n_clusters)
{ /* We need space so try to allocate */
/* Find the end of the files chain */
last_cluster_in_chain = pfile->fptr_cluster;
clno = pfile->fptr_cluster;
{
dword ltemp,fptr_mod_cluster;
/* Round fptr down to cluster boundary */
fptr_mod_cluster = pfile->fptr & ~(pdr->byte_into_cl_mask);
/* Subtract from the rounded up alloced_size value */
ltemp = alloced_size-fptr_mod_cluster;
clusters_in_chain = ltemp >> (int) (pfile->pobj->pdrive->log2_secpalloc+9);
}
if (clusters_in_chain)
{
if ((clno < 2) || (clno > pdr->maxfindex) )
{
rtfs_set_errno(PEINVALIDCLUSTER);
goto alloc_done;
}
range_check = 0;
while (clno != 0xffffffff)
{
if (++range_check > clusters_in_chain)
break;
last_cluster_in_chain = clno;
clno = FATOP(pdr)->fatop_clnext(pdr , clno); /* File */
if (!clno) /* clnext set errno */
goto alloc_done;
}
if (range_check != clusters_in_chain)
{
rtfs_set_errno(PEINVALIDCLUSTER);
goto alloc_done;
}
if (get_errno())
goto alloc_done; /* If FATOP set errno we have trouble */
}
n_alloced = 0;
largest_chain = 0;
if ((method == PC_FIXED_FIT) || (alloced_size != pfile->pobj->finode->fsize))
{
/* If the end of file is not on a cluster boundary
see how many are avalailable that are contiguous
with the last cluster in our file */
/* Also have special code here since FIXED_FIT Works this way */
if (method == PC_FIXED_FIT)
clno = (CLUSTERTYPE) start_cluster;
else
clno = (CLUSTERTYPE) (last_cluster_in_chain + 1);
ltemp = n_clusters;
/* Walk up the FAT linearly. try for n_clusters */
while (ltemp)
{
if (!FATOP(pdr)->fatop_faxx(pdr, clno, &i) || i != 0) /* File */
break;
else
{
largest_chain++;
ltemp--;
clno++;
}
}
if (get_errno())
goto alloc_done; /* If FATOP set errno we have trouble */
if (!ltemp)
{
/* We got a contiguous region */
n_alloced = n_clusters;
largest_chain = 0;
/* That starts here */
if (method == PC_FIXED_FIT)
first_cluster = (CLUSTERTYPE) start_cluster;
else
first_cluster = (CLUSTERTYPE) last_cluster_in_chain + 1;
}
}
else
{
/* Now allocate clusters. To find the free space we look in three
regions until we find space:
1 we look from the last cluster in the file to the end of the fat
(skip 1 if there is no chain)
2 we look from the beginning of the data area to the end of the fat
3 we look from the beginning of the fat area to the end of the fat
*/
clno = last_cluster_in_chain;
if (!clno)
clno = pdr->free_contig_base;
while (clno)
{
n_alloced = pc_find_contig_clusters(pdr, clno, &first_cluster, n_clusters, method);
if (n_alloced == 0xfffffffful)
{
/* Fat operations have set errno */
ret_val = FALSE;
goto alloc_done;
}
else if ((CLUSTERTYPE)n_alloced >= n_clusters)
break; /* We got our chain */
else
{
/* We did not get enough space. keep track of the biggest chain.
Do not need to store first_cluster since we will not alocate chains
smaller than what we need */
if (largest_chain < (CLUSTERTYPE)n_alloced)
largest_chain = (CLUSTERTYPE)n_alloced;
}
/* If we were searching between from the end of the file and end of fat
look from the beginning of the file data area */
if (clno == last_cluster_in_chain)
{
if (last_cluster_in_chain == pdr->free_contig_base)
clno = 2;
else
clno = pdr->free_contig_base;
}
/* If we were searching between the beginning of the file data area
and end of fat look from the fat */
else if (clno == pdr->free_contig_base)
{
if (pdr->free_contig_base == 2)
break;
else
clno = 2;
}
else /* We have looked everywhere. No luck */
break;
}
}
if ((CLUSTERTYPE)n_alloced < n_clusters)
{
/* We did not get what we asked for so we return the biggest free
contiguous chain available in bytes plus whatever is left
in the last cluster */
*new_bytes = (largest_chain << (pdr->log2_secpalloc+9));
if (alloced_size > pfile->pobj->finode->fsize) /* Avoid wrap */
*new_bytes += (alloced_size - pfile->pobj->finode->fsize);
goto alloc_done;
}
/* else */
/* We found a large enough contiguos group of clusters */
/* Turn them into a chain */
clno = first_cluster;
for (i = 0; i < (n_clusters-1); i++, clno++)
{
/* Link the current cluster to the next one */
/* If it fails FATOP will set errno */
if (!FATOP(pdr)->fatop_pfaxx(pdr, clno, (CLUSTERTYPE) (clno+1) )) /* File */
goto alloc_done;
/* 2-19-99 - Bug fix. was not decrementing free cluster count */
pdr->known_free_clusters = (long)(pdr->known_free_clusters - 1);
}
/* Terminate the list */
if (!FATOP(pdr)->fatop_pfaxxterm(pdr, clno)) /* File */
{ /* If it fails FATOP will set errno */
goto alloc_done;
}
else
{
/* 2-19-99 - Bug fix. was not decrementing free cluster count */
pdr->known_free_clusters = (long)(pdr->known_free_clusters - 1);
}
if (last_cluster_in_chain)
{
/* The file already has clusters in it. Append our new chain */
if (!FATOP(pdr)->fatop_pfaxx(pdr, last_cluster_in_chain, first_cluster)) /* File */
{ /* If it fails FATOP will set errno */
goto alloc_done;
}
}
else
{
/* Put our chain into the directory entry */
pc_pfinode_cluster(pfile->pobj->pdrive,pfile->pobj->finode,first_cluster);
/* Use synch_pointers to set our file pointers up */
pfile->fptr_cluster = 0; /* This is already true but... */
pfile->fptr_block = 0;
pfile->fptr = 0;
}
/* Flush the fat */
if (!FATOP(pdr)->fatop_flushfat(pdr->driveno))
{ /* If it fails FATOP will set errno */
goto alloc_done;
}
}
/* If we get here it works and we should update the file size */
*new_bytes = n_bytes;
ret_val = TRUE;
pfile->pobj->finode->fsize = new_file_size;
/* Write the directory entry. Set archive & date */
if (!pc_update_inode(pfile->pobj, TRUE, TRUE) )
{ /* Update inode set errno */
ret_val = FALSE;
goto alloc_done;
}
/* call synch to take care of both the eof condition and the case where
we just alloced the beginning of the chain */
if (!_synch_file_ptrs(pfile))
{ /* synch file pointer set errno */
ret_val = FALSE;
goto alloc_done;
}
/* All code exits through here. ret_val determines if the function was
successful. If -1 it is an error. */
alloc_done:
if (!release_drive_mount_write(pdr->driveno))/* Release lock, unmount if aborted */
ret_val = FALSE;
return_error:
return(ret_val);
}
/******************************************************************************
PC_FIND_CONTIG_CLUSTERS - Find at least MIN_CLUSTER clusters.
Description
Using the provided method, search the FAT from start_pt to the
end for a free contiguous chain of at least MIN_CLUSTERS. If less
than MIN_CLUSTERS are found the largest free chain in the region is
returned.
There are three possible methods:
PC_FIRST_FIT - The first free chain >= MIN_CLUSTERS is returned
PC_BEST_FIT - The smallest chain >= MIN_CLUSTERS is returned
PC_WORST_FIT - The largest chain >= MIN_CLUSTERS is returned
Choose the method that will work best for you.
Note: PC_FIRST_FIT is significantly faster faster than the others
NOTE: The chain is not created. The caller must convert the
clusters to an allocated chain.
Returns
Returns the number of contiguous clusters found up to MIN_CLUSTERS.
*pchain contains the cluster number at the beginning of the chain.
On error return 0xffff
Example:
Get the largest free chain on the disk:
large = pc_find_contig_clusters(pdr, 2, &chain, 0xffff, PC_FIRST_FIT);
*****************************************************************************/
/* Note: the FAT is locked before this call is made */
dword pc_find_contig_clusters(DDRIVE *pdr, CLUSTERTYPE startpt, CLUSTERTYPE *pchain, CLUSTERTYPE min_clusters, int method) /* __apifn__ */
{
CLUSTERTYPE i;
CLUSTERTYPE value;
CLUSTERTYPE best_chain;
CLUSTERTYPE best_size;
CLUSTERTYPE chain_start;
CLUSTERTYPE chain_size;
CLUSTERTYPE largest_size;
CLUSTERTYPE largest_chain;
CLUSTERTYPE endpt;
best_chain = 0;
best_size = 0;
chain_start = 0;
chain_size = 0;
largest_size = 0;
largest_chain = 0;
endpt = pdr->maxfindex;
for (i = startpt; i <= endpt; i++)
{
if (!FATOP(pdr)->fatop_faxx(pdr, i, &value) ) /* File */
return(0xfffffffful); /* IO error .. oops */
if (value == 0)
{
/* Cluster is free. Run some tests on it. */
if (chain_start)
{
/* We are in a contiguous region already. Bump the count */
chain_size++;
}
else
{
/* Just starting a contiguous region */
chain_size = 1;
chain_start = i;
}
/* If using first fit see if we crossed the threshold */
if (method == PC_FIRST_FIT)
{
if (chain_size >= min_clusters)
{
best_chain = chain_start;
best_size = chain_size;
break;
}
}
} /* if value == 0*/
/* Did we just finish scanning a contiguous chain ?? */
if (chain_size && ((value != 0) || (i == endpt)) )
{
/* Remember the largest chain */
if (chain_size > largest_size)
{
largest_size = chain_size;
largest_chain = chain_start;
}
if (method == PC_BEST_FIT)
{
if (chain_size == min_clusters)
{
/* The chain is exactly the size we need take it. */
best_chain = chain_start;
best_size = chain_size;
break;
}
if (chain_size > min_clusters)
{
if (!best_chain || (chain_size < best_size))
{
/* Chain is closest to what we need so far note it. */
best_size = chain_size;
best_chain = chain_start;
}
}
} /* if BEST_FIT */
else if (method == PC_WORST_FIT)
{
if (chain_size >= min_clusters)
{
if (!best_chain || chain_size > best_size)
{
best_size = chain_size;
best_chain = chain_start;
}
}
} /* if WORST_FIT */
/*
* else if (method == PC_BEST_FIT)
* ;
*/
chain_size = 0;
chain_start = 0;
} /* if (chain_size && ((value != 0) || (i == endpt)) ) */
} /* for (i = startpt; i <= endpt; i++) */
/* If we have a best chain return it here. Else return the largest chain */
if (best_chain)
{
*pchain = best_chain;
return((dword)best_size);
}
else
{
*pchain = largest_chain;
return((dword)largest_size);
}
}
/**************************************************************************
PO_CHSIZE - Truncate or extend an open file.
Description
Given a file handle and a new file size either extend the file or
truncate it. If the current file pointer is still within the range
of the file it is unmoved, otherwise it is moved to the end of file.
Note:
This is not an ATOMIC file system operation. It uses other API calls
po_lseek, po_truncate and po_write to size, truncate and extend the
file.
Returns
Returns 0 on suucess -1 on error
errno is set with one of these values
0 - No error
PEBADF - Invalid file descriptor
PEACCES - File is read only
PEINVALIDPARMS - Invalid or inconsistent arguments
An ERTFS system error
*****************************************************************************/
int po_chsize(PCFD fd, dword offset) /*__apifn__*/
{
dword orig_fp;
dword eof_fp;
dword n_to_extend;
dword n_to_try;
dword ltemp;
int ret_val;
rtfs_set_errno(0); /* po_chsize: clear error status. routines that we call will set errno on errors */
if (!po_ulseek(fd, 0, &orig_fp, PSEEK_CUR))
return(-1);
if (!po_ulseek(fd, 0,&eof_fp, PSEEK_END))
return(-1);
/* If size is unchanged just return */
if (eof_fp == offset)
{
ret_val = 0;
}
/* If offset < eof we truncate */
else if (eof_fp > offset)
{
if (!po_truncate(fd, offset))
return(-1);
/* Restore the file pointer if we can */
if (orig_fp < offset)
po_ulseek(fd, orig_fp,&ltemp, PSEEK_SET);
return(0);
}
else
{
if (offset > RTFS_MAX_FILE_SIZE)
{
rtfs_set_errno(PETOOLARGE); /* po_extend_file: new size too large */
return(-1);
}
/* Have to extend the file */
n_to_extend = offset - eof_fp;
ret_val= 0; /* Assume it worked at first */
while (n_to_extend)
{
/* Try to extend the file. po_extend_file will either extend the
file and return the value we sent in or it will not extend the
file and return a hint of what should work */
n_to_try = n_to_extend;
while (n_to_try)
{
if (!po_extend_file(fd, n_to_try, &ltemp, 0, PC_FIRST_FIT))
{
ret_val = -1;
n_to_extend = 0; /* Force break from the outer loop */
break;
}
else
{
if (ltemp == n_to_try)
{
n_to_extend -= ltemp;/* We extended by n_to_try */
n_to_try = 0; /* Break from inner loop */
}
else
n_to_try = ltemp; /* We could not extend but ltemp
should to work so try again*/
}
}
}
}
if (!ret_val)
{
/* restore seek pointer and return */
if (!po_ulseek(fd, orig_fp, &ltemp, PSEEK_SET) || ltemp != orig_fp)
return(-1);
}
return(ret_val);
}
/***************************************************************************
Name:
pc_get_file_extents - Get the list of block segments that make up a file
Summary:
#include <rtfs.h>
int pc_get_file_extents(PCFD fd, int infolistsize,
FILESEGINFO *plist, BOOLEAN raw)
Where FILESEGINFO is a structure defined as:
typedef struct fileseginfo {
long block; Block number of the current extent
long nblocks; Number of blocks in the extent
} FILESEGINFO;
And infolistsize is the number of elements in the storage pointed to
by plist.
If raw is TRUE the blocks are reported as block offsets from the physical
base of the drive. Otherwise the block offset origin is the begining of
the partition. Set raw to TRUE if you will be using the resultant list
to set up DMA transfers to or from the disk.
Description:
This routines traverse the cluster chain of the open file fd and logs
into the list at plist the block location and length in blocks of each
segment of the file.
The block numbers and block length information can then be used to
read and write the file directly using pc_raw_read() and pc_raw_write()
or the information may be used to set up DMA transfers to or from the
raw block locations.
If the file contains more extents than will fit in plist as indicated
by infolistsize then the list is not updated beyond infolistsize elements
but the count is updated and returned so the list size may be adjusted
and the routine may be called again.
Returns
Returns the number of extents in the file or -1 on error.
errno is set to one of the following
0 - No error
PEBADF - Invalid file descriptor
An ERTFS system error
****************************************************************************/
int pc_get_file_extents(PCFD fd, int infolistsize, FILESEGINFO *plist, BOOLEAN raw) /* __apifn__ */
{
int p_errno;
int end_of_chain;
int ret_val;
int n_segments;
CLUSTERTYPE first_cluster;
CLUSTERTYPE next_cluster;
CLUSTERTYPE n_clusters_to_seek;
CLUSTERTYPE n_clusters;
long partition_start;
PC_FILE *pfile;
DDRIVE *pdrive;
CHECK_MEM(int, -1) /* Make sure memory is initted */
p_errno = 0;
rtfs_set_errno(0); /* pc_get_file_extents: clear error status. */
/* Get the file structure and semaphore lock the drive */
pfile = pc_fd2file(fd, 0);
if (!pfile)
{ /* pc_fd2file set errno */
ret_val = -1;
goto return_error;
}
pdrive = pfile->pobj->pdrive;
partition_start = pdrive->partition_base;
ret_val = 0; /* Assume Zero segments to start */
if (pfile->pobj->finode->fsize)
{
n_segments = 0;
/* How many clusters in the file */
n_clusters_to_seek = (CLUSTERTYPE)
((pfile->pobj->finode->fsize+(pdrive->secpalloc<<9)-1) >> (pdrive->log2_secpalloc+9));
first_cluster = pc_finode_cluster(pdrive,pfile->pobj->finode);
/* Traverse the file one chain at a time. Log start point (in blocks)
and the length in blocks of each segment */
while (n_clusters_to_seek)
{
/* Get the chain length and the start of the next chain */
end_of_chain = 0;
n_clusters = FATOP(pdrive)->fatop_get_chain(pdrive, first_cluster,
&next_cluster, n_clusters_to_seek, &end_of_chain);
if (!n_clusters)
{
if (!get_errno()) /* If errno set already use that */
p_errno = PEINVALIDCLUSTER;
n_segments = -1;
break;
}
n_segments += 1;
if (n_segments <= infolistsize)
{
plist->block = pc_cl2sector(pdrive,first_cluster);
if (raw)
plist->block += partition_start;
plist->nblocks = n_clusters << pdrive->log2_secpalloc;
plist++;
}
n_clusters_to_seek = (CLUSTERTYPE) (n_clusters_to_seek - n_clusters);
/* Check for corrupted file
If there are more to seek but the cluster pointer
is at the end this means that the file size is
longer than the actual chain length so set errno
to PEINVALIDCLUSTER and force error return */
if (n_clusters_to_seek && end_of_chain)
{
p_errno = PEINVALIDCLUSTER;
n_segments = -1;
break;
}
else
first_cluster = next_cluster;
}
ret_val = n_segments;
}
release_drive_mount(pdrive->driveno);/* Release lock, unmount if aborted */
return_error:
if (p_errno)
rtfs_set_errno(p_errno);
return(ret_val);
}
/****************************************************************************
Name:
pc_raw_read - Read blocks directly from a disk
Summary:
#include <rtfs.h>
int pc_raw_read(int driveno, byte *buf, long blockno, int nblocks, BOOLEAN raw_io)
Description:
Attempt to read nblocks blocks starting at blockno. If raw_io is TRUE
then blockno is the offset from the beginning of the disk itself. If
raw_io is FALSE then blockno is the offset from the beginning of the
partition.
This routine may be used in conjunction with pc_get_file_extents()
to find and read blocks without the additional overhead incurred
when calling po_read().
The maximum allowable value for nblocks is 128.
Note: It is possible to read any range of blocks in the disk.
Returns:
Returns 0 if the read succeeded or -1 on error.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID - Driveno is incorrect
PEINVALIDPARMS - Invalid or inconsistent arguments
PEIOERRORREAD - The read operation failed
An ERTFS system error
*****************************************************************************/
int pc_raw_read(int driveno, byte *buf, long blockno, int nblocks, BOOLEAN raw_io) /*__apifn__*/
{
CHECK_MEM(int, -1) /* Make sure memory is initted */
rtfs_set_errno(0); /* pc_raw_read: clear error status. */
/* return -1 if bad arguments */
if (!nblocks || !buf || (nblocks > 128))
{
rtfs_set_errno(PEINVALIDPARMS);
return(-1);
}
if (!check_drive_number_mount(driveno)) /* Check set errno */
return(-1);
/* READ */
if (!devio_read(driveno, (dword) blockno, buf, (word)nblocks, raw_io))
{
rtfs_set_errno(PEIOERRORREAD);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(-1);
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(0);
}
/****************************************************************************
Name:
pc_raw_write - Write blocks directly to a disk
Summary:
#include <rtfs.h>
int pc_raw_write(int driveno, byte *buf, long blockno, int nblocks, BOOLEAN raw_io)
Description:
Attempt to write nblocks blocks starting at blockno. If raw_io is TRUE
then blockno is the offset from the beginning of the disk itself. If
raw_io is FALSE then blockno is the offset from the beginning of the
partition.
This routine may be used in conjunction with pc_get_file_extents()
to find and read blocks without the additional overhead incurred
when calling po_read().
The maximum allowable value for nblocks is 128.
Note: It is possible to write any range of blocks in the disk.
Returns
Returns 0 if the write succeeded or -1 on error.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID - Driveno is incorrect
PEINVALIDPARMS - Invalid or inconsistent arguments
PEIOERRORWRITE - The read operation failed
An ERTFS system error
*****************************************************************************/
int pc_raw_write(int driveno, byte *buf, long blockno, int nblocks, BOOLEAN raw_io) /*__apifn__*/
{
CHECK_MEM(int, -1) /* Make sure memory is initted */
rtfs_set_errno(0); /* pc_raw_write: clear error status. */
/* return -1 if bad arguments */
if (!nblocks || !buf || (nblocks > 128))
{
rtfs_set_errno(PEINVALIDPARMS);
return(-1);
}
/* we will use release_drive_mount() not release_drive_mount_write()
since we did not change file system structures */
if (!check_drive_number_mount(driveno)) /* Check set errno */
return(-1);
if (!devio_write(driveno, (dword) blockno, buf, (word)nblocks, raw_io))
{
rtfs_set_errno(PEIOERRORWRITE);
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(-1);
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
return(0);
}
/***************************************************************************
Name:
pc_get_free_list - Get a list free cluster segments on the drive
Summary:
#include <rtfs.h>
int pc_get_free_list(byte *drivename, int listsize, FREELISTINFO *plist, long threshhold)
Where
drivename is a valid drive specifier for example C:. An empty string
denotes the current workin drive.
FREELISTINFO is a structure defined as:
typedef struct freelistinfo {
CLUSTERTYPE cluster; Cluster where the free region starts
long nclusters; Number of free clusters the free segment
} FREELISTINFO;
listsize is the number of elements in the storage pointed to
by plist.
threshhold is the smallest contiguous free region to report.
This is provided to allow the caller to exclude free chains
that are too snall to be interesting. Setting this to a higher
value also reduces the number of entries in plist that will
be used up. The value of threshold must be at least 1. If it
is one then every free cluster segment is reported.
Description:
This routines traverses the file allocation table of the drive.
It places in the results structure the starting point and size
of each free segment
The free list information may then be used by po_extend_file() to
allocate specific clusters for specific files.
If the FAT contains more free extents than will fit in plist as indicated
by listsize then the list is not updated beyond listsize elements
but the count is updated and returned so the list size may be adjusted
and the routine may be called again.
Returns
Returns the number of free segments or -1 on error.
errno is set to one of the following
0 - No error
PEINVALIDDRIVEID - Driveno is incorrect
PEINVALIDPARMS - Invalid or inconsistent arguments
An ERTFS system error
****************************************************************************/
int pc_get_free_list(int driveno, int listsize, FREELISTINFO *plist, long threshhold) /* __apifn__ */
{
CLUSTERTYPE clno;
CLUSTERTYPE value;
int index;
long region_size;
DDRIVE *pdr;
int ret_val;
int p_errno;
CHECK_MEM(PCFD, -1) /* Make sure memory is initted */
ret_val = 0;
p_errno = 0;
index = 0;
region_size = 0;
rtfs_set_errno(0); /* pc_get_free_list: clear error status. */
if (threshhold < 1)
{
rtfs_set_errno(PEINVALIDPARMS);
return(-1);
}
/* Get the drive and make sure it is mounted */
if (!check_drive_number_mount(driveno)) /* Check set errno */
return(-1);
pdr = pc_drno2dr(driveno);
for (clno = 2; clno <= pdr->maxfindex; clno++)
{
if (!FATOP(pdr)->fatop_faxx(pdr, clno, &value) ) /* Fat */
{
/* Fatop will set errno */
region_size = 0;
ret_val = -1;
break;
}
if (value == 0)
{
/* The cluster is free */
if (region_size)
{
/* We are inside a free extent so update counter */
region_size++;
}
else
{
/* Start tracking a new one */
region_size = 1;
if (index < listsize)
{
plist->cluster = clno;
}
}
}
else
{
/* Cluster is non-zero see if we need to terminate a region */
if (region_size >= threshhold && index < listsize)
{
plist->nclusters = region_size;
plist++;
}
if (region_size >= threshhold)
index++;
region_size = 0;
}
}
if (!ret_val)
{
/* If we left the for loop while still in a region note it */
if (region_size >= threshhold)
{
if (index < listsize)
{
plist->nclusters = region_size;
}
index++;
}
ret_val = index;
}
release_drive_mount(driveno);/* Release lock, unmount if aborted */
if (p_errno)
rtfs_set_errno(p_errno);
return(ret_val);
}