#include #include #include #define BUFFER_SIZE 64 #define MAX_FILES 32 #define MAX_CHILDREN 16 #define THRESHOLD 100000 // at most #define RULE <= #define TOTAL_SIZE 70000000 #define SPACE_NEEDED 30000000 typedef enum commands { CD, LS } COMMAND; typedef struct fnode { char name[BUFFER_SIZE]; unsigned long size; } FNODE; typedef struct dir { char name[BUFFER_SIZE]; FNODE files[MAX_FILES]; int files_num; struct dir *parent; struct dir *children[MAX_CHILDREN]; int children_num; int cached; unsigned long cached_size; } DIR; COMMAND map_cmd(char *); DIR* createDir(char*, DIR*); void cp(char*, char*); DIR* findDirName(DIR*, char*); FNODE* findFileName(DIR*, char*); int cmp(char*, char*); void release(DIR*); unsigned long dirsize(DIR*); void gotta_catch_em_all(DIR*); void omelette_du_fromage(DIR*, DIR**, unsigned long); unsigned long sum; int main() { char linebuf[BUFFER_SIZE], buf[BUFFER_SIZE], *p, c; memset(linebuf, 0, BUFFER_SIZE); p = linebuf; COMMAND cmd; DIR *currentDir = NULL, *rootDir = NULL, *target; FNODE *tmpf; unsigned long fsize; while ((c = getchar()) != EOF) { *p++ = c; if (c == '\n') { if (linebuf[0] == '$') { // command memset(buf, 0 , BUFFER_SIZE); sscanf(linebuf, "$ %s", buf); cmd = map_cmd(buf); if (cmd == CD) { memset(buf, 0 , BUFFER_SIZE); sscanf(linebuf + 4, "%s", buf); if (buf[0] == '/' && buf[1] == 0) { // Root if (rootDir == NULL) rootDir = createDir(buf, NULL); currentDir = rootDir; } else if (buf[0] == '.' && buf[1] == '.' && buf[2] == 0) { currentDir = currentDir->parent; } else { target = findDirName(currentDir, buf); if (target == NULL) { target = createDir(buf, currentDir); } currentDir = target; } } else if (cmd == LS) { // Nothing to do } } memset(buf, 0 , BUFFER_SIZE); if (sscanf(linebuf, "%lu %s", &fsize, buf)) { // File tmpf = findFileName(currentDir, buf); if (tmpf == NULL) { cp(buf, currentDir->files[currentDir->files_num].name); currentDir->files[currentDir->files_num].size = fsize; currentDir->files_num++; } } else { // Dir sscanf(linebuf, "dir %s", buf); target = findDirName(currentDir, buf); if (target == NULL) { target = createDir(buf, currentDir); } } memset(linebuf, 0, BUFFER_SIZE); p = linebuf; } } // First part gotta_catch_em_all(rootDir); printf("%lu\n", sum); // Second part DIR *bestMatch = rootDir; unsigned long free_space = TOTAL_SIZE - dirsize(rootDir); printf("\nFREE SPACE: %lu\n", free_space); omelette_du_fromage(rootDir, &bestMatch, free_space); printf("TO DELETE: %s, %lu\n", bestMatch->name, dirsize(bestMatch)); currentDir = NULL; // "Aki malloc-ot mond, mondjon free-t is" release(rootDir); free(rootDir); } COMMAND map_cmd(char *buf) { if (buf[0] == 'c' && buf[1] == 'd') { return CD; } else if (buf[0] == 'l' && buf[1] == 's') { return LS; } return -1; } DIR* createDir(char* name, DIR* parent) { DIR* newDir = (DIR*)malloc(sizeof(DIR)); memset(newDir->files, 0, MAX_FILES*sizeof(FNODE)); memset(newDir->children, 0, MAX_CHILDREN*sizeof(DIR*)); newDir->files_num = 0; newDir->children_num = 0; newDir->parent = parent; newDir->cached = 0; if (parent != NULL) { parent->children[parent->children_num] = newDir; parent->children_num++; } cp(name, newDir->name); return newDir; } void cp(char *p , char *q){ while((*q++ = *p++) != 0) {} } DIR* findDirName(DIR* dir, char *name) { for (int i = 0; i < dir->children_num; i++) { if (cmp(dir->children[i]->name, name)) { return dir->children[i]; } } return NULL; } int cmp(char *p, char *q) { for (int i = 0; i < BUFFER_SIZE; i++) { if (p[i] != q[i]) { return 0; } } return 1; } void release(DIR* dir) { for (int i = 0; i < dir->children_num; i++) { release(dir->children[i]); free(dir->children[i]); } } FNODE* findFileName(DIR* dir, char* name) { for (int i = 0; i < dir->files_num; i++) { if (cmp(dir->files[i].name, name)) { return &dir->files[i]; } } return NULL; } unsigned long dirsize(DIR* dir) { if (dir->cached) { return dir->cached_size; } unsigned long mysize = 0; // Files here for (int i = 0; i < dir->files_num; i++) { mysize += dir->files[i].size; } // Files in subdirectories for (int i = 0; i < dir->children_num; i++) { mysize += dirsize(dir->children[i]); } dir->cached = 1; dir->cached_size = mysize; return mysize; } // I know this is shit, each directory should have a size cache // so if we already know its size we don't recurse it again // But I don't care at this point void gotta_catch_em_all(DIR* dir) { unsigned long schlong = dirsize(dir); if (schlong RULE THRESHOLD) { sum += schlong; } for (int i = 0; i < dir->children_num; i++) { gotta_catch_em_all(dir->children[i]); } } void omelette_du_fromage(DIR* dir, DIR** bestMatch, unsigned long freeSpace) { unsigned long current = freeSpace + dirsize(dir); if (current > SPACE_NEEDED && current < (freeSpace + dirsize(*bestMatch))) { *bestMatch = dir; } for (int i = 0; i < dir->children_num; i++) { omelette_du_fromage(dir->children[i], bestMatch, freeSpace); } }