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 + -
显示快捷键?