OSDN Git Service

c6db3c01aa0eafffae861aaf084818879f342de2
[android-x86/external-exfat.git] / fuse / main.c
1 /*
2         main.c (01.09.09)
3         FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
4
5         Free exFAT implementation.
6         Copyright (C) 2010-2018  Andrew Nayenko
7
8         This program is free software; you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 2 of the License, or
11         (at your option) any later version.
12
13         This program is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License along
19         with this program; if not, write to the Free Software Foundation, Inc.,
20         51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include <exfat.h>
24 #define FUSE_USE_VERSION 26
25 #include <fuse.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <inttypes.h>
32 #include <limits.h>
33 #include <sys/types.h>
34 #include <pwd.h>
35 #include <unistd.h>
36
37 #ifndef DEBUG
38         #define exfat_debug(format, ...)
39 #endif
40
41 #if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
42         #error FUSE 2.6 or later is required
43 #endif
44
45 const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
46                 "default_permissions";
47
48 struct exfat ef;
49
50 static struct exfat_node* get_node(const struct fuse_file_info* fi)
51 {
52         return (struct exfat_node*) (size_t) fi->fh;
53 }
54
55 static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
56 {
57         fi->fh = (uint64_t) (size_t) node;
58         fi->keep_cache = 1;
59 }
60
61 static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
62 {
63         struct exfat_node* node;
64         int rc;
65
66         exfat_debug("[%s] %s", __func__, path);
67
68         rc = exfat_lookup(&ef, &node, path);
69         if (rc != 0)
70                 return rc;
71
72         exfat_stat(&ef, node, stbuf);
73         exfat_put_node(&ef, node);
74         return 0;
75 }
76
77 static int fuse_exfat_truncate(const char* path, off_t size)
78 {
79         struct exfat_node* node;
80         int rc;
81
82         exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
83
84         rc = exfat_lookup(&ef, &node, path);
85         if (rc != 0)
86                 return rc;
87
88         rc = exfat_truncate(&ef, node, size, true);
89         if (rc != 0)
90         {
91                 exfat_flush_node(&ef, node);    /* ignore return code */
92                 exfat_put_node(&ef, node);
93                 return rc;
94         }
95         rc = exfat_flush_node(&ef, node);
96         exfat_put_node(&ef, node);
97         return rc;
98 }
99
100 static int fuse_exfat_readdir(const char* path, void* buffer,
101                 fuse_fill_dir_t filler, UNUSED off_t offset,
102                 UNUSED struct fuse_file_info* fi)
103 {
104         struct exfat_node* parent;
105         struct exfat_node* node;
106         struct exfat_iterator it;
107         int rc;
108         char name[EXFAT_UTF8_NAME_BUFFER_MAX];
109         struct stat stbuf;
110
111         exfat_debug("[%s] %s", __func__, path);
112
113         rc = exfat_lookup(&ef, &parent, path);
114         if (rc != 0)
115                 return rc;
116         if (!(parent->attrib & EXFAT_ATTRIB_DIR))
117         {
118                 exfat_put_node(&ef, parent);
119                 exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
120                 return -ENOTDIR;
121         }
122
123         filler(buffer, ".", NULL, 0);
124         filler(buffer, "..", NULL, 0);
125
126         rc = exfat_opendir(&ef, parent, &it);
127         if (rc != 0)
128         {
129                 exfat_put_node(&ef, parent);
130                 exfat_error("failed to open directory '%s'", path);
131                 return rc;
132         }
133         while ((node = exfat_readdir(&it)))
134         {
135                 exfat_get_name(node, name);
136                 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
137                                 name, node->is_contiguous ? "contiguous" : "fragmented",
138                                 node->size, node->start_cluster);
139                 exfat_stat(&ef, node, &stbuf);
140                 filler(buffer, name, &stbuf, 0);
141                 exfat_put_node(&ef, node);
142         }
143         exfat_closedir(&ef, &it);
144         exfat_put_node(&ef, parent);
145         return 0;
146 }
147
148 static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
149 {
150         struct exfat_node* node;
151         int rc;
152
153         exfat_debug("[%s] %s", __func__, path);
154
155         rc = exfat_lookup(&ef, &node, path);
156         if (rc != 0)
157                 return rc;
158         set_node(fi, node);
159         return 0;
160 }
161
162 static int fuse_exfat_create(const char* path, UNUSED mode_t mode,
163                 struct fuse_file_info* fi)
164 {
165         struct exfat_node* node;
166         int rc;
167
168         exfat_debug("[%s] %s 0%ho", __func__, path, mode);
169
170         rc = exfat_mknod(&ef, path);
171         if (rc != 0)
172                 return rc;
173         rc = exfat_lookup(&ef, &node, path);
174         if (rc != 0)
175                 return rc;
176         set_node(fi, node);
177         return 0;
178 }
179
180 static int fuse_exfat_release(UNUSED const char* path,
181                 struct fuse_file_info* fi)
182 {
183         /*
184            This handler is called by FUSE on close() syscall. If the FUSE
185            implementation does not call flush handler, we will flush node here.
186            But in this case we will not be able to return an error to the caller.
187            See fuse_exfat_flush() below.
188         */
189         exfat_debug("[%s] %s", __func__, path);
190         exfat_flush_node(&ef, get_node(fi));
191         exfat_put_node(&ef, get_node(fi));
192         return 0; /* FUSE ignores this return value */
193 }
194
195 static int fuse_exfat_flush(UNUSED const char* path, struct fuse_file_info* fi)
196 {
197         /*
198            This handler may be called by FUSE on close() syscall. FUSE also deals
199            with removals of open files, so we don't free clusters on close but
200            only on rmdir and unlink. If the FUSE implementation does not call this
201            handler we will flush node on release. See fuse_exfat_relase() above.
202         */
203         exfat_debug("[%s] %s", __func__, path);
204         return exfat_flush_node(&ef, get_node(fi));
205 }
206
207 static int fuse_exfat_fsync(UNUSED const char* path, UNUSED int datasync,
208                 UNUSED struct fuse_file_info *fi)
209 {
210         int rc;
211
212         exfat_debug("[%s] %s", __func__, path);
213         rc = exfat_flush_nodes(&ef);
214         if (rc != 0)
215                 return rc;
216         rc = exfat_flush(&ef);
217         if (rc != 0)
218                 return rc;
219         return exfat_fsync(ef.dev);
220 }
221
222 static int fuse_exfat_read(UNUSED const char* path, char* buffer,
223                 size_t size, off_t offset, struct fuse_file_info* fi)
224 {
225         exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
226         return exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
227 }
228
229 static int fuse_exfat_write(UNUSED const char* path, const char* buffer,
230                 size_t size, off_t offset, struct fuse_file_info* fi)
231 {
232         exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
233         return exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
234 }
235
236 static int fuse_exfat_unlink(const char* path)
237 {
238         struct exfat_node* node;
239         int rc;
240
241         exfat_debug("[%s] %s", __func__, path);
242
243         rc = exfat_lookup(&ef, &node, path);
244         if (rc != 0)
245                 return rc;
246
247         rc = exfat_unlink(&ef, node);
248         exfat_put_node(&ef, node);
249         if (rc != 0)
250                 return rc;
251         return exfat_cleanup_node(&ef, node);
252 }
253
254 static int fuse_exfat_rmdir(const char* path)
255 {
256         struct exfat_node* node;
257         int rc;
258
259         exfat_debug("[%s] %s", __func__, path);
260
261         rc = exfat_lookup(&ef, &node, path);
262         if (rc != 0)
263                 return rc;
264
265         rc = exfat_rmdir(&ef, node);
266         exfat_put_node(&ef, node);
267         if (rc != 0)
268                 return rc;
269         return exfat_cleanup_node(&ef, node);
270 }
271
272 static int fuse_exfat_mknod(const char* path, UNUSED mode_t mode,
273                 UNUSED dev_t dev)
274 {
275         exfat_debug("[%s] %s 0%ho", __func__, path, mode);
276         return exfat_mknod(&ef, path);
277 }
278
279 static int fuse_exfat_mkdir(const char* path, UNUSED mode_t mode)
280 {
281         exfat_debug("[%s] %s 0%ho", __func__, path, mode);
282         return exfat_mkdir(&ef, path);
283 }
284
285 static int fuse_exfat_rename(const char* old_path, const char* new_path)
286 {
287         exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
288         return exfat_rename(&ef, old_path, new_path);
289 }
290
291 static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
292 {
293         struct exfat_node* node;
294         int rc;
295
296         exfat_debug("[%s] %s", __func__, path);
297
298         rc = exfat_lookup(&ef, &node, path);
299         if (rc != 0)
300                 return rc;
301
302         exfat_utimes(node, tv);
303         rc = exfat_flush_node(&ef, node);
304         exfat_put_node(&ef, node);
305         return rc;
306 }
307
308 static int fuse_exfat_chmod(UNUSED const char* path, mode_t mode)
309 {
310         const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
311                         S_IRWXU | S_IRWXG | S_IRWXO;
312
313         exfat_debug("[%s] %s 0%ho", __func__, path, mode);
314         if (mode & ~VALID_MODE_MASK)
315                 return -EPERM;
316         return 0;
317 }
318
319 static int fuse_exfat_chown(UNUSED const char* path, uid_t uid, gid_t gid)
320 {
321         exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
322         if (uid != ef.uid || gid != ef.gid)
323                 return -EPERM;
324         return 0;
325 }
326
327 static int fuse_exfat_statfs(UNUSED const char* path, struct statvfs* sfs)
328 {
329         exfat_debug("[%s]", __func__);
330
331         sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
332         sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
333         sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
334         sfs->f_bavail = exfat_count_free_clusters(&ef);
335         sfs->f_bfree = sfs->f_bavail;
336         sfs->f_namemax = EXFAT_NAME_MAX;
337
338         /*
339            Below are fake values because in exFAT there is
340            a) no simple way to count files;
341            b) no such thing as inode;
342            So here we assume that inode = cluster.
343         */
344         sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
345         sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
346         sfs->f_ffree = sfs->f_bavail;
347
348         return 0;
349 }
350
351 static void* fuse_exfat_init(struct fuse_conn_info* fci)
352 {
353         exfat_debug("[%s]", __func__);
354 #ifdef FUSE_CAP_BIG_WRITES
355         fci->want |= FUSE_CAP_BIG_WRITES;
356 #endif
357
358         /* mark super block as dirty; failure isn't a big deal */
359         exfat_soil_super_block(&ef);
360
361         return NULL;
362 }
363
364 static void fuse_exfat_destroy(UNUSED void* unused)
365 {
366         exfat_debug("[%s]", __func__);
367         exfat_unmount(&ef);
368 }
369
370 static void usage(const char* prog)
371 {
372         fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
373         exit(1);
374 }
375
376 static struct fuse_operations fuse_exfat_ops =
377 {
378         .getattr        = fuse_exfat_getattr,
379         .truncate       = fuse_exfat_truncate,
380         .readdir        = fuse_exfat_readdir,
381         .open           = fuse_exfat_open,
382         .create         = fuse_exfat_create,
383         .release        = fuse_exfat_release,
384         .flush          = fuse_exfat_flush,
385         .fsync          = fuse_exfat_fsync,
386         .fsyncdir       = fuse_exfat_fsync,
387         .read           = fuse_exfat_read,
388         .write          = fuse_exfat_write,
389         .unlink         = fuse_exfat_unlink,
390         .rmdir          = fuse_exfat_rmdir,
391         .mknod          = fuse_exfat_mknod,
392         .mkdir          = fuse_exfat_mkdir,
393         .rename         = fuse_exfat_rename,
394         .utimens        = fuse_exfat_utimens,
395         .chmod          = fuse_exfat_chmod,
396         .chown          = fuse_exfat_chown,
397         .statfs         = fuse_exfat_statfs,
398         .init           = fuse_exfat_init,
399         .destroy        = fuse_exfat_destroy,
400 };
401
402 static char* add_option(char* options, const char* name, const char* value)
403 {
404         size_t size;
405         char* optionsf = options;
406
407         if (value)
408                 size = strlen(options) + strlen(name) + strlen(value) + 3;
409         else
410                 size = strlen(options) + strlen(name) + 2;
411
412         options = realloc(options, size);
413         if (options == NULL)
414         {
415                 free(optionsf);
416                 exfat_error("failed to reallocate options string");
417                 return NULL;
418         }
419         strcat(options, ",");
420         strcat(options, name);
421         if (value)
422         {
423                 strcat(options, "=");
424                 strcat(options, value);
425         }
426         return options;
427 }
428
429 static void escape(char* escaped, const char* orig)
430 {
431         do
432         {
433                 if (*orig == ',' || *orig == '\\')
434                         *escaped++ = '\\';
435         }
436         while ((*escaped++ = *orig++));
437 }
438
439 static char* add_fsname_option(char* options, const char* spec)
440 {
441         /* escaped string cannot be more than twice as big as the original one */
442         char* escaped = malloc(strlen(spec) * 2 + 1);
443
444         if (escaped == NULL)
445         {
446                 free(options);
447                 exfat_error("failed to allocate escaped string for %s", spec);
448                 return NULL;
449         }
450
451         /* on some platforms (e.g. Android, Solaris) device names can contain
452            commas */
453         escape(escaped, spec);
454         options = add_option(options, "fsname", escaped);
455         free(escaped);
456         return options;
457 }
458
459 static char* add_ro_option(char* options, bool ro)
460 {
461         return ro ? add_option(options, "ro", NULL) : options;
462 }
463
464 static char* add_user_option(char* options)
465 {
466         struct passwd* pw;
467
468         if (getuid() == 0)
469                 return options;
470
471         pw = getpwuid(getuid());
472         if (pw == NULL || pw->pw_name == NULL)
473         {
474                 free(options);
475                 exfat_error("failed to determine username");
476                 return NULL;
477         }
478         return add_option(options, "user", pw->pw_name);
479 }
480
481 static char* add_blksize_option(char* options, long cluster_size)
482 {
483         long page_size = sysconf(_SC_PAGESIZE);
484         char blksize[20];
485
486         if (page_size < 1)
487                 page_size = 0x1000;
488
489         snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
490         return add_option(options, "blksize", blksize);
491 }
492
493 static char* add_fuse_options(char* options, const char* spec, bool ro)
494 {
495         options = add_fsname_option(options, spec);
496         if (options == NULL)
497                 return NULL;
498         options = add_ro_option(options, ro);
499         if (options == NULL)
500                 return NULL;
501         options = add_user_option(options);
502         if (options == NULL)
503                 return NULL;
504         options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
505         if (options == NULL)
506                 return NULL;
507
508         return options;
509 }
510
511 int main(int argc, char* argv[])
512 {
513         struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
514         struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
515         const char* spec = NULL;
516         const char* mount_point = NULL;
517         char* mount_options;
518         int debug = 0;
519         struct fuse_chan* fc = NULL;
520         struct fuse* fh = NULL;
521         int opt;
522
523         printf("FUSE exfat %s\n", VERSION);
524
525         mount_options = strdup(default_options);
526         if (mount_options == NULL)
527         {
528                 exfat_error("failed to allocate options string");
529                 return 1;
530         }
531
532         while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
533         {
534                 switch (opt)
535                 {
536                 case 'd':
537                         debug = 1;
538                         break;
539                 case 'n':
540                         break;
541                 case 'o':
542                         mount_options = add_option(mount_options, optarg, NULL);
543                         if (mount_options == NULL)
544                                 return 1;
545                         break;
546                 case 'V':
547                         free(mount_options);
548                         puts("Copyright (C) 2010-2018  Andrew Nayenko");
549                         return 0;
550                 case 'v':
551                         break;
552                 default:
553                         free(mount_options);
554                         usage(argv[0]);
555                         break;
556                 }
557         }
558         if (argc - optind != 2)
559         {
560                 free(mount_options);
561                 usage(argv[0]);
562         }
563         spec = argv[optind];
564         mount_point = argv[optind + 1];
565
566         if (exfat_mount(&ef, spec, mount_options) != 0)
567         {
568                 free(mount_options);
569                 return 1;
570         }
571
572         mount_options = add_fuse_options(mount_options, spec, (ef.ro != 0));
573         if (mount_options == NULL)
574         {
575                 exfat_unmount(&ef);
576                 return 1;
577         }
578
579         /* create arguments for fuse_mount() */
580         if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
581                 fuse_opt_add_arg(&mount_args, "-o") != 0 ||
582                 fuse_opt_add_arg(&mount_args, mount_options) != 0)
583         {
584                 exfat_unmount(&ef);
585                 free(mount_options);
586                 return 1;
587         }
588
589         free(mount_options);
590
591         /* create FUSE mount point */
592         fc = fuse_mount(mount_point, &mount_args);
593         fuse_opt_free_args(&mount_args);
594         if (fc == NULL)
595         {
596                 exfat_unmount(&ef);
597                 return 1;
598         }
599
600         /* create arguments for fuse_new() */
601         if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
602                 (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
603         {
604                 fuse_unmount(mount_point, fc);
605                 exfat_unmount(&ef);
606                 return 1;
607         }
608
609         /* create new FUSE file system */
610         fh = fuse_new(fc, &newfs_args, &fuse_exfat_ops,
611                         sizeof(struct fuse_operations), NULL);
612         fuse_opt_free_args(&newfs_args);
613         if (fh == NULL)
614         {
615                 fuse_unmount(mount_point, fc);
616                 exfat_unmount(&ef);
617                 return 1;
618         }
619
620         /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
621         if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
622         {
623                 fuse_unmount(mount_point, fc);
624                 fuse_destroy(fh);
625                 exfat_unmount(&ef);
626                 exfat_error("failed to set signal handlers");
627                 return 1;
628         }
629
630         /* go to background (unless "-d" option is passed) and run FUSE
631            main loop */
632         if (fuse_daemonize(debug) == 0)
633         {
634                 if (fuse_loop(fh) != 0)
635                         exfat_error("FUSE loop failure");
636         }
637         else
638                 exfat_error("failed to daemonize");
639
640         fuse_remove_signal_handlers(fuse_get_session(fh));
641         /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
642         fuse_unmount(mount_point, fc);
643         fuse_destroy(fh);
644         return 0;
645 }