tom@cogpsi.UUCP (Tom Vijlbrief) (05/08/87)
This (MSC 4.00) C program implements a Un*x like du program. It computes the size of (sub)directory trees. Tom Vijlbrief TNO Institute for Perception P.O. Box 23 Phone: +31 34 63 14 44 3769 DE Soesterberg E-mail: tnosoes!cogpsi!tom@mcvax.cwi.nl The Netherlands {seismo|...}!mcvax!tnosoes!cogpsi!tom PS: It would be nice if someone ON EUNET send me the sources of the Unix patch program, Thanks. C source follows: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /* * du.c: * * `Du' is a disk usage utility which computes the diskusage of * all the files in a directory and it's subdirectories. * * This utility is comparable with the UNIX du program. * * Usage: du [-s] [-a] [d:path ...] * * Option -s (/s) does not show subdirectories (short listing). * Option -a (/a) shows size of all the files. * * Copyright: Tom Vijlbrief, Baarn, The Netherlands * Date: Fri May 8 13:53:29 GMT+1:00 1987 * * This program may be distributed freely for non commercial purposes * and with this Copyright notice unchanged. */ /* * Compilation must be performed with structure packing and larger stack: * Microsoft C 4.00: -Zp -F2000 */ #include <stdio.h> #include <string.h> #include <dos.h> #include <io.h> #include <direct.h> #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> #define BLOCK_SIZE 512 #define ALL_FILES (0x1 | 0x2 | 0x4 | 0x10 |0x20) #define DIRECTORIES (0x10) #define NAME_LEN 8 #define EXT_LEN 3 #define MAX_CWD 256 typedef unsigned char byte; typedef struct { byte FF; byte zero_5[5]; byte attribute; byte drive; char name[NAME_LEN]; char extension[EXT_LEN]; unsigned cur_block; unsigned rec_size; unsigned fs_low; unsigned fs_high; unsigned date; byte unused2[10]; byte cur_record; unsigned ran_low; unsigned ran_high; } ext_fcb; char *get_first(char *, int, ext_fcb *); char *get_next(ext_fcb *); long scan(); byte sector[BLOCK_SIZE]; int cluster_size; int a_flag; int s_flag; int in_tree; ext_fcb return_fcb; main(argc, argv) int argc; char *argv[]; { char *option_p; static char cur_cwd[MAX_CWD]; int drive_nr; int cur_drive; while (argc > 1) { option_p= *++argv; if (*option_p == '-' || *option_p == '/') { for (option_p++; *option_p; option_p++) { switch (*option_p) { case 'a': a_flag++; break; case 's': s_flag++; break; default: fprintf(stderr, "Unknown option: %c\n", *option_p); fprintf(stderr, "Usage: du [-s] [-a] [d:path ...]\n"); exit(1); } } argc--; } else break; } if (argc == 1) { cluster_size= comp_cluster(get_drive()); scan(); } else { for (; argc > 1; argc--, argv++) { cur_drive= get_drive(); getcwd(cur_cwd, MAX_CWD - 1); if ((*argv)[1] == ':') set_drive(tolower((*argv)[0]) - 'a'); if (chdir(*argv) != 0) { perror(*argv); set_drive(cur_drive); continue; } cluster_size= comp_cluster(get_drive()); scan(); set_drive(cur_drive); if (chdir(cur_cwd) != 0) { perror(cur_cwd); exit(1); } in_tree= 0; } } } static struct stat the_stat; static char cwd[MAX_CWD]; long scan() { char *p; long file_size; long disk_use; int tree_flag; ext_fcb the_fcb; char pattern[NAME_LEN + EXT_LEN + 2]; tree_flag= in_tree; disk_use= 0; strcpy(pattern, "????????.???"); p= get_first(pattern, ALL_FILES, &the_fcb); for (; p != NULL; p= get_next(&the_fcb)) { if (strcmp(p, ".. . ") == 0 || strcmp(p, ". . ") == 0) continue; if (stat(p, &the_stat) != 0) { perror(p); exit(1); } if (the_stat.st_mode & S_IFDIR) { if (a_flag) { printf("%s\n", p); printf("========================\n"); } chdir(p); in_tree= 1; disk_use+= scan(); chdir(".."); } else { disk_use+= ((file_size= the_stat.st_size) + (cluster_size - 1)) / cluster_size * cluster_size; if (a_flag) { printf("%s: %10ld\n", p, file_size); } } } if (a_flag) printf("========================\n"); if (!s_flag || !tree_flag) printf("Disk Usage : %10ld (%s)\n", disk_use, getcwd(cwd, MAX_CWD - 1)); if (a_flag) printf("\n"); return(disk_use); } /* * get_first returns the first_name in a directory matching the * pattern (e.g. ????????.OBJ) and attribute */ char *get_first (pattern, attribute, fcb_p) char *pattern; int attribute; ext_fcb *fcb_p; { set_dta(&return_fcb); strncpy(fcb_p->name, pattern, NAME_LEN); strncpy(fcb_p->extension, pattern + NAME_LEN + 1, EXT_LEN); fcb_p->attribute= attribute; fcb_p->FF= 0xFF; fcb_p->drive= get_drive() + 1; if ((bdos(0x11, (int) fcb_p, 0) & 0xFF) == 0) { strncpy(pattern, return_fcb.name, NAME_LEN); strncpy(pattern + NAME_LEN + 1, return_fcb.extension, EXT_LEN); return(pattern); } else return(NULL); } char *get_next(fcb_p) ext_fcb *fcb_p; { static char pattern[]= "12345678.123"; set_dta(&return_fcb); if ((bdos(0x12, (int) fcb_p, 0) & 0xFF) == 0) { strncpy(pattern, return_fcb.name, NAME_LEN); strncpy(pattern + NAME_LEN + 1, return_fcb.extension, EXT_LEN); pattern[NAME_LEN + EXT_LEN + 1]= '\0'; return(pattern); } else { return(NULL); } } /* * `set_drive' changes the current drive. (A = 0, etc). */ int set_drive(drive_nr) int drive_nr; { return(bdos(0xE, drive_nr, 0) & 0xFF); } /* * `get_drive' returns the number of the current drive. (A = 0, etc). */ int get_drive() { return(bdos(0x19, 0, 0) & 0xFF); } set_dta(p) ext_fcb *p; { return(bdos(0x1A, (int) p, 0) & 0xFF); } #define DISK 0x13 #define READ_SECT 0x2 #define RESET_DISK 0x0 #define FLOP_RETRIES 3 int readsect(buffer, drive, head, cyl, sector, n_sectors) char *buffer; unsigned int drive; unsigned int head; unsigned int cyl; unsigned int sector; unsigned int n_sectors; { int result; int retries; int max_retries; union REGS inregs, outregs; struct SREGS segregs; segread(&segregs); segregs.es= segregs.ds; if (drive < 0x80) max_retries= FLOP_RETRIES; else max_retries= 1; for (retries= 0; retries < max_retries; retries++) { if (drive < 0x80) { inregs.h.ah= RESET_DISK; inregs.h.dl= drive; int86(DISK, &inregs, &outregs); } inregs.h.ah= READ_SECT; inregs.x.bx= (unsigned) buffer; inregs.h.dl= drive; inregs.h.dh= head; inregs.h.ch= cyl; inregs.h.cl= sector | ((cyl & ~0xFF) >> 2); inregs.h.al= n_sectors; result= (unsigned) int86x(DISK, &inregs, &outregs, &segregs) >> 8; if (outregs.x.cflag) continue; else break; } if (retries == max_retries) return(-result); else return(0); } int comp_cluster(drive_nr) int drive_nr; { int nr_sectors; int head_nr; int high_head; int sector_nr; if (drive_nr > 1) drive_nr+= 0x80 - 2; high_head= max_head(drive_nr); for (head_nr= 0; head_nr <= high_head; head_nr++) { for (sector_nr= 1; sector_nr <= 8; sector_nr++) { if (readsect(sector, drive_nr, head_nr, 0, sector_nr, 1) != 0) { fprintf(stderr, "Cannot read bootblock from disk\n"); exit(1); } if (sector[0] == 0xEB) break; } if (sector[0] == 0xEB) break; } if (sector_nr > 8 || (nr_sectors= sector[13]) > 16) { nr_sectors= 4; fprintf(stderr, "Unknown bootblock, clustersize of 4 sectors assumed\n"); } if (nr_sectors == 0) nr_sectors= 2; return(nr_sectors * BLOCK_SIZE); } #define GET_PARAM 0x8 int max_head(drive) unsigned int drive; { union REGS inregs, outregs; inregs.h.ah= GET_PARAM; inregs.h.dl= drive; int86(DISK, &inregs, &outregs); if (outregs.x.cflag) return(0); else return(outregs.h.dh); }