(original) (raw)

/* filesystem verification tool, designed to detect data corruption on a filesystem tridge@samba.org, March 2002 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include /* variables settable on the command line */ static int loop_count = 100; static int num_files = 1; static int file_size = 1024*1024; static int block_size = 1024; static char *base_dir = "."; static int use_mmap; static int use_sync; typedef unsigned char uchar; #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif static void *x_malloc(int size) { void *ret = malloc(size); if (!ret) { fprintf(stderr,"Out of memory for size %d!\n", size); exit(1); } return ret; } /* generate a buffer for a particular child, fnum etc. Just use a simple buffer to make debugging easy */ static void gen_buffer(uchar *buf, int loop, int child, int fnum, int ofs) { uchar v = (loop+child+fnum+(ofs/block_size)) % 256; memset(buf, v, block_size); } /* check if a buffer from disk is correct */ static void check_buffer(uchar *buf, int loop, int child, int fnum, int ofs) { uchar *buf2; buf2 = x_malloc(block_size); gen_buffer(buf2, loop, child, fnum, ofs); if (memcmp(buf, buf2, block_size) != 0) { int i, j; for (i=0;buf[i] == buf2[i] && i<block_size;i++) ;="" fprintf(stderr,"corruption="" in="" child="" %d="" fnum="" at="" offset="" %d\n",="" child,="" fnum,="" ofs+i);="" printf("correct:="" ");="" for="" (j="0;j<MIN(20," block_size-i);j++)="" {="" printf("%02x="" ",="" buf2[j+i]);="" }="" printf("\n");="" printf("incorrect:="" buf[j+i]);="" exit(1);="" free(buf2);="" *="" create="" a="" file="" with="" known="" data="" set="" static="" void="" create_file(const="" char="" *dir,="" int="" loop,="" fnum)="" uchar="" *buf;="" size,="" fd;="" fname[1024];="" buf="x_malloc(block_size);" sprintf(fname,="" "%s="" file%d",="" dir,="" fnum);="" fd="open(fname," o_rdwr|o_creat|o_trunc="" |="" (use_sync?o_sync:0),="" 0644);="" if="" (fd="=" -1)="" perror(fname);="" (!use_mmap)="" (size="0;" size<file_size;="" size="" +="block_size)" gen_buffer(buf,="" size);="" (pwrite(fd,="" buf,="" block_size,="" size)="" !="block_size)" fprintf(stderr,"write="" failed="" else="" *p;="" (ftruncate(fd,="" file_size)="" perror("ftruncate");="" p="mmap(NULL," file_size,="" prot_read|prot_write,="" map_shared,="" fd,="" 0);="" (p="=" (char="" *)-1)="" perror("mmap");="" gen_buffer(p+size,="" munmap(p,="" file_size);="" free(buf);="" close(fd);="" check="" that="" has="" the="" right="" check_file(const="" o_rdonly);="" (pread(fd,="" fprintf(stderr,"read="" check_buffer(buf,="" revsusive="" directory="" traversal="" -="" used="" cleanup="" fn()="" is="" called="" on="" all="" files="" dirs="" tree="" traverse(const="" (*fn)(const="" *))="" dir="" *d;="" struct="" dirent="" *de;="" d="opendir(dir);" (!d)="" return;="" while="" ((de="readdir(d)))" stat="" st;="" (strcmp(de-="">d_name,".") == 0) continue; if (strcmp(de->d_name,"..") == 0) continue; sprintf(fname, "%s/%s", dir, de->d_name); if (lstat(fname, &st)) { perror(fname); continue; } if (S_ISDIR(st.st_mode)) { traverse(fname, fn); } fn(fname); } closedir(d); } /* the main child function - this creates/checks the file for one child */ static void run_child(int child) { int i, loop; char dir[1024]; sprintf(dir, "%s/child%d", base_dir, child); /* cleanup any old files */ if (remove(dir) != 0 && errno != ENOENT) { printf("Child %d cleaning %s\n", child, dir); traverse(dir, remove); remove(dir); } if (mkdir(dir, 0755) != 0) { perror(dir); exit(1); } for (loop = 0; loop < loop_count; loop++) { printf("Child %d loop %d\n", child, loop); for (i=0;i</block_size;i++)>