xref: /qemu/hw/9pfs/9p-xattr.c (revision 6f569084)
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 
14*6f569084SChristian Schoenebeck /*
15*6f569084SChristian Schoenebeck  * Not so fast! You might want to read the 9p developer docs first:
16*6f569084SChristian Schoenebeck  * https://wiki.qemu.org/Documentation/9p
17*6f569084SChristian Schoenebeck  */
18*6f569084SChristian Schoenebeck 
19fbc04127SPeter Maydell #include "qemu/osdep.h"
20ebe74f8bSWei Liu #include "9p.h"
21267ae092SWei Liu #include "fsdev/file-op-9p.h"
22267ae092SWei Liu #include "9p-xattr.h"
2356ad3e54SGreg Kurz #include "9p-util.h"
2456ad3e54SGreg Kurz #include "9p-local.h"
25267ae092SWei Liu 
26267ae092SWei Liu 
get_xattr_operations(XattrOperations ** h,const char * name)27267ae092SWei Liu static XattrOperations *get_xattr_operations(XattrOperations **h,
28267ae092SWei Liu                                              const char *name)
29267ae092SWei Liu {
30267ae092SWei Liu     XattrOperations *xops;
31267ae092SWei Liu     for (xops = *(h)++; xops != NULL; xops = *(h)++) {
32267ae092SWei Liu         if (!strncmp(name, xops->name, strlen(xops->name))) {
33267ae092SWei Liu             return xops;
34267ae092SWei Liu         }
35267ae092SWei Liu     }
36267ae092SWei Liu     return NULL;
37267ae092SWei Liu }
38267ae092SWei Liu 
v9fs_get_xattr(FsContext * ctx,const char * path,const char * name,void * value,size_t size)39267ae092SWei Liu ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
40267ae092SWei Liu                        const char *name, void *value, size_t size)
41267ae092SWei Liu {
42267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
43267ae092SWei Liu     if (xops) {
44267ae092SWei Liu         return xops->getxattr(ctx, path, name, value, size);
45267ae092SWei Liu     }
46267ae092SWei Liu     errno = EOPNOTSUPP;
47267ae092SWei Liu     return -1;
48267ae092SWei Liu }
49267ae092SWei Liu 
pt_listxattr(FsContext * ctx,const char * path,char * name,void * value,size_t size)50267ae092SWei Liu ssize_t pt_listxattr(FsContext *ctx, const char *path,
51267ae092SWei Liu                      char *name, void *value, size_t size)
52267ae092SWei Liu {
53267ae092SWei Liu     int name_size = strlen(name) + 1;
54267ae092SWei Liu     if (!value) {
55267ae092SWei Liu         return name_size;
56267ae092SWei Liu     }
57267ae092SWei Liu 
58267ae092SWei Liu     if (size < name_size) {
59267ae092SWei Liu         errno = ERANGE;
60267ae092SWei Liu         return -1;
61267ae092SWei Liu     }
62267ae092SWei Liu 
63267ae092SWei Liu     /* no need for strncpy: name_size is strlen(name)+1 */
64267ae092SWei Liu     memcpy(value, name, name_size);
65267ae092SWei Liu     return name_size;
66267ae092SWei Liu }
67267ae092SWei Liu 
68267ae092SWei Liu /*
69267ae092SWei Liu  * Get the list and pass to each layer to find out whether
70267ae092SWei Liu  * to send the data or not
71267ae092SWei Liu  */
v9fs_list_xattr(FsContext * ctx,const char * path,void * value,size_t vsize)72267ae092SWei Liu ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
73267ae092SWei Liu                         void *value, size_t vsize)
74267ae092SWei Liu {
75267ae092SWei Liu     ssize_t size = 0;
76267ae092SWei Liu     void *ovalue = value;
77267ae092SWei Liu     XattrOperations *xops;
78267ae092SWei Liu     char *orig_value, *orig_value_start;
79267ae092SWei Liu     ssize_t xattr_len, parsed_len = 0, attr_len;
805507904eSGreg Kurz     char *dirpath, *name;
815507904eSGreg Kurz     int dirfd;
82267ae092SWei Liu 
83267ae092SWei Liu     /* Get the actual len */
845507904eSGreg Kurz     dirpath = g_path_get_dirname(path);
855507904eSGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
865507904eSGreg Kurz     g_free(dirpath);
875507904eSGreg Kurz     if (dirfd == -1) {
885507904eSGreg Kurz         return -1;
895507904eSGreg Kurz     }
905507904eSGreg Kurz 
915507904eSGreg Kurz     name = g_path_get_basename(path);
925507904eSGreg Kurz     xattr_len = flistxattrat_nofollow(dirfd, name, value, 0);
93267ae092SWei Liu     if (xattr_len <= 0) {
945507904eSGreg Kurz         g_free(name);
955507904eSGreg Kurz         close_preserve_errno(dirfd);
96267ae092SWei Liu         return xattr_len;
97267ae092SWei Liu     }
98267ae092SWei Liu 
99267ae092SWei Liu     /* Now fetch the xattr and find the actual size */
100267ae092SWei Liu     orig_value = g_malloc(xattr_len);
1015507904eSGreg Kurz     xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len);
1025507904eSGreg Kurz     g_free(name);
1035507904eSGreg Kurz     close_preserve_errno(dirfd);
1045507904eSGreg Kurz     if (xattr_len < 0) {
1054ffcdef4SLi Qiang         g_free(orig_value);
1065507904eSGreg Kurz         return -1;
1075507904eSGreg Kurz     }
108267ae092SWei Liu 
109267ae092SWei Liu     /* store the orig pointer */
110267ae092SWei Liu     orig_value_start = orig_value;
111267ae092SWei Liu     while (xattr_len > parsed_len) {
112267ae092SWei Liu         xops = get_xattr_operations(ctx->xops, orig_value);
113267ae092SWei Liu         if (!xops) {
114267ae092SWei Liu             goto next_entry;
115267ae092SWei Liu         }
116267ae092SWei Liu 
117267ae092SWei Liu         if (!value) {
118267ae092SWei Liu             size += xops->listxattr(ctx, path, orig_value, value, vsize);
119267ae092SWei Liu         } else {
120267ae092SWei Liu             size = xops->listxattr(ctx, path, orig_value, value, vsize);
121267ae092SWei Liu             if (size < 0) {
122267ae092SWei Liu                 goto err_out;
123267ae092SWei Liu             }
124267ae092SWei Liu             value += size;
125267ae092SWei Liu             vsize -= size;
126267ae092SWei Liu         }
127267ae092SWei Liu next_entry:
128267ae092SWei Liu         /* Got the next entry */
129267ae092SWei Liu         attr_len = strlen(orig_value) + 1;
130267ae092SWei Liu         parsed_len += attr_len;
131267ae092SWei Liu         orig_value += attr_len;
132267ae092SWei Liu     }
133267ae092SWei Liu     if (value) {
134267ae092SWei Liu         size = value - ovalue;
135267ae092SWei Liu     }
136267ae092SWei Liu 
137267ae092SWei Liu err_out:
138267ae092SWei Liu     g_free(orig_value_start);
139267ae092SWei Liu     return size;
140267ae092SWei Liu }
141267ae092SWei Liu 
v9fs_set_xattr(FsContext * ctx,const char * path,const char * name,void * value,size_t size,int flags)142267ae092SWei Liu int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
143267ae092SWei Liu                    void *value, size_t size, int flags)
144267ae092SWei Liu {
145267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
146267ae092SWei Liu     if (xops) {
147267ae092SWei Liu         return xops->setxattr(ctx, path, name, value, size, flags);
148267ae092SWei Liu     }
149267ae092SWei Liu     errno = EOPNOTSUPP;
150267ae092SWei Liu     return -1;
151267ae092SWei Liu 
152267ae092SWei Liu }
153267ae092SWei Liu 
v9fs_remove_xattr(FsContext * ctx,const char * path,const char * name)154267ae092SWei Liu int v9fs_remove_xattr(FsContext *ctx,
155267ae092SWei Liu                       const char *path, const char *name)
156267ae092SWei Liu {
157267ae092SWei Liu     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
158267ae092SWei Liu     if (xops) {
159267ae092SWei Liu         return xops->removexattr(ctx, path, name);
160267ae092SWei Liu     }
161267ae092SWei Liu     errno = EOPNOTSUPP;
162267ae092SWei Liu     return -1;
163267ae092SWei Liu 
164267ae092SWei Liu }
165267ae092SWei Liu 
local_getxattr_nofollow(FsContext * ctx,const char * path,const char * name,void * value,size_t size)16656ad3e54SGreg Kurz ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
16756ad3e54SGreg Kurz                                 const char *name, void *value, size_t size)
16856ad3e54SGreg Kurz {
16956ad3e54SGreg Kurz     char *dirpath = g_path_get_dirname(path);
17056ad3e54SGreg Kurz     char *filename = g_path_get_basename(path);
17156ad3e54SGreg Kurz     int dirfd;
17256ad3e54SGreg Kurz     ssize_t ret = -1;
17356ad3e54SGreg Kurz 
17456ad3e54SGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
17556ad3e54SGreg Kurz     if (dirfd == -1) {
17656ad3e54SGreg Kurz         goto out;
17756ad3e54SGreg Kurz     }
17856ad3e54SGreg Kurz 
17956ad3e54SGreg Kurz     ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
18056ad3e54SGreg Kurz     close_preserve_errno(dirfd);
18156ad3e54SGreg Kurz out:
18256ad3e54SGreg Kurz     g_free(dirpath);
18356ad3e54SGreg Kurz     g_free(filename);
18456ad3e54SGreg Kurz     return ret;
18556ad3e54SGreg Kurz }
18656ad3e54SGreg Kurz 
pt_getxattr(FsContext * ctx,const char * path,const char * name,void * value,size_t size)18756fc494bSGreg Kurz ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
18856fc494bSGreg Kurz                     void *value, size_t size)
18956fc494bSGreg Kurz {
19056ad3e54SGreg Kurz     return local_getxattr_nofollow(ctx, path, name, value, size);
19156fc494bSGreg Kurz }
19256fc494bSGreg Kurz 
local_setxattr_nofollow(FsContext * ctx,const char * path,const char * name,void * value,size_t size,int flags)1933e36aba7SGreg Kurz ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
1943e36aba7SGreg Kurz                                 const char *name, void *value, size_t size,
1953e36aba7SGreg Kurz                                 int flags)
1963e36aba7SGreg Kurz {
1973e36aba7SGreg Kurz     char *dirpath = g_path_get_dirname(path);
1983e36aba7SGreg Kurz     char *filename = g_path_get_basename(path);
1993e36aba7SGreg Kurz     int dirfd;
2003e36aba7SGreg Kurz     ssize_t ret = -1;
2013e36aba7SGreg Kurz 
2023e36aba7SGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
2033e36aba7SGreg Kurz     if (dirfd == -1) {
2043e36aba7SGreg Kurz         goto out;
2053e36aba7SGreg Kurz     }
2063e36aba7SGreg Kurz 
2073e36aba7SGreg Kurz     ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags);
2083e36aba7SGreg Kurz     close_preserve_errno(dirfd);
2093e36aba7SGreg Kurz out:
2103e36aba7SGreg Kurz     g_free(dirpath);
2113e36aba7SGreg Kurz     g_free(filename);
2123e36aba7SGreg Kurz     return ret;
2133e36aba7SGreg Kurz }
2143e36aba7SGreg Kurz 
pt_setxattr(FsContext * ctx,const char * path,const char * name,void * value,size_t size,int flags)21556fc494bSGreg Kurz int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
21656fc494bSGreg Kurz                 size_t size, int flags)
21756fc494bSGreg Kurz {
2183e36aba7SGreg Kurz     return local_setxattr_nofollow(ctx, path, name, value, size, flags);
21956fc494bSGreg Kurz }
22056fc494bSGreg Kurz 
local_removexattr_nofollow(FsContext * ctx,const char * path,const char * name)22172f0d0bfSGreg Kurz ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
22272f0d0bfSGreg Kurz                                    const char *name)
22372f0d0bfSGreg Kurz {
22472f0d0bfSGreg Kurz     char *dirpath = g_path_get_dirname(path);
22572f0d0bfSGreg Kurz     char *filename = g_path_get_basename(path);
22672f0d0bfSGreg Kurz     int dirfd;
22772f0d0bfSGreg Kurz     ssize_t ret = -1;
22872f0d0bfSGreg Kurz 
22972f0d0bfSGreg Kurz     dirfd = local_opendir_nofollow(ctx, dirpath);
23072f0d0bfSGreg Kurz     if (dirfd == -1) {
23172f0d0bfSGreg Kurz         goto out;
23272f0d0bfSGreg Kurz     }
23372f0d0bfSGreg Kurz 
23472f0d0bfSGreg Kurz     ret = fremovexattrat_nofollow(dirfd, filename, name);
23572f0d0bfSGreg Kurz     close_preserve_errno(dirfd);
23672f0d0bfSGreg Kurz out:
23772f0d0bfSGreg Kurz     g_free(dirpath);
23872f0d0bfSGreg Kurz     g_free(filename);
23972f0d0bfSGreg Kurz     return ret;
24072f0d0bfSGreg Kurz }
24172f0d0bfSGreg Kurz 
pt_removexattr(FsContext * ctx,const char * path,const char * name)24272f0d0bfSGreg Kurz int pt_removexattr(FsContext *ctx, const char *path, const char *name)
24372f0d0bfSGreg Kurz {
24472f0d0bfSGreg Kurz     return local_removexattr_nofollow(ctx, path, name);
24572f0d0bfSGreg Kurz }
24672f0d0bfSGreg Kurz 
notsup_getxattr(FsContext * ctx,const char * path,const char * name,void * value,size_t size)24756fc494bSGreg Kurz ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
24856fc494bSGreg Kurz                         void *value, size_t size)
24956fc494bSGreg Kurz {
25056fc494bSGreg Kurz     errno = ENOTSUP;
25156fc494bSGreg Kurz     return -1;
25256fc494bSGreg Kurz }
25356fc494bSGreg Kurz 
notsup_setxattr(FsContext * ctx,const char * path,const char * name,void * value,size_t size,int flags)25456fc494bSGreg Kurz int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
25556fc494bSGreg Kurz                     void *value, size_t size, int flags)
25656fc494bSGreg Kurz {
25756fc494bSGreg Kurz     errno = ENOTSUP;
25856fc494bSGreg Kurz     return -1;
25956fc494bSGreg Kurz }
26056fc494bSGreg Kurz 
notsup_listxattr(FsContext * ctx,const char * path,char * name,void * value,size_t size)26156fc494bSGreg Kurz ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
26256fc494bSGreg Kurz                          void *value, size_t size)
26356fc494bSGreg Kurz {
26456fc494bSGreg Kurz     return 0;
26556fc494bSGreg Kurz }
26656fc494bSGreg Kurz 
notsup_removexattr(FsContext * ctx,const char * path,const char * name)26756fc494bSGreg Kurz int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
26856fc494bSGreg Kurz {
26956fc494bSGreg Kurz     errno = ENOTSUP;
27056fc494bSGreg Kurz     return -1;
27156fc494bSGreg Kurz }
27256fc494bSGreg Kurz 
273267ae092SWei Liu XattrOperations *mapped_xattr_ops[] = {
274267ae092SWei Liu     &mapped_user_xattr,
275267ae092SWei Liu     &mapped_pacl_xattr,
276267ae092SWei Liu     &mapped_dacl_xattr,
277267ae092SWei Liu     NULL,
278267ae092SWei Liu };
279267ae092SWei Liu 
280267ae092SWei Liu XattrOperations *passthrough_xattr_ops[] = {
281267ae092SWei Liu     &passthrough_user_xattr,
282267ae092SWei Liu     &passthrough_acl_xattr,
283267ae092SWei Liu     NULL,
284267ae092SWei Liu };
285267ae092SWei Liu 
286267ae092SWei Liu /* for .user none model should be same as passthrough */
287267ae092SWei Liu XattrOperations *none_xattr_ops[] = {
288267ae092SWei Liu     &passthrough_user_xattr,
289267ae092SWei Liu     &none_acl_xattr,
290267ae092SWei Liu     NULL,
291267ae092SWei Liu };
292