home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume15
/
vtree
/
vtree.c
< prev
Wrap
C/C++ Source or Header
|
1988-05-23
|
10KB
|
409 lines
/* 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 */