blob: 3523f948de7d5eb8df5128c23c68f3d55e7c1b35 [file] [log] [blame]
Brian Swetland03ee9472010-08-12 18:01:08 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes300d5642014-07-08 13:53:26 -070017#define LOG_TAG "sdcard"
18
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -040019#include "fuse.h"
Brian Swetlandb14a2c62010-08-12 18:21:12 -070020
Daniel Rosenberg2abee9e2016-04-19 18:33:08 -070021/* FUSE_CANONICAL_PATH is not currently upstreamed */
22#define FUSE_CANONICAL_PATH 2016
23
Jeff Sharkey20ca9832016-04-07 11:05:21 -060024#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
25#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
26
Brian Swetland03ee9472010-08-12 18:01:08 -070027#define FUSE_UNKNOWN_INO 0xffffffff
28
Jeff Brown6249b902012-05-26 14:32:54 -070029/* Pseudo-error constant used to indicate that no fuse status is needed
30 * or that a reply has already been written. */
31#define NO_STATUS 1
32
Jeff Brown6249b902012-05-26 14:32:54 -070033static inline void *id_to_ptr(__u64 nid)
Brian Swetland03ee9472010-08-12 18:01:08 -070034{
Jeff Brown6249b902012-05-26 14:32:54 -070035 return (void *) (uintptr_t) nid;
36}
Brian Swetland03ee9472010-08-12 18:01:08 -070037
Jeff Brown6249b902012-05-26 14:32:54 -070038static inline __u64 ptr_to_id(void *ptr)
39{
40 return (__u64) (uintptr_t) ptr;
41}
Brian Swetland03ee9472010-08-12 18:01:08 -070042
Jeff Brown6249b902012-05-26 14:32:54 -070043static void acquire_node_locked(struct node* node)
44{
45 node->refcount++;
46 TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
47}
48
49static void remove_node_from_parent_locked(struct node* node);
50
51static void release_node_locked(struct node* node)
52{
53 TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
54 if (node->refcount > 0) {
55 node->refcount--;
56 if (!node->refcount) {
57 TRACE("DESTROY %p (%s)\n", node, node->name);
58 remove_node_from_parent_locked(node);
59
60 /* TODO: remove debugging - poison memory */
61 memset(node->name, 0xef, node->namelen);
62 free(node->name);
63 free(node->actual_name);
64 memset(node, 0xfc, sizeof(*node));
65 free(node);
Mike Lockwood575a2bb2011-01-23 14:46:30 -080066 }
Jeff Brown6249b902012-05-26 14:32:54 -070067 } else {
68 ERROR("Zero refcnt %p\n", node);
69 }
70}
71
72static void add_node_to_parent_locked(struct node *node, struct node *parent) {
73 node->parent = parent;
74 node->next = parent->child;
75 parent->child = node;
76 acquire_node_locked(parent);
77}
78
79static void remove_node_from_parent_locked(struct node* node)
80{
81 if (node->parent) {
82 if (node->parent->child == node) {
83 node->parent->child = node->parent->child->next;
84 } else {
85 struct node *node2;
86 node2 = node->parent->child;
87 while (node2->next != node)
88 node2 = node2->next;
89 node2->next = node->next;
90 }
91 release_node_locked(node->parent);
92 node->parent = NULL;
93 node->next = NULL;
94 }
95}
96
97/* Gets the absolute path to a node into the provided buffer.
98 *
99 * Populates 'buf' with the path and returns the length of the path on success,
100 * or returns -1 if the path is too long for the provided buffer.
101 */
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700102static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
103 const char* name;
104 size_t namelen;
105 if (node->graft_path) {
106 name = node->graft_path;
107 namelen = node->graft_pathlen;
108 } else if (node->actual_name) {
109 name = node->actual_name;
110 namelen = node->namelen;
111 } else {
112 name = node->name;
113 namelen = node->namelen;
114 }
115
Jeff Brown6249b902012-05-26 14:32:54 -0700116 if (bufsize < namelen + 1) {
117 return -1;
Brian Swetland03ee9472010-08-12 18:01:08 -0700118 }
119
Jeff Brown6249b902012-05-26 14:32:54 -0700120 ssize_t pathlen = 0;
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700121 if (node->parent && node->graft_path == NULL) {
Daniel Rosenbergdb4638e2016-04-12 16:30:28 -0700122 pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
Jeff Brown6249b902012-05-26 14:32:54 -0700123 if (pathlen < 0) {
124 return -1;
125 }
126 buf[pathlen++] = '/';
127 }
128
Jeff Brown6249b902012-05-26 14:32:54 -0700129 memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
130 return pathlen + namelen;
131}
132
133/* Finds the absolute path of a file within a given directory.
134 * Performs a case-insensitive search for the file and sets the buffer to the path
135 * of the first matching file. If 'search' is zero or if no match is found, sets
136 * the buffer to the path that the file would have, assuming the name were case-sensitive.
137 *
138 * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
139 * or returns NULL if the path is too long for the provided buffer.
140 */
141static char* find_file_within(const char* path, const char* name,
142 char* buf, size_t bufsize, int search)
143{
144 size_t pathlen = strlen(path);
145 size_t namelen = strlen(name);
146 size_t childlen = pathlen + namelen + 1;
147 char* actual;
148
149 if (bufsize <= childlen) {
150 return NULL;
151 }
152
153 memcpy(buf, path, pathlen);
154 buf[pathlen] = '/';
155 actual = buf + pathlen + 1;
156 memcpy(actual, name, namelen + 1);
157
158 if (search && access(buf, F_OK)) {
Mike Lockwood575a2bb2011-01-23 14:46:30 -0800159 struct dirent* entry;
Jeff Brown6249b902012-05-26 14:32:54 -0700160 DIR* dir = opendir(path);
Mike Lockwood575a2bb2011-01-23 14:46:30 -0800161 if (!dir) {
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700162 ERROR("opendir %s failed: %s\n", path, strerror(errno));
Jeff Brown6249b902012-05-26 14:32:54 -0700163 return actual;
Mike Lockwood575a2bb2011-01-23 14:46:30 -0800164 }
Mike Lockwood575a2bb2011-01-23 14:46:30 -0800165 while ((entry = readdir(dir))) {
Jeff Brown6249b902012-05-26 14:32:54 -0700166 if (!strcasecmp(entry->d_name, name)) {
167 /* we have a match - replace the name, don't need to copy the null again */
168 memcpy(actual, entry->d_name, namelen);
Mike Lockwood575a2bb2011-01-23 14:46:30 -0800169 break;
170 }
171 }
172 closedir(dir);
173 }
Jeff Brown6249b902012-05-26 14:32:54 -0700174 return actual;
Mike Lockwood575a2bb2011-01-23 14:46:30 -0800175}
176
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700177static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
178 const struct stat *s, const struct node* node) {
Narayan Kamathfaa09352015-01-13 18:21:10 +0000179 attr->ino = node->ino;
Brian Swetland03ee9472010-08-12 18:01:08 -0700180 attr->size = s->st_size;
181 attr->blocks = s->st_blocks;
Elliott Hughesf1df8542014-11-10 11:03:38 -0800182 attr->atime = s->st_atim.tv_sec;
183 attr->mtime = s->st_mtim.tv_sec;
184 attr->ctime = s->st_ctim.tv_sec;
185 attr->atimensec = s->st_atim.tv_nsec;
186 attr->mtimensec = s->st_mtim.tv_nsec;
187 attr->ctimensec = s->st_ctim.tv_nsec;
Brian Swetland03ee9472010-08-12 18:01:08 -0700188 attr->mode = s->st_mode;
189 attr->nlink = s->st_nlink;
Brian Swetland03ee9472010-08-12 18:01:08 -0700190
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700191 attr->uid = node->uid;
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700192
193 if (fuse->gid == AID_SDCARD_RW) {
194 /* As an optimization, certain trusted system components only run
195 * as owner but operate across all users. Since we're now handing
196 * out the sdcard_rw GID only to trusted apps, we're okay relaxing
197 * the user boundary enforcement for the default view. The UIDs
198 * assigned to app directories are still multiuser aware. */
199 attr->gid = AID_SDCARD_RW;
200 } else {
201 attr->gid = multiuser_get_uid(node->userid, fuse->gid);
202 }
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700203
Jeff Sharkey10a239b2015-07-28 10:49:41 -0700204 int visible_mode = 0775 & ~fuse->mask;
205 if (node->perm == PERM_PRE_ROOT) {
206 /* Top of multi-user view should always be visible to ensure
207 * secondary users can traverse inside. */
208 visible_mode = 0711;
209 } else if (node->under_android) {
210 /* Block "other" access to Android directories, since only apps
211 * belonging to a specific user should be in there; we still
212 * leave +x open for the default view. */
213 if (fuse->gid == AID_SDCARD_RW) {
214 visible_mode = visible_mode & ~0006;
215 } else {
216 visible_mode = visible_mode & ~0007;
217 }
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700218 }
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700219 int owner_mode = s->st_mode & 0700;
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700220 int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700221 attr->mode = (attr->mode & S_IFMT) | filtered_mode;
222}
223
Jeff Sharkey44d63422013-09-12 09:44:48 -0700224static int touch(char* path, mode_t mode) {
225 int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
226 if (fd == -1) {
227 if (errno == EEXIST) {
228 return 0;
229 } else {
230 ERROR("Failed to open(%s): %s\n", path, strerror(errno));
231 return -1;
232 }
233 }
234 close(fd);
235 return 0;
236}
237
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700238static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
239 struct node *node) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700240 appid_t appid;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700241
242 /* By default, each node inherits from its parent */
243 node->perm = PERM_INHERIT;
244 node->userid = parent->userid;
245 node->uid = parent->uid;
Jeff Sharkey10a239b2015-07-28 10:49:41 -0700246 node->under_android = parent->under_android;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700247
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700248 /* Derive custom permissions based on parent and current node */
249 switch (parent->perm) {
250 case PERM_INHERIT:
251 /* Already inherited above */
252 break;
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700253 case PERM_PRE_ROOT:
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700254 /* Legacy internal layout places users at top level */
255 node->perm = PERM_ROOT;
256 node->userid = strtoul(node->name, NULL, 10);
257 break;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700258 case PERM_ROOT:
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700259 /* Assume masked off by default. */
Jeff Sharkey44d63422013-09-12 09:44:48 -0700260 if (!strcasecmp(node->name, "Android")) {
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700261 /* App-specific directories inside; let anyone traverse */
262 node->perm = PERM_ANDROID;
Jeff Sharkey10a239b2015-07-28 10:49:41 -0700263 node->under_android = true;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700264 }
265 break;
266 case PERM_ANDROID:
Jeff Sharkey44d63422013-09-12 09:44:48 -0700267 if (!strcasecmp(node->name, "data")) {
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700268 /* App-specific directories inside; let anyone traverse */
269 node->perm = PERM_ANDROID_DATA;
Jeff Sharkey44d63422013-09-12 09:44:48 -0700270 } else if (!strcasecmp(node->name, "obb")) {
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700271 /* App-specific directories inside; let anyone traverse */
272 node->perm = PERM_ANDROID_OBB;
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700273 /* Single OBB directory is always shared */
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700274 node->graft_path = fuse->global->obb_path;
275 node->graft_pathlen = strlen(fuse->global->obb_path);
Jeff Sharkey2e7d80d2014-05-30 15:38:31 -0700276 } else if (!strcasecmp(node->name, "media")) {
277 /* App-specific directories inside; let anyone traverse */
278 node->perm = PERM_ANDROID_MEDIA;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700279 }
280 break;
281 case PERM_ANDROID_DATA:
282 case PERM_ANDROID_OBB:
Jeff Sharkey2e7d80d2014-05-30 15:38:31 -0700283 case PERM_ANDROID_MEDIA:
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700284 appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700285 if (appid != 0) {
286 node->uid = multiuser_get_uid(parent->userid, appid);
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700287 }
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700288 break;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700289 }
Jeff Sharkeyaa04e812013-08-30 10:26:15 -0700290}
291
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -0400292void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
Jeff Sharkeyfe764612015-12-14 11:02:01 -0700293 struct node *node;
294 for (node = parent->child; node; node = node->next) {
295 derive_permissions_locked(fuse, parent, node);
296 if (node->child) {
297 derive_permissions_recursive_locked(fuse, node);
298 }
299 }
300}
301
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700302/* Kernel has already enforced everything we returned through
303 * derive_permissions_locked(), so this is used to lock down access
304 * even further, such as enforcing that apps hold sdcard_rw. */
305static bool check_caller_access_to_name(struct fuse* fuse,
306 const struct fuse_in_header *hdr, const struct node* parent_node,
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700307 const char* name, int mode) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700308 /* Always block security-sensitive files at root */
309 if (parent_node && parent_node->perm == PERM_ROOT) {
Jeff Sharkey44d63422013-09-12 09:44:48 -0700310 if (!strcasecmp(name, "autorun.inf")
311 || !strcasecmp(name, ".android_secure")
312 || !strcasecmp(name, "android_secure")) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700313 return false;
314 }
315 }
316
Jeff Sharkey44d63422013-09-12 09:44:48 -0700317 /* Root always has access; access for any other UIDs should always
318 * be controlled through packages.list. */
319 if (hdr->uid == 0) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700320 return true;
321 }
322
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700323 /* No extra permissions to enforce */
324 return true;
325}
326
327static bool check_caller_access_to_node(struct fuse* fuse,
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700328 const struct fuse_in_header *hdr, const struct node* node, int mode) {
329 return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700330}
331
Jeff Brown6249b902012-05-26 14:32:54 -0700332struct node *create_node_locked(struct fuse* fuse,
333 struct node *parent, const char *name, const char* actual_name)
Brian Swetland03ee9472010-08-12 18:01:08 -0700334{
335 struct node *node;
Jeff Brown6249b902012-05-26 14:32:54 -0700336 size_t namelen = strlen(name);
Brian Swetland03ee9472010-08-12 18:01:08 -0700337
Narayan Kamathfaa09352015-01-13 18:21:10 +0000338 // Detect overflows in the inode counter. "4 billion nodes should be enough
339 // for everybody".
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700340 if (fuse->global->inode_ctr == 0) {
Narayan Kamathfaa09352015-01-13 18:21:10 +0000341 ERROR("No more inode numbers available");
342 return NULL;
343 }
344
Paul Eastham11ccdb32010-10-14 11:04:26 -0700345 node = calloc(1, sizeof(struct node));
Jeff Brown6249b902012-05-26 14:32:54 -0700346 if (!node) {
347 return NULL;
Brian Swetland03ee9472010-08-12 18:01:08 -0700348 }
Paul Eastham11ccdb32010-10-14 11:04:26 -0700349 node->name = malloc(namelen + 1);
Jeff Brown6249b902012-05-26 14:32:54 -0700350 if (!node->name) {
Paul Eastham11ccdb32010-10-14 11:04:26 -0700351 free(node);
Jeff Brown6249b902012-05-26 14:32:54 -0700352 return NULL;
Paul Eastham11ccdb32010-10-14 11:04:26 -0700353 }
Brian Swetland03ee9472010-08-12 18:01:08 -0700354 memcpy(node->name, name, namelen + 1);
Jeff Brown6249b902012-05-26 14:32:54 -0700355 if (strcmp(name, actual_name)) {
356 node->actual_name = malloc(namelen + 1);
357 if (!node->actual_name) {
358 free(node->name);
359 free(node);
360 return NULL;
361 }
362 memcpy(node->actual_name, actual_name, namelen + 1);
363 }
Brian Swetland03ee9472010-08-12 18:01:08 -0700364 node->namelen = namelen;
Jeff Brown6249b902012-05-26 14:32:54 -0700365 node->nid = ptr_to_id(node);
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700366 node->ino = fuse->global->inode_ctr++;
367 node->gen = fuse->global->next_generation++;
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700368
Krzysztof Adamskic5353122014-07-16 08:34:30 +0200369 node->deleted = false;
370
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700371 derive_permissions_locked(fuse, parent, node);
Jeff Brown6249b902012-05-26 14:32:54 -0700372 acquire_node_locked(node);
373 add_node_to_parent_locked(node, parent);
Brian Swetland03ee9472010-08-12 18:01:08 -0700374 return node;
375}
376
Jeff Brown6249b902012-05-26 14:32:54 -0700377static int rename_node_locked(struct node *node, const char *name,
378 const char* actual_name)
Paul Eastham11ccdb32010-10-14 11:04:26 -0700379{
Jeff Brown6249b902012-05-26 14:32:54 -0700380 size_t namelen = strlen(name);
381 int need_actual_name = strcmp(name, actual_name);
382
383 /* make the storage bigger without actually changing the name
384 * in case an error occurs part way */
385 if (namelen > node->namelen) {
386 char* new_name = realloc(node->name, namelen + 1);
387 if (!new_name) {
388 return -ENOMEM;
389 }
390 node->name = new_name;
391 if (need_actual_name && node->actual_name) {
392 char* new_actual_name = realloc(node->actual_name, namelen + 1);
393 if (!new_actual_name) {
394 return -ENOMEM;
395 }
396 node->actual_name = new_actual_name;
397 }
398 }
399
400 /* update the name, taking care to allocate storage before overwriting the old name */
401 if (need_actual_name) {
402 if (!node->actual_name) {
403 node->actual_name = malloc(namelen + 1);
404 if (!node->actual_name) {
405 return -ENOMEM;
406 }
407 }
408 memcpy(node->actual_name, actual_name, namelen + 1);
409 } else {
410 free(node->actual_name);
411 node->actual_name = NULL;
412 }
413 memcpy(node->name, name, namelen + 1);
414 node->namelen = namelen;
415 return 0;
Paul Eastham11ccdb32010-10-14 11:04:26 -0700416}
417
Jeff Brown6249b902012-05-26 14:32:54 -0700418static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
Brian Swetland03ee9472010-08-12 18:01:08 -0700419{
Jeff Brown6249b902012-05-26 14:32:54 -0700420 if (nid == FUSE_ROOT_ID) {
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700421 return &fuse->global->root;
Brian Swetland03ee9472010-08-12 18:01:08 -0700422 } else {
423 return id_to_ptr(nid);
424 }
425}
426
Jeff Brown6249b902012-05-26 14:32:54 -0700427static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
428 char* buf, size_t bufsize)
429{
430 struct node* node = lookup_node_by_id_locked(fuse, nid);
431 if (node && get_node_path_locked(node, buf, bufsize) < 0) {
432 node = NULL;
433 }
434 return node;
435}
436
437static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
Brian Swetland03ee9472010-08-12 18:01:08 -0700438{
439 for (node = node->child; node; node = node->next) {
Jeff Brown6249b902012-05-26 14:32:54 -0700440 /* use exact string comparison, nodes that differ by case
441 * must be considered distinct even if they refer to the same
442 * underlying file as otherwise operations such as "mv x x"
443 * will not work because the source and target nodes are the same. */
Krzysztof Adamskic5353122014-07-16 08:34:30 +0200444 if (!strcmp(name, node->name) && !node->deleted) {
Brian Swetland03ee9472010-08-12 18:01:08 -0700445 return node;
446 }
447 }
448 return 0;
449}
450
Jeff Brown6249b902012-05-26 14:32:54 -0700451static struct node* acquire_or_create_child_locked(
452 struct fuse* fuse, struct node* parent,
453 const char* name, const char* actual_name)
Brian Swetland03ee9472010-08-12 18:01:08 -0700454{
Jeff Brown6249b902012-05-26 14:32:54 -0700455 struct node* child = lookup_child_by_name_locked(parent, name);
456 if (child) {
457 acquire_node_locked(child);
Paul Eastham77085c52011-01-04 21:06:03 -0800458 } else {
Jeff Brown6249b902012-05-26 14:32:54 -0700459 child = create_node_locked(fuse, parent, name, actual_name);
Paul Eastham77085c52011-01-04 21:06:03 -0800460 }
Jeff Brown6249b902012-05-26 14:32:54 -0700461 return child;
Paul Eastham11ccdb32010-10-14 11:04:26 -0700462}
463
Jeff Brown6249b902012-05-26 14:32:54 -0700464static void fuse_status(struct fuse *fuse, __u64 unique, int err)
Brian Swetland03ee9472010-08-12 18:01:08 -0700465{
466 struct fuse_out_header hdr;
467 hdr.len = sizeof(hdr);
468 hdr.error = err;
469 hdr.unique = unique;
Brian Swetland03ee9472010-08-12 18:01:08 -0700470 write(fuse->fd, &hdr, sizeof(hdr));
471}
472
Jeff Brown6249b902012-05-26 14:32:54 -0700473static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
Brian Swetland03ee9472010-08-12 18:01:08 -0700474{
475 struct fuse_out_header hdr;
476 struct iovec vec[2];
477 int res;
478
479 hdr.len = len + sizeof(hdr);
480 hdr.error = 0;
481 hdr.unique = unique;
482
483 vec[0].iov_base = &hdr;
484 vec[0].iov_len = sizeof(hdr);
485 vec[1].iov_base = data;
486 vec[1].iov_len = len;
487
488 res = writev(fuse->fd, vec, 2);
489 if (res < 0) {
490 ERROR("*** REPLY FAILED *** %d\n", errno);
491 }
492}
493
Jeff Brown6249b902012-05-26 14:32:54 -0700494static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
495 struct node* parent, const char* name, const char* actual_name,
496 const char* path)
Brian Swetland03ee9472010-08-12 18:01:08 -0700497{
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700498 struct node* node;
Jeff Brown6249b902012-05-26 14:32:54 -0700499 struct fuse_entry_out out;
500 struct stat s;
Brian Swetland03ee9472010-08-12 18:01:08 -0700501
Jeff Brown6249b902012-05-26 14:32:54 -0700502 if (lstat(path, &s) < 0) {
Jeff Sharkey44d63422013-09-12 09:44:48 -0700503 return -errno;
Brian Swetland03ee9472010-08-12 18:01:08 -0700504 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700505
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700506 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700507 node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
508 if (!node) {
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700509 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700510 return -ENOMEM;
511 }
512 memset(&out, 0, sizeof(out));
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700513 attr_from_stat(fuse, &out.attr, &s, node);
Jeff Brown6249b902012-05-26 14:32:54 -0700514 out.attr_valid = 10;
515 out.entry_valid = 10;
Brian Swetland03ee9472010-08-12 18:01:08 -0700516 out.nodeid = node->nid;
517 out.generation = node->gen;
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700518 pthread_mutex_unlock(&fuse->global->lock);
Brian Swetland03ee9472010-08-12 18:01:08 -0700519 fuse_reply(fuse, unique, &out, sizeof(out));
Jeff Brown6249b902012-05-26 14:32:54 -0700520 return NO_STATUS;
Brian Swetland03ee9472010-08-12 18:01:08 -0700521}
522
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700523static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
Jeff Brown6249b902012-05-26 14:32:54 -0700524 const char* path)
525{
526 struct fuse_attr_out out;
527 struct stat s;
528
529 if (lstat(path, &s) < 0) {
530 return -errno;
531 }
532 memset(&out, 0, sizeof(out));
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700533 attr_from_stat(fuse, &out.attr, &s, node);
Jeff Brown6249b902012-05-26 14:32:54 -0700534 out.attr_valid = 10;
535 fuse_reply(fuse, unique, &out, sizeof(out));
536 return NO_STATUS;
537}
538
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700539static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
540 const __u64 child, const char* name) {
541 struct fuse_out_header hdr;
542 struct fuse_notify_delete_out data;
543 struct iovec vec[3];
544 size_t namelen = strlen(name);
545 int res;
546
547 hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
548 hdr.error = FUSE_NOTIFY_DELETE;
549 hdr.unique = 0;
550
551 data.parent = parent;
552 data.child = child;
553 data.namelen = namelen;
554 data.padding = 0;
555
556 vec[0].iov_base = &hdr;
557 vec[0].iov_len = sizeof(hdr);
558 vec[1].iov_base = &data;
559 vec[1].iov_len = sizeof(data);
560 vec[2].iov_base = (void*) name;
561 vec[2].iov_len = namelen + 1;
562
563 res = writev(fuse->fd, vec, 3);
564 /* Ignore ENOENT, since other views may not have seen the entry */
565 if (res < 0 && errno != ENOENT) {
566 ERROR("*** NOTIFY FAILED *** %d\n", errno);
567 }
568}
569
Jeff Brown6249b902012-05-26 14:32:54 -0700570static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700571 const struct fuse_in_header *hdr, const char* name)
Brian Swetland03ee9472010-08-12 18:01:08 -0700572{
Jeff Brown6249b902012-05-26 14:32:54 -0700573 struct node* parent_node;
574 char parent_path[PATH_MAX];
575 char child_path[PATH_MAX];
576 const char* actual_name;
Brian Swetland03ee9472010-08-12 18:01:08 -0700577
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700578 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700579 parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
580 parent_path, sizeof(parent_path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100581 TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
Jeff Brown6249b902012-05-26 14:32:54 -0700582 parent_node ? parent_node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700583 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700584
585 if (!parent_node || !(actual_name = find_file_within(parent_path, name,
586 child_path, sizeof(child_path), 1))) {
587 return -ENOENT;
Brian Swetland03ee9472010-08-12 18:01:08 -0700588 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700589 if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700590 return -EACCES;
591 }
592
Jeff Brown6249b902012-05-26 14:32:54 -0700593 return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700594}
595
Jeff Brown6249b902012-05-26 14:32:54 -0700596static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700597 const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
598{
Jeff Brown6249b902012-05-26 14:32:54 -0700599 struct node* node;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700600
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700601 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700602 node = lookup_node_by_id_locked(fuse, hdr->nodeid);
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100603 TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
Jeff Brown6249b902012-05-26 14:32:54 -0700604 hdr->nodeid, node ? node->name : "?");
605 if (node) {
606 __u64 n = req->nlookup;
Daniel Micaydf9c4a02016-04-26 11:42:08 -0400607 while (n) {
608 n--;
Jeff Brown6249b902012-05-26 14:32:54 -0700609 release_node_locked(node);
610 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700611 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700612 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700613 return NO_STATUS; /* no reply */
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700614}
615
Jeff Brown6249b902012-05-26 14:32:54 -0700616static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700617 const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
618{
Jeff Brown6249b902012-05-26 14:32:54 -0700619 struct node* node;
620 char path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700621
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700622 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700623 node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100624 TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700625 req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700626 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700627
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700628 if (!node) {
Jeff Brown6249b902012-05-26 14:32:54 -0700629 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700630 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700631 if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700632 return -EACCES;
633 }
634
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700635 return fuse_reply_attr(fuse, hdr->unique, node, path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700636}
637
Jeff Brown6249b902012-05-26 14:32:54 -0700638static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700639 const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
640{
Jeff Brown6249b902012-05-26 14:32:54 -0700641 struct node* node;
642 char path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700643 struct timespec times[2];
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700644
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700645 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700646 node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100647 TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700648 req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700649 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700650
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700651 if (!node) {
Jeff Brown6249b902012-05-26 14:32:54 -0700652 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700653 }
Marco Nelissena80f0982014-12-10 10:44:20 -0800654
655 if (!(req->valid & FATTR_FH) &&
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700656 !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700657 return -EACCES;
658 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700659
Jeff Brown6249b902012-05-26 14:32:54 -0700660 /* XXX: incomplete implementation on purpose.
661 * chmod/chown should NEVER be implemented.*/
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700662
Elliott Hughes853574d2014-07-31 12:03:03 -0700663 if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
Jeff Brown6249b902012-05-26 14:32:54 -0700664 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700665 }
666
667 /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW
668 * are both set, then set it to the current time. Else, set it to the
669 * time specified in the request. Same goes for mtime. Use utimensat(2)
670 * as it allows ATIME and MTIME to be changed independently, and has
671 * nanosecond resolution which fuse also has.
672 */
673 if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
674 times[0].tv_nsec = UTIME_OMIT;
675 times[1].tv_nsec = UTIME_OMIT;
676 if (req->valid & FATTR_ATIME) {
677 if (req->valid & FATTR_ATIME_NOW) {
678 times[0].tv_nsec = UTIME_NOW;
679 } else {
680 times[0].tv_sec = req->atime;
681 times[0].tv_nsec = req->atimensec;
682 }
683 }
684 if (req->valid & FATTR_MTIME) {
685 if (req->valid & FATTR_MTIME_NOW) {
686 times[1].tv_nsec = UTIME_NOW;
687 } else {
688 times[1].tv_sec = req->mtime;
689 times[1].tv_nsec = req->mtimensec;
690 }
691 }
Jeff Brown6249b902012-05-26 14:32:54 -0700692 TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
693 handler->token, path, times[0].tv_sec, times[1].tv_sec);
694 if (utimensat(-1, path, times, 0) < 0) {
695 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700696 }
697 }
Jeff Sharkeydfe0cba2013-07-03 17:08:29 -0700698 return fuse_reply_attr(fuse, hdr->unique, node, path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700699}
700
Jeff Brown6249b902012-05-26 14:32:54 -0700701static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700702 const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
703{
Jeff Brown6249b902012-05-26 14:32:54 -0700704 struct node* parent_node;
705 char parent_path[PATH_MAX];
706 char child_path[PATH_MAX];
707 const char* actual_name;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700708
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700709 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700710 parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
711 parent_path, sizeof(parent_path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100712 TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700713 name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700714 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700715
716 if (!parent_node || !(actual_name = find_file_within(parent_path, name,
717 child_path, sizeof(child_path), 1))) {
718 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700719 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700720 if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700721 return -EACCES;
722 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700723 __u32 mode = (req->mode & (~0777)) | 0664;
Jeff Brown6249b902012-05-26 14:32:54 -0700724 if (mknod(child_path, mode, req->rdev) < 0) {
725 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700726 }
Jeff Brown6249b902012-05-26 14:32:54 -0700727 return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700728}
729
Jeff Brown6249b902012-05-26 14:32:54 -0700730static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700731 const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
732{
Jeff Brown6249b902012-05-26 14:32:54 -0700733 struct node* parent_node;
734 char parent_path[PATH_MAX];
735 char child_path[PATH_MAX];
736 const char* actual_name;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700737
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700738 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700739 parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
740 parent_path, sizeof(parent_path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100741 TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700742 name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700743 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700744
745 if (!parent_node || !(actual_name = find_file_within(parent_path, name,
746 child_path, sizeof(child_path), 1))) {
747 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700748 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700749 if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700750 return -EACCES;
751 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700752 __u32 mode = (req->mode & (~0777)) | 0775;
Jeff Brown6249b902012-05-26 14:32:54 -0700753 if (mkdir(child_path, mode) < 0) {
754 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700755 }
Jeff Sharkey44d63422013-09-12 09:44:48 -0700756
757 /* When creating /Android/data and /Android/obb, mark them as .nomedia */
758 if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
759 char nomedia[PATH_MAX];
760 snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
761 if (touch(nomedia, 0664) != 0) {
762 ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
763 return -ENOENT;
764 }
765 }
766 if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
767 char nomedia[PATH_MAX];
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700768 snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
Jeff Sharkey44d63422013-09-12 09:44:48 -0700769 if (touch(nomedia, 0664) != 0) {
770 ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
771 return -ENOENT;
772 }
773 }
774
Jeff Brown6249b902012-05-26 14:32:54 -0700775 return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700776}
777
Jeff Brown6249b902012-05-26 14:32:54 -0700778static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700779 const struct fuse_in_header* hdr, const char* name)
780{
Jeff Brown6249b902012-05-26 14:32:54 -0700781 struct node* parent_node;
Krzysztof Adamskic5353122014-07-16 08:34:30 +0200782 struct node* child_node;
Jeff Brown6249b902012-05-26 14:32:54 -0700783 char parent_path[PATH_MAX];
784 char child_path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700785
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700786 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700787 parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
788 parent_path, sizeof(parent_path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100789 TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700790 name, hdr->nodeid, parent_node ? parent_node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700791 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700792
793 if (!parent_node || !find_file_within(parent_path, name,
794 child_path, sizeof(child_path), 1)) {
795 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700796 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700797 if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700798 return -EACCES;
799 }
Jeff Brown6249b902012-05-26 14:32:54 -0700800 if (unlink(child_path) < 0) {
801 return -errno;
802 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700803 pthread_mutex_lock(&fuse->global->lock);
Krzysztof Adamskic5353122014-07-16 08:34:30 +0200804 child_node = lookup_child_by_name_locked(parent_node, name);
805 if (child_node) {
806 child_node->deleted = true;
807 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700808 pthread_mutex_unlock(&fuse->global->lock);
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700809 if (parent_node && child_node) {
810 /* Tell all other views that node is gone */
811 TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
812 handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
813 if (fuse != fuse->global->fuse_default) {
814 fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
815 }
816 if (fuse != fuse->global->fuse_read) {
817 fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
818 }
819 if (fuse != fuse->global->fuse_write) {
820 fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
821 }
822 }
Jeff Brown6249b902012-05-26 14:32:54 -0700823 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700824}
825
Jeff Brown6249b902012-05-26 14:32:54 -0700826static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700827 const struct fuse_in_header* hdr, const char* name)
828{
Krzysztof Adamskic5353122014-07-16 08:34:30 +0200829 struct node* child_node;
Jeff Brown6249b902012-05-26 14:32:54 -0700830 struct node* parent_node;
831 char parent_path[PATH_MAX];
832 char child_path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700833
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700834 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700835 parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
836 parent_path, sizeof(parent_path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100837 TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700838 name, hdr->nodeid, parent_node ? parent_node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700839 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700840
841 if (!parent_node || !find_file_within(parent_path, name,
842 child_path, sizeof(child_path), 1)) {
843 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700844 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700845 if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700846 return -EACCES;
847 }
Jeff Brown6249b902012-05-26 14:32:54 -0700848 if (rmdir(child_path) < 0) {
849 return -errno;
850 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700851 pthread_mutex_lock(&fuse->global->lock);
Krzysztof Adamskic5353122014-07-16 08:34:30 +0200852 child_node = lookup_child_by_name_locked(parent_node, name);
853 if (child_node) {
854 child_node->deleted = true;
855 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700856 pthread_mutex_unlock(&fuse->global->lock);
Jeff Sharkeyed2fe572015-07-16 09:13:52 -0700857 if (parent_node && child_node) {
858 /* Tell all other views that node is gone */
859 TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
860 handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
861 if (fuse != fuse->global->fuse_default) {
862 fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
863 }
864 if (fuse != fuse->global->fuse_read) {
865 fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
866 }
867 if (fuse != fuse->global->fuse_write) {
868 fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
869 }
870 }
Jeff Brown6249b902012-05-26 14:32:54 -0700871 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700872}
873
Jeff Brown6249b902012-05-26 14:32:54 -0700874static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700875 const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
Jeff Brown6249b902012-05-26 14:32:54 -0700876 const char* old_name, const char* new_name)
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700877{
Jeff Brown6249b902012-05-26 14:32:54 -0700878 struct node* old_parent_node;
879 struct node* new_parent_node;
880 struct node* child_node;
881 char old_parent_path[PATH_MAX];
882 char new_parent_path[PATH_MAX];
883 char old_child_path[PATH_MAX];
884 char new_child_path[PATH_MAX];
885 const char* new_actual_name;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700886 int res;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700887
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700888 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700889 old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
890 old_parent_path, sizeof(old_parent_path));
891 new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
892 new_parent_path, sizeof(new_parent_path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100893 TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700894 old_name, new_name,
895 hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
896 req->newdir, new_parent_node ? new_parent_node->name : "?");
897 if (!old_parent_node || !new_parent_node) {
898 res = -ENOENT;
899 goto lookup_error;
900 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700901 if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700902 res = -EACCES;
903 goto lookup_error;
904 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700905 if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700906 res = -EACCES;
907 goto lookup_error;
908 }
Jeff Brown6249b902012-05-26 14:32:54 -0700909 child_node = lookup_child_by_name_locked(old_parent_node, old_name);
910 if (!child_node || get_node_path_locked(child_node,
911 old_child_path, sizeof(old_child_path)) < 0) {
912 res = -ENOENT;
913 goto lookup_error;
914 }
915 acquire_node_locked(child_node);
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700916 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700917
918 /* Special case for renaming a file where destination is same path
919 * differing only by case. In this case we don't want to look for a case
920 * insensitive match. This allows commands like "mv foo FOO" to work as expected.
921 */
922 int search = old_parent_node != new_parent_node
923 || strcasecmp(old_name, new_name);
924 if (!(new_actual_name = find_file_within(new_parent_path, new_name,
925 new_child_path, sizeof(new_child_path), search))) {
926 res = -ENOENT;
927 goto io_error;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700928 }
929
Jeff Brown6249b902012-05-26 14:32:54 -0700930 TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
931 res = rename(old_child_path, new_child_path);
932 if (res < 0) {
933 res = -errno;
934 goto io_error;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700935 }
936
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700937 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700938 res = rename_node_locked(child_node, new_name, new_actual_name);
939 if (!res) {
940 remove_node_from_parent_locked(child_node);
Jeff Sharkeyfe764612015-12-14 11:02:01 -0700941 derive_permissions_locked(fuse, new_parent_node, child_node);
942 derive_permissions_recursive_locked(fuse, child_node);
Jeff Brown6249b902012-05-26 14:32:54 -0700943 add_node_to_parent_locked(child_node, new_parent_node);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700944 }
Jeff Brown6249b902012-05-26 14:32:54 -0700945 goto done;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700946
Jeff Brown6249b902012-05-26 14:32:54 -0700947io_error:
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700948 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700949done:
950 release_node_locked(child_node);
951lookup_error:
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700952 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700953 return res;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700954}
955
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700956static int open_flags_to_access_mode(int open_flags) {
957 if ((open_flags & O_ACCMODE) == O_RDONLY) {
958 return R_OK;
959 } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
960 return W_OK;
961 } else {
962 /* Probably O_RDRW, but treat as default to be safe */
963 return R_OK | W_OK;
964 }
965}
966
Jeff Brown6249b902012-05-26 14:32:54 -0700967static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700968 const struct fuse_in_header* hdr, const struct fuse_open_in* req)
969{
Jeff Brown6249b902012-05-26 14:32:54 -0700970 struct node* node;
971 char path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700972 struct fuse_open_out out;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700973 struct handle *h;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700974
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700975 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700976 node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +0100977 TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -0700978 req->flags, hdr->nodeid, node ? node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700979 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -0700980
981 if (!node) {
982 return -ENOENT;
983 }
Jeff Sharkeyaa04e812013-08-30 10:26:15 -0700984 if (!check_caller_access_to_node(fuse, hdr, node,
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -0700985 open_flags_to_access_mode(req->flags))) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -0700986 return -EACCES;
987 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700988 h = malloc(sizeof(*h));
989 if (!h) {
Jeff Brown6249b902012-05-26 14:32:54 -0700990 return -ENOMEM;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700991 }
Jeff Brown6249b902012-05-26 14:32:54 -0700992 TRACE("[%d] OPEN %s\n", handler->token, path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700993 h->fd = open(path, req->flags);
994 if (h->fd < 0) {
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700995 free(h);
Jeff Brown6249b902012-05-26 14:32:54 -0700996 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -0700997 }
998 out.fh = ptr_to_id(h);
999 out.open_flags = 0;
1000 out.padding = 0;
1001 fuse_reply(fuse, hdr->unique, &out, sizeof(out));
Jeff Brown6249b902012-05-26 14:32:54 -07001002 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001003}
1004
Jeff Brown6249b902012-05-26 14:32:54 -07001005static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001006 const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1007{
1008 struct handle *h = id_to_ptr(req->fh);
1009 __u64 unique = hdr->unique;
1010 __u32 size = req->size;
1011 __u64 offset = req->offset;
Jeff Brown6249b902012-05-26 14:32:54 -07001012 int res;
Elliott Hughese24e9a52015-07-28 16:36:47 -07001013 __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
Jeff Brown6249b902012-05-26 14:32:54 -07001014
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001015 /* Don't access any other fields of hdr or req beyond this point, the read buffer
1016 * overlaps the request buffer and will clobber data in the request. This
1017 * saves us 128KB per request handler thread at the cost of this scary comment. */
Jeff Brown6249b902012-05-26 14:32:54 -07001018
Marcus Oaklande43b99a2014-07-23 13:04:59 +01001019 TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
1020 h, h->fd, size, (uint64_t) offset);
Arpad Horvath80b435a2014-02-14 16:42:27 -08001021 if (size > MAX_READ) {
Jeff Brown6249b902012-05-26 14:32:54 -07001022 return -EINVAL;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001023 }
Arpad Horvath80b435a2014-02-14 16:42:27 -08001024 res = pread64(h->fd, read_buffer, size, offset);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001025 if (res < 0) {
Jeff Brown6249b902012-05-26 14:32:54 -07001026 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001027 }
Arpad Horvath80b435a2014-02-14 16:42:27 -08001028 fuse_reply(fuse, unique, read_buffer, res);
Jeff Brown6249b902012-05-26 14:32:54 -07001029 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001030}
1031
Jeff Brown6249b902012-05-26 14:32:54 -07001032static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001033 const struct fuse_in_header* hdr, const struct fuse_write_in* req,
1034 const void* buffer)
1035{
1036 struct fuse_write_out out;
1037 struct handle *h = id_to_ptr(req->fh);
1038 int res;
Elliott Hughese24e9a52015-07-28 16:36:47 -07001039 __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
Elliott Hughes60281d52014-05-07 14:39:58 -07001040
Arpad Horvath49e93442014-02-18 10:18:25 +01001041 if (req->flags & O_DIRECT) {
1042 memcpy(aligned_buffer, buffer, req->size);
1043 buffer = (const __u8*) aligned_buffer;
1044 }
Jeff Brown6249b902012-05-26 14:32:54 -07001045
Marcus Oaklande43b99a2014-07-23 13:04:59 +01001046 TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -07001047 h, h->fd, req->size, req->offset);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001048 res = pwrite64(h->fd, buffer, req->size, req->offset);
1049 if (res < 0) {
Jeff Brown6249b902012-05-26 14:32:54 -07001050 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001051 }
1052 out.size = res;
Daisuke Okitsu19ec8862013-08-05 12:18:15 +09001053 out.padding = 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001054 fuse_reply(fuse, hdr->unique, &out, sizeof(out));
Jeff Brown6249b902012-05-26 14:32:54 -07001055 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001056}
1057
Jeff Brown6249b902012-05-26 14:32:54 -07001058static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001059 const struct fuse_in_header* hdr)
1060{
Jeff Brown6249b902012-05-26 14:32:54 -07001061 char path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001062 struct statfs stat;
1063 struct fuse_statfs_out out;
1064 int res;
1065
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -07001066 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -07001067 TRACE("[%d] STATFS\n", handler->token);
Jeff Sharkeyed2fe572015-07-16 09:13:52 -07001068 res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -07001069 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -07001070 if (res < 0) {
1071 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001072 }
Jeff Sharkeyed2fe572015-07-16 09:13:52 -07001073 if (statfs(fuse->global->root.name, &stat) < 0) {
Jeff Brown6249b902012-05-26 14:32:54 -07001074 return -errno;
1075 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001076 memset(&out, 0, sizeof(out));
1077 out.st.blocks = stat.f_blocks;
1078 out.st.bfree = stat.f_bfree;
1079 out.st.bavail = stat.f_bavail;
1080 out.st.files = stat.f_files;
1081 out.st.ffree = stat.f_ffree;
1082 out.st.bsize = stat.f_bsize;
1083 out.st.namelen = stat.f_namelen;
1084 out.st.frsize = stat.f_frsize;
1085 fuse_reply(fuse, hdr->unique, &out, sizeof(out));
Jeff Brown6249b902012-05-26 14:32:54 -07001086 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001087}
1088
Jeff Brown6249b902012-05-26 14:32:54 -07001089static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001090 const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1091{
1092 struct handle *h = id_to_ptr(req->fh);
Jeff Brown6249b902012-05-26 14:32:54 -07001093
1094 TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001095 close(h->fd);
1096 free(h);
Jeff Brown6249b902012-05-26 14:32:54 -07001097 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001098}
1099
Jeff Brown6249b902012-05-26 14:32:54 -07001100static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001101 const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
1102{
Elliott Hughesf6d67372014-07-08 14:38:26 -07001103 bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
1104 bool is_data_sync = req->fsync_flags & 1;
Jeff Brown6249b902012-05-26 14:32:54 -07001105
Elliott Hughesf6d67372014-07-08 14:38:26 -07001106 int fd = -1;
1107 if (is_dir) {
1108 struct dirhandle *dh = id_to_ptr(req->fh);
1109 fd = dirfd(dh->d);
1110 } else {
1111 struct handle *h = id_to_ptr(req->fh);
1112 fd = h->fd;
1113 }
1114
1115 TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
1116 is_dir ? "FSYNCDIR" : "FSYNC",
1117 id_to_ptr(req->fh), fd, is_data_sync);
1118 int res = is_data_sync ? fdatasync(fd) : fsync(fd);
1119 if (res == -1) {
Jeff Brown6249b902012-05-26 14:32:54 -07001120 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001121 }
Jeff Brown6249b902012-05-26 14:32:54 -07001122 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001123}
1124
Jeff Brown6249b902012-05-26 14:32:54 -07001125static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001126 const struct fuse_in_header* hdr)
1127{
Jeff Brown6249b902012-05-26 14:32:54 -07001128 TRACE("[%d] FLUSH\n", handler->token);
1129 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001130}
1131
Jeff Brown6249b902012-05-26 14:32:54 -07001132static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001133 const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1134{
Jeff Brown6249b902012-05-26 14:32:54 -07001135 struct node* node;
1136 char path[PATH_MAX];
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001137 struct fuse_open_out out;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001138 struct dirhandle *h;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001139
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -07001140 pthread_mutex_lock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -07001141 node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
Marcus Oaklande43b99a2014-07-23 13:04:59 +01001142 TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
Jeff Brown6249b902012-05-26 14:32:54 -07001143 hdr->nodeid, node ? node->name : "?");
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -07001144 pthread_mutex_unlock(&fuse->global->lock);
Jeff Brown6249b902012-05-26 14:32:54 -07001145
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001146 if (!node) {
Jeff Brown6249b902012-05-26 14:32:54 -07001147 return -ENOENT;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001148 }
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -07001149 if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
Jeff Sharkey977a9f32013-08-12 20:23:49 -07001150 return -EACCES;
1151 }
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001152 h = malloc(sizeof(*h));
1153 if (!h) {
Jeff Brown6249b902012-05-26 14:32:54 -07001154 return -ENOMEM;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001155 }
Jeff Brown6249b902012-05-26 14:32:54 -07001156 TRACE("[%d] OPENDIR %s\n", handler->token, path);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001157 h->d = opendir(path);
Jeff Brown6249b902012-05-26 14:32:54 -07001158 if (!h->d) {
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001159 free(h);
Jeff Brown6249b902012-05-26 14:32:54 -07001160 return -errno;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001161 }
1162 out.fh = ptr_to_id(h);
Ken Sumrall3a876882013-08-14 20:02:13 -07001163 out.open_flags = 0;
1164 out.padding = 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001165 fuse_reply(fuse, hdr->unique, &out, sizeof(out));
Jeff Brown6249b902012-05-26 14:32:54 -07001166 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001167}
1168
Jeff Brown6249b902012-05-26 14:32:54 -07001169static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001170 const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1171{
1172 char buffer[8192];
1173 struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
1174 struct dirent *de;
1175 struct dirhandle *h = id_to_ptr(req->fh);
Jeff Brown6249b902012-05-26 14:32:54 -07001176
1177 TRACE("[%d] READDIR %p\n", handler->token, h);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001178 if (req->offset == 0) {
1179 /* rewinddir() might have been called above us, so rewind here too */
Jeff Brown6249b902012-05-26 14:32:54 -07001180 TRACE("[%d] calling rewinddir()\n", handler->token);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001181 rewinddir(h->d);
1182 }
1183 de = readdir(h->d);
1184 if (!de) {
Jeff Brown6249b902012-05-26 14:32:54 -07001185 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001186 }
1187 fde->ino = FUSE_UNKNOWN_INO;
1188 /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1189 fde->off = req->offset + 1;
1190 fde->type = de->d_type;
1191 fde->namelen = strlen(de->d_name);
1192 memcpy(fde->name, de->d_name, fde->namelen + 1);
1193 fuse_reply(fuse, hdr->unique, fde,
Jeff Brown6249b902012-05-26 14:32:54 -07001194 FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
1195 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001196}
1197
Jeff Brown6249b902012-05-26 14:32:54 -07001198static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001199 const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1200{
1201 struct dirhandle *h = id_to_ptr(req->fh);
Jeff Brown6249b902012-05-26 14:32:54 -07001202
1203 TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001204 closedir(h->d);
1205 free(h);
Jeff Brown6249b902012-05-26 14:32:54 -07001206 return 0;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001207}
1208
Jeff Brown6249b902012-05-26 14:32:54 -07001209static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001210 const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1211{
1212 struct fuse_init_out out;
Christopher Ferrisff649ea2014-09-13 13:53:08 -07001213 size_t fuse_struct_size;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001214
Jeff Brown6249b902012-05-26 14:32:54 -07001215 TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
1216 handler->token, req->major, req->minor, req->max_readahead, req->flags);
Christopher Ferrisff649ea2014-09-13 13:53:08 -07001217
1218 /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
1219 * defined (fuse version 7.6). The structure is the same from 7.6 through
1220 * 7.22. Beginning with 7.23, the structure increased in size and added
1221 * new parameters.
1222 */
1223 if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
1224 ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
1225 req->major, req->minor, FUSE_KERNEL_VERSION);
1226 return -1;
1227 }
1228
Jeff Sharkeyf38f29c2015-06-23 14:30:37 -07001229 /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
1230 out.minor = MIN(req->minor, 15);
Christopher Ferrisff649ea2014-09-13 13:53:08 -07001231 fuse_struct_size = sizeof(out);
1232#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
1233 /* FUSE_KERNEL_VERSION >= 23. */
1234
1235 /* If the kernel only works on minor revs older than or equal to 22,
1236 * then use the older structure size since this code only uses the 7.22
1237 * version of the structure. */
1238 if (req->minor <= 22) {
1239 fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
1240 }
1241#endif
1242
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001243 out.major = FUSE_KERNEL_VERSION;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001244 out.max_readahead = req->max_readahead;
1245 out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1246 out.max_background = 32;
1247 out.congestion_threshold = 32;
1248 out.max_write = MAX_WRITE;
Christopher Ferrisff649ea2014-09-13 13:53:08 -07001249 fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
Jeff Brown6249b902012-05-26 14:32:54 -07001250 return NO_STATUS;
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001251}
1252
Daniel Rosenberg2abee9e2016-04-19 18:33:08 -07001253static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
1254 const struct fuse_in_header *hdr)
1255{
1256 struct node* node;
1257 char path[PATH_MAX];
1258 int len;
1259
1260 pthread_mutex_lock(&fuse->global->lock);
1261 node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
1262 path, sizeof(path));
1263 TRACE("[%d] CANONICAL_PATH @ %" PRIx64 " (%s)\n", handler->token, hdr->nodeid,
1264 node ? node->name : "?");
1265 pthread_mutex_unlock(&fuse->global->lock);
1266
1267 if (!node) {
1268 return -ENOENT;
1269 }
1270 if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
1271 return -EACCES;
1272 }
1273 len = strlen(path);
1274 if (len + 1 > PATH_MAX)
1275 len = PATH_MAX - 1;
1276 path[PATH_MAX - 1] = 0;
1277 fuse_reply(fuse, hdr->unique, path, len + 1);
1278 return NO_STATUS;
1279}
1280
1281
Jeff Brown6249b902012-05-26 14:32:54 -07001282static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001283 const struct fuse_in_header *hdr, const void *data, size_t data_len)
1284{
Brian Swetland03ee9472010-08-12 18:01:08 -07001285 switch (hdr->opcode) {
1286 case FUSE_LOOKUP: { /* bytez[] -> entry_out */
Jeff Brown84715842012-05-25 14:07:47 -07001287 const char* name = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001288 return handle_lookup(fuse, handler, hdr, name);
Brian Swetland03ee9472010-08-12 18:01:08 -07001289 }
Jeff Brown84715842012-05-25 14:07:47 -07001290
Brian Swetland03ee9472010-08-12 18:01:08 -07001291 case FUSE_FORGET: {
Jeff Brown84715842012-05-25 14:07:47 -07001292 const struct fuse_forget_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001293 return handle_forget(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001294 }
Jeff Brown84715842012-05-25 14:07:47 -07001295
Brian Swetland03ee9472010-08-12 18:01:08 -07001296 case FUSE_GETATTR: { /* getattr_in -> attr_out */
Jeff Brown84715842012-05-25 14:07:47 -07001297 const struct fuse_getattr_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001298 return handle_getattr(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001299 }
Jeff Brown84715842012-05-25 14:07:47 -07001300
Brian Swetland03ee9472010-08-12 18:01:08 -07001301 case FUSE_SETATTR: { /* setattr_in -> attr_out */
Jeff Brown84715842012-05-25 14:07:47 -07001302 const struct fuse_setattr_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001303 return handle_setattr(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001304 }
Jeff Brown84715842012-05-25 14:07:47 -07001305
Brian Swetland03ee9472010-08-12 18:01:08 -07001306// case FUSE_READLINK:
1307// case FUSE_SYMLINK:
1308 case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
Jeff Brown84715842012-05-25 14:07:47 -07001309 const struct fuse_mknod_in *req = data;
1310 const char *name = ((const char*) data) + sizeof(*req);
Jeff Brown6249b902012-05-26 14:32:54 -07001311 return handle_mknod(fuse, handler, hdr, req, name);
Brian Swetland03ee9472010-08-12 18:01:08 -07001312 }
Jeff Brown84715842012-05-25 14:07:47 -07001313
Brian Swetland03ee9472010-08-12 18:01:08 -07001314 case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
Jeff Brown84715842012-05-25 14:07:47 -07001315 const struct fuse_mkdir_in *req = data;
1316 const char *name = ((const char*) data) + sizeof(*req);
Jeff Brown6249b902012-05-26 14:32:54 -07001317 return handle_mkdir(fuse, handler, hdr, req, name);
Brian Swetland03ee9472010-08-12 18:01:08 -07001318 }
Jeff Brown84715842012-05-25 14:07:47 -07001319
Brian Swetland03ee9472010-08-12 18:01:08 -07001320 case FUSE_UNLINK: { /* bytez[] -> */
Jeff Brown84715842012-05-25 14:07:47 -07001321 const char* name = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001322 return handle_unlink(fuse, handler, hdr, name);
Brian Swetland03ee9472010-08-12 18:01:08 -07001323 }
Jeff Brown84715842012-05-25 14:07:47 -07001324
Brian Swetland03ee9472010-08-12 18:01:08 -07001325 case FUSE_RMDIR: { /* bytez[] -> */
Jeff Brown84715842012-05-25 14:07:47 -07001326 const char* name = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001327 return handle_rmdir(fuse, handler, hdr, name);
Brian Swetland03ee9472010-08-12 18:01:08 -07001328 }
Jeff Brown84715842012-05-25 14:07:47 -07001329
Brian Swetland03ee9472010-08-12 18:01:08 -07001330 case FUSE_RENAME: { /* rename_in, oldname, newname -> */
Jeff Brown84715842012-05-25 14:07:47 -07001331 const struct fuse_rename_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001332 const char *old_name = ((const char*) data) + sizeof(*req);
1333 const char *new_name = old_name + strlen(old_name) + 1;
1334 return handle_rename(fuse, handler, hdr, req, old_name, new_name);
Brian Swetland03ee9472010-08-12 18:01:08 -07001335 }
Jeff Brown84715842012-05-25 14:07:47 -07001336
Jeff Brownfc1e1a02012-05-25 17:24:17 -07001337// case FUSE_LINK:
Brian Swetland03ee9472010-08-12 18:01:08 -07001338 case FUSE_OPEN: { /* open_in -> open_out */
Jeff Brown84715842012-05-25 14:07:47 -07001339 const struct fuse_open_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001340 return handle_open(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001341 }
Jeff Brown84715842012-05-25 14:07:47 -07001342
Brian Swetland03ee9472010-08-12 18:01:08 -07001343 case FUSE_READ: { /* read_in -> byte[] */
Jeff Brown84715842012-05-25 14:07:47 -07001344 const struct fuse_read_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001345 return handle_read(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001346 }
Jeff Brown84715842012-05-25 14:07:47 -07001347
Brian Swetland03ee9472010-08-12 18:01:08 -07001348 case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
Jeff Brown84715842012-05-25 14:07:47 -07001349 const struct fuse_write_in *req = data;
1350 const void* buffer = (const __u8*)data + sizeof(*req);
Jeff Brown6249b902012-05-26 14:32:54 -07001351 return handle_write(fuse, handler, hdr, req, buffer);
Brian Swetland03ee9472010-08-12 18:01:08 -07001352 }
Jeff Brown84715842012-05-25 14:07:47 -07001353
Mike Lockwood4553b082010-08-16 14:14:44 -04001354 case FUSE_STATFS: { /* getattr_in -> attr_out */
Jeff Brown6249b902012-05-26 14:32:54 -07001355 return handle_statfs(fuse, handler, hdr);
Mike Lockwood4553b082010-08-16 14:14:44 -04001356 }
Jeff Brown84715842012-05-25 14:07:47 -07001357
Brian Swetland03ee9472010-08-12 18:01:08 -07001358 case FUSE_RELEASE: { /* release_in -> */
Jeff Brown84715842012-05-25 14:07:47 -07001359 const struct fuse_release_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001360 return handle_release(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001361 }
Jeff Brown84715842012-05-25 14:07:47 -07001362
Daisuke Okitsub2831a22014-02-17 10:33:11 +01001363 case FUSE_FSYNC:
1364 case FUSE_FSYNCDIR: {
Jeff Brown6fd921a2012-05-25 15:01:21 -07001365 const struct fuse_fsync_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001366 return handle_fsync(fuse, handler, hdr, req);
Jeff Brown6fd921a2012-05-25 15:01:21 -07001367 }
1368
Brian Swetland03ee9472010-08-12 18:01:08 -07001369// case FUSE_SETXATTR:
1370// case FUSE_GETXATTR:
1371// case FUSE_LISTXATTR:
1372// case FUSE_REMOVEXATTR:
Jeff Brown84715842012-05-25 14:07:47 -07001373 case FUSE_FLUSH: {
Jeff Brown6249b902012-05-26 14:32:54 -07001374 return handle_flush(fuse, handler, hdr);
Jeff Brown84715842012-05-25 14:07:47 -07001375 }
1376
Brian Swetland03ee9472010-08-12 18:01:08 -07001377 case FUSE_OPENDIR: { /* open_in -> open_out */
Jeff Brown84715842012-05-25 14:07:47 -07001378 const struct fuse_open_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001379 return handle_opendir(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001380 }
Jeff Brown84715842012-05-25 14:07:47 -07001381
Brian Swetland03ee9472010-08-12 18:01:08 -07001382 case FUSE_READDIR: {
Jeff Brown84715842012-05-25 14:07:47 -07001383 const struct fuse_read_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001384 return handle_readdir(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001385 }
Jeff Brown84715842012-05-25 14:07:47 -07001386
Brian Swetland03ee9472010-08-12 18:01:08 -07001387 case FUSE_RELEASEDIR: { /* release_in -> */
Jeff Brown84715842012-05-25 14:07:47 -07001388 const struct fuse_release_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001389 return handle_releasedir(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001390 }
Jeff Brown84715842012-05-25 14:07:47 -07001391
Brian Swetland03ee9472010-08-12 18:01:08 -07001392 case FUSE_INIT: { /* init_in -> init_out */
Jeff Brown84715842012-05-25 14:07:47 -07001393 const struct fuse_init_in *req = data;
Jeff Brown6249b902012-05-26 14:32:54 -07001394 return handle_init(fuse, handler, hdr, req);
Brian Swetland03ee9472010-08-12 18:01:08 -07001395 }
Jeff Brown84715842012-05-25 14:07:47 -07001396
Daniel Rosenberg2abee9e2016-04-19 18:33:08 -07001397 case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
1398 return handle_canonical_path(fuse, handler, hdr);
1399 }
1400
Brian Swetland03ee9472010-08-12 18:01:08 -07001401 default: {
Marcus Oaklande43b99a2014-07-23 13:04:59 +01001402 TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
Jeff Brown6249b902012-05-26 14:32:54 -07001403 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
1404 return -ENOSYS;
Brian Swetland03ee9472010-08-12 18:01:08 -07001405 }
Jeff Brown84715842012-05-25 14:07:47 -07001406 }
Brian Swetland03ee9472010-08-12 18:01:08 -07001407}
1408
Jorge Lucangeli Obesc255f252016-07-12 15:13:05 -04001409void handle_fuse_requests(struct fuse_handler* handler)
Brian Swetland03ee9472010-08-12 18:01:08 -07001410{
Jeff Brown6249b902012-05-26 14:32:54 -07001411 struct fuse* fuse = handler->fuse;
Brian Swetland03ee9472010-08-12 18:01:08 -07001412 for (;;) {
Mark Salyzyn6b6c1bd2015-07-06 10:00:36 -07001413 ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
1414 handler->request_buffer, sizeof(handler->request_buffer)));
Brian Swetland03ee9472010-08-12 18:01:08 -07001415 if (len < 0) {
Jeff Sharkey4a485812015-06-30 16:02:40 -07001416 if (errno == ENODEV) {
1417 ERROR("[%d] someone stole our marbles!\n", handler->token);
1418 exit(2);
1419 }
Mark Salyzyn6b6c1bd2015-07-06 10:00:36 -07001420 ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
Jeff Brown6249b902012-05-26 14:32:54 -07001421 continue;
Brian Swetland03ee9472010-08-12 18:01:08 -07001422 }
Jeff Brown84715842012-05-25 14:07:47 -07001423
1424 if ((size_t)len < sizeof(struct fuse_in_header)) {
Jeff Brown6249b902012-05-26 14:32:54 -07001425 ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
1426 continue;
Jeff Brown84715842012-05-25 14:07:47 -07001427 }
1428
Jeff Brown7729d242012-05-25 15:35:28 -07001429 const struct fuse_in_header *hdr = (void*)handler->request_buffer;
Jeff Brown84715842012-05-25 14:07:47 -07001430 if (hdr->len != (size_t)len) {
Jeff Brown6249b902012-05-26 14:32:54 -07001431 ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
1432 handler->token, (size_t)len, hdr->len);
1433 continue;
Jeff Brown84715842012-05-25 14:07:47 -07001434 }
1435
Jeff Brown7729d242012-05-25 15:35:28 -07001436 const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
Jeff Brown84715842012-05-25 14:07:47 -07001437 size_t data_len = len - sizeof(struct fuse_in_header);
Jeff Brown6249b902012-05-26 14:32:54 -07001438 __u64 unique = hdr->unique;
1439 int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
Jeff Brown7729d242012-05-25 15:35:28 -07001440
1441 /* We do not access the request again after this point because the underlying
1442 * buffer storage may have been reused while processing the request. */
Jeff Brown6249b902012-05-26 14:32:54 -07001443
1444 if (res != NO_STATUS) {
1445 if (res) {
1446 TRACE("[%d] ERROR %d\n", handler->token, res);
1447 }
1448 fuse_status(fuse, unique, res);
1449 }
Brian Swetland03ee9472010-08-12 18:01:08 -07001450 }
1451}