aboutsummaryrefslogtreecommitdiff
path: root/flx/input_file.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_file.c
parentInitial commit (diff)
downloadflxutils-fcb250efba23ae522c4c8cb03c47dd40edcf9603.tar.xz
[RELEASE] flxutils-0.1.4.2v0.1.4.2
Diffstat (limited to 'flx/input_file.c')
-rw-r--r--flx/input_file.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/flx/input_file.c b/flx/input_file.c
new file mode 100644
index 0000000..5a4b0c5
--- /dev/null
+++ b/flx/input_file.c
@@ -0,0 +1,462 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+
+#include "input_file.h"
+#include "utils.h"
+#include "flx.h"
+
+
+#define STAT_NOTREAD 0x01
+#define STAT_MULTI_FILES 0x02
+
+#define OPT_SORTED 0x01
+#define OPT_READ 0x02
+
+
+char **get_field1(char *line) {
+ static char *tab[10];
+ char *pline = line;
+ int i = 0;
+
+ while (*line && i < 9) {
+ /* pass spaces */
+ while (*line == ' ' || *line == '\t') line++;
+ /* verify */
+ if (!*line) break;
+ /* backup pointer */
+ tab[i] = pline;
+ /* look for data */
+ while (*line && *line != ' ' && *line != '\t') {
+ /* pass '(' in value fields */
+ if (*line == '(') {
+ *line++ = 0;
+ while (*line && *line != ')') line++;
+ break;
+ }
+ /* pass backslashed characters */
+ if (*line == '\\' && *(line+1)) {
+ *pline++ = *(line+1);
+ line += 2 ;
+ }
+ else {
+ *pline++ = *line++ ;
+ }
+ }
+ if (*line) line++;
+ *pline++ = 0;
+ i++;
+ }
+ tab[i] = NULL;
+ return (tab);
+}
+
+/* treat a line, build new tree and compile with current
+ * tab is a tab of char that finish with a NULL string
+ * filename is a pointer address to a filename
+ * desc is the current desc pointer
+ */
+t_file_desc *fill_from_signfs_line(char **tab, char **rpath, t_file_desc **desc) {
+ char *p1, temp[64];
+ struct stat *st;
+ int nfield, i;
+
+ /* just want filename */
+ if (!desc) {
+ /* search the 7th position */
+ for (i=0; (*rpath = tab[i]) && i < 7 ; i++);
+ /* passe bad saved ./ and ../ */
+ if (i == 7) {
+ p1 = NULL;
+ while (p1 != *rpath) {
+ p1 = *rpath;
+ if (!strncmp(*rpath, "./", 2)) *rpath += 2;
+ if (!strncmp(*rpath, "../", 3)) *rpath += 3;
+ }
+ }
+ return (NULL);
+ }
+ /* want to complete data */
+ if (!*desc) {
+ *desc = MALLOC(sizeof(**desc));
+ bzero(*desc, sizeof(**desc));
+ }
+ st = &((*desc)->stat);
+ for(nfield = 0; (p1 = tab[nfield]); nfield++) {
+
+ switch (nfield) {
+ case 0: /* file type */
+ st->st_mode |= (*p1 == 'l' ? S_IFLNK :
+ *p1 == 'd' ? S_IFDIR :
+ *p1 == 'c' ? S_IFCHR :
+ *p1 == 'b' ? S_IFBLK :
+ *p1 == 'f' ? S_IFIFO :
+ *p1 == 's' ? S_IFSOCK :
+ *p1 == '-' ? S_IFREG : 0);
+ break;
+ case 1: /* file mode */
+ st->st_mode |= strtol(p1, NULL, 8); break;
+ case 2: /* user id */
+ st->st_uid = atoi(p1); break;
+ case 3: /* group id */
+ st->st_gid = atoi(p1); break;
+ case 4: /* size or major/minor for devices */
+ strncpy(temp, p1, 64); temp[63] = 0;
+ if ((p1 = strchr(temp, ','))) {
+ *p1++ = 0;
+ st->st_rdev = atoi(temp)*256 + atoi(p1);
+ }
+ else
+ st->st_size = atol(temp);
+ break;
+ case 5: /* checksum */
+ if (p1[0] != '-') {
+ for (i = 0 ; p1[i] ; i++)
+ temp[i] = (unsigned char)
+ (HEXTODEC(p1[i * 2]) * 16 + HEXTODEC(p1[i * 2 + 1]));
+ (*desc)->md5 = MALLOC(i);
+ memcpy((*desc)->md5, temp, i);
+ }
+ break;
+ case 6: /* modification time */
+ st->st_mtime = (time_t)atol(p1); break;
+ case 7: /* filename (p1 is path, p2 is filename) */
+ if (rpath) *rpath = p1;
+ break;
+ case 8: /* link */
+ (*desc)->link = strdup(p1);
+ break;
+ }
+ }
+ return (*desc);
+}
+
+
+
+int input_file_read_files(t_file_status *desc, t_ft *tree, int cmax) {
+ char line[BUFFER_LENGTH], **tab;
+ char *filename, *path;
+ int count = 0;
+ t_ft *new;
+ /* variable used for acceleration */
+ char oldpath[BUFFER_LENGTH] = "", *poldpath = oldpath;
+ t_ft *oldtree;
+
+ if (!desc->fd || feof(desc->fd)) return (0);
+
+ /* possibly have to mark current working directory has SORTING */
+ strcpy(oldpath, desc->cpath);
+ poldpath = oldpath + strlen(oldpath);
+ oldtree = ft_get(tree, oldpath);
+ SET(oldtree->status, READING);
+
+ if (IS(desc->status, STAT_MULTI_FILES)) {
+ SET(oldtree->status, SORTING);
+ }
+
+ /* read count entry in file */
+ while (!cmax || count < cmax) {
+ /* read one line from current fd */
+ if (!fgets(line, BUFFER_LENGTH, desc->fd)) break;
+
+ line[ strlen(line)-1 ] = 0;
+ /* split into field */
+ tab = get_field1(line);
+
+ /* just get filename */
+ fill_from_signfs_line(tab, &path, NULL);
+ if (!path) continue;
+
+ /* look for required string in path */
+ /* remove leading '/' */
+ filename = path + strlen(path) - 1;
+ while (*filename == '/') *filename-- = 0;
+ /* find filename into path */
+ if (!(filename = strrchr(path, '/'))) filename = path;
+ else filename++;
+
+ /* options tell to ignore '.' and '..' */
+ if (IS(Options, GOPT_IGNORE_DOT) && IS_DOTF(filename))
+ continue;
+
+ /* look for old definition */
+ if (filename != path && (poldpath - path) == (filename - path - 1) &&
+ !strncmp(oldpath, path, filename - path - 1)) {
+ new = ft_get(oldtree, filename);
+ // SET(oldtree->status, READING);
+ }
+ else {
+ /* look for this object from base */
+ new = ft_get(tree, path);
+ UNSET(oldtree->status, READING);
+ oldtree = new->parent;
+ strcpy(oldpath, build_path(oldtree));
+ poldpath = oldpath + strlen(oldpath);
+ SET(oldtree->status, READING);
+ }
+
+ /* complete information from line */
+ new->desc = fill_from_signfs_line(tab, NULL, (void*)&new->desc);
+
+ /* mark tree as changed and completed */
+ SET(new->status, FILLED);
+ SET_PARENT(new, CHANGED);
+
+ /* file counter */
+ count++;
+ if (cmax && count >= cmax) return (count);
+ }
+ /* end of file, close it */
+ if (desc->fd != stdin) fclose(desc->fd);
+ desc->fd = NULL;
+
+ return (count);
+}
+
+FILE *input_file_set_next_file(t_file_status *desc, t_ft *tree) {
+ char *pcpath, *pbpath;
+ t_ft *ctree;
+
+ /* something to read or no more dir to read */
+ if (desc->fd || !desc->dirnames) return (desc->fd);
+
+ /* restore/build tree position for cpath */
+ tree = ft_get(tree, desc->cpath);
+
+ /* initialize pointer to end of path */
+ pcpath = desc->cpath + strlen(desc->cpath);
+ pbpath = desc->bpath + strlen(desc->bpath);
+
+ while (1) {
+
+ /* mark directory as unsorted */
+ SET(tree->status, SORTING);
+ /* get directory entries if never done */
+ if (IS(desc->status, STAT_NOTREAD)) {
+ DIR *dir;
+ struct dirent *dirent;
+ struct stat st;
+
+ /* unset all previous flag */
+ UNSET(desc->status, STAT_MULTI_FILES);
+
+ if (!(dir = opendir(desc->bpath)))
+ PFERROR("opendir(%s)", desc->bpath);
+ else {
+ while ((dirent = readdir(dir))) {
+
+ /* build path to work with it */
+ ADD_PATH(desc->bpath, pbpath, dirent->d_name);
+
+ if (stat(desc->bpath, &st)) {
+ /* stat filename to find directory */
+ PFERROR("stat(%s)", desc->bpath);
+ }
+ /* check for specfic files */
+ else if (!strcmp(dirent->d_name, DUMPBASENAME)) {
+ /* set multifiles (unsorted) flag */
+ if (desc->filenames) SET(desc->status, STAT_MULTI_FILES);
+ /* backup filename */
+ SIMPLE_LIST_PUSH(desc->filenames, STRDUP(dirent->d_name));
+ }
+ /* if directory (without . and ..) */
+ else if (S_ISDIR(st.st_mode) && !IS_DOTF(dirent->d_name)) {
+ /* backup path */
+ PUSH_STR_SORTED(SIMPLE_LIST_PTR(desc->dirnames),
+ STRDUP(dirent->d_name));
+ /* set flag SORTING to futur directory */
+ ctree = ft_get(tree, dirent->d_name);
+ SET(ctree->status, SORTING);
+ }
+ }
+ closedir(dir);
+ /* remove all added filenames */
+ *pbpath = *pcpath = 0;
+ }
+ UNSET(desc->status, STAT_NOTREAD);
+ }
+
+ /* look for all files to read */
+ while (desc->filenames) {
+ char *filename;
+
+ /* get filename and build complet path */
+ filename = SIMPLE_LIST_POP(desc->filenames);
+ ADD_PATH(desc->bpath, pbpath, filename);
+ FREE(filename);
+ /* try to open and return */
+ if (!(desc->fd = fopen(desc->bpath, "r"))) PFERROR("fopen(%s)", desc->bpath);
+ else {
+ /* remove filename from cpath */
+ *pbpath = 0;
+ return (desc->fd);
+ }
+ /* clean filename */
+ *pbpath = 0;
+ }
+
+ /* 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);
+ pbpath = ADD_PATH(desc->bpath, pbpath, filename);
+
+ /* 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);
+ /* no more parent */
+ if (!desc->dirnames) return (NULL);
+ /* set to parent */
+ tree = tree->parent;
+ pcpath = REMOVE_DIR(desc->cpath, pcpath);
+ *pcpath = 0;
+ pbpath = REMOVE_DIR(desc->bpath, pbpath);
+ *pbpath = 0;
+
+ }
+ return (desc->fd);
+}
+
+int input_file_read(t_file_status *desc, t_ft *tree) {
+ int count = 0, cmax = COUNT_LEVEL1;
+
+ /* force marking the base : ABNORMAL */
+ SET(tree->status, CHANGED);
+ /* file input loop */
+ while (!cmax || count < cmax) {
+ if (!input_file_set_next_file(desc, tree)) break;
+ count += input_file_read_files(desc, tree, COUNT_LEVEL2);
+ }
+ return (count);
+}
+
+/* traduct a string options descriptions to flags
+ */
+int input_file_fcntl(t_file_status *env, int cmd) {
+ if (IS(cmd, IS_SORTED)) return (env ? IS(env->options, OPT_SORTED) : 1);
+ return (0);
+}
+
+
+t_file_status *input_file_open(char *pathname, char *opts) {
+ t_file_status *new;
+ char *filename;
+ int status;
+ char tmp[BUFFER_LENGTH];
+ char *ppath, *popts, *pvalue;
+ int options = (OPT_SORTED|OPT_READ);
+
+ popts = opts ? strcpy(tmp, opts) : NULL;
+ ppath = pathname ? strcpy(tmp + strlen(tmp) + 1, pathname) : NULL;
+
+ /* part to get source specific options */
+ 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 {
+ error("unknown option : %s", popts);
+ return (0);
+ }
+ popts = t;
+ }
+
+ new = MALLOC(sizeof(*new));
+ bzero(new, sizeof(*new));
+ filename = ppath;
+ new->options = options;
+ /* looking for separator before filename */
+ if (ppath && (ppath = backslashed_strmchr(ppath, DELIM_LIST))) {
+ status = *ppath;
+ *ppath++ = 0;
+ }
+
+ if (!filename || !filename[0] || !strcmp(filename, "-")) {
+ /* special case for stdin */
+ new->fd = stdin;
+ }
+ else {
+ struct stat st;
+ /* case for files, should stat them */
+ if (stat(filename, &st)) {
+ PFERROR("stat(%s)", filename);
+ FREE(new);
+ return (NULL);
+ }
+ if (S_ISDIR(st.st_mode)) {
+ /* directory, directory treatment */
+ strcpy(new->bpath, define_cleaned_path(filename));
+ strcpy(new->cpath, "");
+ new->filenames = NULL;
+ new->dirnames = NULL;
+ SET(new->status, STAT_NOTREAD);
+ SIMPLE_LIST_PUSH(new->dirnames, NULL);
+ }
+ else {
+ /* can test and open */
+ if (!(new->fd = fopen(filename, "r"))) {
+ PFERROR("open(%s)", filename);
+ FREE(new);
+ return (NULL);
+ }
+ }
+ }
+ return (new);
+}
+
+
+t_file_status *input_stdin_open(char *desc, char *opts) {
+ if ((desc = backslashed_strmchr(desc, DELIM_LIST)))
+ return (input_file_open(desc, opts));
+ return (input_file_open("", opts));
+}
+
+t_file_status *input_file_close(t_file_status *old) {
+ if (old->fd && old->fd != stdin) fclose(old->fd);
+ while (old->dirnames) {
+ while (SIMPLE_LIST_PTR(old->dirnames))
+ FREE(SIMPLE_LIST_POP(SIMPLE_LIST_PTR(old->dirnames)));
+ SIMPLE_LIST_POP(old->dirnames);
+ }
+ while (old->filenames)
+ FREE(SIMPLE_LIST_POP(old->dirnames));
+ FREE(old);
+ return (NULL);
+}
+
+
+
+
+
+
+
+