Path: sran265!katsu From: katsu@sran14.sra.co.jp (WATANABE Katsuhiro) Message-ID: Date: 26 Apr 93 22:31:01 Organization: Software Research Associates, Inc.,Japan Newsgroups: sra.test Subject: How many fragments do your directories waste? Distribution: sra YMO復活記念特別企画 「本日のゴミ記事」 この企画の趣旨: 懐かしいな。YMO自体は私はさして興味がないけど、YMOの ファンだった中学校時代の友達が呼んでいるかのようだ。 FFS ではディレクトリファイルが小さくなることがないので、 ファイルを沢山消した後などにはディレクトリファイルがディスクブロックを 無駄使いしていることがありえるけど、さてどれだけ無駄使いしてるかな? 使い方: dirwaste ディレクトリ名 サブディレクトリに ufs のマウントポイントがある程度なら大丈夫のはずだけど、 NFS マウントしているとうまく動かないこともありえる。perl で移植性よく 書くのがとても難しくて c にしたけど、さて NEWS OS 4.2 や Sun OS 4.1.x 以外でもコンパイルできるようになってるかしら? がないシステム では、CFLAGS=-DNO_DIRENT をつけて make。 あんまり沢山無駄があった場合は dump/restore とか、tar -c して tar -x しなおすとかでディレクトリを作り直すと、少しもうかるはず。 ヘッダーファイルで定義されている構造体について、メンバーを参照するのは perl ではどうやるんだろう?perl で書けたらオモテの世界に出そうかな。 -- 渡邊克宏 # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by sran14!katsu on Mon Apr 26 21:24:09 JST 1993 # Contents: Makefile dirwaste.c dirsize.c echo x - Makefile sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//' # # $Id:$ # # # If your system doesn't have , please make with CFLAGS=-DNO_DIRENT. # #CFLAGS= -DNO_DIRENT dirwaste: dirwaste.o dirsize.o $(CC) -o dirwaste dirwaste.o dirsize.o clean: -rm -f *.o dirwaste @//E*O*F Makefile// chmod u=rw,g=r,o=r Makefile echo x - dirwaste.c sed 's/^@//' > "dirwaste.c" <<'@//E*O*F dirwaste.c//' /* Figure out how many blocks are wasted by eliminated entries on directory. Public Domain Software written by WATANABE Katsuhiro . Bugs: It can happen that this doesn't work on NFS mounted directories, because cannot figure out dirblksiz correctly. $Id:$ */ #include #include #include #include #include #include #include #ifdef NO_DIRENT #include typedef struct direct DIRENT; #else #include typedef struct dirent DIRENT; #endif char *myname; int dirblksiz; /* size of directory chunk */ static int total_wasted, total_fs_wasted; char *emalloc(); main(argc, argv) int argc; char **argv; { myname = argv[0]; /* The header file which defines DIRBLKSIZ varies OS to OS. */ #ifdef DIRBLKSIZ dirblksiz = DIRBLKSIZ; #else { static char nameprefix[] = "/tmp/"; char *tempname; struct stat statbuf; tempname = emalloc(strlen(nameprefix) + strlen(myname) + 6 + 1); strcpy(tempname, nameprefix); strcat(tempname, myname); mktemp(strcpy(tempname, "XXXXXX")); if (mkdir(tempname, 0777)) { perror(tempname); exit(1); } if (stat(tempname, &statbuf)) { perror(tempname); exit(2); } rmdir(tempname); free(tempname); dirblksiz = (int)statbuf.st_size; } #endif if (argc != 2) { fprintf(stderr, "Usage: %s directory¥n", myname); exit(3); } printf(" real packed wasted filesys¥n"); total_fs_wasted = total_wasted = 0; list_dir_wastes(argv[1]); printf("total wasted: %d bytes, or %d bytes in fragment size base.¥n", total_wasted, total_fs_wasted); exit(0); } #define isMyself(dirname) (!strcmp((dirname), ".")) #define isMyParent(dirname) (!strcmp((dirname), "..")) #define isDirectory(status) (((status).st_mode & S_IFMT) == S_IFDIR) #define isLostFound(status) ((status).st_ino == LOSTFOUNDINO) list_dir_wastes(dirname) char *dirname; { DIR *dirp; DIRENT *entp; struct stat statbuf; struct statfs statfsbuf; int entrysize; char *ename, *efullname; int dirsize, chunks, dirsize_real, wasted; int fs_fragsize, fs_dirsize, fs_dirsize_real, fs_wasted; if ((dirp = opendir(dirname)) == (DIR *)NULL) { fprintf(stderr, "%s cannot open as a directory. ignored.¥n", dirname); return; } dirsize = 0; chunks = 0; while ((entp = readdir(dirp)) != (DIRENT *)NULL) { entrysize = dent_minsize(entp); if (dirsize + entrysize > chunks * dirblksiz) { dirsize = chunks++ * dirblksiz + entrysize; } else { dirsize += entrysize; } ename = entp->d_name; efullname = emalloc(strlen(dirname) + 1 + strlen(entp->d_name) + 1); if (dirname[strlen(dirname) - 1] == '/') { sprintf(efullname, "%s%s", dirname, ename); } else { sprintf(efullname, "%s/%s", dirname, ename); } if (lstat(efullname, &statbuf)) { fprintf(stderr, "%s cannot fstat. assume not to be a directory.¥n", dirname); } else { if (isDirectory(statbuf) && !isMyself(ename) && !isMyParent(ename)) { if (isLostFound(statbuf)) { fprintf(stderr, "%s ignored.¥n", efullname); } else { list_dir_wastes(efullname); } } } free(efullname); } closedir(dirp); dirsize = ceil_mod(dirsize, dirblksiz); if (stat(dirname, &statbuf)) { fprintf(stderr, "%s cannot fstat. ignored.¥n", dirname); return; } dirsize_real = (int)statbuf.st_size; wasted = dirsize_real - dirsize; if (statfs(dirname, &statfsbuf)) { fprintf(stderr, "%s cannot statfs. ignored.¥n", dirname); return; } fs_fragsize = (int)statfsbuf.f_bsize; fs_dirsize_real = ceil_mod(dirsize_real, fs_fragsize); fs_dirsize = ceil_mod(dirsize, fs_fragsize); fs_wasted = fs_dirsize_real - fs_dirsize; printf("%8d%8d%8d%8d %s¥n", dirsize_real, dirsize, wasted, fs_wasted, dirname); total_wasted += wasted; total_fs_wasted += fs_wasted; } /* dent_minsize: return the minimum amount of space in filesystem required to represent the specified directory entry. */ int dent_minsize(entp) DIRENT *entp; { return dent_minsize_namelen(entp->d_namlen); } /* malloc() with error check */ char *emalloc(size) unsigned int size; { char *malloc(); char *memregion; if ((memregion = malloc(size)) == (char *) NULL) { fprintf(stderr, "%s: cannot allocate memory.¥n"); exit(4); } return memregion; } int ceil_mod(i, mod) int i, mod; { return ((i + mod - 1) / mod) * mod; } @//E*O*F dirwaste.c// chmod u=rw,g=r,o=r dirwaste.c echo x - dirsize.c sed 's/^@//' > "dirsize.c" <<'@//E*O*F dirsize.c//' /* $Id:$ */ #include #include /* dent_minsize_namelen: return the minimum amount of space in filesystem required to represent a directory entry whose name length == len. */ int dent_minsize_namelen(len) int len; { struct direct fs_dirent; fs_dirent.d_namlen = len; return DIRSIZ(&fs_dirent); } @//E*O*F dirsize.c// chmod u=rw,g=r,o=r dirsize.c exit 0