twl_wrapsdk/build/libraries/fatfs/ARM7/apickdsk.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

1347 lines
50 KiB
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.
*/
/****************************************************************************
CHKDSK.C - Check Files System Integrity
Summary
CHKDSK
Description
This program scans the disk searching for crosslinked chains and
and lost clusters. If the -f argument is present it converts lost
chains to FILE???.CHK in the root, and file sizes are adjusted if
they are not correct.
If -v is specified every file on the disk is listed. If crossed cluster
chains are found the files/directories containing them are printed.
NOTE: This program is portable except for calls to exit.
Bugs:
This routine does not recognize bad directories as well as it could.
While travesring directories it calls pc_fndnode(). This in itself is
good but we have to add validation code to fndnode and makenode (soon).
Returns:
Example:
****************************************************************************/
/* Tips for usage:
A. First run chkdsk without the save lost clusters option.
B. If there are any crossed files make copies of them. Chances are all
copies will end up fine since copy will copy only file_size bytes.
Delete the original files.
C. If there are crossed chains in a directory first recreate the
directory in another subdirectory. Then delete all files
and subdirectories inside the bad subdirectory. If the dir is
crossed with a file treat the file as in part B.
D. You will probably not be able to delete the bad directory
because it is non-empty. There is no API call similar to the
icheck -p call in unix. A very slightly modified version of
pc_unlink() could provide this service (do not check for
ADIRENT).
E. If any files are reported to have the wrong size make a copy of them.
F. run chkdsk with save lost clusters on to fix up the file system.
*/
#include <rtfs.h>
/* 10-24-2000 added LBA formatting. Submit to main tree */
typedef CLUSTERTYPE CLTYPE;
#define PATHSIZE 256
/************************************************************************
* *
* Function prototypes *
* *
************************************************************************/
void app_entry(void);
void print_crossed_files(void);
BOOLEAN allocate_chkdsk_core(void);
void free_chkdsk_core(void);
BOOLEAN write_lost_chains(void);
BOOLEAN build_chk_file(long bad_chain_no, long current_file_no, long *ret_file_no);
BOOLEAN scan_all_files(byte *dir_name);
BOOLEAN process_used_map(DROBJ *pobj, byte *filename);
BOOLEAN scan_crossed_files(byte *dir_name);
BOOLEAN process_crossed_file(DROBJ *pobj, byte *filename);
BOOLEAN add_cluster_to_lost_list(DDRIVE *pdr , CLTYPE cluster);
BOOLEAN check_lost_clusters(DDRIVE *pdr);
dword count_lost_clusters(DDRIVE *pdr);
BOOLEAN add_cluster_to_crossed(CLTYPE cluster);
CLTYPE chain_size(CLTYPE cluster);
void clr_bit(byte *bitmap, dword index);
byte get_bit(byte *bitmap, dword index);
void set_bit(byte *bitmap, dword index);
/* Provided in the vfat soecific code section */
dword scan_for_bad_lfns(DROBJ *pmom, int delete_bad_lfn);
/************************************************************************
* *
* Programmer modifiable constants *
* *
************************************************************************/
#define NCROSSED_ALLOWED 50
/* For controlling how much to alloc. You may change it . */
#define NLOST_ALLOWED 50
/* For controlling how much to alloc. You may change it . */
#define MAX_RECURSION_DEPTH 16 /* 8 */
/* For controlling how deep you will allow the directory traversal to
go. This guards against stack overflow in systems with deeply nested
subdirectories. Each recursion chews up around 160 bytes if EMAXPATH_BYTES
is 145. Less if EMAXPATH_BYTES is smaller. */
#define CL_WINDOW_SIZE 0x10000L
/* This is the size of the largest number of clusters that can be
scanned for crossed and lost chains on a single pass:
(# of passes) = (# of clusters)/CL_WINDOW_SIZE */
#define CL_BITMAP_SIZE (int) ((CL_WINDOW_SIZE+7)/8)
/* Size of the bitmap needed to process CL_WINDOW_SIZE clusters on a
single pass */
/************************************************************************
* *
* CHKDSK data structures *
* *
************************************************************************/
typedef struct crossed_file {
byte file_name[EMAXPATH_BYTES];
struct crossed_file *pnext;
} CROSSED_FILE;
typedef struct crossing_point {
CLTYPE cluster;
struct crossed_file *plist;
} CROSSING_POINT;
/* The program uses a lot of global data. To keep it manageable we put
it all in one big structure. */
typedef struct chk_global {
int be_verbose; /* BE_VERBOSE */
int fix_problems;
int write_chains; /* if 1 create chk files otherwise delete */
DDRIVE *drive_structure; /* The drive we are working on */
dword n_user_files; /* Total #user files found */
dword n_hidden_files; /* Total #hidden files found */
dword n_user_directories; /* Total #directories found */
CLTYPE n_free_clusters; /* # free available clusters */
CLTYPE n_bad_clusters; /* # clusters marked bad */
CLTYPE n_file_clusters; /* Clusters in non hidden files */
CLTYPE n_hidden_clusters; /* Clusters in hidden files */
CLTYPE n_dir_clusters; /* Clusters in directories */
CROSSED_FILE *crossed_file_freelist; /* Freelist of crossed file structures */
CROSSING_POINT crossed_points[NCROSSED_ALLOWED]; /* Array: containing cluster number and a list of
files crossed at that cluster. */
dword n_crossed_points; /* Number of crossed chains. */
CLTYPE lost_chain_list[NLOST_ALLOWED]; /* Array listheads of lost chains */
dword n_lost_chains; /* # lost chains */
dword n_lost_clusters; /* # lost clusters */
byte bm_used[CL_BITMAP_SIZE]; /* Bitmap of all clusters used
by directories/files */
/* Use a global buffer so we do not load the stack up during recursion */
byte gl_file_name[26];
byte gl_file_path[EMAXPATH_BYTES];
int recursion_depth; /* how deep in the stack we are */
dword n_bad_lfns; /* # corrupt/disjoint win95 lfn chains */
/* These fields bound the cluster map processing so we can process
disks with very large FATs by making multiple passes */
CLTYPE cl_start;
CLTYPE cl_end;
int on_first_pass;
} CHK_GLOBAL;
/************************************************************************
* *
* CHKDSK parameters - set parameters here if no console input is *
* available *
* *
************************************************************************/
#define VERBOSE TRUE
/* Set to TRUE for verbose mode; FALSE for silent mode */
void print_chkdsk_statistics(CHK_GLOBAL *pgl);
void print_chkdsk_crossed_files(CHK_GLOBAL *pgl);
/************************************************************************
* *
* GLOBAL DATA *
* *
************************************************************************/
/* This is where all the globals are kept. */
CHK_GLOBAL KS_FAR gl;
CROSSED_FILE KS_FAR crossed_file_core[NCROSSED_ALLOWED]; /* Base of the list */
/************************************************************************
* *
* MAIN PROGRAM *
* *
************************************************************************/
BOOLEAN pc_check_disk(byte *drive_id, CHKDISK_STATS *pstat, int verbose, int fix_problems, int write_chains) /* __apifn__*/
{
int drive_number,i;
byte str_slash[8];
BOOLEAN ret_val;
byte *p;
ret_val = FALSE;
rtfs_memset((byte *)&gl, 0, sizeof(gl));
gl.fix_problems = fix_problems;
gl.write_chains = write_chains;
gl.be_verbose = verbose;
/* Initialize filesystem memory */
CHECK_MEM(BOOLEAN, 0) /* Make sure memory is initted */
/* Now make \\ in native char set */
p = &str_slash[0];
CS_OP_ASSIGN_ASCII(p,'\\');
CS_OP_INC_PTR(p);
CS_OP_TERM_STRING(p);
/* Mount the disk */
drive_number = (int) check_drive_name_mount(drive_id);
if (drive_number < 0)
{
goto ex_it;
}
/* Release the lock. chkdsk is not atomic */
release_drive_mount(drive_number); /* Release lock, unmount if aborted */
gl.drive_structure = pc_drno2dr(drive_number);
if (!pc_set_default_drive(drive_id))
{
goto ex_it;
}
/* Allocate the bit maps and data structures we will need we pass in
the size of the fat so we know how many bits we will need to allocate
in our used bitmap. */
if (!allocate_chkdsk_core())
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_02,PRFLG_NL);} /* "Failed Allocating Core To Run" */
goto ex_it;
}
gl.on_first_pass = 1;
gl.cl_start = 2;
gl.cl_end = CL_WINDOW_SIZE + 2;
if (gl.cl_end > gl.drive_structure->maxfindex+1)
gl.cl_end = (CLTYPE) (gl.drive_structure->maxfindex+1);
while (gl.cl_start < gl.drive_structure->maxfindex)
{
gl.n_user_files = 0;
gl.n_hidden_files = 0;
gl.n_user_directories = 0;
/* Build a used map plus get statistics on cluster usage */
if (!scan_all_files(str_slash))
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_03,PRFLG_NL);} /* "Failed Scanning Disk Files" */
goto ex_it;
}
/* Now check if any allocated clusters are unaccounted for */
if (!check_lost_clusters(gl.drive_structure))
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_04,PRFLG_NL);} /* "Failed Scanning Fat" */
goto ex_it;
}
/* Advance the active cluster window */
gl.cl_start = gl.cl_end;
gl.cl_end += CL_WINDOW_SIZE;
if (gl.cl_end > gl.drive_structure->maxfindex+1)
gl.cl_end = (CLTYPE) (gl.drive_structure->maxfindex+1);
gl.on_first_pass = 0;
/* Clear the used cluster table */
rtfs_memset((byte *)gl.bm_used,0,CL_BITMAP_SIZE);
}
/* If there are lost chains count the clusters inside. */
if (gl.n_lost_chains)
count_lost_clusters(gl.drive_structure);
/* Now recover lost chains into .CHK files */
if (gl.fix_problems && gl.n_lost_chains)
{
if (gl.write_chains)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_05,PRFLG_NL);} /* " Creating .CHK Files" */
if (!write_lost_chains())
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_06,PRFLG_NL);} /* " Failed Creating .CHK Files" */
goto ex_it;
}
}
else
{
for (i = 0; i < (long) gl.n_lost_chains; i++)
{
if (!FATOP(gl.drive_structure)->fatop_freechain(gl.drive_structure, gl.lost_chain_list[i], 0, 0xffffffff))
goto ex_it;
}
}
}
/* If there are crossed chains we have to rescan the whole file
system looking for the files that contain he crossed chains. */
if (gl.n_crossed_points)
{
if (!scan_crossed_files(str_slash))
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_08,PRFLG_NL);} /* "Failed Scanning Crossed Files" */
goto ex_it;
}
}
/* Now print the statistics */
if (gl.be_verbose)
print_chkdsk_statistics(&gl);
/* print the names of files with crossed chains. */
if (gl.n_crossed_points)
{
if (gl.be_verbose)
{
RTFS_PRINT_STRING_1(USTRING_CHKDSK_09,PRFLG_NL); /* " Crossed Chains Were Found" */
print_chkdsk_crossed_files(&gl);
}
}
ret_val = TRUE;
pstat->n_user_files = gl.n_user_files;
pstat->n_hidden_files = gl.n_hidden_files;
pstat->n_user_directories = gl.n_user_directories;
pstat->n_free_clusters = gl.n_free_clusters;
pstat->n_bad_clusters = gl.n_bad_clusters;
pstat->n_file_clusters = gl.n_file_clusters;
pstat->n_hidden_clusters = gl.n_hidden_clusters;
pstat->n_dir_clusters = gl.n_dir_clusters;
pstat->n_crossed_points = gl.n_crossed_points;
pstat->n_lost_chains = gl.n_lost_chains;
pstat->n_lost_clusters = gl.n_lost_clusters;
pstat->n_bad_lfns = gl.n_bad_lfns;
ex_it:
return (ret_val);
}
/************************************************************************
* *
* User I/O functions *
* *
************************************************************************/
void print_chkdsk_statistics(CHK_GLOBAL *pgl)
{
dword ltemp;
if (!gl.be_verbose)
return;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)pgl->n_user_files, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_11,0); /* " user files in " */
RTFS_PRINT_LONG_1 ((dword)pgl->n_user_directories, PRFLG_NL);
ltemp = pgl->drive_structure->numsecs;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)(ltemp/2), 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_13, PRFLG_NL); /* " KBytes total disk space" */
ltemp = (dword) pgl->n_hidden_clusters;
ltemp *= (dword) pgl->drive_structure->secpalloc;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)(ltemp/2), 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_15, 0); /* " KBytes in " */
RTFS_PRINT_LONG_1 ((dword)pgl->n_hidden_files, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_16, PRFLG_NL); /* " hidden files" */
ltemp = (dword) pgl->n_dir_clusters;
ltemp *= (dword) pgl->drive_structure->secpalloc;
ltemp += (dword) pgl->drive_structure->secproot;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)(ltemp/2), 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_18, 0); /* " KBytes in " */
RTFS_PRINT_LONG_1 ((dword)pgl->n_user_directories, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_19, PRFLG_NL); /* " directories" */
ltemp = (dword) pgl->n_file_clusters;
ltemp *= (dword) pgl->drive_structure->secpalloc;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)(ltemp/2), 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_21, 0); /* " KBytes in " */
RTFS_PRINT_LONG_1 ((dword)pgl->n_user_files, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_22, PRFLG_NL); /* " user files" */
ltemp = (dword) pgl->n_bad_clusters;
ltemp *= (dword) pgl->drive_structure->secpalloc;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)(ltemp/2), 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_24, PRFLG_NL); /* " KBytes in bad sectors" */
ltemp = (dword) pgl->n_free_clusters;
ltemp *= (dword) pgl->drive_structure->secpalloc;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)(ltemp), 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_26, PRFLG_NL); /* " Free sectors available on disk" */
ltemp = (dword) pgl->drive_structure->secpalloc * 512;
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, PRFLG_NL); /* " " */
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)ltemp, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_29, PRFLG_NL); /* " Bytes Per Allocation Unit" */
ltemp = (dword)(pgl->drive_structure->maxfindex - 1);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_30, PRFLG_NL); /* "" */
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1 ((dword)ltemp, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_32, PRFLG_NL); /* " Total Allocation Units On Disk" */
RTFS_PRINT_STRING_1(USTRING_SYS_NULL, PRFLG_NL); /* "" */
if (pgl->n_lost_chains)
{
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1((dword)pgl->n_lost_clusters, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_35, 0); /* " lost clusters found in " */
RTFS_PRINT_LONG_1((dword)pgl->n_lost_chains, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_36, PRFLG_NL); /* " lost chains" */
}
if (pgl->n_bad_lfns)
{
RTFS_PRINT_STRING_1(USTRING_SYS_TAB, 0); /* " " */
RTFS_PRINT_LONG_1((dword)pgl->n_bad_lfns, 0);
RTFS_PRINT_STRING_1(USTRING_CHKDSK_38, 0); /* " bad long file name chains found" */
if (pgl->fix_problems)
RTFS_PRINT_STRING_1(USTRING_CHKDSK_39, PRFLG_NL); /* " and deleted" */
else
RTFS_PRINT_STRING_1(USTRING_CHKDSK_40, PRFLG_NL); /* " that were not deleted" */
}
}
/* Print the names of all files that we were able to determine were crossed */
void print_chkdsk_crossed_files(CHK_GLOBAL *pgl) /*__fn__*/
{
int i;
CROSSED_FILE *pcross;
int n_printed;
for (i = 0; i < (int) pgl->n_crossed_points; i++)
{
if (gl.be_verbose)
{
RTFS_PRINT_STRING_1(USTRING_CHKDSK_41, 0); /* " Chains Crossed at Cluster" */
RTFS_PRINT_LONG_1((dword) pgl->crossed_points[i].cluster, PRFLG_NL);
}
pcross = pgl->crossed_points[i].plist;
n_printed = 0;
while (pcross)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_42, pcross->file_name, PRFLG_NL);} /* " " */
pcross = pcross->pnext;
n_printed += 1;
}
if (gl.be_verbose)
{
if (!n_printed)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_43, PRFLG_NL);} /* " Lost Chains" */
else if (n_printed == 1)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_44, PRFLG_NL);} /* " A Lost Chain" */
}
}
}
/************************************************************************
* *
* Init/exit functions *
* *
************************************************************************/
/* Allocate core for bitmaps, lost chains and crossed files. */
BOOLEAN allocate_chkdsk_core(void) /*__fn__*/
{
long i;
gl.recursion_depth = 0;
rtfs_memset((byte *)gl.bm_used, 0, CL_BITMAP_SIZE);
rtfs_memset((byte *)gl.crossed_points, 0, NCROSSED_ALLOWED*sizeof(CROSSING_POINT));
rtfs_memset((byte *)gl.lost_chain_list, 0, NLOST_ALLOWED * sizeof(CLTYPE));
/* Build a freelist we can use for crossed files */
gl.crossed_file_freelist = crossed_file_core;
for (i = 0; i < NCROSSED_ALLOWED-1; i++)
{
gl.crossed_file_freelist->pnext = gl.crossed_file_freelist+1;
gl.crossed_file_freelist++;
}
gl.crossed_file_freelist->pnext = 0;
gl.crossed_file_freelist = crossed_file_core;
return(TRUE);
}
void free_chkdsk_core() /*__fn__*/
{
}
/************************************************************************
* *
* Functions for saving lost chains to CHK files *
* *
************************************************************************/
/* Create a FILEXXXX.CHK file for each found lost chain */
BOOLEAN write_lost_chains() /*__fn__*/
{
long current_chk_file;
long i;
current_chk_file = 0;
for (i = 0; i < (long) gl.n_lost_chains; i++)
{
if (!build_chk_file(i, current_chk_file, &current_chk_file))
return(FALSE);
}
return(TRUE);
}
/* Given a lost chain number and a likely starting point for the
FILE???.CHK file create the file from the lost chain. */
BOOLEAN build_chk_file(long bad_chain_no, long current_file_no, long *ret_file_no) /*__fn__*/
{
long remainder;
long temp;
int fd;
PC_FILE *pfile;
DDRIVE *pdrive;
byte filename[13];
byte cs_filename[26];
for ( ; current_file_no < 999; current_file_no++)
{
/* Create a file name */
rtfs_strcpy((byte *) &filename[0], (byte *) (CS_OP_ASCII("\\FILE000.CHK")));
temp = (long) (current_file_no/100);
filename[5] = (byte) (CS_OP_ASCII('0') + temp);
remainder = (long) (current_file_no - (temp * 100));
temp = (long) (remainder/10);
filename[6] = (byte) (CS_OP_ASCII('0') + (byte) temp);
remainder = (long) (remainder - (temp * 10));
filename[7] = (byte) (CS_OP_ASCII('0') + remainder);
/* Map to the native character set */
CS_OP_ASCII_TO_CS_STR(cs_filename, filename);
/* Try to open it exclusive. This will fail if the file exists */
fd = (int)po_open(cs_filename, (word)PO_CREAT|PO_EXCL|PO_WRONLY, (word)PS_IREAD|PS_IWRITE);
if (fd >= 0)
{
/* Get underneath the file and set the first cluster to the
beginning of the lost_chain. */
/* Get the file structure and semaphore lock the drive */
pfile = pc_fd2file(fd, FALSE);
if (pfile)
{
pdrive = pfile->pobj->pdrive;
pc_pfinode_cluster(pfile->pobj->pdrive,pfile->pobj->finode,
gl.lost_chain_list[bad_chain_no]);
/* Update the size. */
pfile->pobj->finode->fsize = chain_size(pc_finode_cluster(pfile->pobj->pdrive,pfile->pobj->finode));
pfile->needs_flush = TRUE;
release_drive_mount(pdrive->driveno); /* Release lock, unmount if aborted */
}
/* Close the file. This will write everything out. */
po_close(fd);
break;
}
}
/* If we get here it did not work */
if (current_file_no == 999)
return(FALSE);
/* Return the next ??? for FILE???.CHK that will probably work */
*ret_file_no = (int) (current_file_no + 1);
return(TRUE);
}
/************************************************************************
* *
* File/Directory Scanning *
* *
************************************************************************/
/* Scan all files/directories on the drive -
* Mark all used clusterd in the used bit map.
* Note any crossed cluster chains
* Adjust any incorrect file sizes
*/
/* int scan_all_files(byte *dir_name)
*
* This routine scans all subdirectories and does the following:
* . calculates gl.n_user_directories
* . calculates gl.n_hidden_files
* . calculates gl.n_user_files
* Then it calls process_used_map for each file in the directory and
* for the directory itself .
* process_used_map does the following:
* . calculates gl.n_dir_clusters
* . calculates gl.n_hidden_clusters
* . calculates gl.n_file_clusters
* . notes and if writing adjusts incorrect filesizes
* . finds crossed chains
* . calls scan_for_bad_lfns
* .
* . scan_all_files calls itself recursively for each subdirectory it
* . encounters.
* .
* .
*/
BOOLEAN scan_all_files(byte *dir_name) /*__fn__*/
{
DROBJ *directory;
DROBJ *entry;
byte ldir_name[EMAXPATH_BYTES];
if (gl.recursion_depth > MAX_RECURSION_DEPTH)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_45, dir_name,PRFLG_NL);} /* "Path too deep , directory == " */
return(FALSE);
}
gl.recursion_depth += 1;
/* Only do this on the first pass */
if (gl.on_first_pass)
{
/* Find the directory again for scanning the dir for lfn errors */
directory = pc_fndnode(dir_name);
if (!directory)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_46, dir_name,PRFLG_NL);} /* "Failed Scanning This Directory on LFN Pass -" */
return(FALSE);
}
/* Scan through the directory looking for bad lfn data */
gl.n_bad_lfns += scan_for_bad_lfns(directory, gl.fix_problems);
pc_freeobj(directory);
}
/* Find the directory for scanning the dir for files */
directory = pc_fndnode(dir_name);
if (!directory)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_47, dir_name,PRFLG_NL);} /* "Failed Scanning This Directory -" */
return(FALSE);
}
if (gl.be_verbose && gl.on_first_pass)
{
RTFS_PRINT_STRING_2(USTRING_SYS_NULL,dir_name,PRFLG_NL);
}
if (!pc_isroot(directory))
gl.n_user_directories += 1;
/* Mark all of this Dirs clusters IN use, and look for crossed chains */
if (!process_used_map(directory, dir_name))
{
pc_freeobj(directory);
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_48, dir_name,PRFLG_NL);} /* "Failed Scanning This Directory -" */
return(FALSE);
}
/* Scan through the directory looking for all files */
entry = pc_get_inode(0,directory, 0, 0, GET_INODE_STAR);
if (entry)
{
do
{
if (!(entry->finode->fattribute & (AVOLUME | ADIRENT) ))
{
pc_cs_mfile((byte*)gl.gl_file_name, (byte*)entry->finode->fname,(byte *) entry->finode->fext);
pc_mpath((byte *)gl.gl_file_path, (byte *)dir_name, (byte *)gl.gl_file_name);
if (gl.be_verbose && gl.on_first_pass)
{
RTFS_PRINT_STRING_2(USTRING_CHKDSK_49, gl.gl_file_path,PRFLG_NL); /* " " */
}
if (entry->finode->fattribute & AHIDDEN)
gl.n_hidden_files += 1;
else
gl.n_user_files += 1;
/* Mark all of this File s clusters IN use, check the size
and look for crossed chains */
if (!process_used_map(entry, gl.gl_file_path))
{
pc_freeobj(entry);
pc_freeobj(directory);
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_50, gl.gl_file_path,PRFLG_NL);} /* "Failed Scanning This File " */
return(FALSE);
}
}
} while (pc_get_inode(entry , directory, 0, 0, GET_INODE_STAR));
pc_freeobj(entry);
}
pc_freeobj(directory);
/* Now we call scan_all_files() for each subdirectory */
/* Find the directory for scanning the dir for files */
directory = pc_fndnode(dir_name);
if (!directory)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_51, dir_name,PRFLG_NL);} /* "Failed Scanning This Directory -" */
return(FALSE);
}
/* Scan through the directory looking for all files */
entry = pc_get_inode(0,directory, 0, 0, GET_INODE_STAR);
if (entry)
{
do
{
/* Scan it if it is a directory and not . or .. */
if (entry->finode->fattribute & ADIRENT)
{
if ( !pc_isdot(entry->finode->fname, entry->finode->fext) &&
!pc_isdotdot(entry->finode->fname, entry->finode->fext) )
{
pc_cs_mfile((byte *)gl.gl_file_name, (byte *)entry->finode->fname, (byte *)entry->finode->fext);
pc_mpath((byte *)ldir_name, (byte *)dir_name, (byte *)gl.gl_file_name);
if (!scan_all_files(ldir_name))
{
pc_freeobj(directory);
pc_freeobj(entry);
return(FALSE);
}
}
}
} while (pc_get_inode(entry , directory, 0, 0, GET_INODE_STAR));
pc_freeobj(entry);
}
pc_freeobj(directory);
gl.recursion_depth -= 1;
return (TRUE);
}
/* process_used_map(DROBJ *pobj, byte *filename)
*
* This routine is called for each subdirectory and file in the system.
* It traverses the chain owned by drobj and does the following with each
* cluster in the chain:
* . updates gl.n_dir_clusters or ..
* . updates gl.n_hidden_clusters or ..
* . updates gl.n_file_clusters
* It then checks the bit map of already accounted for clusters, if the
* cluster is accounted for it adds the cluster to the list of lost
* chains by calling add_cluster_to_crossed(), if another cluster in the
* chain was already found to be crossed we do not call add_cluster_to_crossed()
* since it works with the whole chain.
*
* After the chain has been traversed its size is compared with the size
* recorded in the directory. If they differ the file is printed and if -f
* was specified the size is adjusted.
*/
BOOLEAN process_used_map(DROBJ *pobj, byte *filename) /*__fn__*/
{
CLTYPE cluster;
CLTYPE n_clusters;
CLTYPE proper_size;
CLTYPE true_size;
dword t1,t2,t3;
BOOLEAN is_dir;
BOOLEAN is_hidden;
BOOLEAN found_an_intersection;
is_hidden = FALSE;
if (pc_isroot(pobj))
/* FAT32 stores the root directory as a cluster chain */
{
if (pobj->pdrive->fasize == 8) /* FAT32 volume */
{
cluster = pc_sec2cluster(pobj->pdrive,pobj->pdrive->rootblock);
is_dir = TRUE;
}
else
return(TRUE);
}
else
{
/* For tracking crossed chains. We only want to note the intersection
points of lost chains not every cluster in the chain. */
if (pobj->finode->fattribute & ADIRENT)
is_dir = TRUE;
else
{
if (pobj->finode->fattribute & AHIDDEN)
is_hidden = TRUE;
else
is_hidden = FALSE;
is_dir = FALSE;
}
cluster = pc_finode_cluster(pobj->pdrive, pobj->finode);
}
found_an_intersection = FALSE;
n_clusters = 0;
/* If the incoming value is bad do not traverse */
if ((cluster < 2) || (cluster > pobj->pdrive->maxfindex) )
cluster = 0;
/* 0xffffffff is gnext's end marker, 0 is error */
while (cluster && cluster != 0xffffffff)
{
n_clusters += 1;
if ( (gl.cl_start <= cluster) && (cluster < gl.cl_end) )
{
/* If the cluster is already in use we have a problem its
a crossed chain */
if ( get_bit(gl.bm_used, cluster - gl.cl_start) )
{
if (!found_an_intersection)
{
if (!add_cluster_to_crossed(cluster))
return(FALSE);
found_an_intersection = TRUE;
}
}
set_bit(gl.bm_used, cluster - gl.cl_start);
}
cluster = FATOP(pobj->pdrive)->fatop_clnext(pobj->pdrive, cluster); /* Fat */
}
if (gl.on_first_pass)
{
if (is_dir)
{
/* To do in version 5. if (n_clusters == 0) convert directory
to a file */
gl.n_dir_clusters = (CLTYPE) (gl.n_dir_clusters + n_clusters);
}
else
{
if (is_hidden)
gl.n_hidden_clusters = (CLTYPE) (gl.n_hidden_clusters + n_clusters);
else
gl.n_file_clusters = (CLTYPE) (gl.n_file_clusters + n_clusters);
/* Check the file size here */
/* Re-use the true size variable to save a little stack (we are
inside a recursive algorithm here */
#define cl_size_minus_1 true_size
cl_size_minus_1 = pobj->pdrive->secpalloc;
cl_size_minus_1 <<= 9; /* *= 512 */
cl_size_minus_1 -=1;
/* proper_size =
(pobj->finode->fsize + cl_size_minus_1) & ~cl_size_minus_1;
*/
t1 = (dword) cl_size_minus_1;
t2 = (dword) (pobj->finode->fsize + t1);
t3 = (dword) (t2 & ~t1);
/* This is how many bytes the file should occupy in the FAT. */
proper_size = (CLTYPE) t3;
#undef cl_size_minus_1
true_size = n_clusters;
true_size <<= pobj->pdrive->log2_secpalloc;
true_size <<= 9; /* *= 512 */
if (proper_size != true_size)
{
/* Size in the directory entry does not match the size of the
chain. If -f was specified update the file size in the directory */
if (gl.fix_problems)
{
pobj->finode->fsize = true_size;
if (pobj->finode->fsize == 0)
{ /* File is zero sized so zero the cluster pointer */
pc_pfinode_cluster(pobj->pdrive, pobj->finode, 0);
}
if (!pc_update_inode(pobj, TRUE, TRUE))
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_52, filename,PRFLG_NL);} /* "Failed Writing This Adusted File: " */
return(FALSE);
}
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_53, filename, PRFLG_NL);} /* "Size Adusted, This File: " */
}
else
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_54, filename,PRFLG_NL);} /* "Size Needs Adusting This File: " */
}
}
}
} /* if (on_first_pass) */
return(TRUE);
}
/************************************************************************
* *
* Lost cluster fns *
* *
************************************************************************/
/* check_lost_clusters(DDRIVE *pdr)
*
* This routine is called by (app_entry()) after scan_all_files() was called
* to produce the bm_used bitmap of clusters cliamed by files and
* sub-direcories.
* It scans the FILE allocation table. A cluster is lost if it
* is allocated in the FAT but not in the bm_used bitmap we built up while
* scanning the file system (scan_all_files()). We maintain an array of
* chain heads of lost clusters.
*/
BOOLEAN check_lost_clusters(DDRIVE *pdr) /*__fn__*/
{
CLTYPE cluster;
CLTYPE nxt;
for (cluster = gl.cl_start ; cluster < gl.cl_end; cluster++)
{
if (!FATOP(pdr)->fatop_faxx(pdr, cluster, &nxt)) /* Fat */
{
return(FALSE);
}
if (nxt != 0)
{
/* If we did not see the cluster during the directory scan */
if ( !get_bit(gl.bm_used, cluster - gl.cl_start) )
{
/* ff(f)7 marks a bad cluster if it is not already in
a chain. */
if ( ((pdr->fasize == 3) && (nxt == 0xff7)) ||
((pdr->fasize == 4) && (nxt == 0xfff7))
|| ((pdr->fasize == 8) && (nxt == 0xfffffff7ul))
)
gl.n_bad_clusters += 1;
if ( ((pdr->fasize == 3) && ((nxt < 0xff0) || (nxt > 0xff8))) ||
((pdr->fasize == 4) && ((nxt < 0xfff0) || (nxt > 0xfff8)))
|| ((pdr->fasize == 8) && ((nxt < 0xfffffff0ul) || (nxt > 0xfffffff8ul)))
)
{
/* And if it is not a bad or reserved cluster */
/* Add it to the lost list */
if (!add_cluster_to_lost_list(pdr, cluster))
return(FALSE);
}
}
}
else
gl.n_free_clusters += 1;
}
return (TRUE);
}
/* int add_cluster_to_lost_list(pdrive, cluster)
*
* This routine is called by check_lost_clusters. It takes a cluster known
* to be lost and adds the chain which it heads to the lost chain list. If a
* chain head in the lost chain list is a member of the chain headed by
* cluster, it is replaced. With cluster.
*/
BOOLEAN add_cluster_to_lost_list(DDRIVE *pdr , CLTYPE cluster) /*__fn__*/
{
CLTYPE first_cluster_in_chain;
int i;
BOOLEAN found;
/* Save the top of the chain */
first_cluster_in_chain = cluster;
/* No need to check the incoming cluster argument, known good */
found = FALSE;
/* 0xffffffff is gnext's end marker, 0 is error */
while (cluster && cluster != 0xffffffff)
{
/* See if this cluster is the head of another lost chain
If so replace the head of that chain with the head of
the chain we are traversing */
if (!found)
{
for (i = 0; i < (int)gl.n_lost_chains; i++)
{
if (gl.lost_chain_list[i] == cluster)
{
gl.lost_chain_list[i] = first_cluster_in_chain;
found = TRUE;
break;
}
}
}
/* Now mark the cluster used. - we do this so we do not re-process
any of the clusters in this chain */
if ((gl.cl_start <= cluster) && (cluster < gl.cl_end))
{
set_bit(gl.bm_used, cluster - gl.cl_start);
}
cluster = FATOP(pdr)->fatop_clnext(pdr, cluster); /* Fat */
}
/* If we did not attach the chain to a list we already had we will
add it to the end */
if (!found)
gl.lost_chain_list[gl.n_lost_chains++] = first_cluster_in_chain;
if (gl.n_lost_chains >= NLOST_ALLOWED)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_55,PRFLG_NL);} /* "Chkdsk Giving up. Too Many Lost Chains" */
return(FALSE);
}
return(TRUE);
}
/* count_lost_clusters(DDRIVE *pdr)
*
* This routine scans the lost chain list and tallies the total number of
* clusters that were found.
*/
dword count_lost_clusters(DDRIVE *pdr) /*__fn__*/
{
int i;
CLTYPE cluster;
gl.n_lost_clusters = 0;
for (i = 0; i < (int)gl.n_lost_chains; i++)
{
cluster = gl.lost_chain_list[i];
/* clnext will return zero but check range for initial value */
if ((cluster < 2) || (cluster > pdr->maxfindex) )
cluster = 0;
/* 0xffffffff is gnext's end marker, 0 is error */
while (cluster && cluster != 0xffffffff)
{
gl.n_lost_clusters++;
cluster = FATOP(pdr)->fatop_clnext(pdr, cluster); /* Fat */
}
}
return(gl.n_lost_clusters);
}
/************************************************************************
* *
* Crossed chain fns *
* *
************************************************************************/
/* scan_crossed_files()
*
* This routine scans all files and subdirectories in the whole filesystem.
* For each cluster it looks to see if it is in the crossed file list that
* we generated earlier. If the cluster is found the file or subdirectory
* is added to the list of crossed files at that cluster.
*/
BOOLEAN scan_crossed_files(byte *dir_name) /*__fn__*/
{
DROBJ *directory;
DROBJ *entry;
byte ldir_name[EMAXPATH_BYTES];
/* Find the directory for scanning the dir for files */
directory = pc_fndnode(dir_name);
if (!directory)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_56, dir_name, PRFLG_NL);} /* "Failed Scanning This Directory " */
return(FALSE);
}
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_SYS_NULL,dir_name, PRFLG_NL);}
if (!pc_isroot(directory))
gl.n_user_directories += 1;
/* See if this directory is crossed with another */
if (!process_crossed_file(directory, dir_name))
{
pc_freeobj(directory);
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_57, dir_name, PRFLG_NL);} /* "Failed Scanning This Directory " */
return(FALSE);
}
/* Scan through the directory looking for all files */
entry = pc_get_inode(0,directory, 0, 0, GET_INODE_STAR);
if (entry)
{
do
{
if (!(entry->finode->fattribute & (AVOLUME | ADIRENT) ))
{
pc_cs_mfile((byte *)gl.gl_file_name, (byte *)entry->finode->fname, (byte *)entry->finode->fext);
pc_mpath((byte *)gl.gl_file_path, (byte *)dir_name, (byte *)gl.gl_file_name);
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_58, gl.gl_file_path, PRFLG_NL);} /* " " */
/* See if this file is crossed with another */
if (!process_crossed_file(entry, gl.gl_file_path))
{
pc_freeobj(entry);
pc_freeobj(directory);
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_59, gl.gl_file_path,PRFLG_NL);} /* "Failed Scanning This File " */
return(FALSE);
}
}
} while (pc_get_inode(entry , directory, 0, 0, GET_INODE_STAR));
pc_freeobj(entry);
}
pc_freeobj(directory);
/* Now we call scan_crossed_files() for each subdirectory */
/* Find the directory for scanning the dir for files */
directory = pc_fndnode(dir_name);
if (!directory)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_2(USTRING_CHKDSK_60, dir_name, PRFLG_NL);} /* "Failed Scanning This Directory " */
return(FALSE);
}
/* Scan through the directory looking for all files */
entry = pc_get_inode(0,directory, 0, 0, GET_INODE_STAR);
if (entry)
{
do
{
/* Scan it if it is a directory and not "." or ".." */
if (entry->finode->fattribute & ADIRENT)
{
if ( !pc_isdot(entry->finode->fname, entry->finode->fext) &&
!pc_isdotdot(entry->finode->fname, entry->finode->fext) )
{
pc_cs_mfile((byte *)gl.gl_file_name, (byte *)entry->finode->fname, (byte *)entry->finode->fext);
pc_mpath((byte *)ldir_name, (byte *)dir_name, (byte *)gl.gl_file_name);
if (!scan_crossed_files(ldir_name))
{
pc_freeobj(directory);
pc_freeobj(entry);
return(FALSE);
}
}
}
} while (pc_get_inode(entry , directory, 0, 0, GET_INODE_STAR));
pc_freeobj(entry);
}
pc_freeobj(directory);
return (TRUE);
}
/* Given the file or directory at pobj see if any of its clusters are
crossed with another file or directory. */
BOOLEAN process_crossed_file(DROBJ *pobj, byte *filename) /*__fn__*/
{
CLTYPE cluster;
int i;
CROSSED_FILE *pcross;
if (pc_isroot(pobj))
return(TRUE);
cluster = pc_finode_cluster(pobj->pdrive, pobj->finode);
/* If the incoming value is bad do not traverse */
if ((cluster < 2) || (cluster > pobj->pdrive->maxfindex) )
cluster = 0;
/* 0xffffffff is gnext's end marker, 0 is error */
while (cluster && cluster != 0xffffffff)
{
if ((cluster < 2) || (cluster > pobj->pdrive->maxfindex) )
break;
for (i = 0; i < (int)gl.n_crossed_points; i++)
{
/* If this cluster intersects with another chain. */
if (gl.crossed_points[i].cluster == cluster)
{
pcross = gl.crossed_points[i].plist;
while (pcross)
{
/* If already in the list for this cluster continue
processing the next cluster. */
if (rtfs_cs_strcmp(pcross->file_name, filename) == 0)
break;
pcross = pcross->pnext;
}
if (!pcross)
{
/* Add this file/dir name to the list of files crossed
at this point */
if (!gl.crossed_file_freelist)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_61,PRFLG_NL);} /* "Chkdsk gives up, too many crossed Files" */
return(FALSE);
}
else
{
/* Add the file to the beginning of the list of files
crossed at this cluster */
pcross = gl.crossed_file_freelist;
gl.crossed_file_freelist = pcross->pnext;
pcross->pnext = gl.crossed_points[i].plist;
gl.crossed_points[i].plist = pcross;
rtfs_cs_strcpy(pcross->file_name, filename);
}
}
}
}
cluster = FATOP(pobj->pdrive)->fatop_clnext(pobj->pdrive, cluster); /* Fat */
}
return(TRUE);
}
/* add_cluster_to_crossed(cluster)
*
* This routine is called by process_used_map if it detects a crossed
* chain (by finding a cluster that is already marked in the used map)
* It scans the list of crossed clusters. If cluster is not already in
* the list it is added. If we exceed the predefined value NCROSSED_ALLOWED
* it returns FALSE.
*/
BOOLEAN add_cluster_to_crossed(CLTYPE cluster) /*__fn__*/
{
int i;
if (gl.n_crossed_points >= NCROSSED_ALLOWED)
{
if (gl.be_verbose)
{RTFS_PRINT_STRING_1(USTRING_CHKDSK_62,PRFLG_NL);} /* "Chkdsk gives up, Too many crossed chains" */
return(FALSE);
}
for (i = 0; i < (int) gl.n_crossed_points; i++)
{
if (gl.crossed_points[i].cluster == cluster)
return(TRUE);
}
gl.crossed_points[gl.n_crossed_points].cluster = cluster;
gl.n_crossed_points += 1;
return(TRUE);
}
/************************************************************************
* *
* Utility Functions *
* *
************************************************************************/
/* chain_size (CLTYPE cluster)
*
* Calculate (return) a chain s size in bytes
*
* Called by: build_chk_file
*/
CLTYPE chain_size(CLTYPE cluster) /*__fn__*/
{
CLTYPE n_clusters;
n_clusters = 0;
/* If the incoming value is bad do not traverse */
if ((cluster < 2) || (cluster > gl.drive_structure->maxfindex))
cluster = 0;
/* 0xffffffff is gnext's end marker, 0 is error */
while (cluster && cluster != 0xffffffff)
{
n_clusters = (CLTYPE) (n_clusters + 1);
cluster = FATOP(gl.drive_structure)->fatop_clnext(gl.drive_structure, cluster); /* Fat */
}
n_clusters = (CLTYPE) (n_clusters * gl.drive_structure->secpalloc);
n_clusters *= (CLTYPE) 512;
return(n_clusters);
}
/* clr_bit (byte *bitmap, dword index)
*
* Clear the bit at bitmap[index]
*/
void clr_bit(byte *bitmap, dword index)
{
bitmap[(dword) (index >> 3)] &= ~(1 << (index & 0x7));
}
/* get_bit (byte *bitmap, dword index)
*
* Return the bit at bitmap[index] (assuming bitmap is a bit array)
*/
byte get_bit(byte *bitmap, dword index)
{
return ((byte)(bitmap[(dword) (index >> 3)] & (1 << (index & 0x7))));
}
/* set_bit (byte *bitmap, dword index)
*
* Set the bit at bitmap[index] to 1
*/
void set_bit(byte *bitmap, dword index)
{
bitmap[(dword) (index >> 3)] |= (1 << (index & 0x7));
}