summaryrefslogtreecommitdiff
path: root/metaentry.c
diff options
context:
space:
mode:
authorPrzemyslaw Pawelczyk <przemoc@gmail.com>2015-09-13 22:12:14 +0200
committerPrzemyslaw Pawelczyk <przemoc@gmail.com>2015-09-13 22:12:14 +0200
commit16ab153f3a54194e3217fcf1a235904e4b61623b (patch)
treec27f9326815ebf4454e753028dcb3d388b3c0990 /metaentry.c
parent295428a550bb55a509ce15c5e27a0ab173799ebb (diff)
Move source files to src/ directory.
As a bonus you can build out-of-tree now via make -f. It's part of the work related to issue #22.
Diffstat (limited to 'metaentry.c')
-rw-r--r--metaentry.c677
1 files changed, 0 insertions, 677 deletions
diff --git a/metaentry.c b/metaentry.c
deleted file mode 100644
index f3ba692..0000000
--- a/metaentry.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Various functions to work with meta entries.
- *
- * Copyright (C) 2007 David Härdeman <david@hardeman.nu>
- *
- * 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; only version 2 of the License is applicable.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/xattr.h>
-#include <limits.h>
-#include <dirent.h>
-#include <sys/mman.h>
-#include <utime.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <errno.h>
-#include <bsd/string.h>
-#include <time.h>
-
-#include "metastore.h"
-#include "metaentry.h"
-#include "utils.h"
-
-/* Free's a metaentry and all its parameters */
-static void
-mentry_free(struct metaentry *m)
-{
- unsigned i;
-
- if (!m)
- return;
-
- free(m->path);
- free(m->owner);
- free(m->group);
-
- for (i = 0; i < m->xattrs; i++) {
- free(m->xattr_names[i]);
- free(m->xattr_values[i]);
- }
-
- free(m->xattr_names);
- free(m->xattr_values);
- free(m->xattr_lvalues);
-
- free(m);
-}
-
-/* Allocates an empty metahash table */
-static struct metahash *
-mhash_alloc()
-{
- struct metahash *mhash;
- mhash = xmalloc(sizeof(struct metahash));
- memset(mhash, 0, sizeof(struct metahash));
- return mhash;
-}
-
-/* Generates a hash key (using djb2) */
-static unsigned int
-hash(const char *str)
-{
- unsigned int hash = 5381;
- int c;
-
- while ((c = *str++))
- hash = ((hash << 5) + hash) + c;
-
- return hash % HASH_INDEXES;
-}
-
-/* Allocates an empty metaentry */
-static struct metaentry *
-mentry_alloc()
-{
- struct metaentry *mentry;
- mentry = xmalloc(sizeof(struct metaentry));
- memset(mentry, 0, sizeof(struct metaentry));
- return mentry;
-}
-
-/* Does a bisect search for the closest match in a metaentry list */
-struct metaentry *
-mentry_find(const char *path, struct metahash *mhash)
-{
- struct metaentry *base;
- unsigned int key;
-
- if (!mhash) {
- msg(MSG_ERROR, "%s called with empty hash table\n", __FUNCTION__);
- return NULL;
- }
-
- key = hash(path);
- for (base = mhash->bucket[key]; base; base = base->next) {
- if (!strcmp(base->path, path))
- return base;
- }
-
- return NULL;
-}
-
-/* Inserts a metaentry into a metaentry list */
-static void
-mentry_insert(struct metaentry *mentry, struct metahash *mhash)
-{
- unsigned int key;
-
- key = hash(mentry->path);
- mentry->next = mhash->bucket[key];
- mhash->bucket[key] = mentry;
-}
-
-#ifdef DEBUG
-/* Prints a metaentry */
-static void
-mentry_print(const struct metaentry *mentry)
-{
- int i;
-
- if (!mentry || !mentry->path) {
- msg(MSG_DEBUG,
- "Incorrect meta entry passed to printmetaentry\n");
- return;
- }
-
- msg(MSG_DEBUG, "===========================\n");
- msg(MSG_DEBUG, "Dump of metaentry %p\n", mentry);
- msg(MSG_DEBUG, "===========================\n");
-
- msg(MSG_DEBUG, "path\t\t: %s\n", mentry->path);
- msg(MSG_DEBUG, "owner\t\t: %s\n", mentry->owner);
- msg(MSG_DEBUG, "group\t\t: %s\n", mentry->group);
- msg(MSG_DEBUG, "mtime\t\t: %ld\n", (unsigned long)mentry->mtime);
- msg(MSG_DEBUG, "mtimensec\t: %ld\n", (unsigned long)mentry->mtimensec);
- msg(MSG_DEBUG, "mode\t\t: %ld\n", (unsigned long)mentry->mode);
- for (i = 0; i < mentry->xattrs; i++) {
- msg(MSG_DEBUG, "xattr[%i]\t: %s=\"", i, mentry->xattr_names[i]);
- binary_print(mentry->xattr_values[i], mentry->xattr_lvalues[i]);
- msg(MSG_DEBUG, "\"\n");
- }
-
- msg(MSG_DEBUG, "===========================\n\n");
-}
-
-/* Prints all metaentries in a metaentry list */
-static void
-mentries_print(const struct metahash *mhash)
-{
- const struct metaentry *mentry;
- int index;
-
- for (index = 0; index < HASH_INDEXES; index++)
- for (mentry = mhash->bucket[index]; mentry; mentry = mentry->next)
- mentry_print(mentry);
-
- msg(MSG_DEBUG, "%i entries in total\n", mhash->count);
-}
-#endif
-
-/* Creates a metaentry for the file/dir/etc at path */
-struct metaentry *
-mentry_create(const char *path)
-{
- ssize_t lsize, vsize;
- char *list, *attr;
- struct stat sbuf;
- struct passwd *pbuf;
- struct group *gbuf;
- int i;
- struct metaentry *mentry;
-
- if (lstat(path, &sbuf)) {
- msg(MSG_ERROR, "lstat failed for %s: %s\n",
- path, strerror(errno));
- return NULL;
- }
-
- pbuf = xgetpwuid(sbuf.st_uid);
- if (!pbuf) {
- msg(MSG_ERROR, "getpwuid failed for %s: uid %i not found\n",
- path, (int)sbuf.st_uid);
- return NULL;
- }
-
- gbuf = xgetgrgid(sbuf.st_gid);
- if (!gbuf) {
- msg(MSG_ERROR, "getgrgid failed for %s: gid %i not found\n",
- path, (int)sbuf.st_gid);
- return NULL;
- }
-
- mentry = mentry_alloc();
- mentry->path = xstrdup(path);
- mentry->pathlen = strlen(mentry->path);
- mentry->owner = xstrdup(pbuf->pw_name);
- mentry->group = xstrdup(gbuf->gr_name);
- mentry->mode = sbuf.st_mode & 0177777;
- mentry->mtime = sbuf.st_mtim.tv_sec;
- mentry->mtimensec = sbuf.st_mtim.tv_nsec;
-
- /* symlinks have no xattrs */
- if (S_ISLNK(mentry->mode))
- return mentry;
-
- lsize = listxattr(path, NULL, 0);
- if (lsize < 0) {
- /* Perhaps the FS doesn't support xattrs? */
- if (errno == ENOTSUP)
- return mentry;
-
- msg(MSG_ERROR, "listxattr failed for %s: %s\n",
- path, strerror(errno));
- return NULL;
- }
-
- list = xmalloc(lsize);
- lsize = listxattr(path, list, lsize);
- if (lsize < 0) {
- msg(MSG_ERROR, "listxattr failed for %s: %s\n",
- path, strerror(errno));
- free(list);
- return NULL;
- }
-
- i = 0;
- for (attr = list; attr < list + lsize; attr = strchr(attr, '\0') + 1) {
- if (*attr == '\0')
- continue;
- i++;
- }
-
- if (i == 0)
- return mentry;
-
- mentry->xattrs = i;
- mentry->xattr_names = xmalloc(i * sizeof(char *));
- mentry->xattr_values = xmalloc(i * sizeof(char *));
- mentry->xattr_lvalues = xmalloc(i * sizeof(ssize_t));
-
- i = 0;
- for (attr = list; attr < list + lsize; attr = strchr(attr, '\0') + 1) {
- if (*attr == '\0')
- continue;
-
- mentry->xattr_names[i] = xstrdup(attr);
- vsize = getxattr(path, attr, NULL, 0);
- if (vsize < 0) {
- msg(MSG_ERROR, "getxattr failed for %s: %s\n",
- path, strerror(errno));
- free(list);
- mentry_free(mentry);
- return NULL;
- }
-
- mentry->xattr_lvalues[i] = vsize;
- mentry->xattr_values[i] = xmalloc(vsize);
-
- vsize = getxattr(path, attr, mentry->xattr_values[i], vsize);
- if (vsize < 0) {
- msg(MSG_ERROR, "getxattr failed for %s: %s\n",
- path, strerror(errno));
- free(list);
- mentry_free(mentry);
- return NULL;
- }
- i++;
- }
-
- free(list);
- return mentry;
-}
-
-/* Cleans up a path and makes it relative to current working dir unless it is absolute */
-static char *
-normalize_path(const char *orig)
-{
- char *real = realpath(orig, NULL);
- char cwd[PATH_MAX];
- char *result;
-
- getcwd(cwd, PATH_MAX);
- if (!real)
- return NULL;
-
- if (!strncmp(real, cwd, strlen(cwd))) {
- result = xmalloc(strlen(real) - strlen(cwd) + 1 + 1);
- result[0] = '\0';
- strcat(result, ".");
- strcat(result, real + strlen(cwd));
- } else {
- result = xstrdup(real);
- }
-
- free(real);
- return result;
-}
-
-/* Internal function for the recursive path walk */
-static void
-mentries_recurse(const char *path, struct metahash *mhash, msettings *st)
-{
- struct stat sbuf;
- struct metaentry *mentry;
- char tpath[PATH_MAX];
- DIR *dir;
- struct dirent *dent;
-
- if (!path)
- return;
-
- if (lstat(path, &sbuf)) {
- msg(MSG_ERROR, "lstat failed for %s: %s\n",
- path, strerror(errno));
- return;
- }
-
- mentry = mentry_create(path);
- if (!mentry)
- return;
-
- mentry_insert(mentry, mhash);
-
- if (S_ISDIR(sbuf.st_mode)) {
- dir = opendir(path);
- if (!dir) {
- msg(MSG_ERROR, "opendir failed for %s: %s\n",
- path, strerror(errno));
- return;
- }
-
- while ((dent = readdir(dir))) {
- if (!strcmp(dent->d_name, ".") ||
- !strcmp(dent->d_name, "..") ||
- (!st->do_git && !strcmp(dent->d_name, ".git")))
- continue;
- snprintf(tpath, PATH_MAX, "%s/%s", path, dent->d_name);
- tpath[PATH_MAX - 1] = '\0';
- mentries_recurse(tpath, mhash, st);
- }
-
- closedir(dir);
- }
-}
-
-/* Recurses opath and adds metadata entries to the metaentry list */
-void
-mentries_recurse_path(const char *opath, struct metahash **mhash, msettings *st)
-{
- char *path = normalize_path(opath);
-
- if (!(*mhash))
- *mhash = mhash_alloc();
- mentries_recurse(path, *mhash, st);
- free(path);
-}
-
-/* Stores metaentries to a file */
-void
-mentries_tofile(const struct metahash *mhash, const char *path)
-{
- FILE *to;
- const struct metaentry *mentry;
- int key;
- unsigned i;
-
- to = fopen(path, "w");
- if (!to) {
- msg(MSG_CRITICAL, "Failed to open %s: %s\n",
- path, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- write_binary_string(SIGNATURE, SIGNATURELEN, to);
- write_binary_string(VERSION, VERSIONLEN, to);
-
- for (key = 0; key < HASH_INDEXES; key++) {
- for (mentry = mhash->bucket[key]; mentry; mentry = mentry->next) {
- write_string(mentry->path, to);
- write_string(mentry->owner, to);
- write_string(mentry->group, to);
- write_int((uint64_t)mentry->mtime, 8, to);
- write_int((uint64_t)mentry->mtimensec, 8, to);
- write_int((uint64_t)mentry->mode, 2, to);
- write_int(mentry->xattrs, 4, to);
- for (i = 0; i < mentry->xattrs; i++) {
- write_string(mentry->xattr_names[i], to);
- write_int(mentry->xattr_lvalues[i], 4, to);
- write_binary_string(mentry->xattr_values[i],
- mentry->xattr_lvalues[i], to);
- }
- }
- }
-
- fclose(to);
-}
-
-/* Creates a metaentry list from a file */
-void
-mentries_fromfile(struct metahash **mhash, const char *path)
-{
- struct metaentry *mentry;
- char *mmapstart;
- char *ptr;
- char *max;
- int fd;
- struct stat sbuf;
- unsigned i;
-
- if (!(*mhash))
- *mhash = mhash_alloc();
-
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- msg(MSG_CRITICAL, "Failed to open %s: %s\n",
- path, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (fstat(fd, &sbuf)) {
- msg(MSG_CRITICAL, "Failed to stat %s: %s\n",
- path, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (sbuf.st_size < (SIGNATURELEN + VERSIONLEN)) {
- msg(MSG_CRITICAL, "File %s has an invalid size\n", path);
- exit(EXIT_FAILURE);
- }
-
- mmapstart = mmap(NULL, (size_t)sbuf.st_size, PROT_READ,
- MAP_SHARED, fd, 0);
- if (mmapstart == MAP_FAILED) {
- msg(MSG_CRITICAL, "Unable to mmap %s: %s\n",
- path, strerror(errno));
- exit(EXIT_FAILURE);
- }
- ptr = mmapstart;
- max = mmapstart + sbuf.st_size;
-
- if (strncmp(ptr, SIGNATURE, SIGNATURELEN)) {
- msg(MSG_CRITICAL, "Invalid signature for file %s\n", path);
- goto out;
- }
- ptr += SIGNATURELEN;
-
- if (strncmp(ptr, VERSION, VERSIONLEN)) {
- msg(MSG_CRITICAL, "Invalid version of file %s\n", path);
- goto out;
- }
- ptr += VERSIONLEN;
-
- while (ptr < mmapstart + sbuf.st_size) {
- if (*ptr == '\0') {
- msg(MSG_CRITICAL, "Invalid characters in file %s\n",
- path);
- goto out;
- }
-
- mentry = mentry_alloc();
- mentry->path = read_string(&ptr, max);
- mentry->pathlen = strlen(mentry->path);
- mentry->owner = read_string(&ptr, max);
- mentry->group = read_string(&ptr, max);
- mentry->mtime = (time_t)read_int(&ptr, 8, max);
- mentry->mtimensec = (time_t)read_int(&ptr, 8, max);
- mentry->mode = (mode_t)read_int(&ptr, 2, max);
- mentry->xattrs = (unsigned int)read_int(&ptr, 4, max);
-
- if (!mentry->xattrs) {
- mentry_insert(mentry, *mhash);
- continue;
- }
-
- mentry->xattr_names = xmalloc(mentry->xattrs *
- sizeof(char *));
- mentry->xattr_lvalues = xmalloc(mentry->xattrs *
- sizeof(int));
- mentry->xattr_values = xmalloc(mentry->xattrs *
- sizeof(char *));
-
- for (i = 0; i < mentry->xattrs; i++) {
- mentry->xattr_names[i] = read_string(&ptr, max);
- mentry->xattr_lvalues[i] =
- (int)read_int(&ptr, 4, max);
- mentry->xattr_values[i] =
- read_binary_string(&ptr,
- mentry->xattr_lvalues[i],
- max);
- }
- mentry_insert(mentry, *mhash);
- }
-
-out:
- munmap(mmapstart, sbuf.st_size);
- close(fd);
-}
-
-/* Searches haystack for an xattr matching xattr number n in needle */
-int
-mentry_find_xattr(struct metaentry *haystack, struct metaentry *needle,
- unsigned n)
-{
- unsigned i;
-
- for (i = 0; i < haystack->xattrs; i++) {
- if (strcmp(haystack->xattr_names[i], needle->xattr_names[n]))
- continue;
- if (haystack->xattr_lvalues[i] != needle->xattr_lvalues[n])
- return -1;
- if (bcmp(haystack->xattr_values[i], needle->xattr_values[n],
- needle->xattr_lvalues[n]))
- return -1;
- return i;
- }
- return -1;
-}
-
-/* Returns zero if all xattrs in left and right match */
-static int
-mentry_compare_xattr(struct metaentry *left, struct metaentry *right)
-{
- unsigned i;
-
- if (left->xattrs != right->xattrs)
- return 1;
-
- /* Make sure all xattrs in left are found in right and vice versa */
- for (i = 0; i < left->xattrs; i++) {
- if (mentry_find_xattr(right, left, i) < 0 ||
- mentry_find_xattr(left, right, i) < 0) {
- return 1;
- }
- }
-
- return 0;
-}
-
-/* Compares two metaentries and returns an int with a bitmask of differences */
-int
-mentry_compare(struct metaentry *left, struct metaentry *right, msettings *st)
-{
- int retval = DIFF_NONE;
-
- if (!left || !right) {
- msg(MSG_ERROR, "%s called with empty list\n", __FUNCTION__);
- return -1;
- }
-
- if (strcmp(left->path, right->path))
- return -1;
-
- if (strcmp(left->owner, right->owner))
- retval |= DIFF_OWNER;
-
- if (strcmp(left->group, right->group))
- retval |= DIFF_GROUP;
-
- if ((left->mode & 07777) != (right->mode & 07777))
- retval |= DIFF_MODE;
-
- if ((left->mode & S_IFMT) != (right->mode & S_IFMT))
- retval |= DIFF_TYPE;
-
- if (st->do_mtime && strcmp(left->path, st->metafile) &&
- (left->mtime != right->mtime ||
- left->mtimensec != right->mtimensec))
- retval |= DIFF_MTIME;
-
- if (mentry_compare_xattr(left, right)) {
- retval |= DIFF_XATTR;
- return retval;
- }
-
- return retval;
-}
-
-/* Compares lists of real and stored metadata and calls pfunc for each */
-void
-mentries_compare(struct metahash *mhashreal,
- struct metahash *mhashstored,
- void (*pfunc)
- (struct metaentry *real, struct metaentry *stored, int cmp),
- msettings *st)
-{
- struct metaentry *real, *stored;
- int key;
-
- if (!mhashreal || !mhashstored) {
- msg(MSG_ERROR, "%s called with empty list\n", __FUNCTION__);
- return;
- }
-
- for (key = 0; key < HASH_INDEXES; key++) {
- for (real = mhashreal->bucket[key]; real; real = real->next) {
- stored = mentry_find(real->path, mhashstored);
-
- if (!stored)
- pfunc(real, NULL, DIFF_ADDED);
- else
- pfunc(real, stored, mentry_compare(real, stored, st));
- }
-
- for (stored = mhashstored->bucket[key]; stored; stored = stored->next) {
- real = mentry_find(stored->path, mhashreal);
-
- if (!real)
- pfunc(NULL, stored, DIFF_DELE);
- }
- }
-}
-
-/* Dumps given metadata */
-void
-mentries_dump(struct metahash *mhash)
-{
- const struct metaentry *mentry;
- char mode[11 + 1] = "";
- char date[12 + 2 + 2 + 2*1 + 1 + 2 + 2 + 2 + 2*1 + 1] = "";
- char zone[5 + 1] = "";
- struct tm cal;
-
- for (int key = 0; key < HASH_INDEXES; key++) {
- for (mentry = mhash->bucket[key]; mentry; mentry = mentry->next) {
- strmode(mentry->mode, mode);
- localtime_r(&mentry->mtime, &cal);
- strftime(date, sizeof(date), "%F %T", &cal);
- strftime(zone, sizeof(zone), "%z", &cal);
- printf("%s\t%s\t%s\t%s.%09ld %s\t%s%s\n",
- mode,
- mentry->owner, mentry->group,
- date, mentry->mtimensec, zone,
- mentry->path, S_ISDIR(mentry->mode) ? "/" : "");
- for (int i = 0; i < mentry->xattrs; i++) {
- printf("\t\t\t\t%s%s\t%s=",
- mentry->path, S_ISDIR(mentry->mode) ? "/" : "",
- mentry->xattr_names[i]);
- ssize_t p = 0;
- for (; p < mentry->xattr_lvalues[i]; p++) {
- const char ch = mentry->xattr_values[i][p];
- if ((unsigned)(ch - 32) > 126 - 32) {
- p = -1;
- break;
- }
- }
- if (p >= 0)
- printf("\"%.*s\"\n",
- (int)mentry->xattr_lvalues[i],
- mentry->xattr_values[i]);
- else {
- printf("0x");
- for (p = 0; p < mentry->xattr_lvalues[i]; p++)
- printf("%02hhx", (char)mentry->xattr_values[i][p]);
- printf("\n");
- }
- }
- }
- }
-}