check.c
来自「linux dosfs 工具,可以移植到嵌入式系统下检查存储状态下的磁盘状况,修」· C语言 代码 · 共 850 行 · 第 1/2 页
C
850 行
/* check.c - Check and repair a PC/MS-DOS file system *//* Written 1993 by Werner Almesberger *//* FAT32, VFAT, Atari format support, and various fixes additions May 1998 * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include <time.h>#include "common.h"#include "dosfsck.h"#include "io.h"#include "fat.h"#include "file.h"#include "lfn.h"#include "check.h"static DOS_FILE *root;/* get start field of a dir entry */#define FSTART(p,fs) \ ((unsigned long)CF_LE_W(p->dir_ent.start) | \ (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0))#define MODIFY(p,i,v) \ do { \ if (p->offset) { \ p->dir_ent.i = v; \ fs_write(p->offset+offsetof(DIR_ENT,i), \ sizeof(p->dir_ent.i),&p->dir_ent.i); \ } \ } while(0)#define MODIFY_START(p,v,fs) \ do { \ unsigned long __v = (v); \ if (!p->offset) { \ /* writing to fake entry for FAT32 root dir */ \ if (!__v) die("Oops, deleting FAT32 root dir!"); \ fs->root_cluster = __v; \ p->dir_ent.start = CT_LE_W(__v&0xffff); \ p->dir_ent.starthi = CT_LE_W(__v>>16); \ __v = CT_LE_L(__v); \ fs_write((loff_t)offsetof(struct boot_sector,root_cluster), \ sizeof(((struct boot_sector *)0)->root_cluster), \ &__v); \ } \ else { \ MODIFY(p,start,CT_LE_W((__v)&0xffff)); \ if (fs->fat_bits == 32) \ MODIFY(p,starthi,CT_LE_W((__v)>>16)); \ } \ } while(0)loff_t alloc_rootdir_entry(DOS_FS *fs, DIR_ENT *de, const char *pattern){ static int curr_num = 0; loff_t offset; if (fs->root_cluster) { DIR_ENT d2; int i = 0, got = 0; unsigned long clu_num, prev = 0; loff_t offset2; clu_num = fs->root_cluster; offset = cluster_start(fs,clu_num); while (clu_num > 0 && clu_num != -1) { fs_read(offset,sizeof(DIR_ENT),&d2); if (IS_FREE(d2.name) && d2.attr != VFAT_LN_ATTR) { got = 1; break; } i += sizeof(DIR_ENT); offset += sizeof(DIR_ENT); if (i >= fs->cluster_size) { prev = clu_num; if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1) break; offset = cluster_start(fs,clu_num); } } if (!got) { /* no free slot, need to extend root dir: alloc next free cluster * after previous one */ if (!prev) die("Root directory has no cluster allocated!"); for (clu_num = prev+1; clu_num != prev; clu_num++) { if (clu_num >= fs->clusters+2) clu_num = 2; if (!fs->fat[clu_num].value) break; } if (clu_num == prev) die("Root directory full and no free cluster"); set_fat(fs,prev,clu_num); set_fat(fs,clu_num,-1); /* clear new cluster */ memset( &d2, 0, sizeof(d2) ); offset = cluster_start(fs,clu_num); for( i = 0; i < fs->cluster_size; i += sizeof(DIR_ENT) ) fs_write( offset+i, sizeof(d2), &d2 ); } memset(de,0,sizeof(DIR_ENT)); while (1) { sprintf(de->name,pattern,curr_num); clu_num = fs->root_cluster; i = 0; offset2 = cluster_start(fs,clu_num); while (clu_num > 0 && clu_num != -1) { fs_read(offset2,sizeof(DIR_ENT),&d2); if (offset2 != offset && !strncmp(d2.name,de->name,MSDOS_NAME)) break; i += sizeof(DIR_ENT); offset2 += sizeof(DIR_ENT); if (i >= fs->cluster_size) { if ((clu_num = next_cluster(fs,clu_num)) == 0 || clu_num == -1) break; offset2 = cluster_start(fs,clu_num); } } if (clu_num == 0 || clu_num == -1) break; if (++curr_num >= 10000) die("Unable to create unique name"); } } else { DIR_ENT *root; int next_free = 0, scan; root = alloc(fs->root_entries*sizeof(DIR_ENT)); fs_read(fs->root_start,fs->root_entries*sizeof(DIR_ENT),root); while (next_free < fs->root_entries) if (IS_FREE(root[next_free].name) && root[next_free].attr != VFAT_LN_ATTR) break; else next_free++; if (next_free == fs->root_entries) die("Root directory is full."); offset = fs->root_start+next_free*sizeof(DIR_ENT); memset(de,0,sizeof(DIR_ENT)); while (1) { sprintf(de->name,pattern,curr_num); for (scan = 0; scan < fs->root_entries; scan++) if (scan != next_free && !strncmp(root[scan].name,de->name,MSDOS_NAME)) break; if (scan == fs->root_entries) break; if (++curr_num >= 10000) die("Unable to create unique name"); } free(root); } ++n_files; return offset;}static char *path_name(DOS_FILE *file){ static char path[PATH_MAX*2]; if (!file) *path = 0; else { if (strlen(path_name(file->parent)) > PATH_MAX) die("Path name too long."); if (strcmp(path,"/") != 0) strcat(path,"/"); strcpy(strrchr(path,0),file->lfn?file->lfn:file_name(file->dir_ent.name)); } return path;}static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec *//* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */time_t date_dos2unix(unsigned short time,unsigned short date){ int month,year; time_t secs; month = ((date >> 5) & 15)-1; year = date >> 9; secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && month < 2 ? 1 : 0)+3653); /* days since 1.1.70 plus 80's leap day */ return secs;}static char *file_stat(DOS_FILE *file){ static char temp[100]; struct tm *tm; char tmp[100]; time_t date; date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file-> dir_ent.date)); tm = localtime(&date); strftime(tmp,99,"%H:%M:%S %b %d %Y",tm); sprintf(temp," Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp); return temp;}static int bad_name(unsigned char *name){ int i, spc, suspicious = 0; char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:"; /* Do not complain about (and auto-correct) the extended attribute files * of OS/2. */ if (strncmp(name,"EA DATA SF",11) == 0 || strncmp(name,"WP ROOT SF",11) == 0) return 0; for (i = 0; i < 8; i++) { if (name[i] < ' ' || name[i] == 0x7f) return 1; if (name[i] > 0x7f) ++suspicious; if (strchr(bad_chars,name[i])) return 1; } for (i = 8; i < 11; i++) { if (name[i] < ' ' || name[i] == 0x7f) return 1; if (name[i] > 0x7f) ++suspicious; if (strchr(bad_chars,name[i])) return 1; } spc = 0; for (i = 0; i < 8; i++) { if (name[i] == ' ') spc = 1; else if (spc) /* non-space after a space not allowed, space terminates the name * part */ return 1; } spc = 0; for (i = 8; i < 11; i++) { if (name[i] == ' ') spc = 1; else if (spc) /* non-space after a space not allowed, space terminates the name * part */ return 1; } /* Under GEMDOS, chars >= 128 are never allowed. */ if (atari_format && suspicious) return 1; /* Only complain about too much suspicious chars in interactive mode, * never correct them automatically. The chars are all basically ok, so we * shouldn't auto-correct such names. */ if (interactive && suspicious > 6) return 1; return 0;}static void drop_file(DOS_FS *fs,DOS_FILE *file){ unsigned long cluster; MODIFY(file,name[0],DELETED_FLAG); for (cluster = FSTART(file,fs); cluster > 0 && cluster < fs->clusters+2; cluster = next_cluster(fs,cluster)) set_owner(fs,cluster,NULL); --n_files;}static void truncate_file(DOS_FS *fs,DOS_FILE *file,unsigned long clusters){ int deleting; unsigned long walk,next,prev; walk = FSTART(file,fs); prev = 0; if ((deleting = !clusters)) MODIFY_START(file,0,fs); while (walk > 0 && walk != -1) { next = next_cluster(fs,walk); if (deleting) set_fat(fs,walk,0); else if ((deleting = !--clusters)) set_fat(fs,walk,-1); prev = walk; walk = next; }}static void auto_rename(DOS_FILE *file){ DOS_FILE *first,*walk; int number; if (!file->offset) return; /* cannot rename FAT32 root dir */ first = file->parent ? file->parent->first : root; number = 0; while (1) { sprintf(file->dir_ent.name,"FSCK%04d",number); strncpy(file->dir_ent.ext,"REN",3); for (walk = first; walk; walk = walk->next) if (walk != file && !strncmp(walk->dir_ent.name,file->dir_ent. name,MSDOS_NAME)) break; if (!walk) { fs_write(file->offset,MSDOS_NAME,file->dir_ent.name); return; } number++; } die("Can't generate a unique name.");}static void rename_file(DOS_FILE *file){ unsigned char name[46]; unsigned char *walk,*here; if (!file->offset) { printf( "Cannot rename FAT32 root dir\n" ); return; /* cannot rename FAT32 root dir */ } while (1) { printf("New name: "); fflush(stdout); if (fgets(name,45,stdin)) { if ((here = strchr(name,'\n'))) *here = 0; for (walk = strrchr(name,0); walk >= name && (*walk == ' ' || *walk == '\t'); walk--); walk[1] = 0; for (walk = name; *walk == ' ' || *walk == '\t'; walk++); if (file_cvt(walk,file->dir_ent.name)) { fs_write(file->offset,MSDOS_NAME,file->dir_ent.name); return; } } }}static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots){ char *name; name = strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : "."; if (!(file->dir_ent.attr & ATTR_DIR)) { printf("%s\n Is a non-directory.\n",path_name(file)); if (interactive) printf("1) Drop it\n2) Auto-rename\n3) Rename\n" "4) Convert to directory\n"); else printf(" Auto-renaming it.\n"); switch (interactive ? get_key("1234","?") : '2') { case '1': drop_file(fs,file); return 1; case '2': auto_rename(file); printf(" Renamed to %s\n",file_name(file->dir_ent.name)); return 0; case '3': rename_file(file); return 0; case '4': MODIFY(file,size,CT_LE_L(0)); MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR); break; } } if (!dots) { printf("Root contains directory \"%s\". Dropping it.\n",name); drop_file(fs,file); return 1; } return 0;}static int check_file(DOS_FS *fs,DOS_FILE *file){ DOS_FILE *owner; int restart; unsigned long expect,curr,this,clusters,prev,walk,clusters2; if (file->dir_ent.attr & ATTR_DIR) { if (CF_LE_L(file->dir_ent.size)) { printf("%s\n Directory has non-zero size. Fixing it.\n", path_name(file)); MODIFY(file,size,CT_LE_L(0)); } if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) { expect = FSTART(file->parent,fs); if (FSTART(file,fs) != expect) { printf("%s\n Start (%ld) does not point to parent (%ld)\n", path_name(file),FSTART(file,fs),expect); MODIFY_START(file,expect,fs); } return 0; } if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOTDOT, MSDOS_NAME)) { expect = file->parent->parent ? FSTART(file->parent->parent,fs):0; if (fs->root_cluster && expect == fs->root_cluster) expect = 0; if (FSTART(file,fs) != expect) { printf("%s\n Start (%lu) does not point to .. (%lu)\n", path_name(file),FSTART(file,fs),expect); MODIFY_START(file,expect,fs); } return 0; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?