1 /*
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 
17 #include <errno.h>
18 #include <string.h>
19 #include <unistd.h>
20 
21 #define LOG_TAG "sdcard"
22 
23 #include "fuse.h"
24 
25 #include <android-base/logging.h>
26 
27 /* FUSE_CANONICAL_PATH is not currently upstreamed */
28 #define FUSE_CANONICAL_PATH 2016
29 
30 #define FUSE_UNKNOWN_INO 0xffffffff
31 
32 /* Pseudo-error constant used to indicate that no fuse status is needed
33  * or that a reply has already been written. */
34 #define NO_STATUS 1
35 
id_to_ptr(__u64 nid)36 static inline void *id_to_ptr(__u64 nid)
37 {
38     return (void *) (uintptr_t) nid;
39 }
40 
ptr_to_id(void * ptr)41 static inline __u64 ptr_to_id(void *ptr)
42 {
43     return (__u64) (uintptr_t) ptr;
44 }
45 
acquire_node_locked(struct node * node)46 static void acquire_node_locked(struct node* node)
47 {
48     node->refcount++;
49     DLOG(INFO) << "ACQUIRE " << std::hex << node << std::dec
50                << " (" << node->name << ") rc=" << node->refcount;
51 }
52 
53 static void remove_node_from_parent_locked(struct node* node);
54 
release_node_locked(struct node * node)55 static void release_node_locked(struct node* node)
56 {
57     DLOG(INFO) << "RELEASE " << std::hex << node << std::dec
58                << " (" << node->name << ") rc=" << node->refcount;
59     if (node->refcount > 0) {
60         node->refcount--;
61         if (!node->refcount) {
62             DLOG(INFO) << "DESTROY " << std::hex << node << std::dec << " (" << node->name << ")";
63             remove_node_from_parent_locked(node);
64 
65             /* TODO: remove debugging - poison memory */
66             memset(node->name, 0xef, node->namelen);
67             free(node->name);
68             free(node->actual_name);
69             memset(node, 0xfc, sizeof(*node));
70             free(node);
71         }
72     } else {
73         LOG(ERROR) << std::hex << node << std::dec << " refcount=0";
74     }
75 }
76 
add_node_to_parent_locked(struct node * node,struct node * parent)77 static void add_node_to_parent_locked(struct node *node, struct node *parent) {
78     node->parent = parent;
79     node->next = parent->child;
80     parent->child = node;
81     acquire_node_locked(parent);
82 }
83 
remove_node_from_parent_locked(struct node * node)84 static void remove_node_from_parent_locked(struct node* node)
85 {
86     if (node->parent) {
87         if (node->parent->child == node) {
88             node->parent->child = node->parent->child->next;
89         } else {
90             struct node *node2;
91             node2 = node->parent->child;
92             while (node2->next != node)
93                 node2 = node2->next;
94             node2->next = node->next;
95         }
96         release_node_locked(node->parent);
97         node->parent = NULL;
98         node->next = NULL;
99     }
100 }
101 
102 /* Gets the absolute path to a node into the provided buffer.
103  *
104  * Populates 'buf' with the path and returns the length of the path on success,
105  * or returns -1 if the path is too long for the provided buffer.
106  */
get_node_path_locked(struct node * node,char * buf,size_t bufsize)107 static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
108     const char* name;
109     size_t namelen;
110     if (node->graft_path) {
111         name = node->graft_path;
112         namelen = node->graft_pathlen;
113     } else if (node->actual_name) {
114         name = node->actual_name;
115         namelen = node->namelen;
116     } else {
117         name = node->name;
118         namelen = node->namelen;
119     }
120 
121     if (bufsize < namelen + 1) {
122         return -1;
123     }
124 
125     ssize_t pathlen = 0;
126     if (node->parent && node->graft_path == NULL) {
127         pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
128         if (pathlen < 0) {
129             return -1;
130         }
131         buf[pathlen++] = '/';
132     }
133 
134     memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
135     return pathlen + namelen;
136 }
137 
138 /* Finds the absolute path of a file within a given directory.
139  * Performs a case-insensitive search for the file and sets the buffer to the path
140  * of the first matching file.  If 'search' is zero or if no match is found, sets
141  * the buffer to the path that the file would have, assuming the name were case-sensitive.
142  *
143  * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
144  * or returns NULL if the path is too long for the provided buffer.
145  */
find_file_within(const char * path,const char * name,char * buf,size_t bufsize,int search)146 static char* find_file_within(const char* path, const char* name,
147         char* buf, size_t bufsize, int search)
148 {
149     size_t pathlen = strlen(path);
150     size_t namelen = strlen(name);
151     size_t childlen = pathlen + namelen + 1;
152     char* actual;
153 
154     if (bufsize <= childlen) {
155         return NULL;
156     }
157 
158     memcpy(buf, path, pathlen);
159     buf[pathlen] = '/';
160     actual = buf + pathlen + 1;
161     memcpy(actual, name, namelen + 1);
162 
163     if (search && access(buf, F_OK)) {
164         struct dirent* entry;
165         DIR* dir = opendir(path);
166         if (!dir) {
167             PLOG(ERROR) << "opendir(" << path << ") failed";
168             return actual;
169         }
170         while ((entry = readdir(dir))) {
171             if (!strcasecmp(entry->d_name, name)) {
172                 /* we have a match - replace the name, don't need to copy the null again */
173                 memcpy(actual, entry->d_name, namelen);
174                 break;
175             }
176         }
177         closedir(dir);
178     }
179     return actual;
180 }
181 
attr_from_stat(struct fuse * fuse,struct fuse_attr * attr,const struct stat * s,const struct node * node)182 static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
183         const struct stat *s, const struct node* node) {
184     attr->ino = node->ino;
185     attr->size = s->st_size;
186     attr->blocks = s->st_blocks;
187     attr->atime = s->st_atim.tv_sec;
188     attr->mtime = s->st_mtim.tv_sec;
189     attr->ctime = s->st_ctim.tv_sec;
190     attr->atimensec = s->st_atim.tv_nsec;
191     attr->mtimensec = s->st_mtim.tv_nsec;
192     attr->ctimensec = s->st_ctim.tv_nsec;
193     attr->mode = s->st_mode;
194     attr->nlink = s->st_nlink;
195 
196     attr->uid = node->uid;
197 
198     if (fuse->gid == AID_SDCARD_RW) {
199         /* As an optimization, certain trusted system components only run
200          * as owner but operate across all users. Since we're now handing
201          * out the sdcard_rw GID only to trusted apps, we're okay relaxing
202          * the user boundary enforcement for the default view. The UIDs
203          * assigned to app directories are still multiuser aware. */
204         attr->gid = AID_SDCARD_RW;
205     } else {
206         attr->gid = multiuser_get_uid(node->userid, fuse->gid);
207     }
208 
209     int visible_mode = 0775 & ~fuse->mask;
210     if (node->perm == PERM_PRE_ROOT) {
211         /* Top of multi-user view should always be visible to ensure
212          * secondary users can traverse inside. */
213         visible_mode = 0711;
214     } else if (node->under_android) {
215         /* Block "other" access to Android directories, since only apps
216          * belonging to a specific user should be in there; we still
217          * leave +x open for the default view. */
218         if (fuse->gid == AID_SDCARD_RW) {
219             visible_mode = visible_mode & ~0006;
220         } else {
221             visible_mode = visible_mode & ~0007;
222         }
223     }
224     int owner_mode = s->st_mode & 0700;
225     int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
226     attr->mode = (attr->mode & S_IFMT) | filtered_mode;
227 }
228 
touch(char * path,mode_t mode)229 static int touch(char* path, mode_t mode) {
230     int fd = TEMP_FAILURE_RETRY(open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC,
231                                      mode));
232     if (fd == -1) {
233         if (errno == EEXIST) {
234             return 0;
235         } else {
236             PLOG(ERROR) << "open(" << path << ") failed";
237             return -1;
238         }
239     }
240     close(fd);
241     return 0;
242 }
243 
derive_permissions_locked(struct fuse * fuse,struct node * parent,struct node * node)244 static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
245         struct node *node) {
246     appid_t appid;
247 
248     /* By default, each node inherits from its parent */
249     node->perm = PERM_INHERIT;
250     node->userid = parent->userid;
251     node->uid = parent->uid;
252     node->under_android = parent->under_android;
253 
254     /* Derive custom permissions based on parent and current node */
255     switch (parent->perm) {
256     case PERM_INHERIT:
257         /* Already inherited above */
258         break;
259     case PERM_PRE_ROOT:
260         /* Legacy internal layout places users at top level */
261         node->perm = PERM_ROOT;
262         node->userid = strtoul(node->name, NULL, 10);
263         break;
264     case PERM_ROOT:
265         /* Assume masked off by default. */
266         if (!strcasecmp(node->name, "Android")) {
267             /* App-specific directories inside; let anyone traverse */
268             node->perm = PERM_ANDROID;
269             node->under_android = true;
270         }
271         break;
272     case PERM_ANDROID:
273         if (!strcasecmp(node->name, "data")) {
274             /* App-specific directories inside; let anyone traverse */
275             node->perm = PERM_ANDROID_DATA;
276         } else if (!strcasecmp(node->name, "obb")) {
277             /* App-specific directories inside; let anyone traverse */
278             node->perm = PERM_ANDROID_OBB;
279             /* Single OBB directory is always shared */
280             node->graft_path = fuse->global->obb_path;
281             node->graft_pathlen = strlen(fuse->global->obb_path);
282         } else if (!strcasecmp(node->name, "media")) {
283             /* App-specific directories inside; let anyone traverse */
284             node->perm = PERM_ANDROID_MEDIA;
285         }
286         break;
287     case PERM_ANDROID_DATA:
288     case PERM_ANDROID_OBB:
289     case PERM_ANDROID_MEDIA:
290         const auto& iter = fuse->global->package_to_appid->find(node->name);
291         if (iter != fuse->global->package_to_appid->end()) {
292             appid = iter->second;
293             node->uid = multiuser_get_uid(parent->userid, appid);
294         }
295         break;
296     }
297 }
298 
derive_permissions_recursive_locked(struct fuse * fuse,struct node * parent)299 void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
300     struct node *node;
301     for (node = parent->child; node; node = node->next) {
302         derive_permissions_locked(fuse, parent, node);
303         if (node->child) {
304             derive_permissions_recursive_locked(fuse, node);
305         }
306     }
307 }
308 
309 /* Kernel has already enforced everything we returned through
310  * derive_permissions_locked(), so this is used to lock down access
311  * even further, such as enforcing that apps hold sdcard_rw. */
check_caller_access_to_name(struct fuse * fuse,const struct fuse_in_header * hdr,const struct node * parent_node,const char * name,int mode)312 static bool check_caller_access_to_name(struct fuse* fuse,
313         const struct fuse_in_header *hdr, const struct node* parent_node,
314         const char* name, int mode) {
315     /* Always block security-sensitive files at root */
316     if (parent_node && parent_node->perm == PERM_ROOT) {
317         if (!strcasecmp(name, "autorun.inf")
318                 || !strcasecmp(name, ".android_secure")
319                 || !strcasecmp(name, "android_secure")) {
320             return false;
321         }
322     }
323 
324     /* Root always has access; access for any other UIDs should always
325      * be controlled through packages.list. */
326     if (hdr->uid == 0) {
327         return true;
328     }
329 
330     /* No extra permissions to enforce */
331     return true;
332 }
333 
check_caller_access_to_node(struct fuse * fuse,const struct fuse_in_header * hdr,const struct node * node,int mode)334 static bool check_caller_access_to_node(struct fuse* fuse,
335         const struct fuse_in_header *hdr, const struct node* node, int mode) {
336     return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
337 }
338 
create_node_locked(struct fuse * fuse,struct node * parent,const char * name,const char * actual_name)339 struct node *create_node_locked(struct fuse* fuse,
340         struct node *parent, const char *name, const char* actual_name)
341 {
342     struct node *node;
343     size_t namelen = strlen(name);
344 
345     // Detect overflows in the inode counter. "4 billion nodes should be enough
346     // for everybody".
347     if (fuse->global->inode_ctr == 0) {
348         LOG(ERROR) << "No more inode numbers available";
349         return NULL;
350     }
351 
352     node = static_cast<struct node*>(calloc(1, sizeof(struct node)));
353     if (!node) {
354         return NULL;
355     }
356     node->name = static_cast<char*>(malloc(namelen + 1));
357     if (!node->name) {
358         free(node);
359         return NULL;
360     }
361     memcpy(node->name, name, namelen + 1);
362     if (strcmp(name, actual_name)) {
363         node->actual_name = static_cast<char*>(malloc(namelen + 1));
364         if (!node->actual_name) {
365             free(node->name);
366             free(node);
367             return NULL;
368         }
369         memcpy(node->actual_name, actual_name, namelen + 1);
370     }
371     node->namelen = namelen;
372     node->nid = ptr_to_id(node);
373     node->ino = fuse->global->inode_ctr++;
374     node->gen = fuse->global->next_generation++;
375 
376     node->deleted = false;
377 
378     derive_permissions_locked(fuse, parent, node);
379     acquire_node_locked(node);
380     add_node_to_parent_locked(node, parent);
381     return node;
382 }
383 
rename_node_locked(struct node * node,const char * name,const char * actual_name)384 static int rename_node_locked(struct node *node, const char *name,
385         const char* actual_name)
386 {
387     size_t namelen = strlen(name);
388     int need_actual_name = strcmp(name, actual_name);
389 
390     /* make the storage bigger without actually changing the name
391      * in case an error occurs part way */
392     if (namelen > node->namelen) {
393         char* new_name = static_cast<char*>(realloc(node->name, namelen + 1));
394         if (!new_name) {
395             return -ENOMEM;
396         }
397         node->name = new_name;
398         if (need_actual_name && node->actual_name) {
399             char* new_actual_name = static_cast<char*>(realloc(node->actual_name, namelen + 1));
400             if (!new_actual_name) {
401                 return -ENOMEM;
402             }
403             node->actual_name = new_actual_name;
404         }
405     }
406 
407     /* update the name, taking care to allocate storage before overwriting the old name */
408     if (need_actual_name) {
409         if (!node->actual_name) {
410             node->actual_name = static_cast<char*>(malloc(namelen + 1));
411             if (!node->actual_name) {
412                 return -ENOMEM;
413             }
414         }
415         memcpy(node->actual_name, actual_name, namelen + 1);
416     } else {
417         free(node->actual_name);
418         node->actual_name = NULL;
419     }
420     memcpy(node->name, name, namelen + 1);
421     node->namelen = namelen;
422     return 0;
423 }
424 
lookup_node_by_id_locked(struct fuse * fuse,__u64 nid)425 static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
426 {
427     if (nid == FUSE_ROOT_ID) {
428         return &fuse->global->root;
429     } else {
430         return static_cast<struct node*>(id_to_ptr(nid));
431     }
432 }
433 
lookup_node_and_path_by_id_locked(struct fuse * fuse,__u64 nid,char * buf,size_t bufsize)434 static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
435         char* buf, size_t bufsize)
436 {
437     struct node* node = lookup_node_by_id_locked(fuse, nid);
438     if (node && get_node_path_locked(node, buf, bufsize) < 0) {
439         node = NULL;
440     }
441     return node;
442 }
443 
lookup_child_by_name_locked(struct node * node,const char * name)444 static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
445 {
446     for (node = node->child; node; node = node->next) {
447         /* use exact string comparison, nodes that differ by case
448          * must be considered distinct even if they refer to the same
449          * underlying file as otherwise operations such as "mv x x"
450          * will not work because the source and target nodes are the same. */
451         if (!strcmp(name, node->name) && !node->deleted) {
452             return node;
453         }
454     }
455     return 0;
456 }
457 
acquire_or_create_child_locked(struct fuse * fuse,struct node * parent,const char * name,const char * actual_name)458 static struct node* acquire_or_create_child_locked(
459         struct fuse* fuse, struct node* parent,
460         const char* name, const char* actual_name)
461 {
462     struct node* child = lookup_child_by_name_locked(parent, name);
463     if (child) {
464         acquire_node_locked(child);
465     } else {
466         child = create_node_locked(fuse, parent, name, actual_name);
467     }
468     return child;
469 }
470 
fuse_status(struct fuse * fuse,__u64 unique,int err)471 static void fuse_status(struct fuse *fuse, __u64 unique, int err)
472 {
473     struct fuse_out_header hdr;
474     hdr.len = sizeof(hdr);
475     hdr.error = err;
476     hdr.unique = unique;
477     ssize_t ret = TEMP_FAILURE_RETRY(write(fuse->fd, &hdr, sizeof(hdr)));
478     if (ret == -1) {
479         PLOG(ERROR) << "*** STATUS FAILED ***";
480     } else if (static_cast<size_t>(ret) != sizeof(hdr)) {
481         LOG(ERROR) << "*** STATUS FAILED: written " << ret << " expected "
482                    << sizeof(hdr) << " ***";
483     }
484 }
485 
fuse_reply(struct fuse * fuse,__u64 unique,void * data,int len)486 static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
487 {
488     struct fuse_out_header hdr;
489     hdr.len = len + sizeof(hdr);
490     hdr.error = 0;
491     hdr.unique = unique;
492 
493     struct iovec vec[2];
494     vec[0].iov_base = &hdr;
495     vec[0].iov_len = sizeof(hdr);
496     vec[1].iov_base = data;
497     vec[1].iov_len = len;
498 
499     ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 2));
500     if (ret == -1) {
501         PLOG(ERROR) << "*** REPLY FAILED ***";
502     } else if (static_cast<size_t>(ret) != sizeof(hdr) + len) {
503         LOG(ERROR) << "*** REPLY FAILED: written " << ret << " expected "
504                    << sizeof(hdr) + len << " ***";
505     }
506 }
507 
fuse_reply_entry(struct fuse * fuse,__u64 unique,struct node * parent,const char * name,const char * actual_name,const char * path)508 static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
509         struct node* parent, const char* name, const char* actual_name,
510         const char* path)
511 {
512     struct node* node;
513     struct fuse_entry_out out;
514     struct stat s;
515 
516     if (lstat(path, &s) == -1) {
517         return -errno;
518     }
519 
520     pthread_mutex_lock(&fuse->global->lock);
521     node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
522     if (!node) {
523         pthread_mutex_unlock(&fuse->global->lock);
524         return -ENOMEM;
525     }
526     memset(&out, 0, sizeof(out));
527     attr_from_stat(fuse, &out.attr, &s, node);
528     out.attr_valid = 10;
529     out.entry_valid = 10;
530     out.nodeid = node->nid;
531     out.generation = node->gen;
532     pthread_mutex_unlock(&fuse->global->lock);
533     fuse_reply(fuse, unique, &out, sizeof(out));
534     return NO_STATUS;
535 }
536 
fuse_reply_attr(struct fuse * fuse,__u64 unique,const struct node * node,const char * path)537 static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
538         const char* path)
539 {
540     struct fuse_attr_out out;
541     struct stat s;
542 
543     if (lstat(path, &s) == -1) {
544         return -errno;
545     }
546     memset(&out, 0, sizeof(out));
547     attr_from_stat(fuse, &out.attr, &s, node);
548     out.attr_valid = 10;
549     fuse_reply(fuse, unique, &out, sizeof(out));
550     return NO_STATUS;
551 }
552 
fuse_notify_delete(struct fuse * fuse,const __u64 parent,const __u64 child,const char * name)553 static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
554         const __u64 child, const char* name) {
555     struct fuse_out_header hdr;
556     struct fuse_notify_delete_out data;
557     size_t namelen = strlen(name);
558     hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
559     hdr.error = FUSE_NOTIFY_DELETE;
560     hdr.unique = 0;
561 
562     data.parent = parent;
563     data.child = child;
564     data.namelen = namelen;
565     data.padding = 0;
566 
567     struct iovec vec[3];
568     vec[0].iov_base = &hdr;
569     vec[0].iov_len = sizeof(hdr);
570     vec[1].iov_base = &data;
571     vec[1].iov_len = sizeof(data);
572     vec[2].iov_base = (void*) name;
573     vec[2].iov_len = namelen + 1;
574 
575     ssize_t ret = TEMP_FAILURE_RETRY(writev(fuse->fd, vec, 3));
576     /* Ignore ENOENT, since other views may not have seen the entry */
577     if (ret == -1) {
578         if (errno != ENOENT) {
579             PLOG(ERROR) << "*** NOTIFY FAILED ***";
580         }
581     } else if (static_cast<size_t>(ret) != sizeof(hdr) + sizeof(data) + namelen + 1) {
582         LOG(ERROR) << "*** NOTIFY FAILED: written " << ret << " expected "
583                    << sizeof(hdr) + sizeof(data) + namelen + 1 << " ***";
584     }
585 }
586 
handle_lookup(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const char * name)587 static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
588         const struct fuse_in_header *hdr, const char* name)
589 {
590     struct node* parent_node;
591     char parent_path[PATH_MAX];
592     char child_path[PATH_MAX];
593     const char* actual_name;
594 
595     pthread_mutex_lock(&fuse->global->lock);
596     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
597             parent_path, sizeof(parent_path));
598     DLOG(INFO) << "[" << handler->token << "] LOOKUP " << name << " @ " << hdr->nodeid
599                << " (" << (parent_node ? parent_node->name : "?") << ")";
600     pthread_mutex_unlock(&fuse->global->lock);
601 
602     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
603             child_path, sizeof(child_path), 1))) {
604         return -ENOENT;
605     }
606     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
607         return -EACCES;
608     }
609 
610     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
611 }
612 
handle_forget(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_forget_in * req)613 static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
614         const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
615 {
616     struct node* node;
617 
618     pthread_mutex_lock(&fuse->global->lock);
619     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
620     DLOG(INFO) << "[" << handler->token << "] FORGET #" << req->nlookup
621                << " @ " << std::hex << hdr->nodeid
622                << " (" << (node ? node->name : "?") << ")";
623     if (node) {
624         __u64 n = req->nlookup;
625         while (n) {
626             n--;
627             release_node_locked(node);
628         }
629     }
630     pthread_mutex_unlock(&fuse->global->lock);
631     return NO_STATUS; /* no reply */
632 }
633 
handle_getattr(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_getattr_in * req)634 static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
635         const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
636 {
637     struct node* node;
638     char path[PATH_MAX];
639 
640     pthread_mutex_lock(&fuse->global->lock);
641     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
642     DLOG(INFO) << "[" << handler->token << "] GETATTR flags=" << req->getattr_flags
643                << " fh=" << std::hex << req->fh << " @ " << hdr->nodeid << std::dec
644                << " (" << (node ? node->name : "?") << ")";
645     pthread_mutex_unlock(&fuse->global->lock);
646 
647     if (!node) {
648         return -ENOENT;
649     }
650     if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
651         return -EACCES;
652     }
653 
654     return fuse_reply_attr(fuse, hdr->unique, node, path);
655 }
656 
handle_setattr(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_setattr_in * req)657 static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
658         const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
659 {
660     struct node* node;
661     char path[PATH_MAX];
662     struct timespec times[2];
663 
664     pthread_mutex_lock(&fuse->global->lock);
665     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
666     DLOG(INFO) << "[" << handler->token << "] SETATTR fh=" << std::hex << req->fh
667                << " valid=" << std::hex << req->valid << " @ " << hdr->nodeid << std::dec
668                << " (" << (node ? node->name : "?") << ")";
669     pthread_mutex_unlock(&fuse->global->lock);
670 
671     if (!node) {
672         return -ENOENT;
673     }
674 
675     if (!(req->valid & FATTR_FH) &&
676             !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
677         return -EACCES;
678     }
679 
680     /* XXX: incomplete implementation on purpose.
681      * chmod/chown should NEVER be implemented.*/
682 
683     if ((req->valid & FATTR_SIZE) && TEMP_FAILURE_RETRY(truncate64(path, req->size)) == -1) {
684         return -errno;
685     }
686 
687     /* Handle changing atime and mtime.  If FATTR_ATIME_and FATTR_ATIME_NOW
688      * are both set, then set it to the current time.  Else, set it to the
689      * time specified in the request.  Same goes for mtime.  Use utimensat(2)
690      * as it allows ATIME and MTIME to be changed independently, and has
691      * nanosecond resolution which fuse also has.
692      */
693     if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
694         times[0].tv_nsec = UTIME_OMIT;
695         times[1].tv_nsec = UTIME_OMIT;
696         if (req->valid & FATTR_ATIME) {
697             if (req->valid & FATTR_ATIME_NOW) {
698               times[0].tv_nsec = UTIME_NOW;
699             } else {
700               times[0].tv_sec = req->atime;
701               times[0].tv_nsec = req->atimensec;
702             }
703         }
704         if (req->valid & FATTR_MTIME) {
705             if (req->valid & FATTR_MTIME_NOW) {
706               times[1].tv_nsec = UTIME_NOW;
707             } else {
708               times[1].tv_sec = req->mtime;
709               times[1].tv_nsec = req->mtimensec;
710             }
711         }
712         DLOG(INFO) << "[" << handler->token << "] Calling utimensat on " << path
713                    << " with atime " << times[0].tv_sec << ", mtime=" << times[1].tv_sec;
714         if (utimensat(-1, path, times, 0) < 0) {
715             return -errno;
716         }
717     }
718     return fuse_reply_attr(fuse, hdr->unique, node, path);
719 }
720 
handle_mknod(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_mknod_in * req,const char * name)721 static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
722         const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
723 {
724     struct node* parent_node;
725     char parent_path[PATH_MAX];
726     char child_path[PATH_MAX];
727     const char* actual_name;
728 
729     pthread_mutex_lock(&fuse->global->lock);
730     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
731             parent_path, sizeof(parent_path));
732     DLOG(INFO) << "[" << handler->token << "] MKNOD " << name << " 0" << std::oct << req->mode
733                << " @ " << std::hex << hdr->nodeid
734                << " (" << (parent_node ? parent_node->name : "?") << ")";
735     pthread_mutex_unlock(&fuse->global->lock);
736 
737     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
738             child_path, sizeof(child_path), 1))) {
739         return -ENOENT;
740     }
741     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
742         return -EACCES;
743     }
744     __u32 mode = (req->mode & (~0777)) | 0664;
745     if (mknod(child_path, mode, req->rdev) == -1) {
746         return -errno;
747     }
748     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
749 }
750 
handle_mkdir(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_mkdir_in * req,const char * name)751 static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
752         const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
753 {
754     struct node* parent_node;
755     char parent_path[PATH_MAX];
756     char child_path[PATH_MAX];
757     const char* actual_name;
758 
759     pthread_mutex_lock(&fuse->global->lock);
760     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
761             parent_path, sizeof(parent_path));
762     DLOG(INFO) << "[" << handler->token << "] MKDIR " << name << " 0" << std::oct << req->mode
763                << " @ " << std::hex << hdr->nodeid
764                << " (" << (parent_node ? parent_node->name : "?") << ")";
765     pthread_mutex_unlock(&fuse->global->lock);
766 
767     if (!parent_node || !(actual_name = find_file_within(parent_path, name,
768             child_path, sizeof(child_path), 1))) {
769         return -ENOENT;
770     }
771     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
772         return -EACCES;
773     }
774     __u32 mode = (req->mode & (~0777)) | 0775;
775     if (mkdir(child_path, mode) == -1) {
776         return -errno;
777     }
778 
779     /* When creating /Android/data and /Android/obb, mark them as .nomedia */
780     if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
781         char nomedia[PATH_MAX];
782         snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
783         if (touch(nomedia, 0664) != 0) {
784             PLOG(ERROR) << "touch(" << nomedia << ") failed";
785             return -ENOENT;
786         }
787     }
788     if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
789         char nomedia[PATH_MAX];
790         snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
791         if (touch(nomedia, 0664) != 0) {
792             PLOG(ERROR) << "touch(" << nomedia << ") failed";
793             return -ENOENT;
794         }
795     }
796 
797     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
798 }
799 
handle_unlink(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const char * name)800 static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
801         const struct fuse_in_header* hdr, const char* name)
802 {
803     struct node* parent_node;
804     struct node* child_node;
805     char parent_path[PATH_MAX];
806     char child_path[PATH_MAX];
807 
808     pthread_mutex_lock(&fuse->global->lock);
809     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
810             parent_path, sizeof(parent_path));
811     DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
812                << " (" << (parent_node ? parent_node->name : "?") << ")";
813     pthread_mutex_unlock(&fuse->global->lock);
814 
815     if (!parent_node || !find_file_within(parent_path, name,
816             child_path, sizeof(child_path), 1)) {
817         return -ENOENT;
818     }
819     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
820         return -EACCES;
821     }
822     if (unlink(child_path) == -1) {
823         return -errno;
824     }
825     pthread_mutex_lock(&fuse->global->lock);
826     child_node = lookup_child_by_name_locked(parent_node, name);
827     if (child_node) {
828         child_node->deleted = true;
829     }
830     pthread_mutex_unlock(&fuse->global->lock);
831     if (parent_node && child_node) {
832         /* Tell all other views that node is gone */
833         DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
834                    << " parent=" << std::hex << parent_node->nid
835                    << ", child=" << std::hex << child_node->nid << std::dec
836                    << ", name=" << name;
837         if (fuse != fuse->global->fuse_default) {
838             fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
839         }
840         if (fuse != fuse->global->fuse_read) {
841             fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
842         }
843         if (fuse != fuse->global->fuse_write) {
844             fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
845         }
846     }
847     return 0;
848 }
849 
handle_rmdir(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const char * name)850 static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
851         const struct fuse_in_header* hdr, const char* name)
852 {
853     struct node* child_node;
854     struct node* parent_node;
855     char parent_path[PATH_MAX];
856     char child_path[PATH_MAX];
857 
858     pthread_mutex_lock(&fuse->global->lock);
859     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
860             parent_path, sizeof(parent_path));
861     DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
862                << " (" << (parent_node ? parent_node->name : "?") << ")";
863     pthread_mutex_unlock(&fuse->global->lock);
864 
865     if (!parent_node || !find_file_within(parent_path, name,
866             child_path, sizeof(child_path), 1)) {
867         return -ENOENT;
868     }
869     if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
870         return -EACCES;
871     }
872     if (rmdir(child_path) == -1) {
873         return -errno;
874     }
875     pthread_mutex_lock(&fuse->global->lock);
876     child_node = lookup_child_by_name_locked(parent_node, name);
877     if (child_node) {
878         child_node->deleted = true;
879     }
880     pthread_mutex_unlock(&fuse->global->lock);
881     if (parent_node && child_node) {
882         /* Tell all other views that node is gone */
883         DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
884                    << " parent=" << std::hex << parent_node->nid
885                    << ", child=" << std::hex << child_node->nid << std::dec
886                    << ", name=" << name;
887         if (fuse != fuse->global->fuse_default) {
888             fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
889         }
890         if (fuse != fuse->global->fuse_read) {
891             fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
892         }
893         if (fuse != fuse->global->fuse_write) {
894             fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
895         }
896     }
897     return 0;
898 }
899 
handle_rename(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_rename_in * req,const char * old_name,const char * new_name)900 static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
901         const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
902         const char* old_name, const char* new_name)
903 {
904     struct node* old_parent_node;
905     struct node* new_parent_node;
906     struct node* child_node;
907     char old_parent_path[PATH_MAX];
908     char new_parent_path[PATH_MAX];
909     char old_child_path[PATH_MAX];
910     char new_child_path[PATH_MAX];
911     const char* new_actual_name;
912     int search;
913     int res;
914 
915     pthread_mutex_lock(&fuse->global->lock);
916     old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
917             old_parent_path, sizeof(old_parent_path));
918     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
919             new_parent_path, sizeof(new_parent_path));
920     DLOG(INFO) << "[" << handler->token << "] RENAME " << old_name << "->" << new_name
921                << " @ " << std::hex << hdr->nodeid
922                << " (" << (old_parent_node ? old_parent_node->name : "?") << ") -> "
923                << std::hex << req->newdir
924                << " (" << (new_parent_node ? new_parent_node->name : "?") << ")";
925     if (!old_parent_node || !new_parent_node) {
926         res = -ENOENT;
927         goto lookup_error;
928     }
929     if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
930         res = -EACCES;
931         goto lookup_error;
932     }
933     if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
934         res = -EACCES;
935         goto lookup_error;
936     }
937     child_node = lookup_child_by_name_locked(old_parent_node, old_name);
938     if (!child_node || get_node_path_locked(child_node,
939             old_child_path, sizeof(old_child_path)) < 0) {
940         res = -ENOENT;
941         goto lookup_error;
942     }
943     acquire_node_locked(child_node);
944     pthread_mutex_unlock(&fuse->global->lock);
945 
946     /* Special case for renaming a file where destination is same path
947      * differing only by case.  In this case we don't want to look for a case
948      * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
949      */
950     search = old_parent_node != new_parent_node
951             || strcasecmp(old_name, new_name);
952     if (!(new_actual_name = find_file_within(new_parent_path, new_name,
953             new_child_path, sizeof(new_child_path), search))) {
954         res = -ENOENT;
955         goto io_error;
956     }
957 
958     DLOG(INFO) << "[" << handler->token << "] RENAME " << old_child_path << "->" << new_child_path;
959     res = rename(old_child_path, new_child_path);
960     if (res == -1) {
961         res = -errno;
962         goto io_error;
963     }
964 
965     pthread_mutex_lock(&fuse->global->lock);
966     res = rename_node_locked(child_node, new_name, new_actual_name);
967     if (!res) {
968         remove_node_from_parent_locked(child_node);
969         derive_permissions_locked(fuse, new_parent_node, child_node);
970         derive_permissions_recursive_locked(fuse, child_node);
971         add_node_to_parent_locked(child_node, new_parent_node);
972     }
973     goto done;
974 
975 io_error:
976     pthread_mutex_lock(&fuse->global->lock);
977 done:
978     release_node_locked(child_node);
979 lookup_error:
980     pthread_mutex_unlock(&fuse->global->lock);
981     return res;
982 }
983 
open_flags_to_access_mode(int open_flags)984 static int open_flags_to_access_mode(int open_flags) {
985     if ((open_flags & O_ACCMODE) == O_RDONLY) {
986         return R_OK;
987     } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
988         return W_OK;
989     } else {
990         /* Probably O_RDRW, but treat as default to be safe */
991         return R_OK | W_OK;
992     }
993 }
994 
handle_open(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_open_in * req)995 static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
996         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
997 {
998     struct node* node;
999     char path[PATH_MAX];
1000     struct fuse_open_out out = {};
1001     struct handle *h;
1002 
1003     pthread_mutex_lock(&fuse->global->lock);
1004     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1005     DLOG(INFO) << "[" << handler->token << "] OPEN 0" << std::oct << req->flags
1006                << " @ " << std::hex << hdr->nodeid << std::dec
1007                << " (" << (node ? node->name : "?") << ")";
1008     pthread_mutex_unlock(&fuse->global->lock);
1009 
1010     if (!node) {
1011         return -ENOENT;
1012     }
1013     if (!check_caller_access_to_node(fuse, hdr, node,
1014             open_flags_to_access_mode(req->flags))) {
1015         return -EACCES;
1016     }
1017     h = static_cast<struct handle*>(malloc(sizeof(*h)));
1018     if (!h) {
1019         return -ENOMEM;
1020     }
1021     DLOG(INFO) << "[" << handler->token << "] OPEN " << path;
1022     h->fd = TEMP_FAILURE_RETRY(open(path, req->flags));
1023     if (h->fd == -1) {
1024         free(h);
1025         return -errno;
1026     }
1027     out.fh = ptr_to_id(h);
1028     out.open_flags = 0;
1029     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
1030     return NO_STATUS;
1031 }
1032 
handle_read(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_read_in * req)1033 static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
1034         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1035 {
1036     struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1037     __u64 unique = hdr->unique;
1038     __u32 size = req->size;
1039     __u64 offset = req->offset;
1040     int res;
1041     __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
1042 
1043     /* Don't access any other fields of hdr or req beyond this point, the read buffer
1044      * overlaps the request buffer and will clobber data in the request.  This
1045      * saves us 128KB per request handler thread at the cost of this scary comment. */
1046 
1047     DLOG(INFO) << "[" << handler->token << "] READ " << std::hex << h << std::dec
1048                << "(" << h->fd << ") " << size << "@" << offset;
1049     if (size > MAX_READ) {
1050         return -EINVAL;
1051     }
1052     res = TEMP_FAILURE_RETRY(pread64(h->fd, read_buffer, size, offset));
1053     if (res == -1) {
1054         return -errno;
1055     }
1056     fuse_reply(fuse, unique, read_buffer, res);
1057     return NO_STATUS;
1058 }
1059 
handle_write(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_write_in * req,const void * buffer)1060 static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
1061         const struct fuse_in_header* hdr, const struct fuse_write_in* req,
1062         const void* buffer)
1063 {
1064     struct fuse_write_out out;
1065     struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1066     int res;
1067     __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
1068 
1069     if (req->flags & O_DIRECT) {
1070         memcpy(aligned_buffer, buffer, req->size);
1071         buffer = (const __u8*) aligned_buffer;
1072     }
1073 
1074     DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << std::dec
1075                << "(" << h->fd << ") " << req->size << "@" << req->offset;
1076     res = TEMP_FAILURE_RETRY(pwrite64(h->fd, buffer, req->size, req->offset));
1077     if (res == -1) {
1078         return -errno;
1079     }
1080     out.size = res;
1081     out.padding = 0;
1082     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
1083     return NO_STATUS;
1084 }
1085 
handle_statfs(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr)1086 static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
1087         const struct fuse_in_header* hdr)
1088 {
1089     char path[PATH_MAX];
1090     struct statfs stat;
1091     struct fuse_statfs_out out;
1092     int res;
1093 
1094     pthread_mutex_lock(&fuse->global->lock);
1095     DLOG(INFO) << "[" << handler->token << "] STATFS";
1096     res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
1097     pthread_mutex_unlock(&fuse->global->lock);
1098     if (res < 0) {
1099         return -ENOENT;
1100     }
1101     if (TEMP_FAILURE_RETRY(statfs(fuse->global->root.name, &stat)) == -1) {
1102         return -errno;
1103     }
1104     memset(&out, 0, sizeof(out));
1105     out.st.blocks = stat.f_blocks;
1106     out.st.bfree = stat.f_bfree;
1107     out.st.bavail = stat.f_bavail;
1108     out.st.files = stat.f_files;
1109     out.st.ffree = stat.f_ffree;
1110     out.st.bsize = stat.f_bsize;
1111     out.st.namelen = stat.f_namelen;
1112     out.st.frsize = stat.f_frsize;
1113     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
1114     return NO_STATUS;
1115 }
1116 
handle_release(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_release_in * req)1117 static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
1118         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1119 {
1120     struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1121 
1122     DLOG(INFO) << "[" << handler->token << "] RELEASE " << std::hex << h << std::dec
1123                << "(" << h->fd << ")";
1124     close(h->fd);
1125     free(h);
1126     return 0;
1127 }
1128 
handle_fsync(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_fsync_in * req)1129 static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
1130         const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
1131 {
1132     bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
1133     bool is_data_sync = req->fsync_flags & 1;
1134 
1135     int fd = -1;
1136     if (is_dir) {
1137       struct dirhandle *dh = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
1138       fd = dirfd(dh->d);
1139     } else {
1140       struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
1141       fd = h->fd;
1142     }
1143 
1144     DLOG(INFO) << "[" << handler->token << "] " << (is_dir ? "FSYNCDIR" : "FSYNC") << " "
1145                << std::hex << req->fh << std::dec << "(" << fd << ") is_data_sync=" << is_data_sync;
1146     int res = is_data_sync ? fdatasync(fd) : fsync(fd);
1147     if (res == -1) {
1148         return -errno;
1149     }
1150     return 0;
1151 }
1152 
handle_flush(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr)1153 static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
1154         const struct fuse_in_header* hdr)
1155 {
1156     DLOG(INFO) << "[" << handler->token << "] FLUSH";
1157     return 0;
1158 }
1159 
handle_opendir(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_open_in * req)1160 static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
1161         const struct fuse_in_header* hdr, const struct fuse_open_in* req)
1162 {
1163     struct node* node;
1164     char path[PATH_MAX];
1165     struct fuse_open_out out = {};
1166     struct dirhandle *h;
1167 
1168     pthread_mutex_lock(&fuse->global->lock);
1169     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
1170     DLOG(INFO) << "[" << handler->token << "] OPENDIR @ " << std::hex << hdr->nodeid
1171                << " (" << (node ? node->name : "?") << ")";
1172     pthread_mutex_unlock(&fuse->global->lock);
1173 
1174     if (!node) {
1175         return -ENOENT;
1176     }
1177     if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
1178         return -EACCES;
1179     }
1180     h = static_cast<struct dirhandle*>(malloc(sizeof(*h)));
1181     if (!h) {
1182         return -ENOMEM;
1183     }
1184     DLOG(INFO) << "[" << handler->token << "] OPENDIR " << path;
1185     h->d = opendir(path);
1186     if (!h->d) {
1187         free(h);
1188         return -errno;
1189     }
1190     out.fh = ptr_to_id(h);
1191     out.open_flags = 0;
1192     fuse_reply(fuse, hdr->unique, &out, sizeof(out));
1193     return NO_STATUS;
1194 }
1195 
handle_readdir(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_read_in * req)1196 static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
1197         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
1198 {
1199     char buffer[8192];
1200     struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
1201     struct dirent *de;
1202     struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
1203 
1204     DLOG(INFO) << "[" << handler->token << "] READDIR " << h;
1205     if (req->offset == 0) {
1206         /* rewinddir() might have been called above us, so rewind here too */
1207         DLOG(INFO) << "[" << handler->token << "] calling rewinddir()";
1208         rewinddir(h->d);
1209     }
1210     de = readdir(h->d);
1211     if (!de) {
1212         return 0;
1213     }
1214     fde->ino = FUSE_UNKNOWN_INO;
1215     /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
1216     fde->off = req->offset + 1;
1217     fde->type = de->d_type;
1218     fde->namelen = strlen(de->d_name);
1219     memcpy(fde->name, de->d_name, fde->namelen + 1);
1220     fuse_reply(fuse, hdr->unique, fde,
1221             FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
1222     return NO_STATUS;
1223 }
1224 
handle_releasedir(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_release_in * req)1225 static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
1226         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
1227 {
1228     struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
1229 
1230     DLOG(INFO) << "[" << handler->token << "] RELEASEDIR " << h;
1231     closedir(h->d);
1232     free(h);
1233     return 0;
1234 }
1235 
handle_init(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const struct fuse_init_in * req)1236 static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
1237         const struct fuse_in_header* hdr, const struct fuse_init_in* req)
1238 {
1239     struct fuse_init_out out;
1240     size_t fuse_struct_size;
1241 
1242     DLOG(INFO) << "[" << handler->token << "] INIT ver=" << req->major << "." << req->minor
1243                << " maxread=" << req->max_readahead << " flags=" << std::hex << req->flags;
1244 
1245     /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
1246      * defined (fuse version 7.6). The structure is the same from 7.6 through
1247      * 7.22. Beginning with 7.23, the structure increased in size and added
1248      * new parameters.
1249      */
1250     if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
1251         LOG(ERROR) << "Fuse kernel version mismatch: Kernel version "
1252                    << req->major << "." << req->minor
1253                    << ", Expected at least " << FUSE_KERNEL_VERSION << ".6";
1254         return -1;
1255     }
1256 
1257     /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
1258     out.minor = MIN(req->minor, 15);
1259     fuse_struct_size = sizeof(out);
1260 #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
1261     /* FUSE_KERNEL_VERSION >= 23. */
1262 
1263     /* Since we return minor version 15, the kernel does not accept the latest
1264      * fuse_init_out size. We need to use FUSE_COMPAT_22_INIT_OUT_SIZE always.*/
1265     fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
1266 #endif
1267 
1268     out.major = FUSE_KERNEL_VERSION;
1269     out.max_readahead = req->max_readahead;
1270     out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
1271     out.max_background = 32;
1272     out.congestion_threshold = 32;
1273     out.max_write = MAX_WRITE;
1274     fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
1275     return NO_STATUS;
1276 }
1277 
handle_canonical_path(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr)1278 static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
1279         const struct fuse_in_header *hdr)
1280 {
1281     struct node* node;
1282     char path[PATH_MAX];
1283     int len;
1284 
1285     pthread_mutex_lock(&fuse->global->lock);
1286     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
1287             path, sizeof(path));
1288     DLOG(INFO) << "[" << handler->token << "] CANONICAL_PATH @ " << std::hex << hdr->nodeid
1289                << std::dec << " (" << (node ? node->name : "?") << ")";
1290     pthread_mutex_unlock(&fuse->global->lock);
1291 
1292     if (!node) {
1293         return -ENOENT;
1294     }
1295     if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
1296         return -EACCES;
1297     }
1298     len = strlen(path);
1299     if (len + 1 > PATH_MAX)
1300         len = PATH_MAX - 1;
1301     path[PATH_MAX - 1] = 0;
1302     fuse_reply(fuse, hdr->unique, path, len + 1);
1303     return NO_STATUS;
1304 }
1305 
handle_fuse_request(struct fuse * fuse,struct fuse_handler * handler,const struct fuse_in_header * hdr,const void * data,size_t data_len)1306 static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
1307         const struct fuse_in_header *hdr, const void *data, size_t data_len)
1308 {
1309     switch (hdr->opcode) {
1310     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
1311         const char *name = static_cast<const char*>(data);
1312         return handle_lookup(fuse, handler, hdr, name);
1313     }
1314 
1315     case FUSE_FORGET: {
1316         const struct fuse_forget_in *req = static_cast<const struct fuse_forget_in*>(data);
1317         return handle_forget(fuse, handler, hdr, req);
1318     }
1319 
1320     case FUSE_GETATTR: { /* getattr_in -> attr_out */
1321         const struct fuse_getattr_in *req = static_cast<const struct fuse_getattr_in*>(data);
1322         return handle_getattr(fuse, handler, hdr, req);
1323     }
1324 
1325     case FUSE_SETATTR: { /* setattr_in -> attr_out */
1326         const struct fuse_setattr_in *req = static_cast<const struct fuse_setattr_in*>(data);
1327         return handle_setattr(fuse, handler, hdr, req);
1328     }
1329 
1330 //    case FUSE_READLINK:
1331 //    case FUSE_SYMLINK:
1332     case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
1333         const struct fuse_mknod_in *req = static_cast<const struct fuse_mknod_in*>(data);
1334         const char *name = ((const char*) data) + sizeof(*req);
1335         return handle_mknod(fuse, handler, hdr, req, name);
1336     }
1337 
1338     case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
1339         const struct fuse_mkdir_in *req = static_cast<const struct fuse_mkdir_in*>(data);
1340         const char *name = ((const char*) data) + sizeof(*req);
1341         return handle_mkdir(fuse, handler, hdr, req, name);
1342     }
1343 
1344     case FUSE_UNLINK: { /* bytez[] -> */
1345         const char *name = static_cast<const char*>(data);
1346         return handle_unlink(fuse, handler, hdr, name);
1347     }
1348 
1349     case FUSE_RMDIR: { /* bytez[] -> */
1350         const char *name = static_cast<const char*>(data);
1351         return handle_rmdir(fuse, handler, hdr, name);
1352     }
1353 
1354     case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
1355         const struct fuse_rename_in *req = static_cast<const struct fuse_rename_in*>(data);
1356         const char *old_name = ((const char*) data) + sizeof(*req);
1357         const char *new_name = old_name + strlen(old_name) + 1;
1358         return handle_rename(fuse, handler, hdr, req, old_name, new_name);
1359     }
1360 
1361 //    case FUSE_LINK:
1362     case FUSE_OPEN: { /* open_in -> open_out */
1363         const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
1364         return handle_open(fuse, handler, hdr, req);
1365     }
1366 
1367     case FUSE_READ: { /* read_in -> byte[] */
1368         const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
1369         return handle_read(fuse, handler, hdr, req);
1370     }
1371 
1372     case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
1373         const struct fuse_write_in *req = static_cast<const struct fuse_write_in*>(data);
1374         const void* buffer = (const __u8*)data + sizeof(*req);
1375         return handle_write(fuse, handler, hdr, req, buffer);
1376     }
1377 
1378     case FUSE_STATFS: { /* getattr_in -> attr_out */
1379         return handle_statfs(fuse, handler, hdr);
1380     }
1381 
1382     case FUSE_RELEASE: { /* release_in -> */
1383         const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
1384         return handle_release(fuse, handler, hdr, req);
1385     }
1386 
1387     case FUSE_FSYNC:
1388     case FUSE_FSYNCDIR: {
1389         const struct fuse_fsync_in *req = static_cast<const struct fuse_fsync_in*>(data);
1390         return handle_fsync(fuse, handler, hdr, req);
1391     }
1392 
1393 //    case FUSE_SETXATTR:
1394 //    case FUSE_GETXATTR:
1395 //    case FUSE_LISTXATTR:
1396 //    case FUSE_REMOVEXATTR:
1397     case FUSE_FLUSH: {
1398         return handle_flush(fuse, handler, hdr);
1399     }
1400 
1401     case FUSE_OPENDIR: { /* open_in -> open_out */
1402         const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
1403         return handle_opendir(fuse, handler, hdr, req);
1404     }
1405 
1406     case FUSE_READDIR: {
1407         const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
1408         return handle_readdir(fuse, handler, hdr, req);
1409     }
1410 
1411     case FUSE_RELEASEDIR: { /* release_in -> */
1412         const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
1413         return handle_releasedir(fuse, handler, hdr, req);
1414     }
1415 
1416     case FUSE_INIT: { /* init_in -> init_out */
1417         const struct fuse_init_in *req = static_cast<const struct fuse_init_in*>(data);
1418         return handle_init(fuse, handler, hdr, req);
1419     }
1420 
1421     case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
1422         return handle_canonical_path(fuse, handler, hdr);
1423     }
1424 
1425     default: {
1426         DLOG(INFO) << "[" << handler->token << "] NOTIMPL op=" << hdr->opcode
1427                    << "uniq=" << std::hex << hdr->unique << "nid=" << hdr->nodeid << std::dec;
1428         return -ENOSYS;
1429     }
1430     }
1431 }
1432 
handle_fuse_requests(struct fuse_handler * handler)1433 void handle_fuse_requests(struct fuse_handler* handler)
1434 {
1435     struct fuse* fuse = handler->fuse;
1436     for (;;) {
1437         ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
1438                 handler->request_buffer, sizeof(handler->request_buffer)));
1439         if (len == -1) {
1440             if (errno == ENODEV) {
1441                 LOG(ERROR) << "[" << handler->token << "] someone stole our marbles!";
1442                 exit(2);
1443             }
1444             PLOG(ERROR) << "[" << handler->token << "] handle_fuse_requests";
1445             continue;
1446         }
1447 
1448         if (static_cast<size_t>(len) < sizeof(struct fuse_in_header)) {
1449             LOG(ERROR) << "[" << handler->token << "] request too short: len=" << len;
1450             continue;
1451         }
1452 
1453         const struct fuse_in_header* hdr =
1454             reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
1455         if (hdr->len != static_cast<size_t>(len)) {
1456             LOG(ERROR) << "[" << handler->token << "] malformed header: len=" << len
1457                        << ", hdr->len=" << hdr->len;
1458             continue;
1459         }
1460 
1461         const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
1462         size_t data_len = len - sizeof(struct fuse_in_header);
1463         __u64 unique = hdr->unique;
1464         int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
1465 
1466         /* We do not access the request again after this point because the underlying
1467          * buffer storage may have been reused while processing the request. */
1468 
1469         if (res != NO_STATUS) {
1470             if (res) {
1471                 DLOG(INFO) << "[" << handler->token << "] ERROR " << res;
1472             }
1473             fuse_status(fuse, unique, res);
1474         }
1475     }
1476 }
1477