aboutsummaryrefslogtreecommitdiff
path: root/flx/input_fs.c
diff options
context:
space:
mode:
authorWilly Tarreau <willy@wtap.(none)>2006-07-26 10:46:55 +0200
committerWilly Tarreau <willy@wtap.(none)>2006-07-26 10:46:55 +0200
commitfcb250efba23ae522c4c8cb03c47dd40edcf9603 (patch)
tree3756bd1748842a3f1049d857e8412f148a8741b9 /flx/input_fs.c
parentInitial commit (diff)
downloadflxutils-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.c332
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);
+}
+
+
+
+
+
+
+
+
+