243 lines
6.2 KiB
C
243 lines
6.2 KiB
C
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#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);
|
||
|
|
}
|
||
|
|
}
|