aboutsummaryrefslogtreecommitdiff
path: root/flx/fct1.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--flx/fct1.c452
1 files changed, 452 insertions, 0 deletions
diff --git a/flx/fct1.c b/flx/fct1.c
new file mode 100644
index 0000000..79378a3
--- /dev/null
+++ b/flx/fct1.c
@@ -0,0 +1,452 @@
+/*
+ * Signfs version 0.6, Copyright Benoit DOLEZ, 2002
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "flx.h"
+#include "utils.h"
+
+
+/* function that complete desc from file system informations */
+t_file_desc *complete_info_from_file(char *path, t_file_desc *desc, int flag) {
+ 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);
+}
+
+
+
+/* function that compare 2 tree entry, complete checksum and link if needed */
+int files_are_the_same(t_file_desc *f1, t_file_desc *f2, int Diff, char *path) {
+ int diff = 0;
+
+ // if (!IS(f1->status, STATUS_FILLED) || !IS(f2->status, STATUS_FILLED))
+ // return (diff = DIFF_NOTFILLED, 0);
+
+ if (DIFF(TYPE) && (f1->stat.st_mode & S_IFMT) != (f2->stat.st_mode & S_IFMT))
+ diff |= DIFF_TYPE; /* types differ */
+ if (DIFF(MODE) && (f1->stat.st_mode & 07777) != (f2->stat.st_mode & 07777))
+ diff |= DIFF_MODE; /* modes differ */
+ if (DIFF(OWNER) && (f1->stat.st_uid != f2->stat.st_uid ||
+ f1->stat.st_gid != f2->stat.st_gid))
+ diff |= DIFF_OWNER; /* uid or gid differ */
+ if (DIFF(SIZE) && S_ISREG(f1->stat.st_mode) && S_ISREG(f2->stat.st_mode) &&
+ f1->stat.st_size != f2->stat.st_size)
+ diff |= DIFF_SIZE; /* sizes differ for regular files */
+ if (DIFF(DEV) && ((S_ISBLK(f1->stat.st_mode) && S_ISBLK(f2->stat.st_mode)) ||
+ (S_ISCHR(f1->stat.st_mode) && S_ISCHR(f2->stat.st_mode))) &&
+ f1->stat.st_rdev != f2->stat.st_rdev)
+ diff |= DIFF_DEV; /* minor/major differ for device files */
+ if (DIFF(TIME) && f1->stat.st_mtime != f2->stat.st_mtime) {
+ if (DIFF(LDATE) || !(S_ISLNK(f1->stat.st_mode)))
+ diff |= DIFF_TIME; /* modification times diff */
+ }
+ if (DIFF(LINK) && S_ISLNK(f1->stat.st_mode) && S_ISLNK(f2->stat.st_mode)) {
+ char temp[BUFFER_LENGTH];
+ int l;
+
+ if (f1->link != f2->link) {
+ if (!f1->link || !f2->link) {
+ if (!path) diff |= DIFF_LINK;
+ else {
+ /* rebuild link and link's checksum */
+ if ((l = readlink(path, temp, BUFFER_LENGTH)) < 0) {
+ PFERROR("readlink(%s)",path);
+ } else {
+ temp[l] = 0;
+ if (!f1->link) f1->link = strdup(temp);
+ if (!f2->link) f2->link = strdup(temp);
+ if (!f1->md5) f1->md5 = checksum_md5_from_data(temp, l);
+ if (!f2->md5) f2->md5 = checksum_md5_from_data(temp, l);
+ }
+ }
+ if (strcmp(f1->link, f2->link))
+ diff |= DIFF_LINK; /* links differ */
+ }
+ }
+ }
+ if (DIFF(CHECKSUM) && S_ISREG(f1->stat.st_mode) && S_ISREG(f2->stat.st_mode)) {
+ if (f1->md5 || f2->md5) {
+ if (!f1->md5 || !f2->md5) diff |= DIFF_CHECKSUM;
+ else if (memcmp(f1->md5, f2->md5, 16))
+ diff |= DIFF_CHECKSUM; /* checksums differ */
+ }
+ }
+ return (diff);
+}
+
+/* return the path describe by the structure */
+char *build_path(t_ft *tree) {
+ static char path[BUFFER_LENGTH];
+
+ if (!tree || !tree->filename)
+ path[0] = 0;
+ else if (tree->parent &&
+ (IS_PDOTF(tree) || !tree->parent->filename))
+ strcpy(path, tree->filename);
+ else {
+ build_path(tree->parent);
+ strcat(path, "/");
+ strcat(path, tree->filename);
+ }
+ return (path);
+}
+
+
+/* free memory for an existant tree
+ * tree : tree to clean
+ */
+void free_tree(t_tree *tree) {
+ t_tree *current, *todel;
+
+ if (tree->link) FREE(tree->link);
+ if (tree->checksum) FREE(tree->checksum);
+ if (tree->filename) FREE(tree->filename);
+ if ((current = tree->subtree)) {
+ while (current != tree) {
+ todel = current;
+ current = current->next;
+ todel->prev->next = todel->next;
+ todel->next->prev = todel->prev;
+ free_tree(todel);
+ }
+ }
+ if (tree->subtree) FREE(tree->subtree);
+ FREE(tree);
+}
+
+/* browse only directories */
+/* path : directory to treat
+ * fct : fonction that treat file and return a (new) pointer to data to recursive act
+ * data : pointer for function fct
+ */
+int browse_over_path(char *path, PROTO_FS(*fct), void *data) {
+ struct stat stat;
+ DIR *dir;
+ struct dirent *dirent;
+ off_t current_dir;
+ char *new_filename;
+ int l;
+
+ if (!path) return (0);
+
+ /* initialise new_filename */
+ new_filename = MALLOC((l = strlen(path)) + 1 + FILENAME_LENGTH);
+ memcpy(new_filename, path, l);
+ if (new_filename[l-1] != '/') strcpy(new_filename + l++, "/");
+
+ if ((dir = opendir(path))) {
+ /* each file of the directory */
+ while ((dirent = readdir(dir))) {
+ /* build new filename */
+ strcpy(new_filename + l, dirent->d_name);
+
+ /* get file informations */
+ if (lstat(new_filename, &stat)) {
+ PFERROR("stat(%s)", new_filename);
+ continue;
+ }
+
+ /* directory selection */
+ if (S_ISDIR(stat.st_mode)) {
+ void *new_data;
+ /* save current directory position */
+ current_dir = telldir(dir);
+ closedir(dir);
+
+ /* fonction on file status */
+ if ((new_data = fct(new_filename, new_filename+l, &stat, data))) {
+
+ browse_over_path(new_filename, fct, new_data);
+
+ /* if new pointer return, differs with old one, we should
+ * remove it before use (same, with filename NULL) */
+ if (new_data != data) fct(NULL, NULL, NULL, new_data);
+ }
+ /* restore directory position */
+ dir = opendir(path);
+ seekdir(dir, current_dir);
+ }
+ else {
+ /* fonction on file status */
+ fct(new_filename, new_filename+l, &stat, data);
+ }
+ }
+ closedir(dir);
+ }
+ else {
+ PFERROR("opendir(%s)", path);
+ return (0);
+ }
+ FREE(new_filename);
+ return (1);
+}
+
+
+/* build an MD5 checksum from data in file */
+char *checksum_md5_from_file(char *file) {
+ int fd;
+ size_t size;
+ char *checksum_md5 = 0, blk[BUFFER_LENGTH];
+ MD5_CTX md5_ctx;
+
+ if ((fd = open(file, O_RDONLY)) < 0 ) {
+ PFERROR("open(%s) for MD5 checksum", file);
+ }
+ else {
+ MD5_Init(&md5_ctx);
+ while ((size = read(fd, blk, BUFFER_LENGTH)) > 0)
+ MD5_Update(&md5_ctx, blk, size);
+ close(fd);
+ checksum_md5 = MALLOC(16);
+ MD5_Final(checksum_md5, &md5_ctx);
+ }
+ return (checksum_md5);
+}
+
+/* build an MD5 checksum from a string */
+char *checksum_md5_from_data(char *data, int len) {
+ char *checksum_md5 = 0;
+ MD5_CTX md5_ctx;
+
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, data, len);
+ checksum_md5 = MALLOC(16);
+ MD5_Final(checksum_md5, &md5_ctx);
+ return (checksum_md5);
+}
+
+
+/* remove ended '/' */
+char *remove_ended_slash(char *str) {
+ static char temp[BUFFER_LENGTH];
+ int l = strlen(str);
+
+ strcpy(temp, str);
+ while (temp[l - 1] == '/') temp[--l] = 0;
+ return (temp);
+}
+
+/* return pointer to the end of the current field */
+char *end_field(char *line) {
+ while (*line && *line != ' ' && *line != '\t' && *line != '\n') {
+ if (*line++ == '\\' && (*line == '\\' ||
+ *line == ' ' ||
+ *line == '\t'||
+ *line == '\n'))
+ line++;
+ }
+ if (*line) *line++ = 0;
+ return (*line ? line : 0);
+}
+
+
+/* create directory and parent directory if needed */
+int mkdir_with_parent(char *pathname, mode_t mode) {
+ struct stat st;
+ char tmp[BUFFER_LENGTH], *ptmp = tmp;
+
+ if (*pathname == '/') *ptmp++ = *pathname++;
+ while (pathname && *pathname) {
+ while (*pathname && *pathname != '/') *ptmp++ = *pathname++;
+ while (*pathname == '/') pathname++;
+ *ptmp = 0;
+ if (stat(tmp, &st)) {
+ /* file cannot be stat, try to make directory */
+ if (mkdir(tmp, mode)) {
+ PFERROR("mkdir(%s)", tmp);
+ return (0);
+ }
+ }
+ else if (!S_ISDIR(st.st_mode)) {
+ error("%s exist and isn't a directory", tmp);
+ return (0);
+ }
+ *ptmp++ = '/';
+ }
+ return (1);
+}
+
+/* return formatted info into a static string */
+char *build_line(char *path, char *filename, t_file_desc *info) {
+ struct stat *st = &(info->stat);
+ static char blk[BUFFER_LENGTH], tmp[64];
+ int s;
+
+ /* show informations */
+ blk[s = 0] = 0;
+
+ /* bad data */
+ if (!path) {
+ sprintf(blk,"## anormal action : path=%s desc=%p", path, st);
+ return (blk);
+ }
+
+ if (st) {
+ /* display file type */
+ s += sprintf(blk+s, "%c", FILE_TYPE(st->st_mode));
+
+ /* display file mode */
+ if (IS(Options, GOPT_HUMAN_READABLE))
+ s += sprintf(blk+s," %04o(%s) ", st->st_mode & 0007777,
+ right(st->st_mode));
+ else
+ s += sprintf(blk+s," %04o ", st->st_mode & 0007777);
+
+ /* display user and group id */
+ s += sprintf(blk+s,"%5d %5d ", st->st_uid, st->st_gid);
+
+ /* display size of device info */
+ if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
+ sprintf(tmp, "%d,%d", major(st->st_rdev), minor(st->st_rdev));
+ s += sprintf(blk+s, "%10s ", tmp);
+ } else {
+ s += sprintf(blk+s, "%10ld ", S_ISDIR(st->st_mode) ? 0 : st->st_size );
+ }
+
+ /* display checksum */
+ if (info->md5) {
+ int i;
+ for (i=0; i < 16; i++) s += sprintf(blk+s, "%02x", info->md5[i]);
+ s += sprintf(blk+s, " ");
+ }
+ else
+ s += sprintf(blk+s, "-------------------------------- ");
+
+ /* display date */
+ if (IS(Options, GOPT_HUMAN_READABLE)) {
+ strcpy(tmp, ctime(&(st->st_mtime))); tmp[strlen(tmp) - 1] = 0;
+ s += sprintf(blk+s, "%10ld(%s) ", st->st_mtime, tmp);
+ }
+ else
+ s += sprintf(blk+s, "%10ld ", st->st_mtime);
+
+ s += sprintf(blk+s, "%s", backslashed_str(path, " \\\n()\t"));
+
+ if (S_ISLNK(st->st_mode) && info->link)
+ s += sprintf(blk+s, " %s", backslashed_str(info->link, " \\\n()\t"));
+ }
+ else {
+ if (IS(Options, GOPT_HUMAN_READABLE))
+ s += sprintf(blk+s, "? 0000(-) % 5d % 5d % 10d -------------------------------- %10d(-) %s",0 , 0, 0, 0,
+ backslashed_str(path, " \\\n()\t"));
+ else
+ s += sprintf(blk+s, "? 0000 % 5d % 5d % 10d -------------------------------- %10d %s",0 , 0, 0, 0,
+ backslashed_str(path, " \\\n()\t"));
+ }
+ return (blk);
+}
+
+
+/* view files with recursive method */
+void dump_tree_(t_ft *tree, int force) {
+ static char path[BUFFER_LENGTH];
+ char *ppath;
+
+ ppath = path + strlen(path);
+ while (1) {
+ if (tree->filename) {
+ ADD_PATH(path, ppath, tree->filename);
+ printf("[%02x] %s\n", tree->status, path);
+ // UNSET(tree->status, CHANGED);
+ }
+ if (tree->subtree && (!IS_PDOTF(tree) || force)) {
+ dump_tree_(tree->subtree, 0);
+ }
+ tree = tree->next;
+ if (IS(tree->status, BASE)) break;
+ }
+ *ppath = 0;
+}
+
+void dump_tree(t_ft *tree) {
+ printf("** etat de l'arbre **\n");
+ dump_tree_(tree, 1);
+ printf("** end **\n");
+}
+
+
+/* find last good defined path (without ended '/') */
+char *define_base_path(char *real) {
+ static char tmp[BUFFER_LENGTH];
+ char *last, *breal, *lslash;
+
+ lslash = last = tmp;
+ while (*real) {
+ /* pass multiple '/' */
+ while (*real == '/') real++;
+ if (!*real) break; /* end of pathname */
+ breal = real;
+ /* get directory name */
+ while (*real && *real != '/') *last++ = *real++;
+ /* last have no ended '/' */
+ lslash = last;
+ /* find . or .., restart */
+ if (IS_DOTF(breal) || IS_DOTD(breal)) lslash = last = tmp;
+ else *last++ = *real;
+ }
+ /* remove last slash */
+ *lslash = 0;
+ return (tmp);
+}
+
+/* remove multiple '/' (and ended '/') */
+char *define_cleaned_path(char *real) {
+ static char tmp[BUFFER_LENGTH];
+ char *ptmp = tmp;
+
+ while (*real) {
+ while ((*ptmp = *real)) {
+ ptmp++;
+ if (*real++ == '/') break;
+ }
+ while (*real == '/') real++;
+ }
+ *ptmp = *real;
+ /* do not remove ending '/' */
+#if 1
+ if (ptmp-1 > tmp && *(ptmp-1) == '/') *(ptmp-1) = 0;
+#endif
+ return (tmp);
+}
+
+
+