blob: ef7651f635b6c4ad3345915e6bf611a047f17154 [file] [log] [blame]
shafik1e3a2672019-08-16 14:51:55 +01001// Copyright (C) 2019 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#define LOG_TAG "FuseDaemon"
16
17#include "FuseDaemon.h"
18
shafik458d1102019-09-06 18:21:36 +010019#include <android-base/logging.h>
shafik1e3a2672019-08-16 14:51:55 +010020#include <ctype.h>
21#include <dirent.h>
22#include <errno.h>
23#include <fcntl.h>
shafik8b57cd52019-09-06 10:51:29 +010024#include <fuse_i.h>
25#include <fuse_lowlevel.h>
shafik1e3a2672019-08-16 14:51:55 +010026#include <inttypes.h>
27#include <limits.h>
28#include <linux/fuse.h>
29#include <pthread.h>
30#include <stdbool.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/inotify.h>
shafikb334a612019-09-30 20:38:16 +010035#include <sys/mman.h>
shafik1e3a2672019-08-16 14:51:55 +010036#include <sys/mount.h>
37#include <sys/param.h>
38#include <sys/resource.h>
39#include <sys/stat.h>
40#include <sys/statfs.h>
41#include <sys/statvfs.h>
42#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/uio.h>
45#include <unistd.h>
shafik1e3a2672019-08-16 14:51:55 +010046
shafik8b57cd52019-09-06 10:51:29 +010047#include <iostream>
shafikc3f62672019-08-30 11:15:48 +010048#include <vector>
shafik1e3a2672019-08-16 14:51:55 +010049
shafikc3f62672019-08-30 11:15:48 +010050#include "MediaProviderWrapper.h"
51#include "libfuse_jni/RedactionInfo.h"
52
53using mediaprovider::fuse::RedactionInfo;
Jeff Sharkey7469b982019-08-28 16:51:02 -060054using std::string;
shafikc3f62672019-08-30 11:15:48 +010055using std::vector;
shafik1e3a2672019-08-16 14:51:55 +010056
Narayan Kamath88203dc2019-08-30 17:19:38 +010057// logging macros to avoid duplication.
shafik458d1102019-09-06 18:21:36 +010058#define TRACE LOG(DEBUG)
59#define TRACE_FUSE(__fuse) TRACE << "[" << __fuse->dest_path << "] "
shafik1e3a2672019-08-16 14:51:55 +010060
61#define FUSE_UNKNOWN_INO 0xffffffff
62
shafikb334a612019-09-30 20:38:16 +010063constexpr size_t MAX_READ_SIZE = 128 * 1024;
64
shafik1e3a2672019-08-16 14:51:55 +010065struct handle {
66 int fd;
shafikc3f62672019-08-30 11:15:48 +010067 std::unique_ptr<RedactionInfo> ri;
shafik1e3a2672019-08-16 14:51:55 +010068};
69
70struct dirhandle {
71 DIR* d;
72 off_t next_off;
73};
74
75struct node {
76 __u32 refcount;
77 __u64 nid;
78 __u64 gen;
79 /*
80 * The inode number for this FUSE node. Note that this isn't stable across
81 * multiple invocations of the FUSE daemon.
82 */
83 __u32 ino;
84
85 struct node* next; /* per-dir sibling list */
86 struct node* child; /* first contained file by this dir */
87 struct node* parent; /* containing directory */
88
89 string name;
90
91 bool deleted;
92};
93
94/* Single FUSE mount */
95struct fuse {
96 pthread_mutex_t lock;
97 string source_path;
98 string dest_path;
99
100 __u64 next_generation;
101 struct node root;
102
103 /* Used to allocate unique inode numbers for fuse nodes. We use
104 * a simple counter based scheme where inode numbers from deleted
105 * nodes aren't reused. Note that inode allocations are not stable
106 * across multiple invocation of the sdcard daemon, but that shouldn't
107 * be a huge problem in practice.
108 *
109 * Note that we restrict inodes to 32 bit unsigned integers to prevent
110 * truncation on 32 bit processes when unsigned long long stat.st_ino is
111 * assigned to an unsigned long ino_t type in an LP32 process.
112 *
113 * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
114 * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
115 * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
116 * in fs/fuse/inode.c).
117 *
118 * Accesses must be guarded by |lock|.
119 */
120 __u32 inode_ctr;
shafikc3f62672019-08-30 11:15:48 +0100121
122 /*
123 * Used to make JNI calls to MediaProvider.
124 * Responsibility of freeing this object falls on corresponding
125 * FuseDaemon object.
126 */
127 mediaprovider::fuse::MediaProviderWrapper* mp;
shafikb334a612019-09-30 20:38:16 +0100128
129 /*
130 * Points to a range of zeroized bytes, used by pf_read to represent redacted ranges.
131 * The memory is read only and should never be modified.
132 */
133 char* zero_addr;
shafik1e3a2672019-08-16 14:51:55 +0100134};
135
shafik458d1102019-09-06 18:21:36 +0100136static inline const char* safe_name(struct node* n) {
137 return n ? n->name.c_str() : "?";
138}
139
shafik1e3a2672019-08-16 14:51:55 +0100140static inline __u64 ptr_to_id(void* ptr) {
141 return (__u64)(uintptr_t) ptr;
142}
143
144static void acquire_node_locked(struct node* node) {
145 node->refcount++;
shafik458d1102019-09-06 18:21:36 +0100146 TRACE << "ACQUIRE " << node << " " << node->name << " rc=" << node->refcount;
shafik1e3a2672019-08-16 14:51:55 +0100147}
148
149static void remove_node_from_parent_locked(struct node* node);
150
151static void release_node_n_locked(struct node* node, int count) {
shafik458d1102019-09-06 18:21:36 +0100152 TRACE << "RELEASE " << node << " " << node->name << " rc=" << node->refcount;
shafik1e3a2672019-08-16 14:51:55 +0100153 if (node->refcount >= count) {
154 node->refcount -= count;
155 if (!node->refcount) {
shafik458d1102019-09-06 18:21:36 +0100156 TRACE << "DESTROY " << node << " (" << node->name << ")";
shafik1e3a2672019-08-16 14:51:55 +0100157 remove_node_from_parent_locked(node);
158
159 /* TODO: remove debugging - poison memory */
160 memset(node, 0xfc, sizeof(*node));
161 free(node);
162 }
163 } else {
shafik458d1102019-09-06 18:21:36 +0100164 LOG(ERROR) << "Zero refcnt " << node;
shafik1e3a2672019-08-16 14:51:55 +0100165 }
166}
167
168static void release_node_locked(struct node* node) {
shafik458d1102019-09-06 18:21:36 +0100169 TRACE << "RELEASE " << node << " " << node->name << " rc=" << node->refcount;
shafik1e3a2672019-08-16 14:51:55 +0100170 if (node->refcount > 0) {
171 node->refcount--;
172 if (!node->refcount) {
shafik458d1102019-09-06 18:21:36 +0100173 TRACE << "DESTROY " << node << " (" << node->name << ")";
shafik1e3a2672019-08-16 14:51:55 +0100174 remove_node_from_parent_locked(node);
175
176 /* TODO: remove debugging - poison memory */
177 memset(node, 0xfc, sizeof(*node));
178 free(node);
179 }
180 } else {
shafik458d1102019-09-06 18:21:36 +0100181 LOG(ERROR) << "Zero refcnt " << node;
shafik1e3a2672019-08-16 14:51:55 +0100182 }
183}
184
185static void add_node_to_parent_locked(struct node* node, struct node* parent) {
186 node->parent = parent;
187 node->next = parent->child;
188 parent->child = node;
189 acquire_node_locked(parent);
190}
191
192static void remove_node_from_parent_locked(struct node* node) {
193 if (node->parent) {
194 if (node->parent->child == node) {
195 node->parent->child = node->parent->child->next;
196 } else {
197 struct node* node2;
198 node2 = node->parent->child;
199 while (node2->next != node) node2 = node2->next;
200 node2->next = node->next;
201 }
202 release_node_locked(node->parent);
203 node->parent = NULL;
204 node->next = NULL;
205 }
206}
207
208static void get_node_path_locked_helper(struct node* node, string& path) {
209 if (node->parent) get_node_path_locked_helper(node->parent, path);
210 path += node->name + "/";
211}
212
213/* Gets the absolute path to a node into the provided buffer.
214 *
215 * Populates 'buf' with the path and returns the length of the path on success,
216 * or returns -1 if the path is too long for the provided buffer.
217 */
218static string get_node_path_locked(struct node* node) {
219 string path;
220
221 path.reserve(PATH_MAX);
222 if (node->parent) get_node_path_locked_helper(node->parent, path);
223 path += node->name;
224 return path;
225}
226
227struct node* create_node_locked(struct fuse* fuse,
228 struct node* parent,
229 const string& name) {
230 struct node* node;
231
232 // Detect overflows in the inode counter. "4 billion nodes should be enough
233 // for everybody".
234 if (fuse->inode_ctr == 0) {
shafik458d1102019-09-06 18:21:36 +0100235 LOG(ERROR) << "No more inode numbers available";
shafik1e3a2672019-08-16 14:51:55 +0100236 return NULL;
237 }
238
239 node = (struct node*) calloc(1, sizeof(struct node));
240 if (!node) {
241 return NULL;
242 }
243 node->name = name;
244 node->nid = ptr_to_id(node);
245 node->ino = fuse->inode_ctr++;
246 node->gen = fuse->next_generation++;
247
248 node->deleted = false;
249
250 acquire_node_locked(node);
251 add_node_to_parent_locked(node, parent);
252 return node;
253}
254
255static struct node* lookup_node_by_id_locked(struct fuse* fuse, __u64 nid) {
256 if (nid == FUSE_ROOT_ID) {
257 return &fuse->root;
258 } else {
259 return reinterpret_cast<struct node*>(nid);
260 }
261}
262
263static struct node* lookup_child_by_name_locked(struct node* node,
264 const string& name) {
265 for (node = node->child; node; node = node->next) {
266 /* use exact string comparison, nodes that differ by case
267 * must be considered distinct even if they refer to the same
268 * underlying file as otherwise operations such as "mv x x"
269 * will not work because the source and target nodes are the same. */
270
271 if ((name == node->name) && !node->deleted) {
272 return node;
273 }
274 }
275 return 0;
276}
277
278static struct node* acquire_or_create_child_locked(struct fuse* fuse,
279 struct node* parent,
280 const string& name) {
281 struct node* child = lookup_child_by_name_locked(parent, name);
282 if (child) {
283 acquire_node_locked(child);
284 } else {
285 child = create_node_locked(fuse, parent, name);
286 }
287 return child;
288}
289
290static struct fuse* get_fuse(fuse_req_t req) {
291 return reinterpret_cast<struct fuse*>(fuse_req_userdata(req));
292}
293
294static struct node* make_node_entry(fuse_req_t req,
295 struct node* parent,
296 const string& name,
297 const string& path,
298 struct fuse_entry_param* e) {
299 struct fuse* fuse = get_fuse(req);
300 struct node* node;
301
Jeff Sharkey7469b982019-08-28 16:51:02 -0600302 memset(e, 0, sizeof(*e));
shafik1e3a2672019-08-16 14:51:55 +0100303 if (lstat(path.c_str(), &e->attr) < 0) {
304 return NULL;
305 }
306
307 pthread_mutex_lock(&fuse->lock);
308 node = acquire_or_create_child_locked(fuse, parent, name);
309 if (!node) {
310 pthread_mutex_unlock(&fuse->lock);
311 errno = ENOMEM;
312 return NULL;
313 }
314
315 // Manipulate attr here if needed
316
317 e->attr_timeout = 10;
318 e->entry_timeout = 10;
319 e->ino = node->nid;
320 e->generation = node->gen;
321 pthread_mutex_unlock(&fuse->lock);
322
323 return node;
324}
325
326namespace mediaprovider {
327namespace fuse {
328
329/**
330 * Function implementations
331 *
332 * These implement the various functions in fuse_lowlevel_ops
333 *
334 */
335
336static void pf_init(void* userdata, struct fuse_conn_info* conn) {
Zima9fcd552019-08-29 15:17:04 +0100337 // We don't want a getattr request with every read request
338 conn->want &= ~FUSE_CAP_AUTO_INVAL_DATA;
shafik8b57cd52019-09-06 10:51:29 +0100339 unsigned mask = (FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE | FUSE_CAP_SPLICE_READ |
340 FUSE_CAP_ASYNC_READ | FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_WRITEBACK_CACHE |
341 FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_FLOCK_LOCKS);
shafik1e3a2672019-08-16 14:51:55 +0100342 conn->want |= conn->capable & mask;
shafikb334a612019-09-30 20:38:16 +0100343 LOG(INFO) << "conn->max_read = " << conn->max_read;
344 conn->max_read = MAX_READ_SIZE;
shafik1e3a2672019-08-16 14:51:55 +0100345}
346
347/*
348static void pf_destroy(void* userdata)
349{
350 cout << "TODO:" << __func__;
351}
352*/
353
354static struct node* do_lookup(fuse_req_t req,
355 fuse_ino_t parent,
356 const char* name,
357 struct fuse_entry_param* e) {
358 struct fuse* fuse = get_fuse(req);
359 const struct fuse_ctx* ctx = fuse_req_ctx(req);
360 struct node* parent_node;
361 string parent_path;
362 string child_path;
363
364 errno = 0;
365 pthread_mutex_lock(&fuse->lock);
366 parent_node = lookup_node_by_id_locked(fuse, parent);
367 parent_path = get_node_path_locked(parent_node);
shafik458d1102019-09-06 18:21:36 +0100368 TRACE_FUSE(fuse) << "LOOKUP " << name << " @ " << parent << " (" << safe_name(parent_node)
369 << ")";
shafik1e3a2672019-08-16 14:51:55 +0100370 pthread_mutex_unlock(&fuse->lock);
371
372 child_path = parent_path + "/" + name;
373
374 return make_node_entry(req, parent_node, name, child_path, e);
375}
376
377static void pf_lookup(fuse_req_t req, fuse_ino_t parent, const char* name) {
378 struct fuse_entry_param e;
379
380 if (do_lookup(req, parent, name, &e))
381 fuse_reply_entry(req, &e);
382 else
383 fuse_reply_err(req, errno);
384}
385
386static void do_forget(struct fuse* fuse, fuse_ino_t ino, uint64_t nlookup) {
387 struct node* node = lookup_node_by_id_locked(fuse, ino);
shafik458d1102019-09-06 18:21:36 +0100388 TRACE_FUSE(fuse) << "FORGET #" << nlookup << " @ " << ino << " (" << safe_name(node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100389 if (node) {
390 __u64 n = nlookup;
391 release_node_n_locked(node, n);
392 }
393}
394
395static void pf_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) {
396 struct node* node;
397 struct fuse* fuse = get_fuse(req);
398
399 pthread_mutex_lock(&fuse->lock);
400 do_forget(fuse, ino, nlookup);
401 pthread_mutex_unlock(&fuse->lock);
402 fuse_reply_none(req);
403}
404
405static void pf_forget_multi(fuse_req_t req,
406 size_t count,
407 struct fuse_forget_data* forgets) {
408 struct fuse* fuse = get_fuse(req);
409
410 pthread_mutex_lock(&fuse->lock);
411 for (int i = 0; i < count; i++)
412 do_forget(fuse,
413 forgets[i].ino,
414 forgets[i].nlookup);
415 pthread_mutex_unlock(&fuse->lock);
416 fuse_reply_none(req);
417}
418
419static void pf_getattr(fuse_req_t req,
420 fuse_ino_t ino,
421 struct fuse_file_info* fi) {
422 struct fuse* fuse = get_fuse(req);
423 const struct fuse_ctx* ctx = fuse_req_ctx(req);
424 struct node* node;
425 string path;
426 struct stat s;
427
428 pthread_mutex_lock(&fuse->lock);
429 node = lookup_node_by_id_locked(fuse, ino);
430 path = get_node_path_locked(node);
shafik458d1102019-09-06 18:21:36 +0100431 TRACE_FUSE(fuse) << "GETATTR @ " << ino << " (" << safe_name(node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100432 pthread_mutex_unlock(&fuse->lock);
433
434 if (!node) fuse_reply_err(req, ENOENT);
435
436 memset(&s, 0, sizeof(s));
437 if (lstat(path.c_str(), &s) < 0) {
438 fuse_reply_err(req, errno);
439 } else {
440 fuse_reply_attr(req, &s, 10);
441 }
442}
443
444static void pf_setattr(fuse_req_t req,
445 fuse_ino_t ino,
446 struct stat* attr,
447 int to_set,
448 struct fuse_file_info* fi) {
449 struct node* node;
450 struct fuse* fuse = get_fuse(req);
451 const struct fuse_ctx* ctx = fuse_req_ctx(req);
452 string path;
453 struct timespec times[2];
454 struct stat* newattr;
455
456 pthread_mutex_lock(&fuse->lock);
457 node = lookup_node_by_id_locked(fuse, ino);
458 path = get_node_path_locked(node);
shafik458d1102019-09-06 18:21:36 +0100459 TRACE_FUSE(fuse) << "SETATTR valid=" << to_set << " @ " << ino << "(" << safe_name(node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100460 pthread_mutex_unlock(&fuse->lock);
461
462 if (!node) {
463 fuse_reply_err(req, ENOENT);
464 return;
465 }
466
467 /* XXX: incomplete implementation on purpose.
468 * chmod/chown should NEVER be implemented.*/
469
470 if ((to_set & FUSE_SET_ATTR_SIZE)
471 && truncate64(path.c_str(), attr->st_size) < 0) {
472 fuse_reply_err(req, errno);
473 return;
474 }
475
476 /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW
477 * are both set, then set it to the current time. Else, set it to the
478 * time specified in the request. Same goes for mtime. Use utimensat(2)
479 * as it allows ATIME and MTIME to be changed independently, and has
480 * nanosecond resolution which fuse also has.
481 */
482 if (to_set & (FATTR_ATIME | FATTR_MTIME)) {
483 times[0].tv_nsec = UTIME_OMIT;
484 times[1].tv_nsec = UTIME_OMIT;
485 if (to_set & FATTR_ATIME) {
486 if (to_set & FATTR_ATIME_NOW) {
487 times[0].tv_nsec = UTIME_NOW;
488 } else {
489 times[0].tv_sec = attr->st_atime;
490 // times[0].tv_nsec = attr->st_atime.tv_nsec;
491 }
492 }
493 if (to_set & FATTR_MTIME) {
494 if (to_set & FATTR_MTIME_NOW) {
495 times[1].tv_nsec = UTIME_NOW;
496 } else {
497 times[1].tv_sec = attr->st_mtime;
498 // times[1].tv_nsec = attr->st_mtime.tv_nsec;
499 }
500 }
shafik458d1102019-09-06 18:21:36 +0100501 TRACE_FUSE(fuse) << "Calling utimensat on " << path << " with atime " << times[0].tv_sec
502 << " mtime=" << times[1].tv_sec;
shafik1e3a2672019-08-16 14:51:55 +0100503 if (utimensat(-1, path.c_str(), times, 0) < 0) {
504 fuse_reply_err(req, errno);
505 return;
506 }
507 }
508
Zima9fcd552019-08-29 15:17:04 +0100509 lstat(path.c_str(), attr);
shafik1e3a2672019-08-16 14:51:55 +0100510 fuse_reply_attr(req, attr, 10);
511}
512/*
513static void pf_readlink(fuse_req_t req, fuse_ino_t ino)
514{
515 cout << "TODO:" << __func__;
516}
517*/
518static void pf_mknod(fuse_req_t req,
519 fuse_ino_t parent,
520 const char* name,
521 mode_t mode,
522 dev_t rdev) {
523 struct fuse* fuse = get_fuse(req);
524 const struct fuse_ctx* ctx = fuse_req_ctx(req);
525 struct node* parent_node;
526 string parent_path;
527 string child_path;
528 struct fuse_entry_param e;
529
530 pthread_mutex_lock(&fuse->lock);
531 parent_node = lookup_node_by_id_locked(fuse, parent);
532 parent_path = get_node_path_locked(parent_node);
shafik458d1102019-09-06 18:21:36 +0100533 TRACE_FUSE(fuse) << "MKNOD " << name << " 0" << std::oct << mode << " @ " << parent << " ("
534 << safe_name(parent_node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100535 pthread_mutex_unlock(&fuse->lock);
536
537 if (!parent_node) {
538 fuse_reply_err(req, ENOENT);
539 return;
540 }
541 child_path = parent_path + "/" + name;
542
543 mode = (mode & (~0777)) | 0664;
544 if (mknod(child_path.c_str(), mode, rdev) < 0) {
545 fuse_reply_err(req, errno);
546 return;
547 }
548 if (make_node_entry(req, parent_node, name, child_path, &e))
549 fuse_reply_entry(req, &e);
550 else
551 fuse_reply_err(req, errno);
552}
553
554static void pf_mkdir(fuse_req_t req,
555 fuse_ino_t parent,
556 const char* name,
557 mode_t mode) {
558 struct fuse* fuse = get_fuse(req);
559 const struct fuse_ctx* ctx = fuse_req_ctx(req);
560 struct node* parent_node;
561 string parent_path;
562 string child_path;
563 struct fuse_entry_param e;
564
565 pthread_mutex_lock(&fuse->lock);
566 parent_node = lookup_node_by_id_locked(fuse, parent);
567 parent_path = get_node_path_locked(parent_node);
shafik458d1102019-09-06 18:21:36 +0100568 TRACE_FUSE(fuse) << "MKDIR " << name << " 0" << std::oct << mode << " @ " << parent << " ("
569 << safe_name(parent_node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100570 pthread_mutex_unlock(&fuse->lock);
571
572 child_path = parent_path + "/" + name;
573
574 mode = (mode & (~0777)) | 0775;
575 if (mkdir(child_path.c_str(), mode) < 0) {
576 fuse_reply_err(req, errno);
577 return;
578 }
579
580 if (make_node_entry(req, parent_node, name, child_path, &e))
581 fuse_reply_entry(req, &e);
582 else
583 fuse_reply_err(req, errno);
584}
585
586static void pf_unlink(fuse_req_t req, fuse_ino_t parent, const char* name) {
587 struct fuse* fuse = get_fuse(req);
588 const struct fuse_ctx* ctx = fuse_req_ctx(req);
589 struct node* parent_node;
590 struct node* child_node;
591 string parent_path;
592 string child_path;
593
594 pthread_mutex_lock(&fuse->lock);
595 parent_node = lookup_node_by_id_locked(fuse, parent);
596 parent_path = get_node_path_locked(parent_node);
shafik458d1102019-09-06 18:21:36 +0100597 TRACE_FUSE(fuse) << "UNLINK " << name << " @ " << parent << "(" << safe_name(parent_node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100598 pthread_mutex_unlock(&fuse->lock);
599
600 child_path = parent_path + "/" + name;
601
602 if (unlink(child_path.c_str()) < 0) {
603 fuse_reply_err(req, errno);
604 return;
605 }
606 pthread_mutex_lock(&fuse->lock);
607 child_node = lookup_child_by_name_locked(parent_node, name);
608 if (child_node) {
609 child_node->deleted = true;
610 }
611 pthread_mutex_unlock(&fuse->lock);
612
613 fuse_reply_err(req, 0);
614}
615
616static void pf_rmdir(fuse_req_t req, fuse_ino_t parent, const char* name) {
617 struct fuse* fuse = get_fuse(req);
618 const struct fuse_ctx* ctx = fuse_req_ctx(req);
619 struct node* child_node;
620 struct node* parent_node;
621 string parent_path;
622 string child_path;
623
624 pthread_mutex_lock(&fuse->lock);
625 parent_node = lookup_node_by_id_locked(fuse, parent);
626 parent_path = get_node_path_locked(parent_node);
shafik458d1102019-09-06 18:21:36 +0100627 TRACE_FUSE(fuse) << "RMDIR " << name << " @ " << parent << "(" << safe_name(parent_node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100628 pthread_mutex_unlock(&fuse->lock);
629
630 child_path = parent_path + "/" + name;
631
632 if (rmdir(child_path.c_str()) < 0) {
633 fuse_reply_err(req, errno);
634 return;
635 }
636 pthread_mutex_lock(&fuse->lock);
637 child_node = lookup_child_by_name_locked(parent_node, name);
638 if (child_node) {
639 child_node->deleted = true;
640 }
641 pthread_mutex_unlock(&fuse->lock);
642
643 fuse_reply_err(req, 0);
644}
645/*
646static void pf_symlink(fuse_req_t req, const char* link, fuse_ino_t parent,
647 const char* name)
648{
649 cout << "TODO:" << __func__;
650}
651*/
652static void pf_rename(fuse_req_t req,
653 fuse_ino_t parent,
654 const char* name,
655 fuse_ino_t newparent,
656 const char* newname,
657 unsigned int flags) {
658 struct fuse* fuse = get_fuse(req);
659 const struct fuse_ctx* ctx = fuse_req_ctx(req);
660 struct node* old_parent_node;
661 struct node* new_parent_node;
662 struct node* child_node;
663 string old_parent_path;
664 string new_parent_path;
665 string old_child_path;
666 string new_child_path;
667 int res, search;
668
669 pthread_mutex_lock(&fuse->lock);
670 old_parent_node = lookup_node_by_id_locked(fuse, parent);
671 old_parent_path = get_node_path_locked(old_parent_node);
672 new_parent_node = lookup_node_by_id_locked(fuse, newparent);
673 new_parent_path = get_node_path_locked(new_parent_node);
shafik458d1102019-09-06 18:21:36 +0100674 TRACE_FUSE(fuse) << "RENAME " << name << " -> " << newname << " @ " << parent << " ("
675 << safe_name(old_parent_node) << ") -> " << newparent << " ("
676 << safe_name(new_parent_node) << ")";
shafik1e3a2672019-08-16 14:51:55 +0100677 if (!old_parent_node || !new_parent_node) {
678 res = ENOENT;
679 goto lookup_error;
680 }
681
682 child_node = lookup_child_by_name_locked(old_parent_node, name);
683 old_child_path = get_node_path_locked(child_node);
684 acquire_node_locked(child_node);
685 pthread_mutex_unlock(&fuse->lock);
686
687 new_child_path = new_parent_path + "/" + newname;
688
shafik458d1102019-09-06 18:21:36 +0100689 TRACE_FUSE(fuse) << "RENAME " << old_child_path << " -> " << new_child_path;
shafik1e3a2672019-08-16 14:51:55 +0100690 res = rename(old_child_path.c_str(), new_child_path.c_str());
691 if (res < 0) {
692 res = errno;
693 goto io_error;
694 }
695
696 pthread_mutex_lock(&fuse->lock);
Zim0861ba32019-09-19 22:39:15 +0100697 child_node->name = newname;
shafik1e3a2672019-08-16 14:51:55 +0100698 if (parent != newparent) {
699 remove_node_from_parent_locked(child_node);
shafik1e3a2672019-08-16 14:51:55 +0100700 // do any location based fixups here
701 add_node_to_parent_locked(child_node, new_parent_node);
702 }
703 goto done;
704
705 io_error:
706 pthread_mutex_lock(&fuse->lock);
707 done:
708 release_node_locked(child_node);
709 lookup_error:
710 pthread_mutex_unlock(&fuse->lock);
711 fuse_reply_err(req, res);
712}
713/*
714static void pf_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
715 const char* newname)
716{
717 cout << "TODO:" << __func__;
718}
719*/
720
721static void pf_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
722 struct node* node;
723 string path;
724 struct fuse* fuse = get_fuse(req);
725 const struct fuse_ctx* ctx = fuse_req_ctx(req);
726 struct fuse_open_out out;
727 struct handle* h;
728
729 pthread_mutex_lock(&fuse->lock);
730 node = lookup_node_by_id_locked(fuse, ino);
731 path = get_node_path_locked(node);
shafik458d1102019-09-06 18:21:36 +0100732 TRACE_FUSE(fuse) << "OPEN 0" << std::oct << fi->flags << " @ " << ino << " (" << safe_name(node)
733 << ")";
shafik1e3a2672019-08-16 14:51:55 +0100734 pthread_mutex_unlock(&fuse->lock);
735
736 if (!node) {
737 fuse_reply_err(req, ENOENT);
738 return;
739 }
740
741 h = new handle();
742 if (!h) {
743 fuse_reply_err(req, ENOMEM);
744 return;
745 }
shafik458d1102019-09-06 18:21:36 +0100746 TRACE_FUSE(fuse) << "OPEN " << path;
shafik1e3a2672019-08-16 14:51:55 +0100747 h->fd = open(path.c_str(), fi->flags);
748 if (h->fd < 0) {
749 delete h;
750 fuse_reply_err(req, errno);
751 return;
752 }
shafikc3f62672019-08-30 11:15:48 +0100753 // Initialize ri as nullptr to know that redaction info has not been checked yet.
754 h->ri = nullptr;
shafik1e3a2672019-08-16 14:51:55 +0100755 fi->fh = ptr_to_id(h);
756 fuse_reply_open(req, fi);
757}
758
shafikc3f62672019-08-30 11:15:48 +0100759static void do_read(fuse_req_t req, size_t size, off_t off, struct fuse_file_info* fi) {
shafik1e3a2672019-08-16 14:51:55 +0100760 struct handle* h = reinterpret_cast<struct handle*>(fi->fh);
761 struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
762
763 buf.buf[0].fd = h->fd;
764 buf.buf[0].pos = off;
765 buf.buf[0].flags =
766 (enum fuse_buf_flags) (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
767
768 fuse_reply_data(req, &buf, (enum fuse_buf_copy_flags) 0);
769}
shafikc3f62672019-08-30 11:15:48 +0100770
771static bool range_contains(const RedactionRange& rr, off_t off) {
772 return rr.first <= off && off <= rr.second;
773}
774
775/**
776 * Sets the parameters for a fuse_buf that reads from memory, including flags.
shafikb334a612019-09-30 20:38:16 +0100777 * Makes buf->mem point to an already mapped region of zeroized memory.
778 * This memory is read only.
shafikc3f62672019-08-30 11:15:48 +0100779 */
shafikb334a612019-09-30 20:38:16 +0100780static void create_mem_fuse_buf(size_t size, fuse_buf* buf, struct fuse* fuse) {
shafikc3f62672019-08-30 11:15:48 +0100781 buf->size = size;
shafikb334a612019-09-30 20:38:16 +0100782 buf->mem = fuse->zero_addr;
shafikc3f62672019-08-30 11:15:48 +0100783 buf->flags = static_cast<fuse_buf_flags>(0 /*read from fuse_buf.mem*/);
784 buf->pos = -1;
785 buf->fd = -1;
786}
787
788/**
789 * Sets the parameters for a fuse_buf that reads from file, including flags.
790 */
791static void create_file_fuse_buf(size_t size, off_t pos, int fd, fuse_buf* buf) {
792 buf->size = size;
793 buf->fd = fd;
794 buf->pos = pos;
795 buf->flags = static_cast<fuse_buf_flags>(FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
796 buf->mem = nullptr;
797}
798
799static void do_read_with_redaction(fuse_req_t req, size_t size, off_t off, fuse_file_info* fi) {
800 struct handle* h = reinterpret_cast<struct handle*>(fi->fh);
801 auto overlapping_rr = h->ri->getOverlappingRedactionRanges(size, off);
802
803 if (overlapping_rr->size() <= 0) {
804 // no relevant redaction ranges for this request
805 do_read(req, size, off, fi);
806 return;
807 }
808 // the number of buffers we need, if the read doesn't start or end with
809 // a redaction range.
810 int num_bufs = overlapping_rr->size() * 2 + 1;
811 if (overlapping_rr->front().first <= off) {
812 // the beginning of the read request is redacted
813 num_bufs--;
814 }
815 if (overlapping_rr->back().second >= off + size) {
816 // the end of the read request is redacted
817 num_bufs--;
818 }
819 auto bufvec_ptr = std::unique_ptr<fuse_bufvec, decltype(free)*>{
820 reinterpret_cast<fuse_bufvec*>(
821 malloc(sizeof(fuse_bufvec) + (num_bufs - 1) * sizeof(fuse_buf))),
822 free};
823 fuse_bufvec& bufvec = *bufvec_ptr;
824
825 // initialize bufvec
826 bufvec.count = num_bufs;
827 bufvec.idx = 0;
828 bufvec.off = 0;
shafikc3f62672019-08-30 11:15:48 +0100829
830 int rr_idx = 0;
831 off_t start = off;
832 // Add a dummy redaction range to make sure we don't go out of vector
833 // limits when computing the end of the last non-redacted range.
834 // This ranges is invalid because its starting point is larger than it's ending point.
835 overlapping_rr->push_back(RedactionRange(LLONG_MAX, LLONG_MAX - 1));
836
837 for (int i = 0; i < num_bufs; ++i) {
838 off_t end;
839 if (range_contains(overlapping_rr->at(rr_idx), start)) {
840 // Handle a redacted range
841 // end should be the end of the redacted range, but can't be out of
842 // the read request bounds
843 end = std::min(static_cast<off_t>(off + size - 1), overlapping_rr->at(rr_idx).second);
shafikb334a612019-09-30 20:38:16 +0100844 create_mem_fuse_buf(/*size*/ end - start + 1, &(bufvec.buf[i]), get_fuse(req));
shafikc3f62672019-08-30 11:15:48 +0100845 ++rr_idx;
846 } else {
847 // Handle a non-redacted range
848 // end should be right before the next redaction range starts or
849 // the end of the read request
850 end = std::min(static_cast<off_t>(off + size - 1),
851 overlapping_rr->at(rr_idx).first - 1);
852 create_file_fuse_buf(/*size*/ end - start + 1, start, h->fd, &(bufvec.buf[i]));
853 }
854 start = end + 1;
855 }
856
857 fuse_reply_data(req, &bufvec, static_cast<fuse_buf_copy_flags>(0));
858}
859
860static void pf_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
861 struct fuse_file_info* fi) {
862 struct handle* h = reinterpret_cast<struct handle*>(fi->fh);
863 struct fuse* fuse = get_fuse(req);
864 TRACE_FUSE(fuse) << "READ";
865 if (!h->ri) {
866 h->ri = fuse->mp->GetRedactionInfo(req->ctx.uid, h->fd);
867 if (!h->ri) {
868 errno = EIO;
869 fuse_reply_err(req, errno);
870 return;
871 }
872 }
873
874 if (h->ri->isRedactionNeeded()) {
875 do_read_with_redaction(req, size, off, fi);
876 } else {
877 do_read(req, size, off, fi);
878 }
879}
880
shafik1e3a2672019-08-16 14:51:55 +0100881/*
882static void pf_write(fuse_req_t req, fuse_ino_t ino, const char* buf,
883 size_t size, off_t off, struct fuse_file_info* fi)
884{
885 cout << "TODO:" << __func__;
886}
887*/
888
889static void pf_write_buf(fuse_req_t req,
890 fuse_ino_t ino,
891 struct fuse_bufvec* bufv,
892 off_t off,
893 struct fuse_file_info* fi) {
894 struct handle* h = reinterpret_cast<struct handle*>(fi->fh);
895 struct fuse_bufvec buf = FUSE_BUFVEC_INIT(fuse_buf_size(bufv));
896 ssize_t size;
897
898 buf.buf[0].fd = h->fd;
899 buf.buf[0].pos = off;
900 buf.buf[0].flags =
901 (enum fuse_buf_flags) (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
902 size = fuse_buf_copy(&buf, bufv, (enum fuse_buf_copy_flags) 0);
903
904 if (size < 0)
905 fuse_reply_err(req, -size);
906 else
907 fuse_reply_write(req, size);
908}
909// Haven't tested this one. Not sure what calls it.
910#if 0
911static void pf_copy_file_range(fuse_req_t req, fuse_ino_t ino_in,
912 off_t off_in, struct fuse_file_info* fi_in,
913 fuse_ino_t ino_out, off_t off_out,
914 struct fuse_file_info* fi_out, size_t len,
915 int flags)
916{
917 struct handle* h_in = reinterpret_cast<struct handle *>(fi_in->fh);
918 struct handle* h_out = reinterpret_cast<struct handle *>(fi_out->fh);
919 struct fuse_bufvec buf_in = FUSE_BUFVEC_INIT(len);
920 struct fuse_bufvec buf_out = FUSE_BUFVEC_INIT(len);
921 ssize_t size;
922
923 buf_in.buf[0].fd = h_in->fd;
924 buf_in.buf[0].pos = off_in;
925 buf_in.buf[0].flags = (enum fuse_buf_flags)(FUSE_BUF_IS_FD|FUSE_BUF_FD_SEEK);
926
927 buf_out.buf[0].fd = h_out->fd;
928 buf_out.buf[0].pos = off_out;
929 buf_out.buf[0].flags = (enum fuse_buf_flags)(FUSE_BUF_IS_FD|FUSE_BUF_FD_SEEK);
930 size = fuse_buf_copy(&buf_out, &buf_in, (enum fuse_buf_copy_flags) 0);
931
932 if (size < 0) {
933 fuse_reply_err(req, -size);
934 }
935
936 fuse_reply_write(req, size);
937}
938#endif
939static void pf_flush(fuse_req_t req,
940 fuse_ino_t ino,
941 struct fuse_file_info* fi) {
942 struct fuse* fuse = get_fuse(req);
shafik458d1102019-09-06 18:21:36 +0100943 TRACE_FUSE(fuse) << "FLUSH is a noop";
shafik1e3a2672019-08-16 14:51:55 +0100944 fuse_reply_err(req, 0);
945}
946
947static void pf_release(fuse_req_t req,
948 fuse_ino_t ino,
949 struct fuse_file_info* fi) {
950 struct fuse* fuse = get_fuse(req);
951 struct handle* h = reinterpret_cast<struct handle*>(fi->fh);
952
shafik458d1102019-09-06 18:21:36 +0100953 TRACE_FUSE(fuse) << "RELEASE " << h << "(" << h->fd << ")";
shafik1e3a2672019-08-16 14:51:55 +0100954 close(h->fd);
955 delete h;
956 fuse_reply_err(req, 0);
957}
958
959static int do_sync_common(int fd, bool datasync) {
960 int res = datasync ? fdatasync(fd) : fsync(fd);
961
962 if (res == -1) return errno;
963 return 0;
964}
965
966static void pf_fsync(fuse_req_t req,
967 fuse_ino_t ino,
968 int datasync,
969 struct fuse_file_info* fi) {
970 struct handle* h = reinterpret_cast<struct handle*>(fi->fh);
971 int err = do_sync_common(h->fd, datasync);
972
973 fuse_reply_err(req, err);
974}
975
976static void pf_fsyncdir(fuse_req_t req,
977 fuse_ino_t ino,
978 int datasync,
979 struct fuse_file_info* fi) {
980 struct dirhandle* h = reinterpret_cast<struct dirhandle*>(fi->fh);
981 int err = do_sync_common(dirfd(h->d), datasync);
982
983 fuse_reply_err(req, err);
984}
985
986static void pf_opendir(fuse_req_t req,
987 fuse_ino_t ino,
988 struct fuse_file_info* fi) {
shafik1e3a2672019-08-16 14:51:55 +0100989 struct fuse* fuse = get_fuse(req);
shafik458d1102019-09-06 18:21:36 +0100990 TRACE_FUSE(fuse) << "OPENDIR";
shafik1e3a2672019-08-16 14:51:55 +0100991 const struct fuse_ctx* ctx = fuse_req_ctx(req);
992 struct node* node;
993 string path;
994 struct dirhandle* h;
995
996 pthread_mutex_lock(&fuse->lock);
997 node = lookup_node_by_id_locked(fuse, ino);
998 path = get_node_path_locked(node);
shafik458d1102019-09-06 18:21:36 +0100999
1000 TRACE_FUSE(fuse) << "OPENDIR @ " << ino << " (" << safe_name(node) << ")";
shafik1e3a2672019-08-16 14:51:55 +01001001 pthread_mutex_unlock(&fuse->lock);
1002
1003 if (!node) {
1004 fuse_reply_err(req, ENOENT);
1005 return;
1006 }
1007
1008 h = new dirhandle();
1009 if (!h) {
1010 fuse_reply_err(req, ENOMEM);
1011 return;
1012 }
shafik458d1102019-09-06 18:21:36 +01001013 TRACE_FUSE(fuse) << "OPENDIR " << path;
shafik1e3a2672019-08-16 14:51:55 +01001014 h->d = opendir(path.c_str());
1015 if (!h->d) {
1016 delete h;
1017 fuse_reply_err(req, errno);
1018 return;
1019 }
1020 h->next_off = 0;
1021 fi->fh = ptr_to_id(h);
1022 fuse_reply_open(req, fi);
1023}
1024
1025#define READDIR_BUF 8192LU
1026
1027static void do_readdir_common(fuse_req_t req,
1028 fuse_ino_t ino,
1029 size_t size,
1030 off_t off,
1031 struct fuse_file_info* fi,
1032 bool plus) {
1033 struct fuse* fuse = get_fuse(req);
1034 struct dirhandle* h = reinterpret_cast<struct dirhandle*>(fi->fh);
Jeff Sharkey7469b982019-08-28 16:51:02 -06001035 size_t len = std::min<size_t>(size, READDIR_BUF);
shafik1e3a2672019-08-16 14:51:55 +01001036 char buf[READDIR_BUF];
1037 size_t used = 0;
1038 struct dirent* de;
1039 struct fuse_entry_param e;
Sahana Rao6f9ea982019-09-20 12:21:33 +01001040 size_t entry_size = 0;
shafik1e3a2672019-08-16 14:51:55 +01001041
shafik458d1102019-09-06 18:21:36 +01001042 TRACE_FUSE(fuse) << "READDIR " << h;
shafik1e3a2672019-08-16 14:51:55 +01001043 if (off != h->next_off) {
shafik458d1102019-09-06 18:21:36 +01001044 TRACE_FUSE(fuse) << " calling seekdir(" << h->d << ", " << off << ")";
shafik1e3a2672019-08-16 14:51:55 +01001045 seekdir(h->d, off);
1046 }
Sahana Rao6f9ea982019-09-20 12:21:33 +01001047 while ((de = readdir(h->d)) != NULL) {
shafik1e3a2672019-08-16 14:51:55 +01001048 off += 1;
1049 errno = 0;
1050 h->next_off = de->d_off;
1051 if (plus) {
1052 if (do_lookup(req, ino, de->d_name, &e))
Sahana Rao6f9ea982019-09-20 12:21:33 +01001053 entry_size = fuse_add_direntry_plus(req, buf + used, len - used, de->d_name, &e,
1054 de->d_off);
shafik1e3a2672019-08-16 14:51:55 +01001055 else {
1056 fuse_reply_err(req, errno);
1057 return;
1058 }
1059 } else {
1060 e.attr.st_ino = FUSE_UNKNOWN_INO;
1061 e.attr.st_mode = de->d_type << 12;
Sahana Rao6f9ea982019-09-20 12:21:33 +01001062 entry_size =
1063 fuse_add_direntry(req, buf + used, len - used, de->d_name, &e.attr, de->d_off);
shafik1e3a2672019-08-16 14:51:55 +01001064 }
Sahana Rao6f9ea982019-09-20 12:21:33 +01001065 // If buffer in fuse_add_direntry[_plus] is not large enough then
1066 // the entry is not added to buffer but the size of the entry is still
1067 // returned. Check available buffer size + returned entry size is less
1068 // than actual buffer size to confirm entry is added to buffer.
1069 if (used + entry_size > len) break;
1070 used += entry_size;
shafik1e3a2672019-08-16 14:51:55 +01001071 }
1072
1073 if (!de && errno != 0)
1074 fuse_reply_err(req, errno);
1075 else
1076 fuse_reply_buf(req, buf, used);
1077}
1078
1079static void pf_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1080 struct fuse_file_info* fi) {
1081 do_readdir_common(req, ino, size, off, fi, false);
1082}
1083
1084static void pf_readdirplus(fuse_req_t req,
1085 fuse_ino_t ino,
1086 size_t size,
1087 off_t off,
1088 struct fuse_file_info* fi) {
1089 do_readdir_common(req, ino, size, off, fi, true);
1090}
1091
1092static void pf_releasedir(fuse_req_t req,
1093 fuse_ino_t ino,
1094 struct fuse_file_info* fi) {
1095 struct fuse* fuse = get_fuse(req);
1096 struct dirhandle* h = reinterpret_cast<struct dirhandle*>(fi->fh);
1097
shafik458d1102019-09-06 18:21:36 +01001098 TRACE_FUSE(fuse) << "RELEASEDIR " << h;
shafik1e3a2672019-08-16 14:51:55 +01001099 closedir(h->d);
1100 delete h;
1101 fuse_reply_err(req, 0);
1102}
1103
1104static void pf_statfs(fuse_req_t req, fuse_ino_t ino) {
1105 struct statvfs st;
1106 struct fuse* fuse = get_fuse(req);
1107
1108 if (statvfs(fuse->root.name.c_str(), &st))
1109 fuse_reply_err(req, errno);
1110 else
1111 fuse_reply_statfs(req, &st);
1112}
1113/*
1114static void pf_setxattr(fuse_req_t req, fuse_ino_t ino, const char* name,
1115 const char* value, size_t size, int flags)
1116{
1117 cout << "TODO:" << __func__;
1118}
1119
1120static void pf_getxattr(fuse_req_t req, fuse_ino_t ino, const char* name,
1121 size_t size)
1122{
1123 cout << "TODO:" << __func__;
1124}
1125
1126static void pf_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
1127{
1128 cout << "TODO:" << __func__;
1129}
1130
1131static void pf_removexattr(fuse_req_t req, fuse_ino_t ino, const char* name)
1132{
1133 cout << "TODO:" << __func__;
Zima9fcd552019-08-29 15:17:04 +01001134}*/
1135
1136static void pf_access(fuse_req_t req, fuse_ino_t ino, int mask) {
1137 struct fuse* fuse = get_fuse(req);
1138 const struct fuse_ctx* ctx = fuse_req_ctx(req);
1139
1140 pthread_mutex_lock(&fuse->lock);
1141 struct node* node = lookup_node_by_id_locked(fuse, ino);
1142 string path = get_node_path_locked(node);
shafik458d1102019-09-06 18:21:36 +01001143 TRACE_FUSE(fuse) << "ACCESS " << path;
Zima9fcd552019-08-29 15:17:04 +01001144 pthread_mutex_unlock(&fuse->lock);
1145
1146 int res = access(path.c_str(), F_OK);
1147 fuse_reply_err(req, res ? errno : 0);
shafik1e3a2672019-08-16 14:51:55 +01001148}
Zima9fcd552019-08-29 15:17:04 +01001149
shafik1e3a2672019-08-16 14:51:55 +01001150static void pf_create(fuse_req_t req,
1151 fuse_ino_t parent,
1152 const char* name,
1153 mode_t mode,
1154 struct fuse_file_info* fi) {
1155 struct fuse* fuse = get_fuse(req);
1156 const struct fuse_ctx* ctx = fuse_req_ctx(req);
1157 struct node* parent_node;
1158 string parent_path;
1159 string child_path;
1160 struct fuse_entry_param e;
1161 struct handle* h;
1162
1163 pthread_mutex_lock(&fuse->lock);
1164 parent_node = lookup_node_by_id_locked(fuse, parent);
1165 parent_path = get_node_path_locked(parent_node);
shafik458d1102019-09-06 18:21:36 +01001166 TRACE_FUSE(fuse) << "CREATE " << name << " 0" << std::oct << mode << " @ " << parent << " ("
1167 << safe_name(parent_node) << ")";
shafik1e3a2672019-08-16 14:51:55 +01001168 pthread_mutex_unlock(&fuse->lock);
1169
1170 child_path = parent_path + "/" + name;
1171
1172 h = new handle();
1173 if (!h) {
1174 fuse_reply_err(req, ENOMEM);
1175 return;
1176 }
1177 mode = (mode & (~0777)) | 0664;
1178 h->fd = open(child_path.c_str(),
1179 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
1180 mode);
1181 if (h->fd < 0) {
1182 delete h;
1183 fuse_reply_err(req, errno);
1184 return;
1185 }
1186
1187 fi->fh = ptr_to_id(h);
1188 if (make_node_entry(req, parent_node, name, child_path, &e)) {
1189 fuse_reply_create(req, &e, fi);
1190 } else {
1191 fuse_reply_err(req, errno);
1192 }
1193}
1194/*
1195static void pf_getlk(fuse_req_t req, fuse_ino_t ino,
1196 struct fuse_file_info* fi, struct flock* lock)
1197{
1198 cout << "TODO:" << __func__;
1199}
1200
1201static void pf_setlk(fuse_req_t req, fuse_ino_t ino,
1202 struct fuse_file_info* fi,
1203 struct flock* lock, int sleep)
1204{
1205 cout << "TODO:" << __func__;
1206}
1207
1208static void pf_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
1209 uint64_t idx)
1210{
1211 cout << "TODO:" << __func__;
1212}
1213
1214static void pf_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
1215 void* arg, struct fuse_file_info* fi, unsigned flags,
1216 const void* in_buf, size_t in_bufsz, size_t out_bufsz)
1217{
1218 cout << "TODO:" << __func__;
1219}
1220
1221static void pf_poll(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi,
1222 struct fuse_pollhandle* ph)
1223{
1224 cout << "TODO:" << __func__;
1225}
1226
1227static void pf_retrieve_reply(fuse_req_t req, void* cookie, fuse_ino_t ino,
1228 off_t offset, struct fuse_bufvec* bufv)
1229{
1230 cout << "TODO:" << __func__;
1231}
1232
1233static void pf_flock(fuse_req_t req, fuse_ino_t ino,
1234 struct fuse_file_info* fi, int op)
1235{
1236 cout << "TODO:" << __func__;
1237}
1238
1239static void pf_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
1240 off_t offset, off_t length, struct fuse_file_info* fi)
1241{
1242 cout << "TODO:" << __func__;
1243}
1244*/
1245
1246static struct fuse_lowlevel_ops ops{
shafik8b57cd52019-09-06 10:51:29 +01001247 .init = pf_init,
1248 /*.destroy = pf_destroy,*/
1249 .lookup = pf_lookup, .forget = pf_forget, .forget_multi = pf_forget_multi,
1250 .getattr = pf_getattr, .setattr = pf_setattr,
1251 /*.readlink = pf_readlink,*/
1252 .mknod = pf_mknod, .mkdir = pf_mkdir, .unlink = pf_unlink, .rmdir = pf_rmdir,
1253 /*.symlink = pf_symlink,*/
1254 .rename = pf_rename,
1255 /*.link = pf_link,*/
1256 .open = pf_open, .read = pf_read,
1257 /*.write = pf_write,*/
1258 .write_buf = pf_write_buf,
1259 /*.copy_file_range = pf_copy_file_range,*/
1260 .flush = pf_flush, .release = pf_release, .fsync = pf_fsync, .fsyncdir = pf_fsyncdir,
1261 .opendir = pf_opendir, .readdir = pf_readdir, .readdirplus = pf_readdirplus,
1262 .releasedir = pf_releasedir, .statfs = pf_statfs,
1263 /*.setxattr = pf_setxattr,
1264 .getxattr = pf_getxattr,
1265 .listxattr = pf_listxattr,
1266 .removexattr = pf_removexattr,*/
1267 .access = pf_access, .create = pf_create,
1268 /*.getlk = pf_getlk,
1269 .setlk = pf_setlk,
1270 .bmap = pf_bmap,
1271 .ioctl = pf_ioctl,
1272 .poll = pf_poll,
1273 .retrieve_reply = pf_retrieve_reply,*/
1274 /*.flock = pf_flock,
1275 .fallocate = pf_fallocate,*/
shafik1e3a2672019-08-16 14:51:55 +01001276};
1277
1278static struct fuse_loop_config config = {
1279 .clone_fd = 0,
1280 .max_idle_threads = 10,
1281};
1282
shafikc3f62672019-08-30 11:15:48 +01001283FuseDaemon::FuseDaemon(JNIEnv* env, jobject mediaProvider) : mp(env, mediaProvider) {}
shafik1e3a2672019-08-16 14:51:55 +01001284
Zim3e45d9b2019-08-19 21:14:14 +01001285void FuseDaemon::Stop() {}
shafik1e3a2672019-08-16 14:51:55 +01001286
Zim3e45d9b2019-08-19 21:14:14 +01001287void FuseDaemon::Start(const int fd, const std::string& dest_path, const std::string& source_path) {
shafik1e3a2672019-08-16 14:51:55 +01001288 struct fuse_args args;
1289 struct fuse_cmdline_opts opts;
shafik1e3a2672019-08-16 14:51:55 +01001290
shafik458d1102019-09-06 18:21:36 +01001291 SetMinimumLogSeverity(android::base::DEBUG);
1292
shafik1e3a2672019-08-16 14:51:55 +01001293 struct stat stat;
shafik1e3a2672019-08-16 14:51:55 +01001294
Zim3e45d9b2019-08-19 21:14:14 +01001295 if (lstat(source_path.c_str(), &stat)) {
shafik458d1102019-09-06 18:21:36 +01001296 LOG(ERROR) << "ERROR: failed to stat source " << source_path;
Zim3e45d9b2019-08-19 21:14:14 +01001297 return;
1298 }
shafik1e3a2672019-08-16 14:51:55 +01001299
Zim3e45d9b2019-08-19 21:14:14 +01001300 if (!S_ISDIR(stat.st_mode)) {
shafik458d1102019-09-06 18:21:36 +01001301 LOG(ERROR) << "ERROR: source is not a directory";
Zim3e45d9b2019-08-19 21:14:14 +01001302 return;
1303 }
shafik1e3a2672019-08-16 14:51:55 +01001304
1305 args = FUSE_ARGS_INIT(0, nullptr);
shafikb334a612019-09-30 20:38:16 +01001306 if (fuse_opt_add_arg(&args, source_path.c_str()) || fuse_opt_add_arg(&args, "-odebug") ||
1307 fuse_opt_add_arg(&args, ("-omax_read=" + std::to_string(MAX_READ_SIZE)).c_str())) {
shafik458d1102019-09-06 18:21:36 +01001308 LOG(ERROR) << "ERROR: failed to set options";
shafik1e3a2672019-08-16 14:51:55 +01001309 return;
1310 }
1311
1312 struct fuse fuse_default;
1313 memset(&fuse_default, 0, sizeof(fuse_default));
1314
1315 pthread_mutex_init(&fuse_default.lock, NULL);
1316
1317 fuse_default.next_generation = 0;
1318 fuse_default.inode_ctr = 1;
1319
1320 memset(&fuse_default.root, 0, sizeof(fuse_default.root));
1321 fuse_default.root.nid = FUSE_ROOT_ID; /* 1 */
1322 fuse_default.root.refcount = 2;
1323 fuse_default.root.name = source_path;
1324
1325 fuse_default.source_path = source_path;
1326
1327 fuse_default.dest_path = dest_path;
1328
shafikc3f62672019-08-30 11:15:48 +01001329 fuse_default.mp = &mp;
1330
shafik1e3a2672019-08-16 14:51:55 +01001331 umask(0);
1332
shafikb334a612019-09-30 20:38:16 +01001333 // Used by pf_read: redacted ranges are represented by zeroized ranges of bytes,
1334 // so we mmap the maximum length of redacted ranges in the beginning and save memory allocations
1335 // on each read.
1336 fuse_default.zero_addr = static_cast<char*>(mmap(
1337 NULL, MAX_READ_SIZE, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, /*fd*/ -1, /*off*/ 0));
1338 if (fuse_default.zero_addr == MAP_FAILED) {
1339 LOG(FATAL) << "mmap failed - could not start fuse! errno = " << errno;
1340 }
1341
shafik458d1102019-09-06 18:21:36 +01001342 LOG(INFO) << "Starting fuse...";
shafik1e3a2672019-08-16 14:51:55 +01001343 struct fuse_session
1344 * se = fuse_session_new(&args, &ops, sizeof(ops), &fuse_default);
1345 se->fd = fd;
1346 se->mountpoint = strdup(dest_path.c_str());
Zim3e45d9b2019-08-19 21:14:14 +01001347
1348 // Single thread. Useful for debugging
1349 // fuse_session_loop(se);
1350 // Multi-threaded
shafik1e3a2672019-08-16 14:51:55 +01001351 fuse_session_loop_mt(se, &config);
Zim3e45d9b2019-08-19 21:14:14 +01001352
shafikb334a612019-09-30 20:38:16 +01001353 if (!munmap(fuse_default.zero_addr, MAX_READ_SIZE)) {
1354 LOG(ERROR) << "munmap failed! errno = " << errno;
1355 }
1356
shafik458d1102019-09-06 18:21:36 +01001357 LOG(INFO) << "Ending fuse...";
shafik1e3a2672019-08-16 14:51:55 +01001358 return;
1359}
1360} //namespace fuse
shafik8b57cd52019-09-06 10:51:29 +01001361} // namespace mediaprovider