📄 check.c
字号:
if (FSTART(file,fs) >= fs->clusters+2) {
printf("%s\n Start cluster beyond limit (%lu > %lu). Truncating file.\n",
path_name(file),FSTART(file,fs),fs->clusters+1);
if (!file->offset)
die( "Bad FAT32 root directory! (bad start cluster)\n" );
MODIFY_START(file,0,fs);
}
clusters = prev = 0;
for (curr = FSTART(file,fs) ? FSTART(file,fs) :
-1; curr != -1; curr = next_cluster(fs,curr)) {
if (!fs->fat[curr].value || bad_cluster(fs,curr)) {
printf("%s\n Contains a %s cluster (%lu). Assuming EOF.\n",
path_name(file),fs->fat[curr].value ? "bad" : "free",curr);
if (prev) set_fat(fs,prev,-1);
else if (!file->offset)
die( "FAT32 root dir starts with a bad cluster!" );
else MODIFY_START(file,0,fs);
break;
}
if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <=
clusters*fs->cluster_size) {
printf("%s\n File size is %u bytes, cluster chain length is > %lu "
"bytes.\n Truncating file to %u bytes.\n",path_name(file),
CF_LE_L(file->dir_ent.size),clusters*fs->cluster_size,
CF_LE_L(file->dir_ent.size));
truncate_file(fs,file,clusters);
break;
}
if ((owner = get_owner(fs,curr))) {
int do_trunc = 0;
printf("%s and\n",path_name(owner));
printf("%s\n share clusters.\n",path_name(file));
clusters2 = 0;
for (walk = FSTART(owner,fs); walk > 0 && walk != -1; walk =
next_cluster(fs,walk))
if (walk == curr) break;
else clusters2++;
restart = file->dir_ent.attr & ATTR_DIR;
if (!owner->offset) {
printf( " Truncating second to %lu bytes because first "
"is FAT32 root dir.\n", clusters2*fs->cluster_size );
do_trunc = 2;
}
else if (!file->offset) {
printf( " Truncating first to %lu bytes because second "
"is FAT32 root dir.\n", clusters*fs->cluster_size );
do_trunc = 1;
}
else if (interactive)
printf("1) Truncate first to %lu bytes%s\n"
"2) Truncate second to %lu bytes\n",clusters*fs->cluster_size,
restart ? " and restart" : "",clusters2*fs->cluster_size);
else printf(" Truncating second to %lu bytes.\n",clusters2*
fs->cluster_size);
if (do_trunc != 2 &&
(do_trunc == 1 ||
(interactive && get_key("12","?") == '1'))) {
prev = 0;
clusters = 0;
for (this = FSTART(owner,fs); this > 0 && this != -1; this =
next_cluster(fs,this)) {
if (this == curr) {
if (prev) set_fat(fs,prev,-1);
else MODIFY_START(owner,0,fs);
MODIFY(owner,size,CT_LE_L(clusters*fs->cluster_size));
if (restart) return 1;
while (this > 0 && this != -1) {
set_owner(fs,this,NULL);
this = next_cluster(fs,this);
}
break;
}
clusters++;
prev = this;
}
if (this != curr)
die("Internal error: didn't find cluster %d in chain"
" starting at %d",curr,FSTART(owner,fs));
}
else {
if (prev) set_fat(fs,prev,-1);
else MODIFY_START(file,0,fs);
break;
}
}
set_owner(fs,curr,file);
clusters++;
prev = curr;
}
if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) >
clusters*fs->cluster_size) {
printf("%s\n File size is %u bytes, cluster chain length is %lu bytes."
"\n Truncating file to %lu bytes.\n",path_name(file),CF_LE_L(file->
dir_ent.size),clusters*fs->cluster_size,clusters*fs->cluster_size);
MODIFY(file,size,CT_LE_L(clusters*fs->cluster_size));
}
return 0;
}
static int check_files(DOS_FS *fs,DOS_FILE *start)
{
while (start) {
if (check_file(fs,start)) return 1;
start = start->next;
}
return 0;
}
static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots)
{
DOS_FILE *parent,**walk,**scan;
int dot,dotdot,skip,redo;
int good,bad;
if (!*root) return 0;
parent = (*root)->parent;
good = bad = 0;
for (walk = root; *walk; walk = &(*walk)->next)
if (bad_name((*walk)->dir_ent.name)) bad++;
else good++;
if (*root && parent && good+bad > 4 && bad > good/2) {
printf("%s\n Has a large number of bad entries. (%d/%d)\n",
path_name(parent),bad,good+bad);
if (!dots) printf( " Not dropping root directory.\n" );
else if (!interactive) printf(" Not dropping it in auto-mode.\n");
else if (get_key("yn","Drop directory ? (y/n)") == 'y') {
truncate_file(fs,parent,0);
MODIFY(parent,name[0],DELETED_FLAG);
/* buglet: deleted directory stays in the list. */
return 1;
}
}
dot = dotdot = redo = 0;
walk = root;
while (*walk) {
if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ||
!strncmp((*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) {
if (handle_dot(fs,*walk,dots)) {
*walk = (*walk)->next;
continue;
}
if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++;
else dotdot++;
}
if (!((*walk)->dir_ent.attr & ATTR_VOLUME) &&
bad_name((*walk)->dir_ent.name)) {
printf("%s\n Bad file name.\n",path_name(*walk));
if (interactive)
printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"
"4) Keep it\n");
else printf(" Auto-renaming it.\n");
switch (interactive ? get_key("1234","?") : '3') {
case '1':
drop_file(fs,*walk);
walk = &(*walk)->next;
continue;
case '2':
rename_file(*walk);
redo = 1;
break;
case '3':
auto_rename(*walk);
printf(" Renamed to %s\n",file_name((*walk)->dir_ent.
name));
break;
case '4':
break;
}
}
/* don't check for duplicates of the volume label */
if (!((*walk)->dir_ent.attr & ATTR_VOLUME)) {
scan = &(*walk)->next;
skip = 0;
while (*scan && !skip) {
if (!((*scan)->dir_ent.attr & ATTR_VOLUME) &&
!strncmp((*walk)->dir_ent.name,(*scan)->dir_ent.name,MSDOS_NAME)) {
printf("%s\n Duplicate directory entry.\n First %s\n",
path_name(*walk),file_stat(*walk));
printf(" Second %s\n",file_stat(*scan));
if (interactive)
printf("1) Drop first\n2) Drop second\n3) Rename first\n"
"4) Rename second\n5) Auto-rename first\n"
"6) Auto-rename second\n");
else printf(" Auto-renaming second.\n");
switch (interactive ? get_key("123456","?") : '6') {
case '1':
drop_file(fs,*walk);
*walk = (*walk)->next;
skip = 1;
break;
case '2':
drop_file(fs,*scan);
*scan = (*scan)->next;
continue;
case '3':
rename_file(*walk);
printf(" Renamed to %s\n",path_name(*walk));
redo = 1;
break;
case '4':
rename_file(*scan);
printf(" Renamed to %s\n",path_name(*walk));
redo = 1;
break;
case '5':
auto_rename(*walk);
printf(" Renamed to %s\n",file_name((*walk)->dir_ent.
name));
break;
case '6':
auto_rename(*scan);
printf(" Renamed to %s\n",file_name((*scan)->dir_ent.
name));
break;
}
}
scan = &(*scan)->next;
}
if (skip) continue;
}
if (!redo) walk = &(*walk)->next;
else {
walk = root;
dot = dotdot = redo = 0;
}
}
if (dots && !dot)
printf("%s\n \".\" is missing. Can't fix this yet.\n",
path_name(parent));
if (dots && !dotdot)
printf("%s\n \"..\" is missing. Can't fix this yet.\n",
path_name(parent));
return 0;
}
static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
{
DOS_FILE *owner;
unsigned long walk,prev,clusters,next_clu;
prev = clusters = 0;
for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
walk = next_clu) {
next_clu = next_cluster(fs,walk);
if ((owner = get_owner(fs,walk))) {
if (owner == file) {
printf("%s\n Circular cluster chain. Truncating to %lu "
"cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" :
"s");
if (prev) set_fat(fs,prev,-1);
else if (!file->offset)
die( "Bad FAT32 root directory! (bad start cluster)\n" );
else MODIFY_START(file,0,fs);
}
break;
}
if (bad_cluster(fs,walk)) break;
if (read_test) {
if (fs_test(cluster_start(fs,walk),fs->cluster_size)) {
prev = walk;
clusters++;
}
else {
printf("%s\n Cluster %lu (%lu) is unreadable. Skipping it.\n",
path_name(file),clusters,walk);
if (prev) set_fat(fs,prev,next_cluster(fs,walk));
else MODIFY_START(file,next_cluster(fs,walk),fs);
set_fat(fs,walk,-2);
}
}
set_owner(fs,walk,file);
}
for (walk = FSTART(file,fs); walk > 0 && walk < fs->clusters+2;
walk = next_cluster(fs,walk))
if (bad_cluster(fs,walk)) break;
else if (get_owner(fs,walk) == file) set_owner(fs,walk,NULL);
else break;
}
static void undelete(DOS_FS *fs,DOS_FILE *file)
{
unsigned long clusters,left,prev,walk;
clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/
fs->cluster_size;
prev = 0;
for (walk = FSTART(file,fs); left && walk >= 2 && walk <
fs->clusters+2 && !fs->fat[walk].value; walk++) {
left--;
if (prev) set_fat(fs,prev,walk);
prev = walk;
}
if (prev) set_fat(fs,prev,-1);
else MODIFY_START(file,0,fs);
if (left)
printf("Warning: Did only undelete %lu of %lu cluster%s.\n",clusters-left,
clusters,clusters == 1 ? "" : "s");
}
static void new_dir( void )
{
lfn_reset();
}
static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,
loff_t offset,FDSC **cp)
{
DOS_FILE *new;
DIR_ENT de;
FD_TYPE type;
char tmpBuffer[512]; // TMN:
if (offset) {
// fs_read(offset,sizeof(DIR_ENT),&de);
fs_read(offset,sizeof(tmpBuffer),&tmpBuffer); // TMN:
memcpy(&de, tmpBuffer, sizeof(DIR_ENT)); // TMN:
} else {
memcpy(de.name," ",MSDOS_NAME);
de.attr = ATTR_DIR;
de.size = de.time = de.date = 0;
de.start = CT_LE_W(fs->root_cluster & 0xffff);
de.starthi = CT_LE_W((fs->root_cluster >> 16) & 0xffff);
}
if ((type = file_type(cp,de.name)) != fdt_none) {
if (type == fdt_undelete && (de.attr & ATTR_DIR))
die("Can't undelete directories.");
file_modify(cp,de.name);
fs_write(offset,1,&de);
}
if (IS_FREE(de.name)) {
lfn_check_orphaned();
return;
}
if (de.attr == VFAT_LN_ATTR) {
lfn_add_slot(&de,offset);
return;
}
new = qalloc(&mem_queue,sizeof(DOS_FILE));
new->lfn = lfn_get(&de);
new->offset = offset;
memcpy(&new->dir_ent,&de,sizeof(de));
new->next = new->first = NULL;
new->parent = parent;
if (type == fdt_undelete) undelete(fs,new);
**chain = new;
*chain = &new->next;
if (list) {
printf("Checking file %s",path_name(new));
if (new->lfn)
printf(" (%s)", file_name(new->dir_ent.name) );
printf("\n");
}
if (offset &&
strncmp(de.name,MSDOS_DOT,MSDOS_NAME) != 0 &&
strncmp(de.name,MSDOS_DOTDOT,MSDOS_NAME) != 0)
++n_files;
test_file(fs,new,test);
}
static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp);
static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp)
{
DOS_FILE **chain;
int i;
unsigned long clu_num;
chain = &this->first;
i = 0;
clu_num = FSTART(this,fs);
new_dir();
while (clu_num > 0 && clu_num != -1) {
add_file(fs,&chain,this,cluster_start(fs,clu_num)+(i % fs->
cluster_size),cp);
i += sizeof(DIR_ENT);
if (!(i % fs->cluster_size))
if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1)
break;
}
lfn_check_orphaned();
if (check_dir(fs,&this->first,this->offset)) return 0;
if (check_files(fs,this->first)) return 1;
return subdirs(fs,this,cp);
}
static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp)
{
DOS_FILE *walk;
for (walk = parent ? parent->first : root; walk; walk = walk->next)
if (walk->dir_ent.attr & ATTR_DIR)
if (strncmp(walk->dir_ent.name,MSDOS_DOT,MSDOS_NAME) &&
strncmp(walk->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME))
if (scan_dir(fs,walk,file_cd(cp,walk->dir_ent.name))) return 1;
return 0;
}
int scan_root(DOS_FS *fs)
{
DOS_FILE **chain;
int i;
root = NULL;
chain = &root;
new_dir();
if (fs->root_cluster) {
add_file(fs,&chain,NULL,0,&fp_root);
}
else {
for (i = 0; i < fs->root_entries; i++)
add_file(fs,&chain,NULL,fs->root_start+i*sizeof(DIR_ENT),&fp_root);
}
lfn_check_orphaned();
(void) check_dir(fs,&root,0);
if (check_files(fs,root)) return 1;
return subdirs(fs,NULL,&fp_root);
}
/* Local Variables: */
/* tab-width: 8 */
/* End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -