Codebase list pseudo / d4c7177
Initial draft xattr support Initial, incomplete, support for extended attributes. Extended attributes are implemented fairly naively, using a second table in the file database using the primary file table's id as a foreign key. The ON DELETE CASCADE behavior requires sqlite 3.6.19 or later with foreign key and trigger support compiled in. To reduce round-trips, the client does not check for existing attributes, but rather, sends three distinct set messages; OP_SET_XATTR, OP_CREATE_XATTR, OP_REPLACE_XATTR. A SET message always succeeds, a CREATE fails if the attribute already exists, and a REPLACE fails if the attribute does not already exist. The /* flags */ feature of makewrappers is used to correct path names appropriately, so all functions are already working with complete paths, and can always use functions that work on links; if they were supposed to dereference, the path fixup code got that. The xattr support is enabled, for now, conditional on whether getfattr --help succeeds. Not yet implemented: Translation for system.posix_acl_access, which is used by "cp -a" (or "cp --preserve-all") on some systems to try to copy modes. Signed-off-by: Peter Seebach <peter.seebach@windriver.com> Peter Seebach 10 years ago
54 changed file(s) with 965 addition(s) and 274 deletion(s). Raw diff Collapse all Expand all
2424 invoke, 'k', "invocation and launching"
2525 benchmark, 'b', "performance statistics"
2626 verbose, 'V', "extra detail"
27 xattr, 'x', "extended attributes"
2020 may-unlink, 1
2121 did-unlink, 0
2222 cancel-unlink, 0
23 get-xattr, 1
24 list-xattr, 1
25 remove-xattr, 1
26 set-xattr, 0
27 create-xattr, 1
28 replace-xattr, 1
+0
-18
ports/linux/guts/fgetxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) name;
11 (void) value;
12 (void) size;
13 errno = ENOTSUP;
14
15 /* return rc;
16 * }
17 */
+0
-17
ports/linux/guts/flistxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t flistxattr(int filedes, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) list;
11 (void) size;
12 errno = ENOTSUP;
13
14 /* return rc;
15 * }
16 */
+0
-16
ports/linux/guts/fremovexattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int fremovexattr(int filedes, const char *name)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) name;
11 errno = ENOTSUP;
12
13 /* return rc;
14 * }
15 */
+0
-19
ports/linux/guts/fsetxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) name;
11 (void) value;
12 (void) size;
13 (void) flags;
14 errno = ENOTSUP;
15
16 /* return rc;
17 * }
18 */
+0
-18
ports/linux/guts/getxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 errno = ENOTSUP;
14
15 /* return rc;
16 * }
17 */
+0
-18
ports/linux/guts/lgetxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 errno = ENOTSUP;
14
15 /* return rc;
16 * }
17 */
+0
-17
ports/linux/guts/listxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t listxattr(const char *pathname, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) list;
11 (void) size;
12 errno = ENOTSUP;
13
14 /* return rc;
15 * }
16 */
+0
-17
ports/linux/guts/llistxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t llistxattr(const char *pathname, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) list;
11 (void) size;
12 errno = ENOTSUP;
13
14 /* return rc;
15 * }
16 */
+0
-16
ports/linux/guts/lremovexattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int lremovexattr(const char *pathname, const char *name)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 errno = ENOTSUP;
12
13 /* return rc;
14 * }
15 */
+0
-19
ports/linux/guts/lsetxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 (void) flags;
14 errno = ENOTSUP;
15
16 /* return rc;
17 * }
18 */
+0
-16
ports/linux/guts/removexattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int removexattr(const char *pathname, const char *name)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 errno = ENOTSUP;
12
13 /* return rc;
14 * }
15 */
+0
-19
ports/linux/guts/setxattr.c less more
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 (void) flags;
14 errno = ENOTSUP;
15
16 /* return rc;
17 * }
18 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) name;
11 (void) value;
12 (void) size;
13 errno = ENOTSUP;
14
15 /* return rc;
16 * }
17 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t flistxattr(int filedes, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) list;
11 (void) size;
12 errno = ENOTSUP;
13
14 /* return rc;
15 * }
16 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int fremovexattr(int filedes, const char *name)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) name;
11 errno = ENOTSUP;
12
13 /* return rc;
14 * }
15 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) filedes;
10 (void) name;
11 (void) value;
12 (void) size;
13 (void) flags;
14 errno = ENOTSUP;
15
16 /* return rc;
17 * }
18 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 errno = ENOTSUP;
14
15 /* return rc;
16 * }
17 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 errno = ENOTSUP;
14
15 /* return rc;
16 * }
17 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t listxattr(const char *pathname, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) list;
11 (void) size;
12 errno = ENOTSUP;
13
14 /* return rc;
15 * }
16 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t llistxattr(const char *pathname, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) list;
11 (void) size;
12 errno = ENOTSUP;
13
14 /* return rc;
15 * }
16 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int lremovexattr(const char *pathname, const char *name)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 errno = ENOTSUP;
12
13 /* return rc;
14 * }
15 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 (void) flags;
14 errno = ENOTSUP;
15
16 /* return rc;
17 * }
18 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int removexattr(const char *pathname, const char *name)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 errno = ENOTSUP;
12
13 /* return rc;
14 * }
15 */
0 /*
1 * Copyright (c) 2010 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7
8 /* suppress warnings */
9 (void) pathname;
10 (void) name;
11 (void) value;
12 (void) size;
13 (void) flags;
14 errno = ENOTSUP;
15
16 /* return rc;
17 * }
18 */
0 # we use "pathname" to avoid canonicalizing paths, because these functions are
1 # unimplemented
2 ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size);
3 ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size);
4 ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size);
5 ssize_t listxattr(const char *pathname, char *list, size_t size);
6 ssize_t llistxattr(const char *pathname, char *list, size_t size);
7 ssize_t flistxattr(int filedes, char *list, size_t size);
8 int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags);
9 int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags);
10 int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags);
11 int removexattr(const char *pathname, const char *name);
12 int lremovexattr(const char *pathname, const char *name);
13 int fremovexattr(int filedes, const char *name);
2424 if ! $found; then
2525 echo >&2 "Can't tell, omitting clone(2) support."
2626 fi
27 if getfattr --help >/dev/null 2>&1; then
28 echo "linux/xattr"
29 else
30 echo "linux/noxattr"
31 fi
1212 # just so we know the inums of symlinks
1313 char *canonicalize_file_name(const char *filename);
1414 int eaccess(const char *path, int mode);
15 # we use "pathname" to avoid canonicalizing paths, because these functions are
16 # unimplemented
17 ssize_t getxattr(const char *pathname, const char *name, void *value, size_t size);
18 ssize_t lgetxattr(const char *pathname, const char *name, void *value, size_t size);
19 ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size);
20 ssize_t listxattr(const char *pathname, char *list, size_t size);
21 ssize_t llistxattr(const char *pathname, char *list, size_t size);
22 ssize_t flistxattr(int filedes, char *list, size_t size);
23 int setxattr(const char *pathname, const char *name, const void *value, size_t size, int flags);
24 int lsetxattr(const char *pathname, const char *name, const void *value, size_t size, int flags);
25 int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags);
26 int removexattr(const char *pathname, const char *name);
27 int lremovexattr(const char *pathname, const char *name);
28 int fremovexattr(int filedes, const char *name);
2915 int open64(const char *path, int flags, ...{mode_t mode}); /* flags=0 */
3016 int openat64(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=0 */
3117 int __openat64_2(int dirfd, const char *path, int flags); /* flags=0 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7 rc = shared_getxattr(NULL, filedes, name, value, size);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t flistxattr(int filedes, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7 rc = shared_listxattr(NULL, filedes, list, size);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int fremovexattr(int filedes, const char *name)
5 * int rc = -1;
6 */
7 rc = shared_removexattr(NULL, filedes, name);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7 rc = shared_setxattr(NULL, filedes, name, value, size, flags);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t getxattr(const char *path, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7 rc = shared_getxattr(path, -1, name, value, size);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size)
5 * ssize_t rc = -1;
6 */
7 rc = shared_getxattr(path, -1, name, value, size);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t listxattr(const char *path, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7 rc = shared_listxattr(path, -1, list, size);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * ssize_t llistxattr(const char *path, char *list, size_t size)
5 * ssize_t rc = -1;
6 */
7 rc = shared_listxattr(path, -1, list, size);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int lremovexattr(const char *path, const char *name)
5 * int rc = -1;
6 */
7 rc = shared_removexattr(path, -1, name);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7 rc = shared_setxattr(path, -1, name, value, size, flags);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int removexattr(const char *path, const char *name)
5 * int rc = -1;
6 */
7 rc = shared_removexattr(path, -1, name);
8
9 /* return rc;
10 * }
11 */
0 /*
1 * Copyright (c) 2014 Wind River Systems; see
2 * guts/COPYRIGHT for information.
3 *
4 * int setxattr(const char *path, const char *name, const void *value, size_t size, int flags)
5 * int rc = -1;
6 */
7 rc = shared_setxattr(path, -1, name, value, size, flags);
8
9 /* return rc;
10 * }
11 */
0 #include <attr/xattr.h>
0 /* shared functionality for the xattr code */
1 /* Each of these functions is expecting to get an optional name, and
2 * a populated statbuf to use for sending messages to the server.
3 */
4
5 #define RC_AND_BUF \
6 int rc; \
7 PSEUDO_STATBUF buf; \
8 if (path) { \
9 rc = base_lstat(path, &buf); \
10 } else { \
11 rc = base_fstat(fd, &buf); \
12 } \
13 if (rc == -1) { \
14 return rc; \
15 }
16
17 static ssize_t shared_getxattr(const char *path, int fd, const char *name, void *value, size_t size) {
18 RC_AND_BUF
19
20 pseudo_debug(PDBGF_XATTR, "getxattr(%s/%d, %s)\n",
21 path ? path : "<no path>", fd, name);
22 pseudo_msg_t *result = pseudo_client_op(OP_GET_XATTR, 0, fd, -1, path, &buf, name);
23 if (result->result != RESULT_SUCCEED) {
24 errno = ENOATTR;
25 return -1;
26 }
27
28 if (value) {
29 pseudo_debug(PDBGF_XATTR, "returned attributes: '%s' (%d bytes)\n",
30 result->path, result->pathlen);
31 if (size >= result->pathlen) {
32 memcpy(value, result->path, result->pathlen);
33 } else {
34 memcpy(value, result->path, size);
35 errno = ERANGE;
36 }
37 }
38 return result->pathlen;
39 }
40
41 static int shared_setxattr(const char *path, int fd, const char *name, const void *value, size_t size, int flags) {
42 RC_AND_BUF
43
44 char *combined;
45 size_t nlen = strlen(name);
46 size_t combined_len = nlen + size + 1;
47 combined = malloc(combined_len + 1);
48 memcpy(combined, name, nlen);
49 combined[nlen] = '\0';
50 memcpy(combined + nlen + 1, value, size);
51 combined[combined_len] = '\0';
52
53 pseudo_debug(PDBGF_XATTR, "setxattr(%s/%d, %s, %s => %s [%d])\n",
54 path ? path : "<no path>", fd, name, (char *) value, combined + nlen + 1, (int) size);
55
56 pseudo_op_t op;
57 switch (flags) {
58 case XATTR_CREATE:
59 op = OP_CREATE_XATTR;
60 break;
61 case XATTR_REPLACE:
62 op = OP_REPLACE_XATTR;
63 break;
64 default:
65 op = OP_SET_XATTR;
66 break;
67 }
68
69 pseudo_msg_t *result = pseudo_client_op(op, 0, fd, -1, path, &buf, combined, combined_len);
70
71 /* we automatically assume success */
72 if (op == OP_SET_XATTR) {
73 return 0;
74 }
75
76 /* CREATE/REPLACE operations can report failure */
77 if (!result || result->result == RESULT_FAIL) {
78 return -1;
79 }
80
81 return 0;
82 }
83
84 static ssize_t shared_listxattr(const char *path, int fd, char *list, size_t size) {
85 RC_AND_BUF
86 pseudo_msg_t *result = pseudo_client_op(OP_LIST_XATTR, 0, fd, -1, path, &buf);
87 if (result->result != RESULT_SUCCEED) {
88 pseudo_debug(PDBGF_XATTR, "listxattr: no success.\n");
89 errno = ENOATTR;
90 return -1;
91 }
92 if (list) {
93 pseudo_debug(PDBGF_XATTR, "listxattr: %d bytes of names, starting '%.*s'\n",
94 (int) result->pathlen, (int) result->pathlen, result->path);
95 if (size >= result->pathlen) {
96 memcpy(list, result->path, result->pathlen);
97 } else {
98 memcpy(list, result->path, size);
99 errno = ERANGE;
100 }
101 }
102 return result->pathlen;
103 }
104
105 static int shared_removexattr(const char *path, int fd, const char *name) {
106 RC_AND_BUF
107 pseudo_msg_t *result = pseudo_client_op(OP_REMOVE_XATTR, 0, fd, -1, path, &buf, name);
108
109 if (result->result != RESULT_SUCCEED) {
110 /* docs say ENOATTR, but I don't have one */
111 errno = ENOENT;
112 return -1;
113 }
114 return 0;
115 }
116
0 ssize_t getxattr(const char *path, const char *name, void *value, size_t size) /* flags=0 */;
1 ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size) /* flags=AT_SYMLINK_NOFOLLOW */;
2 ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size);
3 int setxattr(const char *path, const char *name, const void *value, size_t size, int flags) /* flags=0 */;
4 int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags) /* flags=AT_SYMLINK_NOFOLLOW */;
5 int fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags);
6 ssize_t listxattr(const char *path, char *list, size_t size) /* flags=0 */;
7 ssize_t llistxattr(const char *path, char *list, size_t size) /* flags=AT_SYMLINK_NOFOLLOW */;
8 ssize_t flistxattr(int filedes, char *list, size_t size);
9 int removexattr(const char *path, const char *name) /* flags=0 */;
10 int lremovexattr(const char *path, const char *name) /* flags=AT_SYMLINK_NOFOLLOW */;
11 int fremovexattr(int filedes, const char *name);
5050 char *opt_r = NULL;
5151 int opt_S = 0;
5252
53 static int pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag);
53 static int pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len);
5454 static int pseudo_db_check(int fix);
5555
5656 void
317317 pseudo_diag("Couldn't allocate data structure for path.\n");
318318 exit(EXIT_FAILURE);
319319 }
320 if (pdb_find_file_path(msg)) {
320 if (pdb_find_file_path(msg, NULL)) {
321321 pseudo_diag("Couldn't find a database entry for '%s'.\n", opt_i);
322322 exit(EXIT_FAILURE);
323323 }
484484 * sanity checks, then implements the fairly small DB changes required.
485485 */
486486 int
487 pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) {
487 pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len) {
488488 pseudo_msg_t msg_header;
489489 pseudo_msg_t by_path = { .op = 0 }, by_ino = { .op = 0 };
490 long long row = -1;
490491 pseudo_msg_t db_header;
491492 char *path_by_ino = 0;
492493 char *oldpath = 0;
494 size_t oldpathlen = 0;
493495 int found_path = 0, found_ino = 0;
494496 int prefer_ino = 0;
497 int xattr_flags = 0;
495498
496499 if (!msg)
497500 return 1;
519522 * stuff into a rename, break them apart (null seperated)
520523 */
521524
522 if (msg->pathlen && msg->op == OP_RENAME) {
523 /* In a rename there are two paths, null seperate in msg->path */
524 oldpath = msg->path + strlen(msg->path) + 1;
525 pseudo_debug(PDBGF_OP | PDBGF_FILE, "rename: path %s, oldpath %s\n",
526 msg->path, oldpath);
525 if (msg->pathlen) {
526 switch (msg->op) {
527 case OP_RENAME:
528 case OP_CREATE_XATTR:
529 case OP_GET_XATTR:
530 case OP_LIST_XATTR:
531 case OP_REPLACE_XATTR:
532 case OP_SET_XATTR:
533 /* In a rename there are two paths, null separated in msg->path */
534 oldpath = msg->path + strlen(msg->path) + 1;
535 oldpathlen = msg->pathlen - (oldpath - msg->path);
536 pseudo_debug(PDBGF_OP | PDBGF_FILE | PDBGF_XATTR, "%s: path '%s', oldpath '%s' [%d]\n",
537 pseudo_op_name(msg->op), msg->path, oldpath, (int) oldpathlen);
538 break;
539 default:
540 break;
541 }
527542 }
528543
529544 /* stash original header, in case we need it later */
536551
537552 /* Lookup the full path, with inode and dev if available */
538553 if (msg->pathlen && msg->dev && msg->ino) {
539 if (!pdb_find_file_exact(msg)) {
554 if (!pdb_find_file_exact(msg, &row)) {
540555 /* restore header contents */
541556 by_path = *msg;
542557 by_ino = *msg;
552567 if (msg->pathlen) {
553568 /* for now, don't canonicalize paths anymore */
554569 /* used to do it here, but now doing it in client */
555 if (!pdb_find_file_path(msg)) {
570 if (!pdb_find_file_path(msg, &row)) {
556571 by_path = *msg;
557572 found_path = 1;
558573 } else {
563578 }
564579 /* search on original inode -- in case of mismatch */
565580 if (msg->dev && msg->ino) {
566 if (!pdb_find_file_dev(&by_ino)) {
581 if (!pdb_find_file_dev(&by_ino, &row)) {
567582 found_ino = 1;
568583 path_by_ino = pdb_get_file_path(&by_ino);
569584 }
759774 pdb_unlink_file_dev(&by_ino);
760775 }
761776 if (!found_path) {
762 pdb_link_file(msg);
777 pdb_link_file(msg, NULL);
763778 } else {
764779 /* again, an error, but leaving it alone for now. */
765780 pseudo_diag("creat ignored for existing file '%s'.\n",
789804 /* if the path is not known, link it */
790805 if (!found_path) {
791806 pseudo_debug(PDBGF_FILE, "(new) ");
792 pdb_link_file(msg);
807 pdb_link_file(msg, NULL);
793808 }
794809 break;
795810 case OP_CHOWN: /* FALLTHROUGH */
815830 }
816831 /* if the path is not known, link it */
817832 if (!found_path) {
818 pdb_link_file(msg);
833 pdb_link_file(msg, NULL);
819834 }
820835 break;
821836 case OP_STAT: /* FALLTHROUGH */
870885 } else {
871886 *msg = msg_header;
872887 }
873 pdb_link_file(msg);
888 pdb_link_file(msg, NULL);
874889 break;
875890 case OP_RENAME:
876891 /* a rename implies renaming an existing entry... and every
932947 pdb_unlink_file_dev(&by_ino);
933948 }
934949 *msg = msg_header;
935 pdb_link_file(msg);
950 pdb_link_file(msg, NULL);
951 break;
952 case OP_GET_XATTR:
953 if (pdb_get_xattr(row, &oldpath, &oldpathlen)) {
954 msg->result = RESULT_FAIL;
955 } else {
956 *response_path = oldpath;
957 *response_len = oldpathlen;
958 pseudo_debug(PDBGF_XATTR, "get results: '%s' (%d bytes)\n",
959 *response_path, (int) *response_len);
960 }
961 break;
962 case OP_LIST_XATTR:
963 if (pdb_list_xattr(row, &oldpath, &oldpathlen)) {
964 msg->result = RESULT_FAIL;
965 } else {
966 pseudo_debug(PDBGF_XATTR, "got %d bytes of xattrs to list: %.*s\n", (int) oldpathlen, (int) oldpathlen, oldpath);
967 *response_path = oldpath;
968 *response_len = oldpathlen;
969 }
970 break;
971 case OP_CREATE_XATTR:
972 case OP_REPLACE_XATTR: /* fallthrough */
973 if (msg->op == OP_CREATE_XATTR) {
974 xattr_flags = XATTR_CREATE;
975 }
976 if (msg->op == OP_REPLACE_XATTR) {
977 xattr_flags = XATTR_REPLACE;
978 }
979 case OP_SET_XATTR:
980 /* we need a row entry to store xattr info */
981 if (row == -1) {
982 pdb_link_file(msg, &row);
983 }
984 if (pdb_set_xattr(row, oldpath, oldpathlen, xattr_flags)) {
985 msg->result = RESULT_FAIL;
986 }
987 break;
988 case OP_REMOVE_XATTR:
989 pdb_remove_xattr(row, oldpath, oldpathlen);
936990 break;
937991 default:
938992 pseudo_diag("unknown op from client %d, op %d [%s]\n",
9551009
9561010 /* SHUTDOWN does not get this far, it's handled in pseudo_server.c */
9571011 int
958 pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag) {
1012 pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len) {
9591013 switch (msg->type) {
9601014 case PSEUDO_MSG_PING:
9611015 msg->result = RESULT_SUCCEED;
9651019 break;
9661020 case PSEUDO_MSG_OP:
9671021 case PSEUDO_MSG_FASTOP:
968 return pseudo_op(msg, program, tag);
1022 return pseudo_op(msg, program, tag, response_path, response_len);
9691023 break;
9701024 case PSEUDO_MSG_ACK: /* FALLTHROUGH */
9711025 case PSEUDO_MSG_NAK: /* FALLTHROUGH */
133133 */
134134 #define PSEUDO_LINK_SYMLINK_BEHAVIOR 0
135135
136 /* given n, pick a multiple of block enough bigger than n
137 * to give us some breathing room.
138 */
139 static inline size_t
140 round_up(size_t n, size_t block) {
141 return block * (((n + block / 4) / block) + 1);
142 }
143
136144 #include "pseudo_ports.h"
10551055 size_t pathlen = -1;
10561056 int do_request = 0;
10571057 char *oldpath = 0;
1058 size_t oldpathlen = 0;
10581059 char *alloced_path = 0;
10591060
10601061 /* disable wrappers */
10721073 pseudo_magic();
10731074 return 0;
10741075 }
1076 /* we have to calculate this here, because SET_XATTR
1077 * and friends will be using oldpath to hold a hunk of
1078 * data of arbitrary length
1079 */
1080 oldpathlen = strlen(oldpath);
10751081 if (!path) {
10761082 pseudo_diag("rename (%s) without new path.\n",
10771083 path ? path : "<nil>");
10781084 pseudo_magic();
10791085 return 0;
10801086 }
1087 }
1088
1089 /* we treat the "create" and "replace" flags as logically
1090 * distinct operations, because they can fail when set can't.
1091 */
1092 if (op == OP_SET_XATTR || op == OP_CREATE_XATTR || op == OP_REPLACE_XATTR) {
1093 va_list ap;
1094 va_start(ap, buf);
1095 oldpath = va_arg(ap, char *);
1096 oldpathlen = va_arg(ap, size_t);
1097 pseudo_debug(PDBGF_XATTR, "setxattr, oldpath (%d bytes): '%s'\n",
1098 (int) oldpathlen, oldpath);
1099 va_end(ap);
1100 }
1101 if (op == OP_GET_XATTR){
1102 va_list ap;
1103 va_start(ap, buf);
1104 oldpath = va_arg(ap, char *);
1105 oldpathlen = strlen(oldpath);
1106 pseudo_debug(PDBGF_XATTR, "getxattr, oldpath (%d bytes): '%s'\n",
1107 (int) oldpathlen, oldpath);
1108 va_end(ap);
10811109 }
10821110
10831111 if (path) {
10921120 pathlen = strlen(path) + 1;
10931121 int strip_slash = (pathlen > 2 && (path[pathlen - 2]) == '/');
10941122 if (oldpath) {
1095 size_t full_len = strlen(oldpath) + 1 + pathlen;
1123 size_t full_len = oldpathlen + 1 + pathlen;
1124 size_t partial_len = pathlen - 1 - strip_slash;
10961125 char *both_paths = malloc(full_len);
10971126 if (!both_paths) {
10981127 pseudo_diag("Can't allocate space for paths for a rename operation. Sorry.\n");
10991128 pseudo_magic();
11001129 return 0;
11011130 }
1102 snprintf(both_paths, full_len, "%.*s%c%s",
1103 (int) (pathlen - 1 - strip_slash),
1104 path, 0, oldpath);
1131 memcpy(both_paths, path, partial_len);
1132 both_paths[partial_len] = '\0';
1133 memcpy(both_paths + partial_len + 1, oldpath, oldpathlen);
1134 both_paths[full_len - 1] = '\0';
11051135 pseudo_debug(PDBGF_PATH | PDBGF_FILE, "rename: %s -> %s [%d]\n",
11061136 both_paths + pathlen, both_paths, (int) full_len);
11071137 alloced_path = both_paths;
12381268 case OP_DID_UNLINK:
12391269 case OP_CANCEL_UNLINK:
12401270 case OP_MAY_UNLINK:
1271 case OP_GET_XATTR:
1272 case OP_LIST_XATTR:
1273 case OP_SET_XATTR:
1274 case OP_REMOVE_XATTR:
12411275 do_request = 1;
12421276 break;
12431277 default:
8484 "rdev INTEGER",
8585 NULL,
8686 NULL },
87 { "xattrs",
88 "id INTEGER PRIMARY KEY, "
89 "file_id INTEGER REFERENCES files(id) ON DELETE CASCADE, "
90 "name VARCHAR, "
91 "value VARCHAR",
92 NULL,
93 NULL },
8794 { NULL, NULL, NULL, NULL },
8895 }, log_tables[] = {
8996 { "logs",
113120 /* { "files__path", "files", "path" }, */
114121 { "files__path_dev_ino", "files", "path, dev, ino" },
115122 { "files__dev_ino", "files", "dev, ino" },
123 { "xattrs__file", "xattrs", "file_id" },
116124 { NULL, NULL, NULL },
117125 }, log_indexes[] = {
118126 { NULL, NULL, NULL },
135143 * need.
136144 */
137145 "PRAGMA synchronous = OFF;",
146 "PRAGMA foreign_keys = ON;",
138147 NULL
139148 };
140149
364373
365374 for (i = 0; sql_tables[i].name; ++i) {
366375 found = 0;
376 printf("considering table %s\n", sql_tables[i].name);
367377 for (j = 1; j <= rows; ++j) {
368378 if (!strcmp(existing[j], sql_tables[i].name)) {
369379 found = 1;
586596 if (dbinfo->pragmas) {
587597 for (i = 0; dbinfo->pragmas[i]; ++i) {
588598 rc = sqlite3_exec(db, dbinfo->pragmas[i], NULL, NULL, &errmsg);
599 pseudo_debug(PDBGF_SQL | PDBGF_VERBOSE, "executed pragma: '%s', rc %d.\n",
600 dbinfo->pragmas[i], rc);
589601 if (rc) {
590602 dberr(db, dbinfo->pragmas[i]);
591603 }
13551367 * or 'NAMELESS FILE'.
13561368 */
13571369 int
1358 pdb_link_file(pseudo_msg_t *msg) {
1370 pdb_link_file(pseudo_msg_t *msg, long long *row) {
13591371 static sqlite3_stmt *insert;
13601372 int rc;
13611373 char *sql = "INSERT INTO files "
13961408 if (rc != SQLITE_DONE) {
13971409 dberr(file_db, "insert may have failed (rc %d)", rc);
13981410 }
1411 /* some users care what the row ID is */
1412 if (row) {
1413 *row = sqlite3_last_insert_rowid(file_db);
1414 }
13991415 sqlite3_reset(insert);
14001416 sqlite3_clear_bindings(insert);
14011417 return rc != SQLITE_DONE;
19321948
19331949 /* find file using both path AND dev/inode as key */
19341950 int
1935 pdb_find_file_exact(pseudo_msg_t *msg) {
1951 pdb_find_file_exact(pseudo_msg_t *msg, long long *row) {
19361952 static sqlite3_stmt *select;
19371953 int rc;
19381954 char *sql = "SELECT * FROM files WHERE path = ? AND dev = ? AND ino = ?;";
19601976 rc = sqlite3_step(select);
19611977 switch (rc) {
19621978 case SQLITE_ROW:
1979 if (row) {
1980 *row = sqlite3_column_int64(select, 0);
1981 }
19631982 msg->uid = (unsigned long) sqlite3_column_int64(select, 4);
19641983 msg->gid = (unsigned long) sqlite3_column_int64(select, 5);
19651984 msg->mode = (unsigned long) sqlite3_column_int64(select, 6);
19832002
19842003 /* find file using path as a key */
19852004 int
1986 pdb_find_file_path(pseudo_msg_t *msg) {
2005 pdb_find_file_path(pseudo_msg_t *msg, long long *row) {
19872006 static sqlite3_stmt *select;
19882007 int rc;
19892008 char *sql = "SELECT * FROM files WHERE path = ?;";
20142033 rc = sqlite3_step(select);
20152034 switch (rc) {
20162035 case SQLITE_ROW:
2036 if (row) {
2037 *row = sqlite3_column_int64(select, 0);
2038 }
20172039 msg->dev = sqlite3_column_int64(select, 2);
20182040 msg->ino = sqlite3_column_int64(select, 3);
20192041 msg->uid = sqlite3_column_int64(select, 4);
20892111
20902112 /* find file using dev/inode as key */
20912113 int
2092 pdb_find_file_dev(pseudo_msg_t *msg) {
2114 pdb_find_file_dev(pseudo_msg_t *msg, long long *row) {
20932115 static sqlite3_stmt *select;
20942116 int rc;
20952117 char *sql = "SELECT * FROM files WHERE dev = ? AND ino = ?;";
21132135 rc = sqlite3_step(select);
21142136 switch (rc) {
21152137 case SQLITE_ROW:
2138 if (row) {
2139 *row = sqlite3_column_int64(select, 0);
2140 }
21162141 msg->uid = (unsigned long) sqlite3_column_int64(select, 4);
21172142 msg->gid = (unsigned long) sqlite3_column_int64(select, 5);
21182143 msg->mode = (unsigned long) sqlite3_column_int64(select, 6);
21342159 return rc;
21352160 }
21362161
2162 int
2163 pdb_get_xattr(long long file_id, char **value, size_t *len) {
2164 static sqlite3_stmt *select;
2165 int rc;
2166 char *response;
2167 size_t length;
2168 char *sql = "SELECT value FROM xattrs WHERE file_id = ? AND name = ?;";
2169
2170 if (!file_db && get_dbs()) {
2171 pseudo_diag("%s: database error.\n", __func__);
2172 return 0;
2173 }
2174 if (!select) {
2175 rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &select, NULL);
2176 if (rc) {
2177 dberr(file_db, "couldn't prepare SELECT statement");
2178 return 1;
2179 }
2180 }
2181 pseudo_debug(PDBGF_XATTR, "requested xattr named '%s' for file %lld\n", *value, file_id);
2182 sqlite3_bind_int(select, 1, file_id);
2183 rc = sqlite3_bind_text(select, 2, *value, -1, SQLITE_STATIC);
2184 if (rc) {
2185 dberr(file_db, "couldn't bind xattr name to SELECT.");
2186 return 1;
2187 }
2188 rc = sqlite3_step(select);
2189 switch (rc) {
2190 case SQLITE_ROW:
2191 response = (char *) sqlite3_column_text(select, 0);
2192 length = sqlite3_column_bytes(select, 0);
2193 pseudo_debug(PDBGF_XATTR, "got %d-byte results: '%s'\n",
2194 (int) length, response);
2195 if (response && length >= 1) {
2196 /* not a strdup because the values can contain
2197 * arbitrary bytes.
2198 */
2199 *value = malloc(length);
2200 memcpy(*value, response, length);
2201 *len = length;
2202 rc = 0;
2203 } else {
2204 *value = NULL;
2205 *len = 0;
2206 rc = 1;
2207 }
2208 break;
2209 case SQLITE_DONE:
2210 pseudo_debug(PDBGF_DB, "find_exact: sqlite_done on first row\n");
2211 rc = 1;
2212 break;
2213 default:
2214 dberr(file_db, "find_exact: select returned neither a row nor done");
2215 rc = 1;
2216 break;
2217 }
2218 sqlite3_reset(select);
2219 sqlite3_clear_bindings(select);
2220 return rc;
2221 }
2222
2223 int
2224 pdb_list_xattr(long long file_id, char **value, size_t *len) {
2225 static sqlite3_stmt *select;
2226 size_t allocated = 0;
2227 size_t used = 0;
2228 char *buffer = 0;
2229 int rc;
2230 char *sql = "SELECT name FROM xattrs WHERE file_id = ?;";
2231
2232 /* if we don't have a record of the file, it must not have
2233 * any extended attributes...
2234 */
2235 if (file_id == -1) {
2236 *value = NULL;
2237 *len = 0;
2238 return 0;
2239 }
2240
2241 if (!file_db && get_dbs()) {
2242 pseudo_diag("%s: database error.\n", __func__);
2243 return 0;
2244 }
2245 if (!select) {
2246 rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &select, NULL);
2247 if (rc) {
2248 dberr(file_db, "couldn't prepare SELECT statement");
2249 return 1;
2250 }
2251 }
2252 sqlite3_bind_int(select, 1, file_id);
2253 do {
2254 rc = sqlite3_step(select);
2255 if (rc == SQLITE_ROW) {
2256 char *value = (char *) sqlite3_column_text(select, 0);
2257 size_t len = sqlite3_column_bytes(select, 0);
2258 if (!buffer) {
2259 allocated = round_up(len, 256);
2260 buffer = malloc(allocated);
2261 }
2262 if (used + len + 2 > allocated) {
2263 size_t new_allocated = round_up(used + len + 2, 256);
2264 char *new_buffer = malloc(new_allocated);
2265 memcpy(new_buffer, buffer, used);
2266 free(buffer);
2267 allocated = new_allocated;
2268 buffer = new_buffer;
2269 }
2270 memcpy(buffer + used, value, len);
2271 buffer[used + len] = '\0';
2272 used = used + len + 1;
2273 } else if (rc == SQLITE_DONE) {
2274 *value = buffer;
2275 *len = used;
2276 } else {
2277 dberr(file_db, "non-row response from select?");
2278 free(buffer);
2279 *value = NULL;
2280 *len = 0;
2281 }
2282 } while (rc == SQLITE_ROW);
2283 sqlite3_reset(select);
2284 sqlite3_clear_bindings(select);
2285 return rc != SQLITE_DONE;
2286 }
2287
2288 int
2289 pdb_remove_xattr(long long file_id, char *value, size_t len) {
2290 static sqlite3_stmt *delete;
2291 int rc;
2292 char *sql = "DELETE FROM xattrs WHERE file_id = ? AND name = ?;";
2293
2294 if (!file_db && get_dbs()) {
2295 pseudo_diag("%s: database error.\n", __func__);
2296 return 0;
2297 }
2298 if (!delete) {
2299 rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &delete, NULL);
2300 if (rc) {
2301 dberr(file_db, "couldn't prepare DELETE statement");
2302 return 1;
2303 }
2304 }
2305 sqlite3_bind_int(delete, 1, file_id);
2306 rc = sqlite3_bind_text(delete, 2, value, len, SQLITE_STATIC);
2307 if (rc) {
2308 dberr(file_db, "couldn't bind xattr name to DELETE.");
2309 return 1;
2310 }
2311 file_db_dirty = 1;
2312 rc = sqlite3_step(delete);
2313 if (rc != SQLITE_DONE) {
2314 dberr(file_db, "delete xattr may have failed");
2315 }
2316 sqlite3_reset(delete);
2317 sqlite3_clear_bindings(delete);
2318 return rc != SQLITE_DONE;
2319 }
2320
2321 int
2322 pdb_set_xattr(long long file_id, char *value, size_t len, int flags) {
2323 static sqlite3_stmt *select, *update, *insert;
2324 int rc;
2325 long long existing_row = -1;
2326 char *select_sql = "SELECT id FROM xattrs WHERE file_id = ? AND name = ?;";
2327 char *insert_sql = "INSERT INTO xattrs "
2328 " ( file_id, name, value ) "
2329 " VALUES (?, ?, ?);";
2330 char *update_sql = "UPDATE xattrs SET value = ? WHERE id = ?;";
2331 char *vname = value;
2332 size_t vlen;
2333
2334 if (!file_db && get_dbs()) {
2335 pseudo_diag("%s: database error.\n", __func__);
2336 return 0;
2337 }
2338 if (!select) {
2339 rc = sqlite3_prepare_v2(file_db, select_sql, strlen(select_sql), &select, NULL);
2340 if (rc) {
2341 dberr(file_db, "couldn't prepare SELECT statement");
2342 return 1;
2343 }
2344 }
2345 sqlite3_bind_int(select, 1, file_id);
2346 rc = sqlite3_bind_text(select, 2, value, -1, SQLITE_STATIC);
2347 if (rc) {
2348 dberr(file_db, "couldn't bind xattr name to SELECT.");
2349 return 1;
2350 }
2351 rc = sqlite3_step(select);
2352 switch (rc) {
2353 case SQLITE_ROW:
2354 existing_row = sqlite3_column_int64(select, 0);
2355 break;
2356 case SQLITE_DONE:
2357 pseudo_debug(PDBGF_DB | PDBGF_VERBOSE, "find_exact: sqlite_done on first row\n");
2358 existing_row = -1;
2359 break;
2360 default:
2361 dberr(file_db, "set_xattr: select returned neither a row nor done");
2362 rc = 1;
2363 break;
2364 }
2365 sqlite3_reset(select);
2366 sqlite3_clear_bindings(select);
2367 if (flags == XATTR_CREATE && existing_row != -1) {
2368 pseudo_debug(PDBGF_DB, "XATTR_CREATE with an existing row, failing.");
2369 return 1;
2370 }
2371 if (flags == XATTR_REPLACE && existing_row == -1) {
2372 pseudo_debug(PDBGF_DB, "XATTR_REPLACE with no existing row, failing.");
2373 return 1;
2374 }
2375 /* the material after the name is the value */
2376 vlen = strlen(value);
2377 len = len - (vlen + 1);
2378 value = value + len;
2379 pseudo_debug(PDBGF_XATTR, "trying to set a value for %lld: name is '%s', value is '%s'. Existing row %lld.\n",
2380 file_id, vname, value, existing_row);
2381 if (existing_row != -1) {
2382 /* update */
2383 if (!update) {
2384 rc = sqlite3_prepare_v2(file_db, update_sql, strlen(update_sql), &update, NULL);
2385 if (rc) {
2386 dberr(file_db, "couldn't prepare UPDATE statement");
2387 return 1;
2388 }
2389 }
2390 rc = sqlite3_bind_text(update, 1, value, -1, SQLITE_STATIC);
2391 if (rc) {
2392 dberr(file_db, "couldn't bind xattr value to UPDATE.");
2393 return 1;
2394 }
2395 sqlite3_bind_int(update, 2, existing_row);
2396 file_db_dirty = 1;
2397 rc = sqlite3_step(update);
2398 if (rc != SQLITE_DONE) {
2399 dberr(file_db, "update xattr may have failed");
2400 }
2401 sqlite3_reset(update);
2402 sqlite3_clear_bindings(update);
2403 return rc != SQLITE_DONE;
2404 } else {
2405 /* insert */
2406 if (!insert) {
2407 rc = sqlite3_prepare_v2(file_db, insert_sql, strlen(insert_sql), &insert, NULL);
2408 if (rc) {
2409 dberr(file_db, "couldn't prepare INSERT statement");
2410 return 1;
2411 }
2412 }
2413 pseudo_debug(PDBGF_XATTR, "insert should be getting ID %lld\n", file_id);
2414 sqlite3_bind_int64(insert, 1, file_id);
2415 rc = sqlite3_bind_text(insert, 2, vname, -1, SQLITE_STATIC);
2416 if (rc) {
2417 dberr(file_db, "couldn't bind xattr name to INSERT statement");
2418 return 1;
2419 }
2420 rc = sqlite3_bind_text(insert, 3, value, vlen, SQLITE_STATIC);
2421 if (rc) {
2422 dberr(file_db, "couldn't bind xattr value to INSERT statement");
2423 return 1;
2424 }
2425 file_db_dirty = 1;
2426 rc = sqlite3_step(insert);
2427 if (rc != SQLITE_DONE) {
2428 dberr(file_db, "insert xattr may have failed");
2429 }
2430 sqlite3_reset(insert);
2431 sqlite3_clear_bindings(insert);
2432 return rc != SQLITE_DONE;
2433 }
2434 return rc;
2435 }
2436
21372437 /* find file using only inode as key. Unused for now, planned to come
21382438 * in for NFS usage.
21392439 */
21402440 int
2141 pdb_find_file_ino(pseudo_msg_t *msg) {
2441 pdb_find_file_ino(pseudo_msg_t *msg, long long *row) {
21422442 static sqlite3_stmt *select;
21432443 int rc;
21442444 char *sql = "SELECT * FROM files WHERE ino = ?;";
21612461 rc = sqlite3_step(select);
21622462 switch (rc) {
21632463 case SQLITE_ROW:
2464 if (row) {
2465 *row = sqlite3_column_int64(select, 0);
2466 }
21642467 msg->dev = (unsigned long) sqlite3_column_int64(select, 2);
21652468 msg->uid = (unsigned long) sqlite3_column_int64(select, 4);
21662469 msg->gid = (unsigned long) sqlite3_column_int64(select, 5);
4040 extern int pdb_cancel_unlink_file(pseudo_msg_t *msg);
4141 extern int pdb_did_unlink_file(char *path, int deleting);
4242 extern int pdb_did_unlink_files(int deleting);
43 extern int pdb_link_file(pseudo_msg_t *msg);
43 extern int pdb_link_file(pseudo_msg_t *msg, long long *row);
4444 extern int pdb_may_unlink_file(pseudo_msg_t *msg, int deleting);
4545 extern int pdb_unlink_file(pseudo_msg_t *msg);
4646 extern int pdb_unlink_file_dev(pseudo_msg_t *msg);
5050 extern int pdb_unlink_contents(pseudo_msg_t *msg);
5151 extern int pdb_rename_file(const char *oldpath, pseudo_msg_t *msg);
5252 extern int pdb_renumber_all(dev_t from, dev_t to);
53 extern int pdb_find_file_exact(pseudo_msg_t *msg);
54 extern int pdb_find_file_path(pseudo_msg_t *msg);
55 extern int pdb_find_file_dev(pseudo_msg_t *msg);
56 extern int pdb_find_file_ino(pseudo_msg_t *msg);
53 extern int pdb_find_file_exact(pseudo_msg_t *msg, long long *row);
54 extern int pdb_find_file_path(pseudo_msg_t *msg, long long *row);
55 extern int pdb_find_file_dev(pseudo_msg_t *msg, long long *row);
56 extern int pdb_find_file_ino(pseudo_msg_t *msg, long long *row);
5757 extern char *pdb_get_file_path(pseudo_msg_t *msg);
58 extern int pdb_get_xattr(long long file_id, char **value, size_t *len);
59 extern int pdb_list_xattr(long long file_id, char **value, size_t *len);
60 extern int pdb_remove_xattr(long long file_id, char *value, size_t len);
61 extern int pdb_set_xattr(long long file_id, char *value, size_t len, int flags);
5862
5963 struct log_history;
6064 typedef struct log_history *log_history;
00 /*
11 * pseudo_server.c, pseudo's server-side logic and message handling
2
23 *
34 * Copyright (c) 2008-2010, 2013 Wind River Systems, Inc.
45 *
267268 in = pseudo_msg_receive(clients[i].fd);
268269 if (in) {
269270 char *response_path = 0;
271 size_t response_pathlen;
270272 int send_response = 1;
271273 pseudo_debug(PDBGF_SERVER | PDBGF_VERBOSE, "got a message (%d): %s\n", in->type, (in->pathlen ? in->path : "<no path>"));
272274 /* handle incoming ping */
305307 if (in->type != PSEUDO_MSG_SHUTDOWN) {
306308 if (in->type == PSEUDO_MSG_FASTOP)
307309 send_response = 0;
308 if (pseudo_server_response(in, clients[i].program, clients[i].tag)) {
310 /* most messages don't need these, but xattr may */
311 response_path = 0;
312 response_pathlen = -1;
313 if (pseudo_server_response(in, clients[i].program, clients[i].tag, &response_path, &response_pathlen)) {
309314 in->type = PSEUDO_MSG_NAK;
310315 } else {
311316 in->type = PSEUDO_MSG_ACK;
312317 pseudo_debug(PDBGF_SERVER | PDBGF_VERBOSE, "response: %d (%s)\n",
313318 in->result, pseudo_res_name(in->result));
314319 }
315 /* no path in response */
316 in->pathlen = 0;
317320 in->client = i;
321 if (response_path) {
322 in->pathlen = response_pathlen;
323 } else {
324 in->pathlen = 0;
325 }
318326 } else {
319327 /* the server's listen fd is "a client", and
320328 * so is the program connecting to request a shutdown.
346354 }
347355 }
348356 if (send_response) {
349 if ((rc = pseudo_msg_send(clients[i].fd, in, -1, response_path)) != 0) {
357 if ((rc = pseudo_msg_send(clients[i].fd, in, in->pathlen, response_path)) != 0) {
350358 pseudo_debug(PDBGF_SERVER, "failed to send response to client %d [%d]: %d (%s)\n",
351359 i, (int) clients[i].pid, rc, strerror(errno));
352360 }
1717 *
1818 */
1919 extern int pseudo_server_start(int);
20 extern int pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag);
20 extern int pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag, char **response_path, size_t *response_len);
2121 extern int pseudo_server_timeout;
2222 extern int opt_l;
418418
419419 wrote += write(pseudo_util_debug_fd, debuff, len);
420420 return wrote;
421 }
422
423 /* given n, pick a multiple of block enough bigger than n
424 * to give us some breathing room.
425 */
426 static inline size_t
427 round_up(size_t n, size_t block) {
428 return block * (((n + block / 4) / block) + 1);
429421 }
430422
431423 /* store pid in text form for prepending to messages */
4747 #include "pseudo_ipc.h"
4848 #include "pseudo_client.h"
4949
50 /* Types and declarations we need in advance. */
51 #include "pseudo_wrapper_table.c"
52
5053 static void pseudo_enosys(const char *);
5154 static int pseudo_check_wrappers(void);
5255 static volatile int antimagic = 0;
6063
6164 extern char *program_invocation_short_name;
6265 static sigset_t pseudo_saved_sigmask;
63
64 /* the generated code goes here */
65 #include "pseudo_wrapper_table.c"
66 #include "pseudo_wrapfuncs.c"
6766
6867 /* Constructor only exists in libpseudo */
6968 static void _libpseudo_init(void) __attribute__ ((constructor));
251250 return _libpseudo_initted;
252251 }
253252
253 /* the generated code goes here */
254254 #include "port_wrappers.c"
255 #include "pseudo_wrapfuncs.c"
256
3737 exit(1);
3838 }
3939 msg = pseudo_msg_new(0, argv[1]);
40 rc = pdb_find_file_path(msg);
40 rc = pdb_find_file_path(msg, NULL);
4141 if (rc) {
4242 printf("error.\n");
4343 return 1;