PL3026: This is the upgraded version of vdu that maintains an internal
[util-vserver.git] / src / vdu.c
index 04c060c..19b5dec 100644 (file)
--- 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 <enrico.scholz@informatik.tu-chemnitz.de>
 // based on vdu.cc by Jacques Gelinas
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-#include "compat.h"
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <dirent.h>
 #include <errno.h>
 #include <string.h>
-
 #include <sys/ioctl.h>
-#include "ext2fs.h"
 
-// Patch to help compile this utility on unpatched kernel source
-#ifndef EXT2_IMMUTABLE_FILE_FL
-       #define EXT2_IMMUTABLE_FILE_FL  0x00000010
-       #define EXT2_IMMUTABLE_LINK_FL  0x00008000
-#endif
+#include <assert.h>
+
+#include "vdu.h"
 
+HashTable tbl;
+
+static int // boolean
+INOPut(PHashTable tbl, ino_t* key, struct stat **val){
+    return Put(tbl, key, val);
+}
 
-//__extension__ typedef long long              longlong;
-__extension__ typedef long             longlong;
+__extension__ typedef long long                longlong;
+//__extension__ typedef long           longlong;
 
 static longlong inodes;
 static longlong blocks;
@@ -62,6 +59,7 @@ void panic(char *s) {
 
 static void vdu_onedir (char const *path)
 {
+    char const *foo = path;
     struct stat dirst, st;
     struct dirent *ent;
     char *name;
@@ -94,8 +92,9 @@ static void vdu_onedir (char const *path)
 
 
     /* Walk the directory entries and compute the sum of inodes,
-       blocks, and disk space used. This code will recursively descend
-       down the directory structure. */
+     * blocks, and disk space used. This code will recursively descend
+     * down the directory structure. 
+     */
 
     while ((ent=readdir(dir))!=NULL){
        if (lstat(ent->d_name,&st)==-1){
@@ -108,27 +107,58 @@ static void vdu_onedir (char const *path)
 
        if (S_ISREG(st.st_mode)){
            if (st.st_nlink > 1){
-               long flags;
-               int fd, res;
-
-               if ((fd = open(ent->d_name,O_RDONLY))==-1) {
-                   fprintf (stderr,"Can't open file %s/%s\n",path,ent->d_name);                    
-                   warning ("open failed");
-                   continue;
-               }
-
-               flags = 0;
-               res = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-               close(fd);
-
-               if ((res == 0) && (flags & EXT2_IMMUTABLE_LINK_FL)){
-                   if (verbose)
-                       printf ("Skipping %s\n",ent->d_name);               
-                   continue;
+               struct stat *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;
            }
-           dirsize += st.st_size;
-           dirblocks += st.st_blocks;
 
        } else if (S_ISDIR(st.st_mode)) {
            if ((st.st_dev == dirst.st_dev) &&
@@ -147,43 +177,71 @@ static void vdu_onedir (char const *path)
                fchdir(dirfd);
            }
        } else {
-           dirsize += st.st_size;
-           dirblocks += st.st_blocks;
+           // dirsize += st.st_size;
+           // dirblocks += st.st_blocks;
        }
     }
     closedir (dir);
     close (dirfd);
     if (verbose)
-       printf("%8ld %8ld %8ld %s\n",dirinodes, dirblocks, dirsize>>10,path);
+       printf("%16lld %16lld %16lld %s\n",dirinodes, dirblocks, dirsize,foo);
     inodes += dirinodes;
     blocks += dirblocks;
     size   += dirsize;
 }
 
+static void
+Count(ino_t* key, struct stat* val) {
+    if(val->st_nlink) {
+       blocks += val->st_blocks;
+       size += val->st_size;
+       printf("ino=%ld nlink=%d\n",val->st_ino, val->st_nlink);
+    }
+}
 
-
-int main (int argc, char *argv[])
+int
+main (int argc, char **argv)
 {
     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.");
+       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");
        }
 
+       /* hash table support for hard link count */
+       (void) Init(&tbl,0,0);
+
        for (i=1; i<argc; i++){
            inodes = blocks = size = 0;
            vdu_onedir (argv[i]);
-           printf("%8ld %8ld %8ld %s TOTAL\n",inodes, blocks, size>>10,argv[i]);
+
+           printf("%16lld %16lld %16lld %s\n",
+                  inodes, 
+                  blocks>>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;