Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/file.h> // FOR: read, write. IF NOT ON MACOS/BSD, TRY: <fcntl.h>
- #include <unistd.h> // FOR: read, write flags. IF NOT ON MACOS/BSD, TRY: <fcntl.h>
- #include <sys/types.h> // FOR: types within struct stat
- #include <sys/dir.h> // FOR: struct direct
- #include <sys/stat.h> // FOR: stat, fstat
- #include <sys/dirent.h> // FOR: Dirent
- /*************************** TYPEDEF & STRUCTURES ****************************/
- #if defined(DO_NOT_DEFINE)
- /* structure describing an open directory for macOS. */
- typedef struct {
- int __dd_fd; /* file descriptor associated with directory */
- long __dd_loc; /* offset in current buffer */
- long __dd_size; /* amount of data returned */
- char *__dd_buf; /* data buffer */
- int __dd_len; /* size of data buffer */
- long __dd_seek; /* magic cookie returned */
- long __dd_rewind; /* magic cookie for rewinding */
- int __dd_flags; /* flags for readdir */
- __darwin_pthread_mutex_t __dd_lock; /* for thread locking */
- struct _telldir *__dd_td; /* telldir position recording */
- } DIR;
- /* structure describing dirent for freeBSD because fuck macOS */
- struct dirent {
- __uint32_t d_fileno; /* file number of entry */
- __uint16_t d_reclen; /* length of this record */
- __uint8_t d_type; /* file type, see below */
- __uint8_t d_namlen; /* length of string in d_name */
- #ifdef _POSIX_SOURCE
- char d_name[255 + 1]; /* name must be no longer than this */
- #else
- #define MAXNAMLEN 255
- char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
- #endif
- };
- #endif
- /**************************** SYMBOLIC CONSTANTS *****************************/
- #define LOCAL_DIR "."
- #define SUPER_DIR ".."
- #define SKIP_NAME(n) ((strcmp((n), LOCAL_DIR) == 0) || (strcmp((n), SUPER_DIR) == 0))
- /* FILE NAMES */
- #define DIRENT_FNAME(ep) ((ep)->d_name) // FROM: Directory "Entry" structure
- #define DIRECT_FNAME(drp) ((drp)->d_name) // FROM: 'struct direct' type (not DIR or DIRENT)
- #define DIR_FNAME(dp) ((dp)->name) // FROM: Directory structure
- /* FILE DESCRIPTORS */
- #define DIR_FD(dp) ((dp)->__dd_fd) // FROM: Directory structure
- /* FILE INODES */
- #define DIRENT_INODE(ep) ((ep)->d_fileno) // FROM: Directory "Entry" structure
- #define DIRECT_INODE(drp) ((drp)->d_ino) // FROM: 'struct direct' type (not DIR or dirent)
- /* CUSTOM DEFINITIONS */
- #define MAX_PATH 1024 // Maximum length for a filename within a directory
- #define Dirent struct dirent
- /**************************** OPEN / CLOSE / READ ****************************/
- /* Allocates and returns an instance of DIR configured with the current directory inode information */
- DIR *openDirectory (const char *dirName) {
- int fileDescriptor;
- struct stat statBuffer;
- DIR *dp = NULL;
- if ((fileDescriptor = open(dirName, O_RDONLY, 0)) == -1) {
- fprintf(stderr, "openDirectory: Couldn't open %s\n", dirName);
- return dp;
- }
- if (fstat(fileDescriptor, &statBuffer) == -1) {
- fprintf(stderr, "openDirectory: Couldn't get inode info on %s\n", dirName);
- return dp;
- }
- if ((statBuffer.st_mode & S_IFMT) != S_IFDIR) {
- fprintf(stderr, "openDirectory: %s isn't a directory you twat\n", dirName);
- return dp;
- }
- if ((dp = malloc(sizeof(DIR))) == NULL) {
- fprintf(stderr, "openDirectory: Couldn't allocate space for DIR\n");
- return dp;
- }
- DIR_FD(dp) = fileDescriptor;
- return dp;
- }
- /* Closes an open file, and frees the given DIR instance */
- void closeDirectory (DIR *dp) {
- if (dp != NULL) {
- close(DIR_FD(dp));
- free(dp);
- }
- }
- /* Returns consecutive file entires in a DIR. Returns NULL when none remain */
- Dirent *readEntry (DIR *dp) {
- struct direct directoryBuffer;
- // DIRSIZ(dp) (((unsigned long)&((struct direct *)0)->d_name + (dp)->d_namlen+1 + 3) & ~3)
- size_t dirSize = DIRSIZ(&directoryBuffer);
- static Dirent e; // Static, so it persists outside function stack
- int code;
- while ((code = (read(DIR_FD(dp), (char *)&directoryBuffer, dirSize))) == dirSize) {
- /* If the inode is zero, the file slot is unused/removed */
- if (DIRECT_INODE(&directoryBuffer) == 0) {
- continue;
- }
- /* Assign inode number, copy name, add terminating null char */
- DIRENT_INODE(&e) = DIRECT_INODE(&directoryBuffer);
- strncpy(DIRENT_FNAME(&e), DIRECT_FNAME(&directoryBuffer), dirSize);
- DIRENT_FNAME(&e)[dirSize] = '\0';
- return &e; // &e -> ep
- }
- if (code == -1) {
- fprintf(stderr, "readEntry: Couldn't read at least one entry.\n");
- }
- return NULL;
- }
- /**************************** MAIN / FSIZE / MAP *****************************/
- /* Maps the given function to a directory's contents. Ignores self, super directory */
- void dmap (void (*f)(const char *), const char *dirName) {
- char path[MAX_PATH];
- DIR *dp; /* Directory pointer */
- Dirent *ep; /* Directory-ENTRY pointer */
- if ((dp = openDirectory(dirName)) == NULL) {
- fprintf(stderr, "dmap: Couldn't open directory %s\n", dirName);
- return;
- }
- while ((ep = readEntry(dp)) != NULL) {
- if (SKIP_NAME(DIRENT_FNAME(ep))) {
- continue;
- }
- if (strlen(dirName) + strlen(DIRENT_FNAME(ep)) + 2 > sizeof(path)) {
- fprintf(stderr, "dmap: Name %s/%s exceeds MAX_PATH (%d)\n", dirName, DIRENT_FNAME(ep), MAX_PATH);
- } else {
- sprintf(path, "%s/%s", dirName, DIRENT_FNAME(ep));
- (*f)(path);
- }
- }
- closeDirectory(dp);
- }
- /* Output file size, or map self to contents if directory */
- void fsize (const char *fileName) {
- struct stat statBuffer;
- if (stat(fileName, &statBuffer) == -1) {
- fprintf(stderr, "fsize: Couldn't get inode info on %s\n", fileName);
- return;
- }
- if ((statBuffer.st_mode & S_IFMT) == S_IFDIR) {
- dmap(fsize, fileName);
- }
- fprintf(stdout, "%s: %8lld bytes", fileName, statBuffer.st_size);
- }
- /* Output sizes of specified files, else of local directory */
- int main (int argc, const char *argv[]) {
- if (argc == 1) {
- fsize(LOCAL_DIR);
- } else {
- while (--argc > 0) {
- fsize(*(++argv));
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement