/* DU : List the space consumed by the current directory. (C) Copyright 1996. Scott Corcoran. All rights reserved. This program is free software. You may copy and/or modify it under the terms of the General Public License published by the Free Software Foundation, version 2 or later. NO WARRANTY. The author and his assignees make no guarantees about the performance or adequacy of this program for any particular purpose. */ static char *Usage[] = { "Options:", "\t-b: Report the number of 512 byte blocks\n", "\t-k: Report the number of 1024 byte blocks\n", "\t-n: Report the number of bytes in a form suitable for arithmetic\n", (char *) 0 }; #include #include #include #include #include typedef unsigned long long Long; void PrintUsage(); /* Program options live here */ char *program_path; bool nocommas; bool countblocks; bool countkilos; #ifdef WIN32 #include #include #define DIR_SEPARATOR '\\' Long du(const char *path); #else #include #include #include #define DIR_SEPARATOR '/' #define MOSTPATHLEN 256 Long du(const char *arg, int arglen); #endif int prettyprint(Long size, const char *path); int main(int argc, char **argv) { program_path = argv[0]; int i; int errcount = 0; /* Interpret options */ for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; if (argv[i][0] == '-' && argv[i][2] == '\0') { switch (argv[i][1]) { case 'b': countblocks = true; continue; case 'n': nocommas = true; continue; case 'k': countkilos = true; continue; } } /* Dropped through to handle bogus option */ (void) fprintf(stderr, "%s: Bogus option, %s\n", program_path, argv[i]); errcount++; } if (errcount) { PrintUsage(); exit(1); } /* If no remaining arguments, use . */ i--; argc -= i; argv += i; if (countblocks) printf("512-blocks directory\n"); else if (countkilos) printf("1k-blocks directory\n"); else printf("bytes directory\n"); #ifdef WIN32 if (argc == 1) (void) du("."); else for (int i = 1; i < argc; i++) (void) du(argv[i]); #else if (argc == 1) (void) du(".", 1); else for (int i = 1; i < argc; i++) (void) du(argv[i], strlen(argv[i])); #endif return 0; } #ifdef unix /* Visit a single file or directory */ Long du(const char *arg, int arglen) { Long size = 0; /* Size including all subdirs of current node */ struct stat statpacket; /* File status for the current node */ if (lstat(arg, &statpacket)) { if (errno == EOVERFLOW) size = statpacket.st_blocks * statpacket.st_blocks * 512; else { perror(arg); return 0; } } else size = statpacket.st_size; if (countblocks) size = size / 512 + (size % 512 > 0); else if (countkilos) size = size / 1024 + (size % 1024 > 0); /* If it is a directory, go and visit all of the files inside */ if ((statpacket.st_mode & S_IFMT) == S_IFDIR) { DIR *dirp = opendir(arg); if (dirp == (DIR *) 0) { perror(arg); return 0; } struct dirent *ent; char *path = (char *) alloca(arglen + sizeof ent->d_name + 1); memcpy(path, arg, arglen); path[arglen] = DIR_SEPARATOR; while (ent = readdir(dirp)) { if (ent->d_name[1] == '\0' && ent->d_name[0] == '.') continue; if (ent->d_name[2] == '\0' && ent->d_name[0] == '.' && ent->d_name[1] == '.') continue; int len = arglen + 1 + strlen(ent->d_name); memcpy(&path[arglen + 1], ent->d_name, len); path[len] = '\0'; size += du(path, len); } (void) closedir(dirp); prettyprint(size, arg); } return size; } #endif #ifdef WIN32 Long du(const char *arg) { short len = strlen(arg); if (len == 0) return 0; // ERROR_INVALID_NAME char *path = (char *) alloca(len + MAX_PATH + 1); memcpy(path, arg, len + 1); // Do not start in the root directory if a disk name. if (len == 1 && path[0] == '.') { strcpy_s(path, 4, "*.*"); len = 0; } else if (len < 3 && path[len - 1] == ':') { strcpy_s(&path[len], 6, ".\\*.*"); len += 2; } else { if (len >= 2 && path[len - 2] == '\\' && path[len - 1] == '.') len -= 2; else if (path[len - 1] == '\\') len -= 1; strcpy_s(&path[len++], 5, "\\*.*"); } Long totalsize = 0; WIN32_FIND_DATA dirent; HANDLE dir = FindFirstFile(path, &dirent); if (dir == INVALID_HANDLE_VALUE) { fprintf(stderr, "%s: Error number %d\n", path, GetLastError()); return 0; } do { char *name = dirent.cFileName; if (name[0] == '.') { if (name[1] == '.') if (name[2] == '\0') continue; else; else if (name[1] == '\0') continue; } strcpy_s(&path[len], strlen(name) + 1, name); Long filesize = ((Long)dirent.nFileSizeHigh << 32) | dirent.nFileSizeLow; if (countblocks) filesize = filesize / 512 + (filesize % 512 > 0); else if (countkilos) filesize = filesize / 1024 + (filesize % 1024 > 0); if (dirent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) totalsize += du(path); else totalsize += filesize; } while (FindNextFile(dir, &dirent)); if (!FindClose(dir)) fprintf(stderr, "%s: Close error %d\n", path, GetLastError()); int x = prettyprint(totalsize, arg); if (x <= 0) { perror("write: disk full? "); exit(1); } return totalsize; } #endif int prettyprint(Long size, const char *path) { /* Create a pointer to a path worth printing */ if (path[0] == '.' && path[1] == DIR_SEPARATOR) path += 2; #ifdef unix else if (path[0] == DIR_SEPARATOR && path[1] == DIR_SEPARATOR) path++; #endif if (!nocommas) { if (size >= 1000000000) return printf("%ld,%.3ld,%.3ld,%.3ld %s\n", (int)(size / 1000000000), (int)((size / 1000000) % 1000), (int)((size / 1000) % 1000), (int)(size % 1000), path); if (size >= 100000000) return printf("%ld,%.3ld,%.3ld %s\n", (int)(size / 1000000), (int)((size / 1000) % 1000), (int)(size % 1000), path); if (size >= 10000000) return printf("%ld,%.3ld,%.3ld %s\n", (int)(size / 1000000), (int)((size / 1000) % 1000), (int)(size % 1000), path); if (size >= 1000000) return printf("%ld,%.3ld,%.3ld %s\n", (int)(size / 1000000), (int)(size / 1000) % 1000, (int)(size % 1000), path); if (size >= 100000) return printf("%ld,%.3ld %s\n", (int)size / 1000, (int)(size % 1000), path); if (size >= 10000) return printf("%ld,%.3ld %s\n", (int)size / 1000, (int)(size % 1000), path); if (size >= 1000) return printf("%ld,%.3ld %s\n", (int)size / 1000, (int)(size % 1000), path); if (size >= 100) return printf("%ld %s\n", (int)size, path); if (size >= 10) return printf("%ld %s\n", (int)size, path); return printf("%ld %s\n", (int)size, path); } else { return printf("%-13lld %s\n", size, path); } } void PrintUsage() { (void) fprintf(stderr, "%s: Program aborted\n", program_path); for (int i = 0; Usage[i]; i++) (void) fprintf(stderr, "%s\n", Usage[i]); exit(1); }