Archived
1
0
Fork 0
This repository has been archived on 2026-05-10. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
archived/src/fs/tree.c

194 lines
3.3 KiB
C

/* fs/tree.c - Filesystem traversal
*
* (C) Copyright 2010 Henrik Hautakoski <henrik.hautakoski@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <errno.h>
#include <dirent.h>
#include "../common/mem.h"
#include "../common/path.h"
#include "tree.h"
#if 0
#define pdebug(...) fprintf(stderr, __VA_ARGS__)
#else
#define pdebug(...) 0
#endif
#define isrefdir(x) (!strcmp(x->d_name, ".") || !strcmp(x->d_name, ".."))
/* REF:1 */
static int have_perm(const char *base, const char *name) {
char buf[1024];
sprintf(buf, "%s%s", base, name);
return access(buf, R_OK | X_OK) == 0;
}
struct tree* tree_new(const char *path) {
int i;
struct tree *t = malloc(sizeof(struct tree));
if (t == NULL)
return NULL;
t->path = fmt_path(path, NULL, 0);
if (t->path == NULL) {
free(t);
return NULL;
}
t->depth = 0;
t->dirs[0] = opendir(t->path);
if (!t->dirs[0]) {
free(t->path);
free(t);
return NULL;
}
t->ent.name = NULL;
t->ent.base = NULL;
t->ent.dir = 0;
return t;
}
void tree_del(struct tree *tree) {
int i;
for(i=0; i < tree->depth; i++)
closedir(tree->dirs[i]);
if (tree->path != NULL)
free(tree->path);
free(tree);
}
/* REF:1 */
int tree_mvup(struct tree *tree) {
char *slash;
if (closedir(tree->dirs[tree->depth]) == -1) {
perror("TREE");
return -1;
}
if (tree->depth == 0)
return 0;
#if __DEBUG__
printf("tree_next_ent: tree depth is: %i \n", tree->depth);
#endif
tree->depth--;
slash = tree->path + strlen(tree->path)-1;
if (*slash == '/')
*slash = 0;
slash = strrchr(tree->path, '/');
*(slash+1) = 0;
tree->path = realloc(tree->path, sizeof(char) * (strlen(tree->path)+1));
return 1;
}
/* REF:1 */
int tree_mvdown(struct tree *tree, const char *dir) {
char buf[PATH_MAX];
DIR *ds;
if (tree->depth >= MAX_DEPTH-1)
return 0;
sprintf(buf, "%s%s/\0", tree->path, dir);
if ((ds = opendir(buf)) == NULL) {
if (errno != EACCES)
perror("DIROPEN");
return 0;
}
tree->path = realloc(tree->path, sizeof(char) * (strlen(buf)+1));
memcpy(tree->path, buf, strlen(buf)+1);
tree->dirs[++tree->depth] = ds;
return 1;
}
struct entry* tree_cpy_ent(struct entry *ent) {
struct entry *ptr = malloc(sizeof(struct entry));
if (ptr == NULL)
return NULL;
memcpy(ptr, ent, sizeof(struct entry));
return ptr;
}
/*
* NOTE: only read from the struct returned and DO NOT free it.
* use tree_cpy_ent() if you need to store it.
*/
struct entry* tree_next_ent(struct tree *tree) {
struct dirent *ent = NULL;
if (tree == NULL)
return NULL;
if (tree->ent.dir)
tree_mvdown(tree, tree->ent.name);
for(;;) {
ent = readdir(tree->dirs[tree->depth]);
if (ent == NULL) {
if (tree_mvup(tree))
continue;
tree_del(tree);
return NULL;
} else if (isrefdir(ent)) {
continue;
} else if (ent->d_type == 4) {
if (have_perm(tree->path, ent->d_name))
break;
} else {
break;
}
}
tree->ent.dir = ent->d_type == 4;
tree->ent.base = tree->path;
tree->ent.name = &ent->d_name[0];
return &tree->ent;
}