diff options
author | Willy Tarreau <willy@wtap.(none)> | 2006-07-26 10:46:55 +0200 |
---|---|---|
committer | Willy Tarreau <willy@wtap.(none)> | 2006-07-26 10:46:55 +0200 |
commit | fcb250efba23ae522c4c8cb03c47dd40edcf9603 (patch) | |
tree | 3756bd1748842a3f1049d857e8412f148a8741b9 /flx/input_fs.c | |
parent | Initial commit (diff) | |
download | flxutils-fcb250efba23ae522c4c8cb03c47dd40edcf9603.tar.xz |
[RELEASE] flxutils-0.1.4.2v0.1.4.2
Diffstat (limited to 'flx/input_fs.c')
-rw-r--r-- | flx/input_fs.c | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/flx/input_fs.c b/flx/input_fs.c new file mode 100644 index 0000000..042134c --- /dev/null +++ b/flx/input_fs.c @@ -0,0 +1,332 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> + +#include "input_fs.h" +#include "flx.h" +#include "utils.h" + +#define STAT_NOTREAD 0x01 +#define STAT_TOBECONTINUED 0x02 +#define STAT_DOINIT 0x04 + + +#define OPT_XDEV 0x01 +#define OPT_FOLLOW_LINKS 0x02 +#define OPT_SORTED 0x04 +#define OPT_READ 0x08 + +static t_file_desc *complete_info_from_fs(char *path, t_file_desc *desc) { + struct stat stat; + + /* try to stat it */ + if (lstat(path, &stat)) { + PFERROR("stat(%s)", path); + return (0); + } + if (!desc) { + /* have to create it */ + desc = MALLOC(sizeof(*desc)); + bzero(desc, sizeof(*desc)); + } + /* copy stat informations */ + memcpy(&desc->stat, &stat, sizeof(stat)); + + if (S_ISREG(stat.st_mode) && !desc->md5) /* get md5 checksum */ + desc->md5 = checksum_md5_from_file(path); + else if (S_ISLNK(stat.st_mode) && !desc->link) { + /* get link and md5 associed */ + char temp[BUFFER_LENGTH]; + int l; + + if ((l = readlink(path, temp, BUFFER_LENGTH)) < 0) { + PFERROR("readlink(%s)", path); + } else { + temp[l] = 0; + desc->link = strdup(temp); + desc->md5 = checksum_md5_from_data(temp, l); + } + } + return (desc); +} + +int desc_s_isdir_from_fs(char *filename, t_file_desc *desc) { + if (!desc) { + struct stat st; + if (!filename) return (0); + + if (stat(filename, &st)) { + PFERROR("stat(%s)", filename); + return (0); + } + return (S_ISDIR(st.st_mode)); + } + return (S_ISDIR(desc->stat.st_mode)); +} + +#define DESC_S_ISDIR(desc) ((desc)?(S_ISDIR(((t_file_desc*)(desc))->stat.st_mode)):0) +#define DESC_DEV(desc) ((desc)?(((t_file_desc*)(desc))->stat.st_dev):0) + + +/* get file entries from filesystem + * ics : input current status + * tree : tree to load + * return the number of entries readed + */ +int input_fs_read(t_fs_status *desc, t_ft *tree) { + char *pcpath, *pbpath; + int count = 0, cmax = COUNT_LEVEL2; + + /* something to read or no more dir to read */ + if (!desc->dirnames) return (0); + + /* force to mark base ABNORMAL! */ + SET(tree->status, CHANGED); + /* restore/build tree position for cpath */ + tree = ft_get(tree, desc->cpath); + + /* set base path pointers */ + pcpath = desc->cpath + strlen(desc->cpath); + pbpath = desc->bpath + strlen(desc->bpath); + + /* read infos for wanted directory */ + if (IS(desc->status, STAT_DOINIT)) { + + if (!(tree->desc = complete_info_from_fs(desc->bpath, tree->desc))) + return (0); + SET_PARENT(tree, CHANGED); + SET(tree->status, FILLED); + count++; + + /* remove init flag */ + UNSET(desc->status, STAT_DOINIT); + + /* set base device */ + desc->dev = DESC_DEV(tree->desc); + + /* this part is used to detect directory and directly */ + if (IS(Options, GOPT_IGNORE_DEPTH) || + !DESC_S_ISDIR(tree->desc) || desc->depth == 1) { + SIMPLE_LIST_POP(desc->dirnames); + return (count); + } + + /* sub directory recursion */ + desc->depth--; + } + + while (1) { + + /* get directory entries if never done */ + if (IS(desc->status, STAT_NOTREAD)) { + DIR *dir; + struct dirent *dirent = NULL; + t_ft *new; + + /* mark directory as unsorted */ + SET(tree->status, SORTING); + + if (!(dir = opendir(desc->bpath))) + PFERROR("opendir(%s)", desc->bpath); + else { + /* restore old stored position */ + if (IS(desc->status, STAT_TOBECONTINUED)) { + seekdir(dir, desc->off_dir); + } + + /* look for each files */ + while ((!cmax || count < cmax)) { + + if (!(dirent = readdir(dir))) break; + + /* options tell to ignore '.' and '..' */ + if (IS(Options, GOPT_IGNORE_DOT) && IS_DOTF(dirent->d_name)) + continue; + + /* build path to work with it */ + // ADD_PATH(desc->cpath, pcpath, dirent->d_name); + ADD_PATH(desc->bpath, pbpath, dirent->d_name); + + /* create/get entry */ + new = ft_get(tree, dirent->d_name); + + /* get file informations */ + new->desc = complete_info_from_fs(desc->bpath, new->desc); + SET_PARENT(new, CHANGED); + SET(new->status, FILLED); + + /* if directory (without . and ..) and not XDEV */ + /* if not maximum directory level reached */ + if (desc->depth != 1 && + DESC_S_ISDIR(new->desc) && !IS_DOTF(dirent->d_name) && + (!IS(desc->options, OPT_XDEV) || desc->dev == DESC_DEV(new->desc))) { + + PUSH_STR_SORTED(SIMPLE_LIST_PTR(desc->dirnames), + STRDUP(dirent->d_name)); + /* set flag SORTING to futur directory */ + SET(new->status, SORTING); + } + count++; + } + *pcpath = *pbpath = 0; + + /* have finished to read ?? */ + if (dirent) { + /* no break and return number */ + desc->off_dir = telldir(dir); + closedir(dir); + SET(desc->status, STAT_TOBECONTINUED); + return (count); + } + closedir(dir); + } + UNSET(desc->status, STAT_NOTREAD|STAT_TOBECONTINUED); + } + + /* all files in this directory are read */ + UNSET(tree->status, SORTING); + + /* look for all directories marked */ + if (SIMPLE_LIST_PTR(desc->dirnames)) { + char *filename; + + filename = SIMPLE_LIST_POP(SIMPLE_LIST_PTR(desc->dirnames)); + /* get new path and add it to current */ + pcpath = ADD_PATH(desc->cpath, pcpath, filename); + /* set new complet path */ + pbpath = ADD_PATH(desc->bpath, pbpath, filename); + + /* decrease directory depth */ + if (desc->depth) desc->depth--; + + /* push a new directory stack */ + SIMPLE_LIST_PUSH(desc->dirnames, NULL); + /* seek tree with new path */ + tree = ft_get(tree, filename); + + SET(desc->status, STAT_NOTREAD); + FREE(filename); + continue; + } + + /* nothing to do return to parent */ + SIMPLE_LIST_POP(desc->dirnames); + + /* increase directory depth */ + if (desc->depth) desc->depth++; + + /* no more parent */ + if (!desc->dirnames) return (count); + /* set to parent */ + tree = tree->parent; + pcpath = REMOVE_DIR(desc->cpath, pcpath); + *pcpath = 0; + pbpath = REMOVE_DIR(desc->bpath, pbpath); + *pbpath = 0; + } + return (count); +} + + +/* traduct a string options descriptions to flags + */ +int input_fs_fcntl(t_fs_status *env, int cmd) { + if (IS(cmd, IS_SORTED)) return (env ? IS(env->options, OPT_SORTED) : 1); + return (0); +} + +/* initialise or add data to current input driver + */ +t_fs_status *input_fs_open(char *pathname, char *opts) { + t_fs_status *new; + char tmp[BUFFER_LENGTH]; + char *ppath, *popts, *pvalue, *filename; + int status = 0; + int options = (OPT_SORTED|OPT_XDEV|OPT_READ); + int depth = 0; + + popts = opts ? strcpy(tmp, opts) : NULL; + ppath = pathname ? strcpy(tmp + strlen(tmp) + 1, pathname) : NULL; + + while (popts) { + int sign = 1; + char *t; + + /* select an option and its value */ + if ((t = strchr(popts, '+'))) *t++ = 0; + if ((pvalue = strchr(popts, '='))) *pvalue++ = 0; + + /* remove negative */ + while (*popts == '!') { sign = -sign ; popts++; } + + /* treat option */ + if (!*popts) continue; + else if (!strcmp(popts, "sort")) /* sorted flag */ + options = (sign > 0 ? (options|OPT_SORTED) : (options&~OPT_SORTED)); + else if (!strcmp(popts, "xdev")) /* do not recurse across fs */ + options = (sign > 0 ? (options|OPT_XDEV) : (options&~OPT_XDEV)); + else if (!strcmp(popts, "depth")) /* recursive level across directory */ + depth = atoi(pvalue); + else if (!strcmp(popts, "flw")) /* follow links */ + options = (sign > 0 ? (options|OPT_FOLLOW_LINKS) : (options&~OPT_FOLLOW_LINKS)); + else { + error("unknown option : %s", popts); + return (0); + } + popts = t; + } + + new = MALLOC(sizeof(*new)); + bzero(new, sizeof(*new)); + + new->dirnames = NULL; + SIMPLE_LIST_PUSH(new->dirnames, NULL); + new->status = STAT_NOTREAD | STAT_DOINIT; + + /* save special options */ + new->options = options; + new->depth = depth; + + filename = ppath; + /* looking for separator before filename */ + if (ppath && (ppath = backslashed_strmchr(ppath, DELIM_LIST))) { + status = *ppath; + *ppath++ = 0; + } + + strcpy(new->bpath, define_cleaned_path(filename)); + if (!*new->bpath) strcpy(new->bpath, "."); + + /* have to remove sub parameters */ + // HERE + + if (status == '=' && ppath) + strcpy(new->cpath, define_cleaned_path(ppath)); + else + strcpy(new->cpath, define_base_path(filename)); + return (new); +} + +/* free all used memory + */ +t_fs_status *input_fs_close(t_fs_status *old) { + while (old->dirnames) { + while (SIMPLE_LIST_PTR(old->dirnames)) + FREE(SIMPLE_LIST_POP(SIMPLE_LIST_PTR(old->dirnames))); + SIMPLE_LIST_POP(old->dirnames); + } + FREE(old); + return (NULL); +} + + + + + + + + + |