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