X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fvdu.c;h=b6cfc596d571b537f60c8e7670801114352aee46;hb=67aea2526fdfc31c7cfe6ccc369ac5e6974756e5;hp=55f6082465d44eb378fd90a5d8716a6cb03f81c8;hpb=6bf3f95de36c804c97716b2d0bdf10680c559044;p=util-vserver.git diff --git a/src/vdu.c b/src/vdu.c index 55f6082..b6cfc59 100644 --- a/src/vdu.c +++ b/src/vdu.c @@ -1,4 +1,4 @@ -// $Id: vdu.c,v 1.1 2003/09/29 22:01:57 ensc Exp $ +// $Id: vdu-new.c,v 1.2 2004/08/17 14:44:14 mef-pl_kernel Exp $ // Copyright (C) 2003 Enrico Scholz // based on vdu.cc by Jacques Gelinas @@ -17,6 +17,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#define _LARGEFILE64_SOURCE + #include #include #include @@ -26,89 +28,229 @@ #include #include #include +#include + +#include + +#include "vdu.h" + +HashTable tbl; + +static int // boolean +INOPut(PHashTable tbl, ino64_t* key, struct stat64 **val){ + return Put(tbl, key, val); +} __extension__ typedef long long longlong; +//__extension__ typedef long longlong; + +static longlong inodes; +static longlong blocks; +static longlong size; + +static short verbose = 0; + +static inline void warning(char *s) { + fprintf(stderr,"%s (%s)\n",s,strerror(errno)); +} + +void panic(char *s) { + warning(s); + exit(2); +} -static int vdu_onedir (char const *path, longlong *size) +static void vdu_onedir (char const *path) { - int ret = -1; - int dirfd = open (path,O_RDONLY); // A handle to speed up - // chdir - if (dirfd == -1){ - fprintf (stderr,"Can't open directory %s (%s)\n",path - ,strerror(errno)); - }else{ - DIR *dir; - - fchdir (dirfd); - dir = opendir ("."); - if (dir == NULL){ - fprintf (stderr,"Can't open (opendir) directory %s (%s)\n",path - ,strerror(errno)); - }else{ - struct stat dirst; - struct dirent *ent; - longlong dirsize = 0; - - ret = 0; - lstat (".",&dirst); - while ((ent=readdir(dir))!=NULL){ - struct stat st; - if (lstat(ent->d_name,&st)==-1){ - fprintf (stderr,"Can't stat %s/%s (%s)\n",path - ,ent->d_name,strerror(errno)); - ret = -1; - break; - }else if (S_ISREG(st.st_mode)){ - if (st.st_nlink == 1){ - dirsize += st.st_size; - } - }else if (S_ISDIR(st.st_mode) && st.st_dev == dirst.st_dev){ - if (strcmp(ent->d_name,".")!=0 - && strcmp(ent->d_name,"..")!=0){ - char *tmp = malloc(strlen(path) + strlen(ent->d_name) + 2); - if (tmp==0) ret=-1; - else { - strcpy(tmp, path); - strcat(tmp, "/"); - strcat(tmp, ent->d_name); - ret = vdu_onedir(tmp,&dirsize); - free(tmp); - fchdir (dirfd); - } - } - } - } - closedir (dir); - *size += dirsize; + char const *foo = path; + struct stat64 dirst, st; + struct dirent *ent; + char *name; + DIR *dir; + int dirfd; + longlong dirsize, dirinodes, dirblocks; + + dirsize = dirinodes = dirblocks = 0; + + // A handle to speed up chdir + if ((dirfd = open (path,O_RDONLY)) == -1) { + fprintf (stderr,"Can't open directory %s\n",path); + panic("open failed"); + } + + if (fchdir (dirfd) == -1) { + fprintf (stderr,"Can't fchdir directory %s\n",path); + panic("fchdir failed"); + } + + if (fstat64 (dirfd,&dirst) != 0) { + fprintf (stderr,"Can't lstat directory %s\n",path); + panic("lstat failed"); + } + + if ((dir = opendir (".")) == NULL) { + fprintf (stderr,"Can't open (opendir) directory %s\n",path); + panic("opendir failed"); + } + + + /* Walk the directory entries and compute the sum of inodes, + * blocks, and disk space used. This code will recursively descend + * down the directory structure. + */ + + while ((ent=readdir(dir))!=NULL){ + if (lstat64(ent->d_name,&st)==-1){ + fprintf (stderr,"Can't stat %s/%s\n",path,ent->d_name); + warning("lstat failed"); + continue; + } + + dirinodes ++; + + if (S_ISREG(st.st_mode)){ + if (st.st_nlink > 1){ + struct stat64 *val; + int nlink; + + /* Check hash table if we've seen this inode + * before. Note that the hash maintains a + * (inode,struct stat) key value pair. + */ + + val = &st; + + (void) INOPut(&tbl,&st.st_ino,&val); + + /* Note that after the INOPut call "val" refers to the + * value entry in the hash table --- not &st. This + * means that if the inode has been put into the hash + * table before, val will refer to the first st that + * was put into the hashtable. Otherwise, if it is + * the first time it is put into the hash table, then + * val will be equal to this &st. + */ + nlink = val->st_nlink; + nlink --; + + /* val refers to value in hash tbale */ + if (nlink == 0) { + + /* We saw all hard links to this particular inode + * as part of this sweep of vdu. So account for + * the size and blocks required by the file. + */ + + dirsize += val->st_size; + dirblocks += val->st_blocks; + + /* Do not delete the (ino,val) tuple from the tbl, + * as we need to handle the case when we are + * double counting a file due to a bind mount. + */ + val->st_nlink = 0; + + } else if (nlink > 0) { + val->st_nlink = nlink; + } else /* if(nlink < 0) */ { + /* We get here when we are double counting nlinks + due a bind mount. */ + + /* DO NOTHING */ + } + } else { + dirsize += st.st_size; + dirblocks += st.st_blocks; + } + + } else if (S_ISDIR(st.st_mode)) { + if ((st.st_dev == dirst.st_dev) && + (strcmp(ent->d_name,".")!=0) && + (strcmp(ent->d_name,"..")!=0)) { + + dirsize += st.st_size; + dirblocks += st.st_blocks; + + name = strdup(ent->d_name); + if (name==0) { + panic("Out of memory\n"); } - close (dirfd); + vdu_onedir(name); + free(name); + fchdir(dirfd); + } + } else { + // dirsize += st.st_size; + // dirblocks += st.st_blocks; } - return ret; + } + closedir (dir); + close (dirfd); + if (verbose) + printf("%16lld %16lld %16lld %s\n",dirinodes, dirblocks, dirsize,foo); + inodes += dirinodes; + blocks += dirblocks; + size += dirsize; } -int main (int argc, char *argv[]) +static void +Count(ino64_t* key, struct stat64* val) { + if(val->st_nlink) { + blocks += val->st_blocks; + size += val->st_size; + printf("ino=%16lld nlink=%d\n",val->st_ino, val->st_nlink); + } +} + +int +main (int argc, char **argv) { - int ret = -1; - if (argc < 2){ - fprintf (stderr,"vdu version %s\n",VERSION); - fprintf (stderr,"vdu directory ...\n\n"); - fprintf (stderr - ,"Compute the size of a directory tree, ignoring files\n" - "with more than one link.\n"); - }else{ - int i; - - ret = 0; - for (i=1; i> 10; - printf ("%s\t%ldK\n",argv[i],ksize); - } + int startdir, i; + + if (argc < 2){ + fprintf (stderr,"vdu version %s\n",VERSION); + fprintf (stderr,"vdu directory ...\n\n"); + fprintf (stderr,"Compute the size of a directory tree.\n"); + }else{ + if ((startdir = open (".",O_RDONLY)) == -1) { + fprintf (stderr,"Can't open current working directory\n"); + panic("open failed"); } - return ret; + + /* hash table support for hard link count */ + (void) Init(&tbl,0,0); + + for (i=1; i>1, + size, + argv[i]); + if (fchdir (startdir) == -1) { + panic("fchdir failed"); + } + } + + if(0) { + /* show size & blocks for files with nlinks from outside of dir */ + inodes = blocks = size = 0; + Iterate(&tbl,Count); + printf("%16lld %16lld %16lld NOT COUNTED\n", + inodes, + blocks, + size); + } + + // Dispose(&tbl); this fails to delete all entries + close(startdir); + } + return 0; } +/* + * Local variables: + * c-basic-offset: 4 + * End: + */