xref: /qemu/hw/9pfs/9p-xattr.c (revision 5507904e)
1267ae092SWei Liu /*
2267ae092SWei Liu  * 9p  xattr callback
3267ae092SWei Liu  *
4267ae092SWei Liu  * Copyright IBM, Corp. 2010
5267ae092SWei Liu  *
6267ae092SWei Liu  * Authors:
7267ae092SWei Liu  * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
8267ae092SWei Liu  *
9267ae092SWei Liu  * This work is licensed under the terms of the GNU GPL, version 2.  See
10267ae092SWei Liu  * the COPYING file in the top-level directory.
11267ae092SWei Liu  *
12267ae092SWei Liu  */
13267ae092SWei Liu 
14fbc04127SPeter Maydell #include "qemu/osdep.h"
15ebe74f8bSWei Liu #include "9p.h"
16267ae092SWei Liu #include "fsdev/file-op-9p.h"
17267ae092SWei Liu #include "9p-xattr.h"
1856ad3e54SGreg Kurz #include "9p-util.h"
1956ad3e54SGreg Kurz #include "9p-local.h"
20267ae092SWei Liu 
21267ae092SWei Liu 
22267ae092SWei Liu static XattrOperations *get_xattr_operations(XattrOperations **h,
23267ae092SWei Liu                                              const char *name)
24267ae092SWei Liu {
25267ae092SWei Liu     XattrOperations *xops;
26267ae092SWei Liu     for (xops = *(h)++; xops != NULL; xops = *(h)++) {
27267ae092SWei Liu         if (!strncmp(name, xops->name, strlen(xops->name))) {
28267ae092SWei Liu             return xops;
29267ae092SWei Liu         }
30267ae092SWei Liu     }
31267ae092SWei Liu     return NULL;
32267ae092SWei Liu }
33267ae092SWei Liu 
34267ae092SWei Liu ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
35267ae092SWei Liu                        const char *name, void *value, size_t size)
36267ae092SWei Liu {
37267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
38267ae092SWei Liu     if (xops) {
39267ae092SWei Liu         return xops->getxattr(ctx, path, name, value, size);
40267ae092SWei Liu     }
41267ae092SWei Liu     errno = EOPNOTSUPP;
42267ae092SWei Liu     return -1;
43267ae092SWei Liu }
44267ae092SWei Liu 
45267ae092SWei Liu ssize_t pt_listxattr(FsContext *ctx, const char *path,
46267ae092SWei Liu                      char *name, void *value, size_t size)
47267ae092SWei Liu {
48267ae092SWei Liu     int name_size = strlen(name) + 1;
49267ae092SWei Liu     if (!value) {
50267ae092SWei Liu         return name_size;
51267ae092SWei Liu     }
52267ae092SWei Liu 
53267ae092SWei Liu     if (size < name_size) {
54267ae092SWei Liu         errno = ERANGE;
55267ae092SWei Liu         return -1;
56267ae092SWei Liu     }
57267ae092SWei Liu 
58267ae092SWei Liu     /* no need for strncpy: name_size is strlen(name)+1 */
59267ae092SWei Liu     memcpy(value, name, name_size);
60267ae092SWei Liu     return name_size;
61267ae092SWei Liu }
62267ae092SWei Liu 
63*5507904eSGreg Kurz static ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
64*5507904eSGreg Kurz                                      char *list, size_t size)
65*5507904eSGreg Kurz {
66*5507904eSGreg Kurz     char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
67*5507904eSGreg Kurz     int ret;
68*5507904eSGreg Kurz 
69*5507904eSGreg Kurz     ret = llistxattr(proc_path, list, size);
70*5507904eSGreg Kurz     g_free(proc_path);
71*5507904eSGreg Kurz     return ret;
72*5507904eSGreg Kurz }
73267ae092SWei Liu 
74267ae092SWei Liu /*
75267ae092SWei Liu  * Get the list and pass to each layer to find out whether
76267ae092SWei Liu  * to send the data or not
77267ae092SWei Liu  */
78267ae092SWei Liu ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
79267ae092SWei Liu                         void *value, size_t vsize)
80267ae092SWei Liu {
81267ae092SWei Liu     ssize_t size = 0;
82267ae092SWei Liu     void *ovalue = value;
83267ae092SWei Liu     XattrOperations *xops;
84267ae092SWei Liu     char *orig_value, *orig_value_start;
85267ae092SWei Liu     ssize_t xattr_len, parsed_len = 0, attr_len;
86*5507904eSGreg Kurz     char *dirpath, *name;
87*5507904eSGreg Kurz     int dirfd;
88267ae092SWei Liu 
89267ae092SWei Liu     /* Get the actual len */
90*5507904eSGreg Kurz     dirpath = g_path_get_dirname(path);
91*5507904eSGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
92*5507904eSGreg Kurz     g_free(dirpath);
93*5507904eSGreg Kurz     if (dirfd == -1) {
94*5507904eSGreg Kurz         return -1;
95*5507904eSGreg Kurz     }
96*5507904eSGreg Kurz 
97*5507904eSGreg Kurz     name = g_path_get_basename(path);
98*5507904eSGreg Kurz     xattr_len = flistxattrat_nofollow(dirfd, name, value, 0);
99267ae092SWei Liu     if (xattr_len <= 0) {
100*5507904eSGreg Kurz         g_free(name);
101*5507904eSGreg Kurz         close_preserve_errno(dirfd);
102267ae092SWei Liu         return xattr_len;
103267ae092SWei Liu     }
104267ae092SWei Liu 
105267ae092SWei Liu     /* Now fetch the xattr and find the actual size */
106267ae092SWei Liu     orig_value = g_malloc(xattr_len);
107*5507904eSGreg Kurz     xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len);
108*5507904eSGreg Kurz     g_free(name);
109*5507904eSGreg Kurz     close_preserve_errno(dirfd);
110*5507904eSGreg Kurz     if (xattr_len < 0) {
111*5507904eSGreg Kurz         return -1;
112*5507904eSGreg Kurz     }
113267ae092SWei Liu 
114267ae092SWei Liu     /* store the orig pointer */
115267ae092SWei Liu     orig_value_start = orig_value;
116267ae092SWei Liu     while (xattr_len > parsed_len) {
117267ae092SWei Liu         xops = get_xattr_operations(ctx->xops, orig_value);
118267ae092SWei Liu         if (!xops) {
119267ae092SWei Liu             goto next_entry;
120267ae092SWei Liu         }
121267ae092SWei Liu 
122267ae092SWei Liu         if (!value) {
123267ae092SWei Liu             size += xops->listxattr(ctx, path, orig_value, value, vsize);
124267ae092SWei Liu         } else {
125267ae092SWei Liu             size = xops->listxattr(ctx, path, orig_value, value, vsize);
126267ae092SWei Liu             if (size < 0) {
127267ae092SWei Liu                 goto err_out;
128267ae092SWei Liu             }
129267ae092SWei Liu             value += size;
130267ae092SWei Liu             vsize -= size;
131267ae092SWei Liu         }
132267ae092SWei Liu next_entry:
133267ae092SWei Liu         /* Got the next entry */
134267ae092SWei Liu         attr_len = strlen(orig_value) + 1;
135267ae092SWei Liu         parsed_len += attr_len;
136267ae092SWei Liu         orig_value += attr_len;
137267ae092SWei Liu     }
138267ae092SWei Liu     if (value) {
139267ae092SWei Liu         size = value - ovalue;
140267ae092SWei Liu     }
141267ae092SWei Liu 
142267ae092SWei Liu err_out:
143267ae092SWei Liu     g_free(orig_value_start);
144267ae092SWei Liu     return size;
145267ae092SWei Liu }
146267ae092SWei Liu 
147267ae092SWei Liu int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
148267ae092SWei Liu                    void *value, size_t size, int flags)
149267ae092SWei Liu {
150267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
151267ae092SWei Liu     if (xops) {
152267ae092SWei Liu         return xops->setxattr(ctx, path, name, value, size, flags);
153267ae092SWei Liu     }
154267ae092SWei Liu     errno = EOPNOTSUPP;
155267ae092SWei Liu     return -1;
156267ae092SWei Liu 
157267ae092SWei Liu }
158267ae092SWei Liu 
159267ae092SWei Liu int v9fs_remove_xattr(FsContext *ctx,
160267ae092SWei Liu                       const char *path, const char *name)
161267ae092SWei Liu {
162267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
163267ae092SWei Liu     if (xops) {
164267ae092SWei Liu         return xops->removexattr(ctx, path, name);
165267ae092SWei Liu     }
166267ae092SWei Liu     errno = EOPNOTSUPP;
167267ae092SWei Liu     return -1;
168267ae092SWei Liu 
169267ae092SWei Liu }
170267ae092SWei Liu 
17156ad3e54SGreg Kurz ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
17256ad3e54SGreg Kurz                                 const char *name, void *value, size_t size)
17356ad3e54SGreg Kurz {
17456ad3e54SGreg Kurz     char *dirpath = g_path_get_dirname(path);
17556ad3e54SGreg Kurz     char *filename = g_path_get_basename(path);
17656ad3e54SGreg Kurz     int dirfd;
17756ad3e54SGreg Kurz     ssize_t ret = -1;
17856ad3e54SGreg Kurz 
17956ad3e54SGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
18056ad3e54SGreg Kurz     if (dirfd == -1) {
18156ad3e54SGreg Kurz         goto out;
18256ad3e54SGreg Kurz     }
18356ad3e54SGreg Kurz 
18456ad3e54SGreg Kurz     ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
18556ad3e54SGreg Kurz     close_preserve_errno(dirfd);
18656ad3e54SGreg Kurz out:
18756ad3e54SGreg Kurz     g_free(dirpath);
18856ad3e54SGreg Kurz     g_free(filename);
18956ad3e54SGreg Kurz     return ret;
19056ad3e54SGreg Kurz }
19156ad3e54SGreg Kurz 
19256fc494bSGreg Kurz ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
19356fc494bSGreg Kurz                     void *value, size_t size)
19456fc494bSGreg Kurz {
19556ad3e54SGreg Kurz     return local_getxattr_nofollow(ctx, path, name, value, size);
19656fc494bSGreg Kurz }
19756fc494bSGreg Kurz 
19856fc494bSGreg Kurz int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
19956fc494bSGreg Kurz                 size_t size, int flags)
20056fc494bSGreg Kurz {
20156fc494bSGreg Kurz     char *buffer;
20256fc494bSGreg Kurz     int ret;
20356fc494bSGreg Kurz 
20456fc494bSGreg Kurz     buffer = rpath(ctx, path);
20556fc494bSGreg Kurz     ret = lsetxattr(buffer, name, value, size, flags);
20656fc494bSGreg Kurz     g_free(buffer);
20756fc494bSGreg Kurz     return ret;
20856fc494bSGreg Kurz }
20956fc494bSGreg Kurz 
21056fc494bSGreg Kurz int pt_removexattr(FsContext *ctx, const char *path, const char *name)
21156fc494bSGreg Kurz {
21256fc494bSGreg Kurz     char *buffer;
21356fc494bSGreg Kurz     int ret;
21456fc494bSGreg Kurz 
21556fc494bSGreg Kurz     buffer = rpath(ctx, path);
21656fc494bSGreg Kurz     ret = lremovexattr(path, name);
21756fc494bSGreg Kurz     g_free(buffer);
21856fc494bSGreg Kurz     return ret;
21956fc494bSGreg Kurz }
22056fc494bSGreg Kurz 
22156fc494bSGreg Kurz ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
22256fc494bSGreg Kurz                         void *value, size_t size)
22356fc494bSGreg Kurz {
22456fc494bSGreg Kurz     errno = ENOTSUP;
22556fc494bSGreg Kurz     return -1;
22656fc494bSGreg Kurz }
22756fc494bSGreg Kurz 
22856fc494bSGreg Kurz int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
22956fc494bSGreg Kurz                     void *value, size_t size, int flags)
23056fc494bSGreg Kurz {
23156fc494bSGreg Kurz     errno = ENOTSUP;
23256fc494bSGreg Kurz     return -1;
23356fc494bSGreg Kurz }
23456fc494bSGreg Kurz 
23556fc494bSGreg Kurz ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
23656fc494bSGreg Kurz                          void *value, size_t size)
23756fc494bSGreg Kurz {
23856fc494bSGreg Kurz     return 0;
23956fc494bSGreg Kurz }
24056fc494bSGreg Kurz 
24156fc494bSGreg Kurz int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
24256fc494bSGreg Kurz {
24356fc494bSGreg Kurz     errno = ENOTSUP;
24456fc494bSGreg Kurz     return -1;
24556fc494bSGreg Kurz }
24656fc494bSGreg Kurz 
247267ae092SWei Liu XattrOperations *mapped_xattr_ops[] = {
248267ae092SWei Liu     &mapped_user_xattr,
249267ae092SWei Liu     &mapped_pacl_xattr,
250267ae092SWei Liu     &mapped_dacl_xattr,
251267ae092SWei Liu     NULL,
252267ae092SWei Liu };
253267ae092SWei Liu 
254267ae092SWei Liu XattrOperations *passthrough_xattr_ops[] = {
255267ae092SWei Liu     &passthrough_user_xattr,
256267ae092SWei Liu     &passthrough_acl_xattr,
257267ae092SWei Liu     NULL,
258267ae092SWei Liu };
259267ae092SWei Liu 
260267ae092SWei Liu /* for .user none model should be same as passthrough */
261267ae092SWei Liu XattrOperations *none_xattr_ops[] = {
262267ae092SWei Liu     &passthrough_user_xattr,
263267ae092SWei Liu     &none_acl_xattr,
264267ae092SWei Liu     NULL,
265267ae092SWei Liu };
266