diff options
-rw-r--r-- | Makefile.in | 14 | ||||
-rwxr-xr-x | configure | 26 | ||||
-rw-r--r-- | offsets.c | 2 | ||||
-rw-r--r-- | ports/darwin/guts/stat.c | 2 | ||||
-rw-r--r-- | ports/unix/guts/fchown.c | 11 | ||||
-rw-r--r-- | ports/unix/guts/fchownat.c | 14 | ||||
-rw-r--r-- | ports/unix/guts/linkat.c | 2 | ||||
-rw-r--r-- | pseudo_client.c | 180 | ||||
-rw-r--r-- | pseudo_util.c | 6 | ||||
-rw-r--r-- | pseudo_wrappers.c | 18 |
10 files changed, 244 insertions, 31 deletions
diff --git a/Makefile.in b/Makefile.in index 1c8bd6a..ea90b5b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,13 +26,19 @@ SQLITE_LIB=@SQLITE_LIB@ SQLITE_MEMORY=@SQLITE_MEMORY@ FORCE_ASYNC=@FORCE_ASYNC@ XATTR=@XATTR@ -ifeq (true,@PROFILING@) - PROFILING=-DPSEUDO_PROFILING +XATTRDB=@XATTRDB@ +PROFILING=@PROFILING@ +ifeq (true,$(PROFILING)) PSEUDO_PROFILE=$(BIN)/pseudo_profile else - PROFILING= PSEUDO_PROFILE= endif +define cond + $(if $(filter true,$($(1))),-D$(2)) +endef +OPTDEFS=$(call cond,XATTR,PSEUDO_XATTR_SUPPORT) \ + $(call cond,XATTRDB,PSEUDO_XATTRDB) \ + $(call cond,PROFILING,PSEUDO_PROFILING) PASSWD_FALLBACK=@PASSWD_FALLBACK@ BITS=@BITS@ ARCH_FLAGS=@ARCH_FLAGS@ @@ -48,7 +54,7 @@ LOCALSTATEDIR=$(PREFIX)/$(LOCALSTATE) CFLAGS_BASE=-pipe -std=gnu99 -Wall -W -Wextra CFLAGS_CODE=-fPIC -D_LARGEFILE64_SOURCE -D_ATFILE_SOURCE $(ARCH_FLAGS) -CFLAGS_DEFS=-DPSEUDO_PREFIX='"$(PREFIX)"' -DPSEUDO_SUFFIX='"$(SUFFIX)"' -DPSEUDO_BINDIR='"$(BIN)"' -DPSEUDO_LIBDIR='"$(LIB)"' -DPSEUDO_LOCALSTATEDIR='"$(LOCALSTATE)"' -DPSEUDO_VERSION='"$(VERSION)"' $(SQLITE_MEMORY) $(FORCE_ASYNC) -DPSEUDO_PASSWD_FALLBACK='$(PASSWD_FALLBACK)' $(PROFILING) +CFLAGS_DEFS=-DPSEUDO_PREFIX='"$(PREFIX)"' -DPSEUDO_SUFFIX='"$(SUFFIX)"' -DPSEUDO_BINDIR='"$(BIN)"' -DPSEUDO_LIBDIR='"$(LIB)"' -DPSEUDO_LOCALSTATEDIR='"$(LOCALSTATE)"' -DPSEUDO_VERSION='"$(VERSION)"' $(SQLITE_MEMORY) $(FORCE_ASYNC) -DPSEUDO_PASSWD_FALLBACK='$(PASSWD_FALLBACK)' $(OPTDEFS) CFLAGS_DEBUG=-O2 -g @DEFAULT_SQLITE@CFLAGS_SQL=-L$(SQLITE)/$(SQLITE_LIB) -I$(SQLITE)/include $(RPATH) CFLAGS_PSEUDO=$(CFLAGS_BASE) $(CFLAGS_CODE) $(CFLAGS_DEFS) \ @@ -28,6 +28,7 @@ opt_rpath= opt_memory= opt_async= opt_xattr= +opt_xattrdb=false opt_profile=false opt_passwd_fallback='""' @@ -42,6 +43,7 @@ usage() echo >&2 " [--suffix=...]" echo >&2 " [--enable-memory-db]" echo >&2 " [--enable-xattr]" + echo >&2 " [--enable-xattrdb]" echo >&2 " [--enable-profiling]" echo >&2 " [--enable-force-async]" echo >&2 " [--with-sqlite=...]" @@ -76,7 +78,7 @@ do else maybe_prefix=$opt_prefix fi - if [ "$maybe_prefix" == "$(pwd)" ]; then + if [ "$maybe_prefix" = "$(pwd)" ]; then echo >&2 "ERROR: Prefix is current directory. That doesn't work." exit 1 fi @@ -119,6 +121,12 @@ do --enable-xattr=yes | --enable-xattr) opt_xattr=true ;; + --enable-xattrdb=no) + opt_xattrdb=false + ;; + --enable-xattrdb=yes | --enable-xattrdb) + opt_xattrdb=true + ;; --enable-memory-db=no) opt_memory=false ;; @@ -259,16 +267,21 @@ fi if [ -z "$opt_xattr" ]; then - if $xattr_runs; then + if $opt_xattrdb; then opt_xattr=true - echo "getfattr runs, enabling extended attribute support" + echo "xattr DB support implies extended attribute support" else - opt_xattr=false - echo "getfattr fails, disabling extended attribute support" + if $xattr_runs; then + opt_xattr=true + echo "getfattr runs, enabling extended attribute support" + else + opt_xattr=false + echo "getfattr fails, disabling extended attribute support" + fi fi fi -if $opt_xattr; then +if $opt_xattr || $opt_xattrdb; then if ! $xattr_runs; then echo >&2 "WARNING: getfattr doesn't work, but xattr-related features requestd." fi @@ -308,6 +321,7 @@ touch func_deps.mk sed -e ' s,@PREFIX@,'"$opt_prefix"',g s,@XATTR@,'"$opt_xattr"',g + s,@XATTRDB@,'"$opt_xattrdb"',g s,@PROFILING@,'"$opt_profiling"',g s,@LIBDIR@,'"$opt_libdir"',g s,@LIB@,'"$opt_lib"',g @@ -17,7 +17,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ +#ifndef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE +#endif #include <stdio.h> #include <sys/stat.h> #include <unistd.h> diff --git a/ports/darwin/guts/stat.c b/ports/darwin/guts/stat.c index 1e1cf67..8a0742c 100644 --- a/ports/darwin/guts/stat.c +++ b/ports/darwin/guts/stat.c @@ -20,7 +20,7 @@ * don't need to check for a symlink on this end */ msg = pseudo_client_op(OP_STAT, 0, -1, AT_FDCWD, path, buf); - if (msg) { + if (msg && msg->result == RESULT_SUCCEED) { pseudo_stat_msg(buf, msg); } diff --git a/ports/unix/guts/fchown.c b/ports/unix/guts/fchown.c index 6e33f0f..89cabe2 100644 --- a/ports/unix/guts/fchown.c +++ b/ports/unix/guts/fchown.c @@ -20,15 +20,10 @@ if (owner == (uid_t) -1 || group == (gid_t) -1) { msg = pseudo_client_op(OP_STAT, 0, fd, -1, NULL, &buf); /* copy in any existing values... */ - if (msg) { - if (msg->result == RESULT_SUCCEED) { - pseudo_stat_msg(&buf, msg); - } else { - pseudo_debug(PDBGF_FILE, "fchown fd %d, ino %llu, unknown file.\n", - fd, (unsigned long long) buf.st_ino); - } + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); } else { - pseudo_diag("stat within chown of fd %d [%llu] failed.\n", + pseudo_debug(PDBGF_FILE, "fchown fd %d, ino %llu, unknown file.\n", fd, (unsigned long long) buf.st_ino); } } diff --git a/ports/unix/guts/fchownat.c b/ports/unix/guts/fchownat.c index f976d91..295726b 100644 --- a/ports/unix/guts/fchownat.c +++ b/ports/unix/guts/fchownat.c @@ -36,14 +36,12 @@ if (owner == (uid_t) -1 || group == (gid_t) -1) { msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, &buf); /* copy in any existing values... */ - if (msg) { - if (msg->result == RESULT_SUCCEED) { - pseudo_stat_msg(&buf, msg); - } else { - pseudo_debug(PDBGF_FILE, "chownat to %d:%d on %d/%s, ino %llu, new file.\n", - owner, group, dirfd, path, - (unsigned long long) buf.st_ino); - } + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } else { + pseudo_debug(PDBGF_FILE, "chownat to %d:%d on %d/%s, ino %llu, new file.\n", + owner, group, dirfd, path, + (unsigned long long) buf.st_ino); } } /* now override with arguments */ diff --git a/ports/unix/guts/linkat.c b/ports/unix/guts/linkat.c index fe29b39..ec27e47 100644 --- a/ports/unix/guts/linkat.c +++ b/ports/unix/guts/linkat.c @@ -55,7 +55,7 @@ return rc; } msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &buf); - if (msg) { + if (msg && msg->result == RESULT_SUCCEED) { pseudo_stat_msg(&buf, msg); } /* Long story short: I am pretty sure we still want OP_LINK even diff --git a/pseudo_client.c b/pseudo_client.c index 7f30467..bb9e1e8 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -37,6 +37,10 @@ #include <pwd.h> #include <grp.h> +#ifdef PSEUDO_XATTRDB +#include <sys/xattr.h> +#endif + #include "pseudo.h" #include "pseudo_ipc.h" #include "pseudo_client.h" @@ -190,6 +194,125 @@ build_passwd_paths(void) return; } +#ifdef PSEUDO_XATTRDB +/* We really want to avoid calling the wrappers for these inside the + * implementation. pseudo_wrappers will reinitialize these after it's + * gotten the real_* found. + */ +ssize_t (*pseudo_real_lgetxattr)(const char *, const char *, void *, size_t) = lgetxattr; +ssize_t (*pseudo_real_fgetxattr)(int, const char *, void *, size_t) = fgetxattr; +int (*pseudo_real_lsetxattr)(const char *, const char *, const void *, size_t, int) = lsetxattr; +int (*pseudo_real_fsetxattr)(int, const char *, const void *, size_t, int) = fsetxattr; +/* Executive summary: We use an extended attribute, + * user.pseudo_data, to store exactly the data we would otherwise + * have stored in the database. Which is to say, uid, gid, mode, rdev. + * + * If we don't find a value, save an empty one with a lower version + * number to indicate that we don't have data to reduce round trips. + */ +typedef struct { + int version; + uid_t uid; + gid_t gid; + mode_t mode; + dev_t rdev; +} pseudo_db_data_t; + +static pseudo_msg_t xattrdb_data; + +pseudo_msg_t * +pseudo_xattrdb_save(int fd, const char *path, const struct stat64 *buf) { + int rc = -1; + if (!path && fd < 0) + return NULL; + if (!buf) + return NULL; + pseudo_db_data_t pseudo_db_data = { + .version = 1, + .uid = buf->st_uid, + .gid = buf->st_gid, + .mode = buf->st_mode, + .rdev = buf->st_rdev + }; + if (path) { + rc = pseudo_real_lsetxattr(path, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0); + } else if (fd >= 0) { + rc = pseudo_real_fsetxattr(fd, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0); + } + pseudo_debug(PDBGF_XATTRDB, "tried to save data for %s/%d: uid %d, mode %o, rc %d.\n", + path ? path : "<nil>", fd, (int) pseudo_db_data.uid, (int) pseudo_db_data.mode, rc); + /* none of the other fields are checked on save, and the value + * is currently only really used by mknod. + */ + if (rc == 0) { + xattrdb_data.result = RESULT_SUCCEED; + return &xattrdb_data; + } + return NULL; +} + +pseudo_msg_t * +pseudo_xattrdb_load(int fd, const char *path, const struct stat64 *buf) { + int rc = -1, retryrc = -1; + if (!path && fd < 0) + return NULL; + /* don't try to getxattr on a thing unless we think it is + * likely to work. + */ + if (buf) { + if (!S_ISDIR(buf->st_mode) && !S_ISREG(buf->st_mode)) { + return NULL; + } + } + pseudo_db_data_t pseudo_db_data; + if (path) { + rc = pseudo_real_lgetxattr(path, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data)); + if (rc == -1) { + pseudo_db_data = (pseudo_db_data_t) { .version = 0 }; + retryrc = pseudo_real_lsetxattr(path, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0); + } + } else if (fd >= 0) { + rc = pseudo_real_fgetxattr(fd, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data)); + if (rc == -1) { + pseudo_db_data = (pseudo_db_data_t) { .version = 0 }; + retryrc = pseudo_real_fsetxattr(fd, "user.pseudo_data", &pseudo_db_data, sizeof(pseudo_db_data), 0); + } + } + pseudo_debug(PDBGF_XATTRDB, "tried to load data for %s/%d: rc %d, version %d.\n", + path ? path : "<nil>", fd, rc, pseudo_db_data.version); + if (rc == -1 && retryrc == 0) { + /* there's no data, but there could have been; treat + * this as an empty database result. + */ + xattrdb_data.result = RESULT_FAIL; + return &xattrdb_data; + } else if (rc == -1) { + /* we can't create an extended attribute, so we may have + * used the database. + */ + return NULL; + } + /* Version 0 = just recording that we looked and found + * nothing. + * Version 1 = actually implemented. + */ + switch (pseudo_db_data.version) { + case 0: + default: + xattrdb_data.result = RESULT_FAIL; + break; + case 1: + xattrdb_data.uid = pseudo_db_data.uid; + xattrdb_data.gid = pseudo_db_data.gid; + xattrdb_data.mode = pseudo_db_data.mode; + xattrdb_data.rdev = pseudo_db_data.rdev; + xattrdb_data.result = RESULT_SUCCEED; + break; + } + return &xattrdb_data; +} +#endif + #ifdef PSEUDO_PROFILING static int pseudo_profile_pid = -2; @@ -379,7 +502,8 @@ pseudo_init_client(void) { pseudo_set_value("PSEUDO_ALLOW_FSYNC", env); } if (env) { - pseudo_allow_fsync = 1; + // stupid hack + // pseudo_allow_fsync = 1; } else { pseudo_allow_fsync = 0; } @@ -1309,6 +1433,42 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path } } +#ifdef PSEUDO_XATTRDB + /* maybe use xattr instead */ + /* note: if we use xattr, logging won't work reliably + * because the server won't get messages if these work. + */ + switch (op) { + case OP_CHMOD: + case OP_CREAT: + case OP_FCHMOD: + case OP_MKDIR: + case OP_MKNOD: + { + /* use magic uid/gid */ + struct stat64 bufcopy; + bufcopy = *buf; + bufcopy.st_uid = pseudo_fuid; + bufcopy.st_gid = pseudo_fgid; + result = pseudo_xattrdb_save(fd, path, &bufcopy); + } + break; + case OP_CHOWN: + case OP_FCHOWN: + case OP_LINK: + result = pseudo_xattrdb_save(fd, path, buf); + break; + case OP_FSTAT: + case OP_STAT: + result = pseudo_xattrdb_load(fd, path, buf); + break; + default: + break; + } + if (result) + goto skip_path; +#endif + if (op == OP_RENAME) { va_list ap; if (!path) { @@ -1427,6 +1587,13 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path } } +#ifdef PSEUDO_XATTRDB + /* If we were able to store things in xattr, we can easily skip + * most of the fancy path computations and such. + */ + skip_path: +#endif + if (buf) pseudo_msg_stat(&msg, buf); @@ -1555,7 +1722,10 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path pseudo_diag("error: unknown or unimplemented operator %d (%s)", op, pseudo_op_name(op)); break; } - if (do_request) { + /* result can only be set when PSEUDO_XATTRDB resulted in a + * successful store to or read from the local database. + */ + if (do_request && !result) { #ifdef PSEUDO_PROFILING struct timeval tv1_ipc, tv2_ipc; #endif @@ -1598,6 +1768,12 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path } else if (!result) { pseudo_debug(PDBGF_OP, "(%d) (no request)", getpid()); } + #ifdef PSEUDO_XATTRDB + else { + pseudo_debug(PDBGF_OP, "(%d) (handled through xattrdb)", getpid()); + pseudo_debug(PDBGF_OP, "result: %d\n", result->result); + } + #endif pseudo_debug(PDBGF_OP, "\n"); #ifdef PSEUDO_PROFILING diff --git a/pseudo_util.c b/pseudo_util.c index 865222a..7142670 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -82,6 +82,10 @@ static struct pseudo_variables pseudo_env[] = { */ static int pseudo_util_initted = -1; /* Not yet run */ +/* bypass wrapper logic on path computations */ +int (*pseudo_real_lstat)(const char *path, struct stat *buf) = lstat; +int (*pseudo_real_fstat)(int, struct stat *buf) = fstat; + #if 0 static void dump_env(char **envp) { @@ -512,7 +516,7 @@ pseudo_append_element(char *newpath, char *root, size_t allocated, char **pcurre /* if lstat fails, that's fine -- nonexistent files aren't symlinks */ if (!leave_this) { int is_link; - is_link = (lstat(newpath, &buf) != -1) && S_ISLNK(buf.st_mode); + is_link = (pseudo_real_lstat(newpath, &buf) != -1) && S_ISLNK(buf.st_mode); if (link_recursion >= PSEUDO_MAX_LINK_RECURSION && is_link) { pseudo_diag("link recursion too deep, not expanding path '%s'.\n", newpath); is_link = 0; diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c index b2e3810..7920f9e 100644 --- a/pseudo_wrappers.c +++ b/pseudo_wrappers.c @@ -86,6 +86,15 @@ extern struct timeval *pseudo_wrapper_time; #define PROFILE_DONE do {} while(0) #endif +#ifdef PSEUDO_XATTRDB +extern ssize_t (*pseudo_real_lgetxattr)(const char *, const char *, void *, size_t); +extern ssize_t (*pseudo_real_fgetxattr)(int, const char *, void *, size_t); +extern int (*pseudo_real_lsetxattr)(const char *, const char *, const void *, size_t, int); +extern int (*pseudo_real_fsetxattr)(int, const char *, const void *, size_t, int); +#endif +extern int (*pseudo_real_lstat)(const char *, struct stat *); +extern int (*pseudo_real_fstat)(int, struct stat *); + static void _libpseudo_init(void) { pseudo_getlock(); @@ -160,6 +169,15 @@ pseudo_init_wrappers(void) { done = 1; } +#ifdef PSEUDO_XATTRDB + pseudo_real_lgetxattr = real_lgetxattr; + pseudo_real_fgetxattr = real_fgetxattr; + pseudo_real_lsetxattr = real_lsetxattr; + pseudo_real_fsetxattr = real_fsetxattr; +#endif + pseudo_real_lstat = real_lstat; + pseudo_real_fstat = real_fstat; + /* Once the wrappers are setup, we can now use open... so * setup the logfile, if necessary... */ |