check.c
来自「linux dosfs 工具,可以移植到嵌入式系统下检查存储状态下的磁盘状况,修」· C语言 代码 · 共 850 行 · 第 1/2 页
C
850 行
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; if (offset) fs_read(offset,sizeof(DIR_ENT),&de); 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)) 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; } 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); } (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 + =
减小字号Ctrl + -
显示快捷键?