home *** CD-ROM | disk | FTP | other *** search
- /* vtree
-
- +=======================================+
- | This program is in the public domain. |
- +=======================================+
-
- This program shows the directory structure of a filesystem or
- part of one. It also shows the amount of space taken up by files
- in each subdirectory.
-
- Call via
-
- vtree fn1 fn2 fn3 ...
-
- If any of the given filenames is a directory (the usual case),
- vtree will recursively descend into it, and the output line will
- reflect the accumulated totals for all files in the directory.
-
- This program is based upon "agef" written by David S. Hayes at the
- Army Artificial Intelligence Center at the Pentagon.
-
- This program is dependent upon the new directory routines written by
- Douglas A. Gwyn at the US Army Ballistic Research Laboratory at the
- Aberdeen Proving Ground in Maryland.
- */
-
- #include "patchlevel.h"
-
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/param.h>
- #include <stdio.h>
-
- #include "customize.h"
- #include "hash.h"
-
- #define SAME 0 /* for strcmp */
- #define BLOCKSIZE 512 /* size of a disk block */
-
- #define K(x) ((x + 1023)/1024) /* convert stat(2) blocks into
- * k's. On my machine, a block
- * is 512 bytes. */
-
- #define TRUE 1
- #define FALSE 0
- #define V_CHAR "|" /* Vertical character */
- #define H_CHAR "-" /* Horizontal character */
- #define A_CHAR ">" /* Arrow char */
- #define T_CHAR "+" /* Tee char */
- #define L_CHAR "\\" /* L char, bottom of a branch */
-
- #define MAX_COL_WIDTH 15
- #define MAX_V_DEPTH 256 /* max depth for visual display */
-
- int indent = 0, /* current indent */
- depth = 9999, /* max depth */
- cur_depth = 0,
- sum = FALSE, /* sum the subdirectories */
- dup = FALSE, /* use duplicate inodes */
- cnt_inodes = FALSE, /* count inodes */
- quick = FALSE; /* quick display */
- visual = FALSE; /* visual display */
- version = 0; /* = 1 display version, = 2 show options */
- sub_dirs[MAX_V_DEPTH];
-
- struct stat stb; /* Normally not a good idea, but */
- /* this structure is used through- */
- /* out the program */
-
- extern char *optarg; /* from getopt(3) */
- extern int optind,
- opterr;
-
-
- char *Program; /* our name */
- short sw_follow_links = 1; /* follow symbolic links */
- short sw_summary; /* print Grand Total line */
-
- int total_inodes, inodes; /* inode count */
- long total_sizes, sizes; /* block count */
-
- char topdir[NAMELEN]; /* our starting directory */
-
-
- /*
- * We ran into a subdirectory. Go down into it, and read everything
- * in there.
- */
- int indented = FALSE; /* These had to be global since they */
- int last_indent = 0; /* determine what gets displayed during */
- /* the visual display */
-
- down(subdir)
- char *subdir;
- {
- OPEN *dp; /* stream from a directory */
- OPEN *opendir ();
- char cwd[NAMELEN];
- READ *file; /* directory entry */
- READ *readdir ();
- int i;
- struct stat stb;
-
- if ( (cur_depth == depth) && (!sum) )
- return;
-
- /* display the tree */
-
- if (cur_depth < depth) {
- if (visual) {
- if (!indented) {
- for (i = 1; i <cur_depth; i++) {
- if (sub_dirs[i]) {
- printf("%*s%s ",MAX_COL_WIDTH-4," ",V_CHAR);
- }
- else printf("%*s ",MAX_COL_WIDTH-3," ");
- }
- if (cur_depth>0) {
- if (sub_dirs[cur_depth] == 0) {
- printf("%*s%s%s%s ",MAX_COL_WIDTH-4," ",L_CHAR,H_CHAR,A_CHAR);
- }
- else printf("%*s%s%s%s ",MAX_COL_WIDTH-4," ",T_CHAR,H_CHAR,A_CHAR);
- }
- } else {
- for (i = 1; i<MAX_COL_WIDTH-last_indent-3; i++)
- printf("%s",H_CHAR);
- printf("%s%s%s ",T_CHAR,H_CHAR,A_CHAR);
- }
-
- /* This will only happen on the first entry into this routine */
-
- if (strlen(subdir) > MAX_COL_WIDTH - 4) {
- printf("%s\n",subdir);
- printf("%s ",&subdir[strlen(subdir)-MAX_COL_WIDTH+5]);
- last_indent = MAX_COL_WIDTH - 4;
- }
- else {
- printf("%s ",subdir);
- last_indent = strlen(subdir)+1;
- }
- indented = TRUE;
- }
- else printf("%*s%s",indent," ",subdir);
- }
-
- /* open subdirectory */
-
- if ((dp = opendir(subdir)) == NULL) {
- printf(" - can't read %s\n", subdir);
- indented = FALSE;
- return;
- }
-
- cur_depth++;
- indent+=3;
-
- getcwd(cwd, sizeof(cwd)); /* remember where we are */
- chdir(subdir); /* go into subdir */
- if ( (!quick) && (!visual) ) {
-
- /* accumulate total sizes and inodes in current directory */
-
- for (file = readdir(dp); file != NULL; file = readdir(dp))
- if (strcmp(NAME(*file), "..") != SAME)
- get_data(NAME(*file),FALSE);
-
- if (cur_depth<depth) {
- if (cnt_inodes) printf(" %d",inodes);
- printf(" : %ld\n",sizes);
- total_sizes += sizes;
- total_inodes += inodes;
- sizes = 0;
- inodes = 0;
- }
- rewinddir(dp);
- } else if (!visual) printf("\n");
-
- if (visual) {
-
- /* count subdirectories */
-
- for (file = readdir(dp); file != NULL; file = readdir(dp)) {
- if ( (strcmp(NAME(*file), "..") != SAME) &&
- (strcmp(NAME(*file), ".") != SAME) ) {
- if (chk_4_dir(NAME(*file))) {
- sub_dirs[cur_depth]++;
- }
- }
- }
- rewinddir(dp);
- }
-
- /* go down into the subdirectory */
-
- for (file = readdir(dp); file != NULL; file = readdir(dp)) {
- if ( (strcmp(NAME(*file), "..") != SAME) &&
- (strcmp(NAME(*file), ".") != SAME) ) {
- if (chk_4_dir(NAME(*file)))
- sub_dirs[cur_depth]--;
- get_data(NAME(*file),TRUE);
- }
- }
-
- if ( (!quick) && (!visual) ) {
-
- /* print totals */
-
- if (cur_depth == depth) {
- if (cnt_inodes) printf(" %d",inodes);
- printf(" : %ld\n",sizes);
- total_sizes += sizes;
- total_inodes += inodes;
- sizes = 0;
- inodes = 0;
- }
- } else if (visual && indented) {
- printf("\n");
- indented = FALSE;
- }
-
- indent-=3;
- sub_dirs[cur_depth] = 0;
- cur_depth--;
-
- chdir(cwd); /* go back where we were */
- closedir(dp); /* shut down the directory */
- } /* down */
-
-
-
- int chk_4_dir(path)
- char *path;
- {
- if (is_directory(path)) return TRUE;
- else return FALSE;
-
- } /* chk_4_dir */
-
-
-
- /* Is the specified path a directory ? */
-
- int is_directory(path)
- char *path;
- {
-
- #ifdef LSTAT
- if (sw_follow_links)
- stat(path, &stb); /* follows symbolic links */
- else
- lstat(path, &stb); /* doesn't follow symbolic links */
- #else
- stat(path, &stb);
- #endif
-
- if ((stb.st_mode & S_IFMT) == S_IFDIR)
- return TRUE;
- else return FALSE;
- } /* is_directory */
-
-
-
- /*
- * Get the aged data on a file whose name is given. If the file is a
- * directory, go down into it, and get the data from all files inside.
- */
-
- get_data(path,cont)
- char *path;
- int cont;
- {
- /* struct stat stb; */
- int i;
-
- if (cont) {
- if (is_directory(path))
- down(path);
- }
- else {
- if (is_directory(path)) return;
-
- /* Don't do it again if we've already done it once. */
-
- if ( (h_enter(stb.st_dev, stb.st_ino) == OLD) && (!dup) )
- return;
- inodes++;
- sizes+= K(stb.st_size);
- }
- } /* get_data */
-
-
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int i,
- j,
- err = FALSE;
- int option;
- int user_file_list_supplied = 0;
-
- Program = *argv; /* save our name for error messages */
-
- /* Pick up options from command line */
-
- while ((option = getopt(argc, argv, "dh:istqvV")) != EOF) {
- switch (option) {
- case 'h': depth = atoi(optarg);
- while (*optarg) {
- if (!isdigit(*optarg)) {
- err = TRUE;
- break;
- }
- optarg++;
- }
- break;
- case 'd': dup = TRUE;
- break;
- case 'i': cnt_inodes = TRUE;
- break;
- case 's': sum = TRUE;
- break;
- case 't': sw_summary = TRUE;
- break;
- case 'q': quick = TRUE;
- dup = FALSE;
- sum = FALSE;
- cnt_inodes = FALSE;
- break;
- case 'v': visual = TRUE;
- break;
- case 'V': version++;
- break;
- default: err = TRUE;
- }
- if (err) {
- fprintf(stderr,"%s: [ -d ] [ -h # ] [ -i ] [ -s ] [ -q ] [ -v ] [ -V ]\n",Program);
- fprintf(stderr," -d count duplicate inodes\n");
- fprintf(stderr," -h # height of tree to look at\n");
- fprintf(stderr," -i count inodes\n");
- fprintf(stderr," -s include subdirectories not shown due to -h option\n");
- fprintf(stderr," -t totals at the end\n");
- fprintf(stderr," -q quick display, no counts\n");
- fprintf(stderr," -v visual display\n");
- fprintf(stderr," -V show current version\n");
- fprintf(stderr," (2 Vs shows specified options)\n");
- exit(-1);
- }
-
- }
-
- if (version > 0 ) {
- printf("%s",VERSION);
- if (version>1) {
- printf("Tree height: %d\n",depth);
- if (dup) printf("Include duplicate inodes\n");
- if (cnt_inodes) printf("Count inodes\n");
- if (sum) printf("Include unseen subdirectories in totals\n");
- if (sw_summary) printf("Print totals at end\n");
- if (quick) printf("Quick display only\n");
- if (visual) printf("Visual tree\n");
- }
- }
-
- /* If user didn't specify targets, inspect current directory. */
-
- if (optind >= argc) {
- user_file_list_supplied = 0;
- } else {
- user_file_list_supplied = 1;
- }
-
- getcwd(topdir, sizeof (topdir)); /* find out where we are */
-
- /* Zero out grand totals */
- total_inodes = total_sizes = 0;
- /* Zero out sub_dirs */
- for (i=0; i<=MAX_V_DEPTH; i++) {
- sub_dirs[i] = 0;
- }
-
- /* Inspect each argument */
- for (i = optind; i < argc || (!user_file_list_supplied && i == argc); i++) {
- cur_depth = inodes = sizes = 0;
-
- chdir(topdir); /* be sure to start from the same place */
- get_data(user_file_list_supplied?argv[i] : topdir, TRUE);/* this may change our cwd */
-
- total_inodes += inodes;
- total_sizes += sizes;
- }
-
- if (sw_summary) {
- printf("\n\nTotal space used: %ld\n",total_sizes);
- if (cnt_inodes) printf("Total inodes: %d\n",inodes);
- }
-
- #ifdef HSTATS
- fflush(stdout);
- h_stats();
- #endif
-
- exit(0);
- } /* main */
-
-
-