📄 apiext.c
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* APIEXT.C - Extensions to the API */
#include "pcdisk.h"
IMPORT PFILE_SYSTEM_USER fs_current_user_structure(void);
/* 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.
*****************************************************************************/
COUNT pc_cluster_size(TEXT *drive) /*__fn__*/
{
COUNT drive_no;
DDRIVE *pdrive;
/* get drive no */
if ( *drive && (*(drive+1) == ':'))
{
drive_no = (COUNT) (*drive - 'A');
pdrive = pc_drno2dr(drive_no);
if (pdrive)
return(pdrive->bytespcluster);
}
return(0);
}
/******************************************************************************
PO_EXTEND_FILE - Extend a file by N contiguous clusters.
Description
Given a file descriptor, n_clusters clusters and method, extend the file and
update the file size.
Method may be one of the following:
PC_FIRST_FIT - The first free chain >= n_clusters is alloced
PC_BEST_FIT - The smallest chain >= n_clusters is alloced
PC_WORST_FIT - The largest chain >= n_clusters is alloced
Note: PC_FIRST_FIT is significantly faster than the others
See: pc_find_contig_clusters()
Returns
0xffff if an error occured.
Returns n_clusters if the file was extended. Otherwise it returns the largest
free chain available. If it n_clusters is not returned the files was not extended.
If the return value is not n_clusters fs_user->p_errno will be set with one of the following:
Note: FIRST_FIT is the highest prformance option
PENBADF - File descriptor invalid or open read only
PENOSPC - IO failure
*****************************************************************************/
UCOUNT po_extend_file(PCFD fd, UCOUNT n_clusters, COUNT method) /* __fn__ */
{
UCOUNT ret_val;
UCOUNT clno;
UCOUNT n_alloced;
UCOUNT largest_chain;
UCOUNT first_cluster;
UCOUNT last_cluster_in_chain;
UCOUNT i;
ULONG ltemp;
PC_FILE *pfile;
DDRIVE *pdr;
PC_FS_ENTER() /* Must be last line in declarations */
CHECK_USER(UCOUNT, 0xffff) /* Check if a valid user if multitasking */
if (!n_clusters)
{
fs_user->p_errno = 0;
ret_val = 0;
goto return_error;
}
/* Assume error to start */
fs_user->p_errno = PENOSPC;
ret_val = 0xffff;
/* Get the FILE. Second argument is ignored */
pfile = pc_fd2file(fd, NO);
/* Make sure we have write privilages. Make sure we got a count */
if ( (!pfile) || !n_clusters || !((pfile->flag & PO_WRONLY) || (pfile->flag & PO_RDWR)))
{
fs_user->p_errno = PEBADF;
goto return_error;
}
/* From here on we exit through alloc_done so we will unlock these resources */
pdr = pfile->pobj->pdrive;
PC_DRIVE_ENTER(pdr->driveno, NO)
PC_INODE_ENTER(pfile->pobj->finode, YES) /* Exclusive */
PC_FAT_ENTER(pdr->driveno)
/* Make sure our file pointer is ok */
_synch_file_ptrs(pfile);
/* Find the end of the file's chain */
last_cluster_in_chain = 0;
clno = pfile->fptr_cluster;
while (clno)
{
last_cluster_in_chain = clno;
clno = pc_clnext(pdr , clno);
}
/* 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
*/
n_alloced = 0;
largest_chain = 0;
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 == 0xffff)
goto alloc_done;
else if (n_alloced >= n_clusters)
break; /* We got our chain */
else
{
/* We didn't get enough space. keep track of the biggest chain.
Don't need to store first_cluster since we won't alocate chains
smaller than what we need */
if (largest_chain < n_alloced)
largest_chain = 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)
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)
clno = 2;
else /* We've looked everywhere. No luck */
break;
}
if (n_alloced < n_clusters)
{
/* We didn't get what we asked for so we return the biggest free
contiguous chain */
ret_val = largest_chain;
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 (!pc_pfaxx(pdr, clno, (UCOUNT) (clno+1) ))
goto alloc_done;
}
/* Terminate the list */
if (!pc_pfaxx(pdr, clno, 0xffff))
goto alloc_done;
if (last_cluster_in_chain)
{
/* The file already has clusters in it. Append our new chain */
if (!pc_pfaxx(pdr, last_cluster_in_chain, first_cluster))
goto alloc_done;
}
else
{
/* Put our chain into the directory entry */
pfile->pobj->finode->fcluster = 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;
}
/* Now recalculate the file size */
ltemp = n_clusters;
ltemp <<= (pdr->log2_secpalloc + 9);
pfile->pobj->finode->fsize += ltemp;
/* call synch to take care of both the eof condition and the case where
we just alloced the beginning of the chain */
_synch_file_ptrs(pfile);
/* Flush the fat */
if (!pc_flushfat(pdr->driveno))
goto alloc_done;
/* Write the directory entry */
if (!pc_update_inode(pfile->pobj) )
goto alloc_done;
/* It worked ! Set the return to the number of clusters requested */
ret_val = n_clusters;
fs_user->p_errno = 0;
/* All code exits through here. ret_val determines if the function was
successful. If 0xffff it's an error. If n_clusters it's a success and
the file is expanded. Otherwise the return value */
alloc_done:
PC_FAT_EXIT(pdr->driveno)
PC_INODE_EXIT(pfile->pobj->finode)
PC_DRIVE_EXIT(pdr->driveno)
return_error:
/* Restore the kernel state */
PC_FS_EXIT()
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);
*****************************************************************************/
UCOUNT pc_find_contig_clusters(DDRIVE *pdr, UCOUNT startpt, UCOUNT *pchain, UCOUNT min_clusters, COUNT method) /* __fn__ */
{
UCOUNT i;
UCOUNT value;
UCOUNT best_chain;
UCOUNT best_size;
UCOUNT chain_start;
UCOUNT chain_size;
UCOUNT largest_size;
UCOUNT largest_chain;
UCOUNT 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 (!pc_faxx(pdr, i, &value) )
return(0xffff); /* IO error .. oops */
if (value == 0)
{
/* Cluster is free. Run some tests on it. */
if (chain_start)
{
/* We're 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(best_size);
}
else
{
*pchain = largest_chain;
return(largest_size);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -