1 /*
2  * fuse2fs.c - FUSE server for e2fsprogs.
3  *
4  * Copyright (C) 2014 Oracle.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11 #define _FILE_OFFSET_BITS 64
12 #define FUSE_USE_VERSION 29
13 #ifndef _GNU_SOURCE
14 #define _GNU_SOURCE
15 #endif
16 #include "config.h"
17 #include <pthread.h>
18 #ifdef __linux__
19 # include <linux/fs.h>
20 # include <linux/falloc.h>
21 # include <linux/xattr.h>
22 # define FUSE_PLATFORM_OPTS	",big_writes"
23 # ifdef HAVE_SYS_ACL_H
24 #  define TRANSLATE_LINUX_ACLS
25 # endif
26 #else
27 # define FUSE_PLATFORM_OPTS	""
28 #endif
29 #ifdef TRANSLATE_LINUX_ACLS
30 # include <sys/acl.h>
31 #endif
32 #include <sys/ioctl.h>
33 #include <unistd.h>
34 #include <fuse.h>
35 #include <inttypes.h>
36 #include "ext2fs/ext2fs.h"
37 #include "ext2fs/ext2_fs.h"
38 
39 #include "../version.h"
40 
41 #ifdef ENABLE_NLS
42 #include <libintl.h>
43 #include <locale.h>
44 #define _(a) (gettext(a))
45 #ifdef gettext_noop
46 #define N_(a) gettext_noop(a)
47 #else
48 #define N_(a) (a)
49 #endif
50 #define P_(singular, plural, n) (ngettext(singular, plural, n))
51 #ifndef NLS_CAT_NAME
52 #define NLS_CAT_NAME "e2fsprogs"
53 #endif
54 #ifndef LOCALEDIR
55 #define LOCALEDIR "/usr/share/locale"
56 #endif
57 #else
58 #define _(a) (a)
59 #define N_(a) a
60 #define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
61 #endif
62 
63 static ext2_filsys global_fs; /* Try not to use this directly */
64 
65 #undef DEBUG
66 
67 #ifdef DEBUG
68 # define dbg_printf(f, a...)  do {printf("FUSE2FS-" f, ## a); \
69 	fflush(stdout); \
70 } while (0)
71 #else
72 # define dbg_printf(f, a...)
73 #endif
74 
75 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
76 # ifdef _IOR
77 #  ifdef _IOW
78 #   define SUPPORT_I_FLAGS
79 #  endif
80 # endif
81 #endif
82 
83 #ifdef FALLOC_FL_KEEP_SIZE
84 # define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE
85 # define SUPPORT_FALLOCATE
86 #else
87 # define FL_KEEP_SIZE_FLAG (0)
88 #endif
89 
90 #ifdef FALLOC_FL_PUNCH_HOLE
91 # define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE
92 #else
93 # define FL_PUNCH_HOLE_FLAG (0)
94 #endif
95 
96 errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
97 
98 #ifdef CONFIG_JBD_DEBUG		/* Enabled by configure --enable-jbd-debug */
99 int journal_enable_debug = -1;
100 #endif
101 
102 /* ACL translation stuff */
103 #ifdef TRANSLATE_LINUX_ACLS
104 /*
105  * Copied from acl_ea.h in libacl source; ACLs have to be sent to and from fuse
106  * in this format... at least on Linux.
107  */
108 #define ACL_EA_ACCESS		"system.posix_acl_access"
109 #define ACL_EA_DEFAULT		"system.posix_acl_default"
110 
111 #define ACL_EA_VERSION		0x0002
112 
113 typedef struct {
114 	u_int16_t	e_tag;
115 	u_int16_t	e_perm;
116 	u_int32_t	e_id;
117 } acl_ea_entry;
118 
119 typedef struct {
120 	u_int32_t	a_version;
121 #if __GNUC_PREREQ (4, 8)
122 #pragma GCC diagnostic push
123 #pragma GCC diagnostic ignored "-Wpedantic"
124 #endif
125 	acl_ea_entry	a_entries[0];
126 #if __GNUC_PREREQ (4, 8)
127 #pragma GCC diagnostic pop
128 #endif
129 } acl_ea_header;
130 
acl_ea_size(int count)131 static inline size_t acl_ea_size(int count)
132 {
133 	return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry);
134 }
135 
acl_ea_count(size_t size)136 static inline int acl_ea_count(size_t size)
137 {
138 	if (size < sizeof(acl_ea_header))
139 		return -1;
140 	size -= sizeof(acl_ea_header);
141 	if (size % sizeof(acl_ea_entry))
142 		return -1;
143 	return size / sizeof(acl_ea_entry);
144 }
145 
146 /*
147  * ext4 ACL structures, copied from fs/ext4/acl.h.
148  */
149 #define EXT4_ACL_VERSION	0x0001
150 
151 typedef struct {
152 	__u16		e_tag;
153 	__u16		e_perm;
154 	__u32		e_id;
155 } ext4_acl_entry;
156 
157 typedef struct {
158 	__u16		e_tag;
159 	__u16		e_perm;
160 } ext4_acl_entry_short;
161 
162 typedef struct {
163 	__u32		a_version;
164 } ext4_acl_header;
165 
ext4_acl_size(int count)166 static inline size_t ext4_acl_size(int count)
167 {
168 	if (count <= 4) {
169 		return sizeof(ext4_acl_header) +
170 		       count * sizeof(ext4_acl_entry_short);
171 	} else {
172 		return sizeof(ext4_acl_header) +
173 		       4 * sizeof(ext4_acl_entry_short) +
174 		       (count - 4) * sizeof(ext4_acl_entry);
175 	}
176 }
177 
ext4_acl_count(size_t size)178 static inline int ext4_acl_count(size_t size)
179 {
180 	ssize_t s;
181 
182 	size -= sizeof(ext4_acl_header);
183 	s = size - 4 * sizeof(ext4_acl_entry_short);
184 	if (s < 0) {
185 		if (size % sizeof(ext4_acl_entry_short))
186 			return -1;
187 		return size / sizeof(ext4_acl_entry_short);
188 	}
189 	if (s % sizeof(ext4_acl_entry))
190 		return -1;
191 	return s / sizeof(ext4_acl_entry) + 4;
192 }
193 
fuse_to_ext4_acl(acl_ea_header * facl,size_t facl_sz,ext4_acl_header ** eacl,size_t * eacl_sz)194 static errcode_t fuse_to_ext4_acl(acl_ea_header *facl, size_t facl_sz,
195 				  ext4_acl_header **eacl, size_t *eacl_sz)
196 {
197 	int i, facl_count;
198 	ext4_acl_header *h;
199 	size_t h_sz;
200 	ext4_acl_entry *e;
201 	acl_ea_entry *a;
202 	unsigned char *hptr;
203 	errcode_t err;
204 
205 	facl_count = acl_ea_count(facl_sz);
206 	h_sz = ext4_acl_size(facl_count);
207 	if (facl_count < 0 || facl->a_version != ACL_EA_VERSION)
208 		return EXT2_ET_INVALID_ARGUMENT;
209 
210 	err = ext2fs_get_mem(h_sz, &h);
211 	if (err)
212 		return err;
213 
214 	h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
215 	hptr = (unsigned char *) (h + 1);
216 	for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) {
217 		e = (ext4_acl_entry *) hptr;
218 		e->e_tag = ext2fs_cpu_to_le16(a->e_tag);
219 		e->e_perm = ext2fs_cpu_to_le16(a->e_perm);
220 
221 		switch (a->e_tag) {
222 		case ACL_USER:
223 		case ACL_GROUP:
224 			e->e_id = ext2fs_cpu_to_le32(a->e_id);
225 			hptr += sizeof(ext4_acl_entry);
226 			break;
227 		case ACL_USER_OBJ:
228 		case ACL_GROUP_OBJ:
229 		case ACL_MASK:
230 		case ACL_OTHER:
231 			hptr += sizeof(ext4_acl_entry_short);
232 			break;
233 		default:
234 			err = EXT2_ET_INVALID_ARGUMENT;
235 			goto out;
236 		}
237 	}
238 
239 	*eacl = h;
240 	*eacl_sz = h_sz;
241 	return err;
242 out:
243 	ext2fs_free_mem(&h);
244 	return err;
245 }
246 
ext4_to_fuse_acl(acl_ea_header ** facl,size_t * facl_sz,ext4_acl_header * eacl,size_t eacl_sz)247 static errcode_t ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz,
248 				  ext4_acl_header *eacl, size_t eacl_sz)
249 {
250 	int i, eacl_count;
251 	acl_ea_header *f;
252 	ext4_acl_entry *e;
253 	acl_ea_entry *a;
254 	size_t f_sz;
255 	unsigned char *hptr;
256 	errcode_t err;
257 
258 	eacl_count = ext4_acl_count(eacl_sz);
259 	f_sz = acl_ea_size(eacl_count);
260 	if (eacl_count < 0 ||
261 	    eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION))
262 		return EXT2_ET_INVALID_ARGUMENT;
263 
264 	err = ext2fs_get_mem(f_sz, &f);
265 	if (err)
266 		return err;
267 
268 	f->a_version = ACL_EA_VERSION;
269 	hptr = (unsigned char *) (eacl + 1);
270 	for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) {
271 		e = (ext4_acl_entry *) hptr;
272 		a->e_tag = ext2fs_le16_to_cpu(e->e_tag);
273 		a->e_perm = ext2fs_le16_to_cpu(e->e_perm);
274 
275 		switch (a->e_tag) {
276 		case ACL_USER:
277 		case ACL_GROUP:
278 			a->e_id = ext2fs_le32_to_cpu(e->e_id);
279 			hptr += sizeof(ext4_acl_entry);
280 			break;
281 		case ACL_USER_OBJ:
282 		case ACL_GROUP_OBJ:
283 		case ACL_MASK:
284 		case ACL_OTHER:
285 			hptr += sizeof(ext4_acl_entry_short);
286 			break;
287 		default:
288 			err = EXT2_ET_INVALID_ARGUMENT;
289 			goto out;
290 		}
291 	}
292 
293 	*facl = f;
294 	*facl_sz = f_sz;
295 	return err;
296 out:
297 	ext2fs_free_mem(&f);
298 	return err;
299 }
300 #endif /* TRANSLATE_LINUX_ACLS */
301 
302 /*
303  * ext2_file_t contains a struct inode, so we can't leave files open.
304  * Use this as a proxy instead.
305  */
306 #define FUSE2FS_FILE_MAGIC	(0xEF53DEAFUL)
307 struct fuse2fs_file_handle {
308 	unsigned long magic;
309 	ext2_ino_t ino;
310 	int open_flags;
311 };
312 
313 /* Main program context */
314 #define FUSE2FS_MAGIC		(0xEF53DEADUL)
315 struct fuse2fs {
316 	unsigned long magic;
317 	ext2_filsys fs;
318 	pthread_mutex_t bfl;
319 	char *device;
320 	int ro;
321 	int debug;
322 	int no_default_opts;
323 	int panic_on_error;
324 	int minixdf;
325 	int fakeroot;
326 	int alloc_all_blocks;
327 	int norecovery;
328 	FILE *err_fp;
329 	unsigned int next_generation;
330 };
331 
332 #define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \
333 	return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \
334 } while (0)
335 
336 #define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \
337 	return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \
338 } while (0)
339 
340 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
341 			     const char *file, int line);
342 #define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \
343 			__FILE__, __LINE__)
344 
345 /* for macosx */
346 #ifndef W_OK
347 #  define W_OK 2
348 #endif
349 
350 #ifndef R_OK
351 #  define R_OK 4
352 #endif
353 
354 #define EXT4_EPOCH_BITS 2
355 #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
356 #define EXT4_NSEC_MASK  (~0UL << EXT4_EPOCH_BITS)
357 
358 /*
359  * Extended fields will fit into an inode if the filesystem was formatted
360  * with large inodes (-I 256 or larger) and there are not currently any EAs
361  * consuming all of the available space. For new inodes we always reserve
362  * enough space for the kernel's known extended fields, but for inodes
363  * created with an old kernel this might not have been the case. None of
364  * the extended inode fields is critical for correct filesystem operation.
365  * This macro checks if a certain field fits in the inode. Note that
366  * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
367  */
368 #define EXT4_FITS_IN_INODE(ext4_inode, field)		\
369 	((offsetof(typeof(*ext4_inode), field) +	\
370 	  sizeof((ext4_inode)->field))			\
371 	 <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE +		\
372 	    (ext4_inode)->i_extra_isize))		\
373 
ext4_encode_extra_time(const struct timespec * time)374 static inline __u32 ext4_encode_extra_time(const struct timespec *time)
375 {
376 	__u32 extra = sizeof(time->tv_sec) > 4 ?
377 			((time->tv_sec - (__s32)time->tv_sec) >> 32) &
378 			EXT4_EPOCH_MASK : 0;
379 	return extra | (time->tv_nsec << EXT4_EPOCH_BITS);
380 }
381 
ext4_decode_extra_time(struct timespec * time,__u32 extra)382 static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra)
383 {
384 	if (sizeof(time->tv_sec) > 4 && (extra & EXT4_EPOCH_MASK)) {
385 		__u64 extra_bits = extra & EXT4_EPOCH_MASK;
386 		/*
387 		 * Prior to kernel 3.14?, we had a broken decode function,
388 		 * wherein we effectively did this:
389 		 * if (extra_bits == 3)
390 		 *     extra_bits = 0;
391 		 */
392 		time->tv_sec += extra_bits << 32;
393 	}
394 	time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
395 }
396 
397 #define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode)		       \
398 do {									       \
399 	(raw_inode)->xtime = (timespec)->tv_sec;			       \
400 	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))		       \
401 		(raw_inode)->xtime ## _extra =				       \
402 				ext4_encode_extra_time(timespec);	       \
403 } while (0)
404 
405 #define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode)		       \
406 do {									       \
407 	if (EXT4_FITS_IN_INODE(raw_inode, xtime))			       \
408 		(raw_inode)->xtime = (timespec)->tv_sec;		       \
409 	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))		       \
410 		(raw_inode)->xtime ## _extra =				       \
411 				ext4_encode_extra_time(timespec);	       \
412 } while (0)
413 
414 #define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode)		       \
415 do {									       \
416 	(timespec)->tv_sec = (signed)((raw_inode)->xtime);		       \
417 	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))		       \
418 		ext4_decode_extra_time((timespec),			       \
419 				       (raw_inode)->xtime ## _extra);	       \
420 	else								       \
421 		(timespec)->tv_nsec = 0;				       \
422 } while (0)
423 
424 #define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode)		       \
425 do {									       \
426 	if (EXT4_FITS_IN_INODE(raw_inode, xtime))			       \
427 		(timespec)->tv_sec =					       \
428 			(signed)((raw_inode)->xtime);			       \
429 	if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra))		       \
430 		ext4_decode_extra_time((timespec),			       \
431 				       raw_inode->xtime ## _extra);	       \
432 	else								       \
433 		(timespec)->tv_nsec = 0;				       \
434 } while (0)
435 
get_now(struct timespec * now)436 static void get_now(struct timespec *now)
437 {
438 #ifdef CLOCK_REALTIME
439 	if (!clock_gettime(CLOCK_REALTIME, now))
440 		return;
441 #endif
442 
443 	now->tv_sec = time(NULL);
444 	now->tv_nsec = 0;
445 }
446 
increment_version(struct ext2_inode_large * inode)447 static void increment_version(struct ext2_inode_large *inode)
448 {
449 	__u64 ver;
450 
451 	ver = inode->osd1.linux1.l_i_version;
452 	if (EXT4_FITS_IN_INODE(inode, i_version_hi))
453 		ver |= (__u64)inode->i_version_hi << 32;
454 	ver++;
455 	inode->osd1.linux1.l_i_version = ver;
456 	if (EXT4_FITS_IN_INODE(inode, i_version_hi))
457 		inode->i_version_hi = ver >> 32;
458 }
459 
init_times(struct ext2_inode_large * inode)460 static void init_times(struct ext2_inode_large *inode)
461 {
462 	struct timespec now;
463 
464 	get_now(&now);
465 	EXT4_INODE_SET_XTIME(i_atime, &now, inode);
466 	EXT4_INODE_SET_XTIME(i_ctime, &now, inode);
467 	EXT4_INODE_SET_XTIME(i_mtime, &now, inode);
468 	EXT4_EINODE_SET_XTIME(i_crtime, &now, inode);
469 	increment_version(inode);
470 }
471 
update_ctime(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode_large * pinode)472 static int update_ctime(ext2_filsys fs, ext2_ino_t ino,
473 			struct ext2_inode_large *pinode)
474 {
475 	errcode_t err;
476 	struct timespec now;
477 	struct ext2_inode_large inode;
478 
479 	get_now(&now);
480 
481 	/* If user already has a inode buffer, just update that */
482 	if (pinode) {
483 		increment_version(pinode);
484 		EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
485 		return 0;
486 	}
487 
488 	/* Otherwise we have to read-modify-write the inode */
489 	memset(&inode, 0, sizeof(inode));
490 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
491 				     sizeof(inode));
492 	if (err)
493 		return translate_error(fs, ino, err);
494 
495 	increment_version(&inode);
496 	EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
497 
498 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
499 				      sizeof(inode));
500 	if (err)
501 		return translate_error(fs, ino, err);
502 
503 	return 0;
504 }
505 
update_atime(ext2_filsys fs,ext2_ino_t ino)506 static int update_atime(ext2_filsys fs, ext2_ino_t ino)
507 {
508 	errcode_t err;
509 	struct ext2_inode_large inode, *pinode;
510 	struct timespec atime, mtime, now;
511 
512 	if (!(fs->flags & EXT2_FLAG_RW))
513 		return 0;
514 	memset(&inode, 0, sizeof(inode));
515 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
516 				     sizeof(inode));
517 	if (err)
518 		return translate_error(fs, ino, err);
519 
520 	pinode = &inode;
521 	EXT4_INODE_GET_XTIME(i_atime, &atime, pinode);
522 	EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode);
523 	get_now(&now);
524 	/*
525 	 * If atime is newer than mtime and atime hasn't been updated in thirty
526 	 * seconds, skip the atime update.  Same idea as Linux "relatime".
527 	 */
528 	if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30)
529 		return 0;
530 	EXT4_INODE_SET_XTIME(i_atime, &now, &inode);
531 
532 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
533 				      sizeof(inode));
534 	if (err)
535 		return translate_error(fs, ino, err);
536 
537 	return 0;
538 }
539 
update_mtime(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode_large * pinode)540 static int update_mtime(ext2_filsys fs, ext2_ino_t ino,
541 			struct ext2_inode_large *pinode)
542 {
543 	errcode_t err;
544 	struct ext2_inode_large inode;
545 	struct timespec now;
546 
547 	if (pinode) {
548 		get_now(&now);
549 		EXT4_INODE_SET_XTIME(i_mtime, &now, pinode);
550 		EXT4_INODE_SET_XTIME(i_ctime, &now, pinode);
551 		increment_version(pinode);
552 		return 0;
553 	}
554 
555 	memset(&inode, 0, sizeof(inode));
556 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
557 				     sizeof(inode));
558 	if (err)
559 		return translate_error(fs, ino, err);
560 
561 	get_now(&now);
562 	EXT4_INODE_SET_XTIME(i_mtime, &now, &inode);
563 	EXT4_INODE_SET_XTIME(i_ctime, &now, &inode);
564 	increment_version(&inode);
565 
566 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
567 				      sizeof(inode));
568 	if (err)
569 		return translate_error(fs, ino, err);
570 
571 	return 0;
572 }
573 
ext2_file_type(unsigned int mode)574 static int ext2_file_type(unsigned int mode)
575 {
576 	if (LINUX_S_ISREG(mode))
577 		return EXT2_FT_REG_FILE;
578 
579 	if (LINUX_S_ISDIR(mode))
580 		return EXT2_FT_DIR;
581 
582 	if (LINUX_S_ISCHR(mode))
583 		return EXT2_FT_CHRDEV;
584 
585 	if (LINUX_S_ISBLK(mode))
586 		return EXT2_FT_BLKDEV;
587 
588 	if (LINUX_S_ISLNK(mode))
589 		return EXT2_FT_SYMLINK;
590 
591 	if (LINUX_S_ISFIFO(mode))
592 		return EXT2_FT_FIFO;
593 
594 	if (LINUX_S_ISSOCK(mode))
595 		return EXT2_FT_SOCK;
596 
597 	return 0;
598 }
599 
fs_can_allocate(struct fuse2fs * ff,blk64_t num)600 static int fs_can_allocate(struct fuse2fs *ff, blk64_t num)
601 {
602 	ext2_filsys fs = ff->fs;
603 	blk64_t reserved;
604 
605 	dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu "
606 		   "rsvd=%llu\n", __func__, num, ff->alloc_all_blocks,
607 		   ext2fs_blocks_count(fs->super),
608 		   ext2fs_free_blocks_count(fs->super),
609 		   ext2fs_r_blocks_count(fs->super));
610 	if (num > ext2fs_blocks_count(fs->super))
611 		return 0;
612 
613 	if (ff->alloc_all_blocks)
614 		return 1;
615 
616 	/*
617 	 * Different meaning for r_blocks -- libext2fs has bugs where the FS
618 	 * can get corrupted if it totally runs out of blocks.  Avoid this
619 	 * by refusing to allocate any of the reserve blocks to anybody.
620 	 */
621 	reserved = ext2fs_r_blocks_count(fs->super);
622 	if (reserved == 0)
623 		reserved = ext2fs_blocks_count(fs->super) / 10;
624 	return ext2fs_free_blocks_count(fs->super) > reserved + num;
625 }
626 
fs_writeable(ext2_filsys fs)627 static int fs_writeable(ext2_filsys fs)
628 {
629 	return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0);
630 }
631 
check_inum_access(ext2_filsys fs,ext2_ino_t ino,mode_t mask)632 static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask)
633 {
634 	struct fuse_context *ctxt = fuse_get_context();
635 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
636 	struct ext2_inode inode;
637 	mode_t perms;
638 	errcode_t err;
639 
640 	/* no writing to read-only or broken fs */
641 	if ((mask & W_OK) && !fs_writeable(fs))
642 		return -EROFS;
643 
644 	err = ext2fs_read_inode(fs, ino, &inode);
645 	if (err)
646 		return translate_error(fs, ino, err);
647 	perms = inode.i_mode & 0777;
648 
649 	dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d "
650 		   "uid=%d gid=%d\n", ino,
651 		   (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""),
652 		   (mask & X_OK ? "x" : ""), perms, inode_uid(inode),
653 		   inode_gid(inode), ctxt->uid, ctxt->gid);
654 
655 	/* existence check */
656 	if (mask == 0)
657 		return 0;
658 
659 	/* is immutable? */
660 	if ((mask & W_OK) &&
661 	    (inode.i_flags & EXT2_IMMUTABLE_FL))
662 		return -EACCES;
663 
664 	/* Figure out what root's allowed to do */
665 	if (ff->fakeroot || ctxt->uid == 0) {
666 		/* Non-file access always ok */
667 		if (!LINUX_S_ISREG(inode.i_mode))
668 			return 0;
669 
670 		/* R/W access to a file always ok */
671 		if (!(mask & X_OK))
672 			return 0;
673 
674 		/* X access to a file ok if a user/group/other can X */
675 		if (perms & 0111)
676 			return 0;
677 
678 		/* Trying to execute a file that's not executable. BZZT! */
679 		return -EACCES;
680 	}
681 
682 	/* allow owner, if perms match */
683 	if (inode_uid(inode) == ctxt->uid) {
684 		if ((mask & (perms >> 6)) == mask)
685 			return 0;
686 		return -EACCES;
687 	}
688 
689 	/* allow group, if perms match */
690 	if (inode_gid(inode) == ctxt->gid) {
691 		if ((mask & (perms >> 3)) == mask)
692 			return 0;
693 		return -EACCES;
694 	}
695 
696 	/* otherwise check other */
697 	if ((mask & perms) == mask)
698 		return 0;
699 	return -EACCES;
700 }
701 
op_destroy(void * p EXT2FS_ATTR ((unused)))702 static void op_destroy(void *p EXT2FS_ATTR((unused)))
703 {
704 	struct fuse_context *ctxt = fuse_get_context();
705 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
706 	ext2_filsys fs;
707 	errcode_t err;
708 
709 	if (ff->magic != FUSE2FS_MAGIC) {
710 		translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
711 		return;
712 	}
713 	fs = ff->fs;
714 	dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
715 	if (fs->flags & EXT2_FLAG_RW) {
716 		fs->super->s_state |= EXT2_VALID_FS;
717 		if (fs->super->s_error_count)
718 			fs->super->s_state |= EXT2_ERROR_FS;
719 		ext2fs_mark_super_dirty(fs);
720 		err = ext2fs_set_gdt_csum(fs);
721 		if (err)
722 			translate_error(fs, 0, err);
723 
724 		err = ext2fs_flush2(fs, 0);
725 		if (err)
726 			translate_error(fs, 0, err);
727 	}
728 }
729 
op_init(struct fuse_conn_info * conn)730 static void *op_init(struct fuse_conn_info *conn)
731 {
732 	struct fuse_context *ctxt = fuse_get_context();
733 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
734 	ext2_filsys fs;
735 	errcode_t err;
736 
737 	if (ff->magic != FUSE2FS_MAGIC) {
738 		translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC);
739 		return NULL;
740 	}
741 	fs = ff->fs;
742 	dbg_printf("%s: dev=%s\n", __func__, fs->device_name);
743 #ifdef FUSE_CAP_IOCTL_DIR
744 	conn->want |= FUSE_CAP_IOCTL_DIR;
745 #endif
746 	if (fs->flags & EXT2_FLAG_RW) {
747 		fs->super->s_mnt_count++;
748 		fs->super->s_mtime = time(NULL);
749 		fs->super->s_state &= ~EXT2_VALID_FS;
750 		ext2fs_mark_super_dirty(fs);
751 		err = ext2fs_flush2(fs, 0);
752 		if (err)
753 			translate_error(fs, 0, err);
754 	}
755 	return ff;
756 }
757 
stat_inode(ext2_filsys fs,ext2_ino_t ino,struct stat * statbuf)758 static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf)
759 {
760 	struct ext2_inode_large inode;
761 	dev_t fakedev = 0;
762 	errcode_t err;
763 	int ret = 0;
764 	struct timespec tv;
765 
766 	memset(&inode, 0, sizeof(inode));
767 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
768 				     sizeof(inode));
769 	if (err)
770 		return translate_error(fs, ino, err);
771 
772 	memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev));
773 	statbuf->st_dev = fakedev;
774 	statbuf->st_ino = ino;
775 	statbuf->st_mode = inode.i_mode;
776 	statbuf->st_nlink = inode.i_links_count;
777 	statbuf->st_uid = inode_uid(inode);
778 	statbuf->st_gid = inode_gid(inode);
779 	statbuf->st_size = EXT2_I_SIZE(&inode);
780 	statbuf->st_blksize = fs->blocksize;
781 	statbuf->st_blocks = ext2fs_get_stat_i_blocks(fs,
782 						(struct ext2_inode *)&inode);
783 	EXT4_INODE_GET_XTIME(i_atime, &tv, &inode);
784 	statbuf->st_atime = tv.tv_sec;
785 	EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode);
786 	statbuf->st_mtime = tv.tv_sec;
787 	EXT4_INODE_GET_XTIME(i_ctime, &tv, &inode);
788 	statbuf->st_ctime = tv.tv_sec;
789 	if (LINUX_S_ISCHR(inode.i_mode) ||
790 	    LINUX_S_ISBLK(inode.i_mode)) {
791 		if (inode.i_block[0])
792 			statbuf->st_rdev = inode.i_block[0];
793 		else
794 			statbuf->st_rdev = inode.i_block[1];
795 	}
796 
797 	return ret;
798 }
799 
op_getattr(const char * path,struct stat * statbuf)800 static int op_getattr(const char *path, struct stat *statbuf)
801 {
802 	struct fuse_context *ctxt = fuse_get_context();
803 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
804 	ext2_filsys fs;
805 	ext2_ino_t ino;
806 	errcode_t err;
807 	int ret = 0;
808 
809 	FUSE2FS_CHECK_CONTEXT(ff);
810 	fs = ff->fs;
811 	dbg_printf("%s: path=%s\n", __func__, path);
812 	pthread_mutex_lock(&ff->bfl);
813 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
814 	if (err) {
815 		ret = translate_error(fs, 0, err);
816 		goto out;
817 	}
818 	ret = stat_inode(fs, ino, statbuf);
819 out:
820 	pthread_mutex_unlock(&ff->bfl);
821 	return ret;
822 }
823 
op_readlink(const char * path,char * buf,size_t len)824 static int op_readlink(const char *path, char *buf, size_t len)
825 {
826 	struct fuse_context *ctxt = fuse_get_context();
827 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
828 	ext2_filsys fs;
829 	errcode_t err;
830 	ext2_ino_t ino;
831 	struct ext2_inode inode;
832 	unsigned int got;
833 	ext2_file_t file;
834 	int ret = 0;
835 
836 	FUSE2FS_CHECK_CONTEXT(ff);
837 	fs = ff->fs;
838 	dbg_printf("%s: path=%s\n", __func__, path);
839 	pthread_mutex_lock(&ff->bfl);
840 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
841 	if (err || ino == 0) {
842 		ret = translate_error(fs, 0, err);
843 		goto out;
844 	}
845 
846 	err = ext2fs_read_inode(fs, ino, &inode);
847 	if (err) {
848 		ret = translate_error(fs, ino, err);
849 		goto out;
850 	}
851 
852 	if (!LINUX_S_ISLNK(inode.i_mode)) {
853 		ret = -EINVAL;
854 		goto out;
855 	}
856 
857 	len--;
858 	if (inode.i_size < len)
859 		len = inode.i_size;
860 	if (ext2fs_is_fast_symlink(&inode))
861 		memcpy(buf, (char *)inode.i_block, len);
862 	else {
863 		/* big/inline symlink */
864 
865 		err = ext2fs_file_open(fs, ino, 0, &file);
866 		if (err) {
867 			ret = translate_error(fs, ino, err);
868 			goto out;
869 		}
870 
871 		err = ext2fs_file_read(file, buf, len, &got);
872 		if (err || got != len) {
873 			ext2fs_file_close(file);
874 			ret = translate_error(fs, ino, err);
875 			goto out2;
876 		}
877 
878 out2:
879 		err = ext2fs_file_close(file);
880 		if (ret)
881 			goto out;
882 		if (err) {
883 			ret = translate_error(fs, ino, err);
884 			goto out;
885 		}
886 	}
887 	buf[len] = 0;
888 
889 	if (fs_writeable(fs)) {
890 		ret = update_atime(fs, ino);
891 		if (ret)
892 			goto out;
893 	}
894 
895 out:
896 	pthread_mutex_unlock(&ff->bfl);
897 	return ret;
898 }
899 
op_mknod(const char * path,mode_t mode,dev_t dev)900 static int op_mknod(const char *path, mode_t mode, dev_t dev)
901 {
902 	struct fuse_context *ctxt = fuse_get_context();
903 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
904 	ext2_filsys fs;
905 	ext2_ino_t parent, child;
906 	char *temp_path;
907 	errcode_t err;
908 	char *node_name, a;
909 	int filetype;
910 	struct ext2_inode_large inode;
911 	int ret = 0;
912 
913 	FUSE2FS_CHECK_CONTEXT(ff);
914 	fs = ff->fs;
915 	dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode,
916 		   (unsigned int)dev);
917 	temp_path = strdup(path);
918 	if (!temp_path) {
919 		ret = -ENOMEM;
920 		goto out;
921 	}
922 	node_name = strrchr(temp_path, '/');
923 	if (!node_name) {
924 		ret = -ENOMEM;
925 		goto out;
926 	}
927 	node_name++;
928 	a = *node_name;
929 	*node_name = 0;
930 
931 	pthread_mutex_lock(&ff->bfl);
932 	if (!fs_can_allocate(ff, 2)) {
933 		ret = -ENOSPC;
934 		goto out2;
935 	}
936 
937 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
938 			   &parent);
939 	if (err) {
940 		ret = translate_error(fs, 0, err);
941 		goto out2;
942 	}
943 
944 	ret = check_inum_access(fs, parent, W_OK);
945 	if (ret)
946 		goto out2;
947 
948 	*node_name = a;
949 
950 	if (LINUX_S_ISCHR(mode))
951 		filetype = EXT2_FT_CHRDEV;
952 	else if (LINUX_S_ISBLK(mode))
953 		filetype = EXT2_FT_BLKDEV;
954 	else if (LINUX_S_ISFIFO(mode))
955 		filetype = EXT2_FT_FIFO;
956 	else if (LINUX_S_ISSOCK(mode))
957 		filetype = EXT2_FT_SOCK;
958 	else {
959 		ret = -EINVAL;
960 		goto out2;
961 	}
962 
963 	err = ext2fs_new_inode(fs, parent, mode, 0, &child);
964 	if (err) {
965 		ret = translate_error(fs, 0, err);
966 		goto out2;
967 	}
968 
969 	dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__, child,
970 		   node_name, parent);
971 	err = ext2fs_link(fs, parent, node_name, child, filetype);
972 	if (err == EXT2_ET_DIR_NO_SPACE) {
973 		err = ext2fs_expand_dir(fs, parent);
974 		if (err) {
975 			ret = translate_error(fs, parent, err);
976 			goto out2;
977 		}
978 
979 		err = ext2fs_link(fs, parent, node_name, child,
980 				     filetype);
981 	}
982 	if (err) {
983 		ret = translate_error(fs, parent, err);
984 		goto out2;
985 	}
986 
987 	ret = update_mtime(fs, parent, NULL);
988 	if (ret)
989 		goto out2;
990 
991 	memset(&inode, 0, sizeof(inode));
992 	inode.i_mode = mode;
993 
994 	if (dev & ~0xFFFF)
995 		inode.i_block[1] = dev;
996 	else
997 		inode.i_block[0] = dev;
998 	inode.i_links_count = 1;
999 	inode.i_extra_isize = sizeof(struct ext2_inode_large) -
1000 		EXT2_GOOD_OLD_INODE_SIZE;
1001 	inode.i_uid = ctxt->uid;
1002 	ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
1003 	inode.i_gid = ctxt->gid;
1004 	ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
1005 
1006 	err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
1007 	if (err) {
1008 		ret = translate_error(fs, child, err);
1009 		goto out2;
1010 	}
1011 
1012 	inode.i_generation = ff->next_generation++;
1013 	init_times(&inode);
1014 	err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1015 				      sizeof(inode));
1016 	if (err) {
1017 		ret = translate_error(fs, child, err);
1018 		goto out2;
1019 	}
1020 
1021 	ext2fs_inode_alloc_stats2(fs, child, 1, 0);
1022 
1023 out2:
1024 	pthread_mutex_unlock(&ff->bfl);
1025 out:
1026 	free(temp_path);
1027 	return ret;
1028 }
1029 
op_mkdir(const char * path,mode_t mode)1030 static int op_mkdir(const char *path, mode_t mode)
1031 {
1032 	struct fuse_context *ctxt = fuse_get_context();
1033 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1034 	ext2_filsys fs;
1035 	ext2_ino_t parent, child;
1036 	char *temp_path;
1037 	errcode_t err;
1038 	char *node_name, a;
1039 	struct ext2_inode_large inode;
1040 	char *block;
1041 	blk64_t blk;
1042 	int ret = 0;
1043 	mode_t parent_sgid;
1044 
1045 	FUSE2FS_CHECK_CONTEXT(ff);
1046 	fs = ff->fs;
1047 	dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
1048 	temp_path = strdup(path);
1049 	if (!temp_path) {
1050 		ret = -ENOMEM;
1051 		goto out;
1052 	}
1053 	node_name = strrchr(temp_path, '/');
1054 	if (!node_name) {
1055 		ret = -ENOMEM;
1056 		goto out;
1057 	}
1058 	node_name++;
1059 	a = *node_name;
1060 	*node_name = 0;
1061 
1062 	pthread_mutex_lock(&ff->bfl);
1063 	if (!fs_can_allocate(ff, 1)) {
1064 		ret = -ENOSPC;
1065 		goto out2;
1066 	}
1067 
1068 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1069 			   &parent);
1070 	if (err) {
1071 		ret = translate_error(fs, 0, err);
1072 		goto out2;
1073 	}
1074 
1075 	ret = check_inum_access(fs, parent, W_OK);
1076 	if (ret)
1077 		goto out2;
1078 
1079 	/* Is the parent dir sgid? */
1080 	err = ext2fs_read_inode_full(fs, parent, (struct ext2_inode *)&inode,
1081 				     sizeof(inode));
1082 	if (err) {
1083 		ret = translate_error(fs, parent, err);
1084 		goto out2;
1085 	}
1086 	parent_sgid = inode.i_mode & S_ISGID;
1087 
1088 	*node_name = a;
1089 
1090 	err = ext2fs_mkdir(fs, parent, 0, node_name);
1091 	if (err == EXT2_ET_DIR_NO_SPACE) {
1092 		err = ext2fs_expand_dir(fs, parent);
1093 		if (err) {
1094 			ret = translate_error(fs, parent, err);
1095 			goto out2;
1096 		}
1097 
1098 		err = ext2fs_mkdir(fs, parent, 0, node_name);
1099 	}
1100 	if (err) {
1101 		ret = translate_error(fs, parent, err);
1102 		goto out2;
1103 	}
1104 
1105 	ret = update_mtime(fs, parent, NULL);
1106 	if (ret)
1107 		goto out2;
1108 
1109 	/* Still have to update the uid/gid of the dir */
1110 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1111 			   &child);
1112 	if (err) {
1113 		ret = translate_error(fs, 0, err);
1114 		goto out2;
1115 	}
1116 	dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__, child,
1117 		   node_name, parent);
1118 
1119 	memset(&inode, 0, sizeof(inode));
1120 	err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1121 				     sizeof(inode));
1122 	if (err) {
1123 		ret = translate_error(fs, child, err);
1124 		goto out2;
1125 	}
1126 
1127 	inode.i_uid = ctxt->uid;
1128 	ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
1129 	inode.i_gid = ctxt->gid;
1130 	ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
1131 	inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) |
1132 		       parent_sgid;
1133 	inode.i_generation = ff->next_generation++;
1134 
1135 	err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1136 				      sizeof(inode));
1137 	if (err) {
1138 		ret = translate_error(fs, child, err);
1139 		goto out2;
1140 	}
1141 
1142 	/* Rewrite the directory block checksum, having set i_generation */
1143 	if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
1144 	    !ext2fs_has_feature_metadata_csum(fs->super))
1145 		goto out2;
1146 	err = ext2fs_new_dir_block(fs, child, parent, &block);
1147 	if (err) {
1148 		ret = translate_error(fs, child, err);
1149 		goto out2;
1150 	}
1151 	err = ext2fs_bmap2(fs, child, (struct ext2_inode *)&inode, NULL, 0, 0,
1152 			   NULL, &blk);
1153 	if (err) {
1154 		ret = translate_error(fs, child, err);
1155 		goto out3;
1156 	}
1157 	err = ext2fs_write_dir_block4(fs, blk, block, 0, child);
1158 	if (err) {
1159 		ret = translate_error(fs, child, err);
1160 		goto out3;
1161 	}
1162 
1163 out3:
1164 	ext2fs_free_mem(&block);
1165 out2:
1166 	pthread_mutex_unlock(&ff->bfl);
1167 out:
1168 	free(temp_path);
1169 	return ret;
1170 }
1171 
unlink_file_by_name(ext2_filsys fs,const char * path)1172 static int unlink_file_by_name(ext2_filsys fs, const char *path)
1173 {
1174 	errcode_t err;
1175 	ext2_ino_t dir;
1176 	char *filename = strdup(path);
1177 	char *base_name;
1178 	int ret;
1179 
1180 	base_name = strrchr(filename, '/');
1181 	if (base_name) {
1182 		*base_name++ = '\0';
1183 		err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename,
1184 				   &dir);
1185 		if (err) {
1186 			free(filename);
1187 			return translate_error(fs, 0, err);
1188 		}
1189 	} else {
1190 		dir = EXT2_ROOT_INO;
1191 		base_name = filename;
1192 	}
1193 
1194 	ret = check_inum_access(fs, dir, W_OK);
1195 	if (ret) {
1196 		free(filename);
1197 		return ret;
1198 	}
1199 
1200 	dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__,
1201 		   base_name, dir);
1202 	err = ext2fs_unlink(fs, dir, base_name, 0, 0);
1203 	free(filename);
1204 	if (err)
1205 		return translate_error(fs, dir, err);
1206 
1207 	return update_mtime(fs, dir, NULL);
1208 }
1209 
remove_inode(struct fuse2fs * ff,ext2_ino_t ino)1210 static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino)
1211 {
1212 	ext2_filsys fs = ff->fs;
1213 	errcode_t err;
1214 	struct ext2_inode_large inode;
1215 	int ret = 0;
1216 
1217 	memset(&inode, 0, sizeof(inode));
1218 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1219 				     sizeof(inode));
1220 	if (err) {
1221 		ret = translate_error(fs, ino, err);
1222 		goto out;
1223 	}
1224 	dbg_printf("%s: put ino=%d links=%d\n", __func__, ino,
1225 		   inode.i_links_count);
1226 
1227 	switch (inode.i_links_count) {
1228 	case 0:
1229 		return 0; /* XXX: already done? */
1230 	case 1:
1231 		inode.i_links_count--;
1232 		inode.i_dtime = fs->now ? fs->now : time(0);
1233 		break;
1234 	default:
1235 		inode.i_links_count--;
1236 	}
1237 
1238 	ret = update_ctime(fs, ino, &inode);
1239 	if (ret)
1240 		goto out;
1241 
1242 	if (inode.i_links_count)
1243 		goto write_out;
1244 
1245 	/* Nobody holds this file; free its blocks! */
1246 	err = ext2fs_free_ext_attr(fs, ino, &inode);
1247 	if (err)
1248 		goto write_out;
1249 
1250 	if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) {
1251 		err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL,
1252 				   0, ~0ULL);
1253 		if (err) {
1254 			ret = translate_error(fs, ino, err);
1255 			goto write_out;
1256 		}
1257 	}
1258 
1259 	ext2fs_inode_alloc_stats2(fs, ino, -1,
1260 				  LINUX_S_ISDIR(inode.i_mode));
1261 
1262 write_out:
1263 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1264 				      sizeof(inode));
1265 	if (err) {
1266 		ret = translate_error(fs, ino, err);
1267 		goto out;
1268 	}
1269 out:
1270 	return ret;
1271 }
1272 
__op_unlink(struct fuse2fs * ff,const char * path)1273 static int __op_unlink(struct fuse2fs *ff, const char *path)
1274 {
1275 	ext2_filsys fs = ff->fs;
1276 	ext2_ino_t ino;
1277 	errcode_t err;
1278 	int ret = 0;
1279 
1280 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1281 	if (err) {
1282 		ret = translate_error(fs, 0, err);
1283 		goto out;
1284 	}
1285 
1286 	ret = unlink_file_by_name(fs, path);
1287 	if (ret)
1288 		goto out;
1289 
1290 	ret = remove_inode(ff, ino);
1291 	if (ret)
1292 		goto out;
1293 out:
1294 	return ret;
1295 }
1296 
op_unlink(const char * path)1297 static int op_unlink(const char *path)
1298 {
1299 	struct fuse_context *ctxt = fuse_get_context();
1300 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1301 	int ret;
1302 
1303 	FUSE2FS_CHECK_CONTEXT(ff);
1304 	pthread_mutex_lock(&ff->bfl);
1305 	ret = __op_unlink(ff, path);
1306 	pthread_mutex_unlock(&ff->bfl);
1307 	return ret;
1308 }
1309 
1310 struct rd_struct {
1311 	ext2_ino_t	parent;
1312 	int		empty;
1313 };
1314 
rmdir_proc(ext2_ino_t dir EXT2FS_ATTR ((unused)),int entry EXT2FS_ATTR ((unused)),struct ext2_dir_entry * dirent,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * private)1315 static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
1316 		      int	entry EXT2FS_ATTR((unused)),
1317 		      struct ext2_dir_entry *dirent,
1318 		      int	offset EXT2FS_ATTR((unused)),
1319 		      int	blocksize EXT2FS_ATTR((unused)),
1320 		      char	*buf EXT2FS_ATTR((unused)),
1321 		      void	*private)
1322 {
1323 	struct rd_struct *rds = (struct rd_struct *) private;
1324 
1325 	if (dirent->inode == 0)
1326 		return 0;
1327 	if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.'))
1328 		return 0;
1329 	if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') &&
1330 	    (dirent->name[1] == '.')) {
1331 		rds->parent = dirent->inode;
1332 		return 0;
1333 	}
1334 	rds->empty = 0;
1335 	return 0;
1336 }
1337 
__op_rmdir(struct fuse2fs * ff,const char * path)1338 static int __op_rmdir(struct fuse2fs *ff, const char *path)
1339 {
1340 	ext2_filsys fs = ff->fs;
1341 	ext2_ino_t child;
1342 	errcode_t err;
1343 	struct ext2_inode_large inode;
1344 	struct rd_struct rds;
1345 	int ret = 0;
1346 
1347 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &child);
1348 	if (err) {
1349 		ret = translate_error(fs, 0, err);
1350 		goto out;
1351 	}
1352 	dbg_printf("%s: rmdir path=%s ino=%d\n", __func__, path, child);
1353 
1354 	rds.parent = 0;
1355 	rds.empty = 1;
1356 
1357 	err = ext2fs_dir_iterate2(fs, child, 0, 0, rmdir_proc, &rds);
1358 	if (err) {
1359 		ret = translate_error(fs, child, err);
1360 		goto out;
1361 	}
1362 
1363 	if (rds.empty == 0) {
1364 		ret = -ENOTEMPTY;
1365 		goto out;
1366 	}
1367 
1368 	ret = unlink_file_by_name(fs, path);
1369 	if (ret)
1370 		goto out;
1371 	/* Directories have to be "removed" twice. */
1372 	ret = remove_inode(ff, child);
1373 	if (ret)
1374 		goto out;
1375 	ret = remove_inode(ff, child);
1376 	if (ret)
1377 		goto out;
1378 
1379 	if (rds.parent) {
1380 		dbg_printf("%s: decr dir=%d link count\n", __func__,
1381 			   rds.parent);
1382 		err = ext2fs_read_inode_full(fs, rds.parent,
1383 					     (struct ext2_inode *)&inode,
1384 					     sizeof(inode));
1385 		if (err) {
1386 			ret = translate_error(fs, rds.parent, err);
1387 			goto out;
1388 		}
1389 		if (inode.i_links_count > 1)
1390 			inode.i_links_count--;
1391 		ret = update_mtime(fs, rds.parent, &inode);
1392 		if (ret)
1393 			goto out;
1394 		err = ext2fs_write_inode_full(fs, rds.parent,
1395 					      (struct ext2_inode *)&inode,
1396 					      sizeof(inode));
1397 		if (err) {
1398 			ret = translate_error(fs, rds.parent, err);
1399 			goto out;
1400 		}
1401 	}
1402 
1403 out:
1404 	return ret;
1405 }
1406 
op_rmdir(const char * path)1407 static int op_rmdir(const char *path)
1408 {
1409 	struct fuse_context *ctxt = fuse_get_context();
1410 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1411 	int ret;
1412 
1413 	FUSE2FS_CHECK_CONTEXT(ff);
1414 	pthread_mutex_lock(&ff->bfl);
1415 	ret = __op_rmdir(ff, path);
1416 	pthread_mutex_unlock(&ff->bfl);
1417 	return ret;
1418 }
1419 
op_symlink(const char * src,const char * dest)1420 static int op_symlink(const char *src, const char *dest)
1421 {
1422 	struct fuse_context *ctxt = fuse_get_context();
1423 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1424 	ext2_filsys fs;
1425 	ext2_ino_t parent, child;
1426 	char *temp_path;
1427 	errcode_t err;
1428 	char *node_name, a;
1429 	struct ext2_inode_large inode;
1430 	int ret = 0;
1431 
1432 	FUSE2FS_CHECK_CONTEXT(ff);
1433 	fs = ff->fs;
1434 	dbg_printf("%s: symlink %s to %s\n", __func__, src, dest);
1435 	temp_path = strdup(dest);
1436 	if (!temp_path) {
1437 		ret = -ENOMEM;
1438 		goto out;
1439 	}
1440 	node_name = strrchr(temp_path, '/');
1441 	if (!node_name) {
1442 		ret = -ENOMEM;
1443 		goto out;
1444 	}
1445 	node_name++;
1446 	a = *node_name;
1447 	*node_name = 0;
1448 
1449 	pthread_mutex_lock(&ff->bfl);
1450 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1451 			   &parent);
1452 	*node_name = a;
1453 	if (err) {
1454 		ret = translate_error(fs, 0, err);
1455 		goto out2;
1456 	}
1457 
1458 	ret = check_inum_access(fs, parent, W_OK);
1459 	if (ret)
1460 		goto out2;
1461 
1462 
1463 	/* Create symlink */
1464 	err = ext2fs_symlink(fs, parent, 0, node_name, src);
1465 	if (err == EXT2_ET_DIR_NO_SPACE) {
1466 		err = ext2fs_expand_dir(fs, parent);
1467 		if (err) {
1468 			ret = translate_error(fs, parent, err);
1469 			goto out2;
1470 		}
1471 
1472 		err = ext2fs_symlink(fs, parent, 0, node_name, src);
1473 	}
1474 	if (err) {
1475 		ret = translate_error(fs, parent, err);
1476 		goto out2;
1477 	}
1478 
1479 	/* Update parent dir's mtime */
1480 	ret = update_mtime(fs, parent, NULL);
1481 	if (ret)
1482 		goto out2;
1483 
1484 	/* Still have to update the uid/gid of the symlink */
1485 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1486 			   &child);
1487 	if (err) {
1488 		ret = translate_error(fs, 0, err);
1489 		goto out2;
1490 	}
1491 	dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__,
1492 		   child, node_name, parent);
1493 
1494 	memset(&inode, 0, sizeof(inode));
1495 	err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode,
1496 				     sizeof(inode));
1497 	if (err) {
1498 		ret = translate_error(fs, child, err);
1499 		goto out2;
1500 	}
1501 
1502 	inode.i_uid = ctxt->uid;
1503 	ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
1504 	inode.i_gid = ctxt->gid;
1505 	ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
1506 	inode.i_generation = ff->next_generation++;
1507 
1508 	err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
1509 				      sizeof(inode));
1510 	if (err) {
1511 		ret = translate_error(fs, child, err);
1512 		goto out2;
1513 	}
1514 out2:
1515 	pthread_mutex_unlock(&ff->bfl);
1516 out:
1517 	free(temp_path);
1518 	return ret;
1519 }
1520 
1521 struct update_dotdot {
1522 	ext2_ino_t new_dotdot;
1523 };
1524 
update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR ((unused)),int entry EXT2FS_ATTR ((unused)),struct ext2_dir_entry * dirent,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * priv_data)1525 static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)),
1526 				int entry EXT2FS_ATTR((unused)),
1527 				struct ext2_dir_entry *dirent,
1528 				int offset EXT2FS_ATTR((unused)),
1529 				int blocksize EXT2FS_ATTR((unused)),
1530 				char *buf EXT2FS_ATTR((unused)),
1531 				void *priv_data)
1532 {
1533 	struct update_dotdot *ud = priv_data;
1534 
1535 	if (ext2fs_dirent_name_len(dirent) == 2 &&
1536 	    dirent->name[0] == '.' && dirent->name[1] == '.') {
1537 		dirent->inode = ud->new_dotdot;
1538 		return DIRENT_CHANGED | DIRENT_ABORT;
1539 	}
1540 
1541 	return 0;
1542 }
1543 
op_rename(const char * from,const char * to)1544 static int op_rename(const char *from, const char *to)
1545 {
1546 	struct fuse_context *ctxt = fuse_get_context();
1547 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1548 	ext2_filsys fs;
1549 	errcode_t err;
1550 	ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino;
1551 	char *temp_to = NULL, *temp_from = NULL;
1552 	char *cp, a;
1553 	struct ext2_inode inode;
1554 	struct update_dotdot ud;
1555 	int ret = 0;
1556 
1557 	FUSE2FS_CHECK_CONTEXT(ff);
1558 	fs = ff->fs;
1559 	dbg_printf("%s: renaming %s to %s\n", __func__, from, to);
1560 	pthread_mutex_lock(&ff->bfl);
1561 	if (!fs_can_allocate(ff, 5)) {
1562 		ret = -ENOSPC;
1563 		goto out;
1564 	}
1565 
1566 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, from, &from_ino);
1567 	if (err || from_ino == 0) {
1568 		ret = translate_error(fs, 0, err);
1569 		goto out;
1570 	}
1571 
1572 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, to, &to_ino);
1573 	if (err && err != EXT2_ET_FILE_NOT_FOUND) {
1574 		ret = translate_error(fs, 0, err);
1575 		goto out;
1576 	}
1577 
1578 	if (err == EXT2_ET_FILE_NOT_FOUND)
1579 		to_ino = 0;
1580 
1581 	/* Already the same file? */
1582 	if (to_ino != 0 && to_ino == from_ino) {
1583 		ret = 0;
1584 		goto out;
1585 	}
1586 
1587 	temp_to = strdup(to);
1588 	if (!temp_to) {
1589 		ret = -ENOMEM;
1590 		goto out;
1591 	}
1592 
1593 	temp_from = strdup(from);
1594 	if (!temp_from) {
1595 		ret = -ENOMEM;
1596 		goto out2;
1597 	}
1598 
1599 	/* Find parent dir of the source and check write access */
1600 	cp = strrchr(temp_from, '/');
1601 	if (!cp) {
1602 		ret = -EINVAL;
1603 		goto out2;
1604 	}
1605 
1606 	a = *(cp + 1);
1607 	*(cp + 1) = 0;
1608 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_from,
1609 			   &from_dir_ino);
1610 	*(cp + 1) = a;
1611 	if (err) {
1612 		ret = translate_error(fs, 0, err);
1613 		goto out2;
1614 	}
1615 	if (from_dir_ino == 0) {
1616 		ret = -ENOENT;
1617 		goto out2;
1618 	}
1619 
1620 	ret = check_inum_access(fs, from_dir_ino, W_OK);
1621 	if (ret)
1622 		goto out2;
1623 
1624 	/* Find parent dir of the destination and check write access */
1625 	cp = strrchr(temp_to, '/');
1626 	if (!cp) {
1627 		ret = -EINVAL;
1628 		goto out2;
1629 	}
1630 
1631 	a = *(cp + 1);
1632 	*(cp + 1) = 0;
1633 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_to,
1634 			   &to_dir_ino);
1635 	*(cp + 1) = a;
1636 	if (err) {
1637 		ret = translate_error(fs, 0, err);
1638 		goto out2;
1639 	}
1640 	if (to_dir_ino == 0) {
1641 		ret = -ENOENT;
1642 		goto out2;
1643 	}
1644 
1645 	ret = check_inum_access(fs, to_dir_ino, W_OK);
1646 	if (ret)
1647 		goto out2;
1648 
1649 	/* If the target exists, unlink it first */
1650 	if (to_ino != 0) {
1651 		err = ext2fs_read_inode(fs, to_ino, &inode);
1652 		if (err) {
1653 			ret = translate_error(fs, to_ino, err);
1654 			goto out2;
1655 		}
1656 
1657 		dbg_printf("%s: unlinking %s ino=%d\n", __func__,
1658 			   LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file",
1659 			   to_ino);
1660 		if (LINUX_S_ISDIR(inode.i_mode))
1661 			ret = __op_rmdir(ff, to);
1662 		else
1663 			ret = __op_unlink(ff, to);
1664 		if (ret)
1665 			goto out2;
1666 	}
1667 
1668 	/* Get ready to do the move */
1669 	err = ext2fs_read_inode(fs, from_ino, &inode);
1670 	if (err) {
1671 		ret = translate_error(fs, from_ino, err);
1672 		goto out2;
1673 	}
1674 
1675 	/* Link in the new file */
1676 	dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__,
1677 		   from_ino, cp + 1, to_dir_ino);
1678 	err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1679 			  ext2_file_type(inode.i_mode));
1680 	if (err == EXT2_ET_DIR_NO_SPACE) {
1681 		err = ext2fs_expand_dir(fs, to_dir_ino);
1682 		if (err) {
1683 			ret = translate_error(fs, to_dir_ino, err);
1684 			goto out2;
1685 		}
1686 
1687 		err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino,
1688 				     ext2_file_type(inode.i_mode));
1689 	}
1690 	if (err) {
1691 		ret = translate_error(fs, to_dir_ino, err);
1692 		goto out2;
1693 	}
1694 
1695 	/* Update '..' pointer if dir */
1696 	err = ext2fs_read_inode(fs, from_ino, &inode);
1697 	if (err) {
1698 		ret = translate_error(fs, from_ino, err);
1699 		goto out2;
1700 	}
1701 
1702 	if (LINUX_S_ISDIR(inode.i_mode)) {
1703 		ud.new_dotdot = to_dir_ino;
1704 		dbg_printf("%s: updating .. entry for dir=%d\n", __func__,
1705 			   to_dir_ino);
1706 		err = ext2fs_dir_iterate2(fs, from_ino, 0, NULL,
1707 					  update_dotdot_helper, &ud);
1708 		if (err) {
1709 			ret = translate_error(fs, from_ino, err);
1710 			goto out2;
1711 		}
1712 
1713 		/* Decrease from_dir_ino's links_count */
1714 		dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n",
1715 			   __func__, from_dir_ino, to_dir_ino);
1716 		err = ext2fs_read_inode(fs, from_dir_ino, &inode);
1717 		if (err) {
1718 			ret = translate_error(fs, from_dir_ino, err);
1719 			goto out2;
1720 		}
1721 		inode.i_links_count--;
1722 		err = ext2fs_write_inode(fs, from_dir_ino, &inode);
1723 		if (err) {
1724 			ret = translate_error(fs, from_dir_ino, err);
1725 			goto out2;
1726 		}
1727 
1728 		/* Increase to_dir_ino's links_count */
1729 		err = ext2fs_read_inode(fs, to_dir_ino, &inode);
1730 		if (err) {
1731 			ret = translate_error(fs, to_dir_ino, err);
1732 			goto out2;
1733 		}
1734 		inode.i_links_count++;
1735 		err = ext2fs_write_inode(fs, to_dir_ino, &inode);
1736 		if (err) {
1737 			ret = translate_error(fs, to_dir_ino, err);
1738 			goto out2;
1739 		}
1740 	}
1741 
1742 	/* Update timestamps */
1743 	ret = update_ctime(fs, from_ino, NULL);
1744 	if (ret)
1745 		goto out2;
1746 
1747 	ret = update_mtime(fs, to_dir_ino, NULL);
1748 	if (ret)
1749 		goto out2;
1750 
1751 	/* Remove the old file */
1752 	ret = unlink_file_by_name(fs, from);
1753 	if (ret)
1754 		goto out2;
1755 
1756 	/* Flush the whole mess out */
1757 	err = ext2fs_flush2(fs, 0);
1758 	if (err)
1759 		ret = translate_error(fs, 0, err);
1760 
1761 out2:
1762 	free(temp_from);
1763 	free(temp_to);
1764 out:
1765 	pthread_mutex_unlock(&ff->bfl);
1766 	return ret;
1767 }
1768 
op_link(const char * src,const char * dest)1769 static int op_link(const char *src, const char *dest)
1770 {
1771 	struct fuse_context *ctxt = fuse_get_context();
1772 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1773 	ext2_filsys fs;
1774 	char *temp_path;
1775 	errcode_t err;
1776 	char *node_name, a;
1777 	ext2_ino_t parent, ino;
1778 	struct ext2_inode_large inode;
1779 	int ret = 0;
1780 
1781 	FUSE2FS_CHECK_CONTEXT(ff);
1782 	fs = ff->fs;
1783 	dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest);
1784 	temp_path = strdup(dest);
1785 	if (!temp_path) {
1786 		ret = -ENOMEM;
1787 		goto out;
1788 	}
1789 	node_name = strrchr(temp_path, '/');
1790 	if (!node_name) {
1791 		ret = -ENOMEM;
1792 		goto out;
1793 	}
1794 	node_name++;
1795 	a = *node_name;
1796 	*node_name = 0;
1797 
1798 	pthread_mutex_lock(&ff->bfl);
1799 	if (!fs_can_allocate(ff, 2)) {
1800 		ret = -ENOSPC;
1801 		goto out2;
1802 	}
1803 
1804 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
1805 			   &parent);
1806 	*node_name = a;
1807 	if (err) {
1808 		err = -ENOENT;
1809 		goto out2;
1810 	}
1811 
1812 	ret = check_inum_access(fs, parent, W_OK);
1813 	if (ret)
1814 		goto out2;
1815 
1816 
1817 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, src, &ino);
1818 	if (err || ino == 0) {
1819 		ret = translate_error(fs, 0, err);
1820 		goto out2;
1821 	}
1822 
1823 	memset(&inode, 0, sizeof(inode));
1824 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1825 				     sizeof(inode));
1826 	if (err) {
1827 		ret = translate_error(fs, ino, err);
1828 		goto out2;
1829 	}
1830 
1831 	inode.i_links_count++;
1832 	ret = update_ctime(fs, ino, &inode);
1833 	if (ret)
1834 		goto out2;
1835 
1836 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1837 				      sizeof(inode));
1838 	if (err) {
1839 		ret = translate_error(fs, ino, err);
1840 		goto out2;
1841 	}
1842 
1843 	dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__, ino,
1844 		   node_name, parent);
1845 	err = ext2fs_link(fs, parent, node_name, ino,
1846 			  ext2_file_type(inode.i_mode));
1847 	if (err == EXT2_ET_DIR_NO_SPACE) {
1848 		err = ext2fs_expand_dir(fs, parent);
1849 		if (err) {
1850 			ret = translate_error(fs, parent, err);
1851 			goto out2;
1852 		}
1853 
1854 		err = ext2fs_link(fs, parent, node_name, ino,
1855 				     ext2_file_type(inode.i_mode));
1856 	}
1857 	if (err) {
1858 		ret = translate_error(fs, parent, err);
1859 		goto out2;
1860 	}
1861 
1862 	ret = update_mtime(fs, parent, NULL);
1863 	if (ret)
1864 		goto out2;
1865 
1866 out2:
1867 	pthread_mutex_unlock(&ff->bfl);
1868 out:
1869 	free(temp_path);
1870 	return ret;
1871 }
1872 
op_chmod(const char * path,mode_t mode)1873 static int op_chmod(const char *path, mode_t mode)
1874 {
1875 	struct fuse_context *ctxt = fuse_get_context();
1876 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1877 	ext2_filsys fs;
1878 	errcode_t err;
1879 	ext2_ino_t ino;
1880 	struct ext2_inode_large inode;
1881 	int ret = 0;
1882 
1883 	FUSE2FS_CHECK_CONTEXT(ff);
1884 	fs = ff->fs;
1885 	pthread_mutex_lock(&ff->bfl);
1886 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1887 	if (err) {
1888 		ret = translate_error(fs, 0, err);
1889 		goto out;
1890 	}
1891 	dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__, path, mode, ino);
1892 
1893 	memset(&inode, 0, sizeof(inode));
1894 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1895 				     sizeof(inode));
1896 	if (err) {
1897 		ret = translate_error(fs, ino, err);
1898 		goto out;
1899 	}
1900 
1901 	if (!ff->fakeroot && ctxt->uid != 0 && ctxt->uid != inode_uid(inode)) {
1902 		ret = -EPERM;
1903 		goto out;
1904 	}
1905 
1906 	/*
1907 	 * XXX: We should really check that the inode gid is not in /any/
1908 	 * of the user's groups, but FUSE only tells us about the primary
1909 	 * group.
1910 	 */
1911 	if (!ff->fakeroot && ctxt->uid != 0 && ctxt->gid != inode_gid(inode))
1912 		mode &= ~S_ISGID;
1913 
1914 	inode.i_mode &= ~0xFFF;
1915 	inode.i_mode |= mode & 0xFFF;
1916 	ret = update_ctime(fs, ino, &inode);
1917 	if (ret)
1918 		goto out;
1919 
1920 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1921 				      sizeof(inode));
1922 	if (err) {
1923 		ret = translate_error(fs, ino, err);
1924 		goto out;
1925 	}
1926 
1927 out:
1928 	pthread_mutex_unlock(&ff->bfl);
1929 	return ret;
1930 }
1931 
op_chown(const char * path,uid_t owner,gid_t group)1932 static int op_chown(const char *path, uid_t owner, gid_t group)
1933 {
1934 	struct fuse_context *ctxt = fuse_get_context();
1935 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
1936 	ext2_filsys fs;
1937 	errcode_t err;
1938 	ext2_ino_t ino;
1939 	struct ext2_inode_large inode;
1940 	int ret = 0;
1941 
1942 	FUSE2FS_CHECK_CONTEXT(ff);
1943 	fs = ff->fs;
1944 	pthread_mutex_lock(&ff->bfl);
1945 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
1946 	if (err) {
1947 		ret = translate_error(fs, 0, err);
1948 		goto out;
1949 	}
1950 	dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__,
1951 		   path, owner, group, ino);
1952 
1953 	memset(&inode, 0, sizeof(inode));
1954 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
1955 				     sizeof(inode));
1956 	if (err) {
1957 		ret = translate_error(fs, ino, err);
1958 		goto out;
1959 	}
1960 
1961 	/* FUSE seems to feed us ~0 to mean "don't change" */
1962 	if (owner != (uid_t) ~0) {
1963 		/* Only root gets to change UID. */
1964 		if (!ff->fakeroot && ctxt->uid != 0 &&
1965 		    !(inode_uid(inode) == ctxt->uid && owner == ctxt->uid)) {
1966 			ret = -EPERM;
1967 			goto out;
1968 		}
1969 		inode.i_uid = owner;
1970 		ext2fs_set_i_uid_high(inode, owner >> 16);
1971 	}
1972 
1973 	if (group != (gid_t) ~0) {
1974 		/* Only root or the owner get to change GID. */
1975 		if (!ff->fakeroot && ctxt->uid != 0 &&
1976 		    inode_uid(inode) != ctxt->uid) {
1977 			ret = -EPERM;
1978 			goto out;
1979 		}
1980 
1981 		/* XXX: We /should/ check group membership but FUSE */
1982 		inode.i_gid = group;
1983 		ext2fs_set_i_gid_high(inode, group >> 16);
1984 	}
1985 
1986 	ret = update_ctime(fs, ino, &inode);
1987 	if (ret)
1988 		goto out;
1989 
1990 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
1991 				      sizeof(inode));
1992 	if (err) {
1993 		ret = translate_error(fs, ino, err);
1994 		goto out;
1995 	}
1996 
1997 out:
1998 	pthread_mutex_unlock(&ff->bfl);
1999 	return ret;
2000 }
2001 
op_truncate(const char * path,off_t len)2002 static int op_truncate(const char *path, off_t len)
2003 {
2004 	struct fuse_context *ctxt = fuse_get_context();
2005 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2006 	ext2_filsys fs;
2007 	errcode_t err;
2008 	ext2_ino_t ino;
2009 	ext2_file_t file;
2010 	int ret = 0;
2011 
2012 	FUSE2FS_CHECK_CONTEXT(ff);
2013 	fs = ff->fs;
2014 	pthread_mutex_lock(&ff->bfl);
2015 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2016 	if (err || ino == 0) {
2017 		ret = translate_error(fs, 0, err);
2018 		goto out;
2019 	}
2020 	dbg_printf("%s: ino=%d len=%jd\n", __func__, ino, len);
2021 
2022 	ret = check_inum_access(fs, ino, W_OK);
2023 	if (ret)
2024 		goto out;
2025 
2026 	err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file);
2027 	if (err) {
2028 		ret = translate_error(fs, ino, err);
2029 		goto out;
2030 	}
2031 
2032 	err = ext2fs_file_set_size2(file, len);
2033 	if (err) {
2034 		ret = translate_error(fs, ino, err);
2035 		goto out2;
2036 	}
2037 
2038 out2:
2039 	err = ext2fs_file_close(file);
2040 	if (ret)
2041 		goto out;
2042 	if (err) {
2043 		ret = translate_error(fs, ino, err);
2044 		goto out;
2045 	}
2046 
2047 	ret = update_mtime(fs, ino, NULL);
2048 
2049 out:
2050 	pthread_mutex_unlock(&ff->bfl);
2051 	return err;
2052 }
2053 
2054 #ifdef __linux__
detect_linux_executable_open(int kernel_flags,int * access_check,int * e2fs_open_flags)2055 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2056 				  int *e2fs_open_flags)
2057 {
2058 	/*
2059 	 * On Linux, execve will bleed __FMODE_EXEC into the file mode flags,
2060 	 * and FUSE is more than happy to let that slip through.
2061 	 */
2062 	if (kernel_flags & 0x20) {
2063 		*access_check = X_OK;
2064 		*e2fs_open_flags &= ~EXT2_FILE_WRITE;
2065 	}
2066 }
2067 #else
detect_linux_executable_open(int kernel_flags,int * access_check,int * e2fs_open_flags)2068 static void detect_linux_executable_open(int kernel_flags, int *access_check,
2069 				  int *e2fs_open_flags)
2070 {
2071 	/* empty */
2072 }
2073 #endif /* __linux__ */
2074 
__op_open(struct fuse2fs * ff,const char * path,struct fuse_file_info * fp)2075 static int __op_open(struct fuse2fs *ff, const char *path,
2076 		     struct fuse_file_info *fp)
2077 {
2078 	ext2_filsys fs = ff->fs;
2079 	errcode_t err;
2080 	struct fuse2fs_file_handle *file;
2081 	int check = 0, ret = 0;
2082 
2083 	dbg_printf("%s: path=%s\n", __func__, path);
2084 	err = ext2fs_get_mem(sizeof(*file), &file);
2085 	if (err)
2086 		return translate_error(fs, 0, err);
2087 	file->magic = FUSE2FS_FILE_MAGIC;
2088 
2089 	file->open_flags = 0;
2090 	switch (fp->flags & O_ACCMODE) {
2091 	case O_RDONLY:
2092 		check = R_OK;
2093 		break;
2094 	case O_WRONLY:
2095 		check = W_OK;
2096 		file->open_flags |= EXT2_FILE_WRITE;
2097 		break;
2098 	case O_RDWR:
2099 		check = R_OK | W_OK;
2100 		file->open_flags |= EXT2_FILE_WRITE;
2101 		break;
2102 	}
2103 
2104 	detect_linux_executable_open(fp->flags, &check, &file->open_flags);
2105 
2106 	if (fp->flags & O_CREAT)
2107 		file->open_flags |= EXT2_FILE_CREATE;
2108 
2109 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &file->ino);
2110 	if (err || file->ino == 0) {
2111 		ret = translate_error(fs, 0, err);
2112 		goto out;
2113 	}
2114 	dbg_printf("%s: ino=%d\n", __func__, file->ino);
2115 
2116 	ret = check_inum_access(fs, file->ino, check);
2117 	if (ret) {
2118 		/*
2119 		 * In a regular (Linux) fs driver, the kernel will open
2120 		 * binaries for reading if the user has --x privileges (i.e.
2121 		 * execute without read).  Since the kernel doesn't have any
2122 		 * way to tell us if it's opening a file via execve, we'll
2123 		 * just assume that allowing access is ok if asking for ro mode
2124 		 * fails but asking for x mode succeeds.  Of course we can
2125 		 * also employ undocumented hacks (see above).
2126 		 */
2127 		if (check == R_OK) {
2128 			ret = check_inum_access(fs, file->ino, X_OK);
2129 			if (ret)
2130 				goto out;
2131 		} else
2132 			goto out;
2133 	}
2134 	fp->fh = (uintptr_t)file;
2135 
2136 out:
2137 	if (ret)
2138 		ext2fs_free_mem(&file);
2139 	return ret;
2140 }
2141 
op_open(const char * path,struct fuse_file_info * fp)2142 static int op_open(const char *path, struct fuse_file_info *fp)
2143 {
2144 	struct fuse_context *ctxt = fuse_get_context();
2145 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2146 	int ret;
2147 
2148 	FUSE2FS_CHECK_CONTEXT(ff);
2149 	pthread_mutex_lock(&ff->bfl);
2150 	ret = __op_open(ff, path, fp);
2151 	pthread_mutex_unlock(&ff->bfl);
2152 	return ret;
2153 }
2154 
op_read(const char * path EXT2FS_ATTR ((unused)),char * buf,size_t len,off_t offset,struct fuse_file_info * fp)2155 static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf,
2156 		   size_t len, off_t offset,
2157 		   struct fuse_file_info *fp)
2158 {
2159 	struct fuse_context *ctxt = fuse_get_context();
2160 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2161 	struct fuse2fs_file_handle *fh =
2162 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2163 	ext2_filsys fs;
2164 	ext2_file_t efp;
2165 	errcode_t err;
2166 	unsigned int got = 0;
2167 	int ret = 0;
2168 
2169 	FUSE2FS_CHECK_CONTEXT(ff);
2170 	fs = ff->fs;
2171 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2172 	dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2173 		   len);
2174 	pthread_mutex_lock(&ff->bfl);
2175 	err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2176 	if (err) {
2177 		ret = translate_error(fs, fh->ino, err);
2178 		goto out;
2179 	}
2180 
2181 	err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2182 	if (err) {
2183 		ret = translate_error(fs, fh->ino, err);
2184 		goto out2;
2185 	}
2186 
2187 	err = ext2fs_file_read(efp, buf, len, &got);
2188 	if (err) {
2189 		ret = translate_error(fs, fh->ino, err);
2190 		goto out2;
2191 	}
2192 
2193 out2:
2194 	err = ext2fs_file_close(efp);
2195 	if (ret)
2196 		goto out;
2197 	if (err) {
2198 		ret = translate_error(fs, fh->ino, err);
2199 		goto out;
2200 	}
2201 
2202 	if (fs_writeable(fs)) {
2203 		ret = update_atime(fs, fh->ino);
2204 		if (ret)
2205 			goto out;
2206 	}
2207 out:
2208 	pthread_mutex_unlock(&ff->bfl);
2209 	return got ? (int) got : ret;
2210 }
2211 
op_write(const char * path EXT2FS_ATTR ((unused)),const char * buf,size_t len,off_t offset,struct fuse_file_info * fp)2212 static int op_write(const char *path EXT2FS_ATTR((unused)),
2213 		    const char *buf, size_t len, off_t offset,
2214 		    struct fuse_file_info *fp)
2215 {
2216 	struct fuse_context *ctxt = fuse_get_context();
2217 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2218 	struct fuse2fs_file_handle *fh =
2219 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2220 	ext2_filsys fs;
2221 	ext2_file_t efp;
2222 	errcode_t err;
2223 	unsigned int got = 0;
2224 	int ret = 0;
2225 
2226 	FUSE2FS_CHECK_CONTEXT(ff);
2227 	fs = ff->fs;
2228 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2229 	dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset,
2230 		   len);
2231 	pthread_mutex_lock(&ff->bfl);
2232 	if (!fs_writeable(fs)) {
2233 		ret = -EROFS;
2234 		goto out;
2235 	}
2236 
2237 	if (!fs_can_allocate(ff, len / fs->blocksize)) {
2238 		ret = -ENOSPC;
2239 		goto out;
2240 	}
2241 
2242 	err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2243 	if (err) {
2244 		ret = translate_error(fs, fh->ino, err);
2245 		goto out;
2246 	}
2247 
2248 	err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL);
2249 	if (err) {
2250 		ret = translate_error(fs, fh->ino, err);
2251 		goto out2;
2252 	}
2253 
2254 	err = ext2fs_file_write(efp, buf, len, &got);
2255 	if (err) {
2256 		ret = translate_error(fs, fh->ino, err);
2257 		goto out2;
2258 	}
2259 
2260 	err = ext2fs_file_flush(efp);
2261 	if (err) {
2262 		got = 0;
2263 		ret = translate_error(fs, fh->ino, err);
2264 		goto out2;
2265 	}
2266 
2267 out2:
2268 	err = ext2fs_file_close(efp);
2269 	if (ret)
2270 		goto out;
2271 	if (err) {
2272 		ret = translate_error(fs, fh->ino, err);
2273 		goto out;
2274 	}
2275 
2276 	ret = update_mtime(fs, fh->ino, NULL);
2277 	if (ret)
2278 		goto out;
2279 
2280 out:
2281 	pthread_mutex_unlock(&ff->bfl);
2282 	return got ? (int) got : ret;
2283 }
2284 
op_release(const char * path EXT2FS_ATTR ((unused)),struct fuse_file_info * fp)2285 static int op_release(const char *path EXT2FS_ATTR((unused)),
2286 		      struct fuse_file_info *fp)
2287 {
2288 	struct fuse_context *ctxt = fuse_get_context();
2289 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2290 	struct fuse2fs_file_handle *fh =
2291 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2292 	ext2_filsys fs;
2293 	errcode_t err;
2294 	int ret = 0;
2295 
2296 	FUSE2FS_CHECK_CONTEXT(ff);
2297 	fs = ff->fs;
2298 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2299 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2300 	pthread_mutex_lock(&ff->bfl);
2301 	if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2302 		err = ext2fs_flush2(fs, EXT2_FLAG_FLUSH_NO_SYNC);
2303 		if (err)
2304 			ret = translate_error(fs, fh->ino, err);
2305 	}
2306 	fp->fh = 0;
2307 	pthread_mutex_unlock(&ff->bfl);
2308 
2309 	ext2fs_free_mem(&fh);
2310 
2311 	return ret;
2312 }
2313 
op_fsync(const char * path EXT2FS_ATTR ((unused)),int datasync EXT2FS_ATTR ((unused)),struct fuse_file_info * fp)2314 static int op_fsync(const char *path EXT2FS_ATTR((unused)),
2315 		    int datasync EXT2FS_ATTR((unused)),
2316 		    struct fuse_file_info *fp)
2317 {
2318 	struct fuse_context *ctxt = fuse_get_context();
2319 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2320 	struct fuse2fs_file_handle *fh =
2321 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2322 	ext2_filsys fs;
2323 	errcode_t err;
2324 	int ret = 0;
2325 
2326 	FUSE2FS_CHECK_CONTEXT(ff);
2327 	fs = ff->fs;
2328 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2329 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2330 	/* For now, flush everything, even if it's slow */
2331 	pthread_mutex_lock(&ff->bfl);
2332 	if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) {
2333 		err = ext2fs_flush2(fs, 0);
2334 		if (err)
2335 			ret = translate_error(fs, fh->ino, err);
2336 	}
2337 	pthread_mutex_unlock(&ff->bfl);
2338 
2339 	return ret;
2340 }
2341 
op_statfs(const char * path EXT2FS_ATTR ((unused)),struct statvfs * buf)2342 static int op_statfs(const char *path EXT2FS_ATTR((unused)),
2343 		     struct statvfs *buf)
2344 {
2345 	struct fuse_context *ctxt = fuse_get_context();
2346 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2347 	ext2_filsys fs;
2348 	uint64_t fsid, *f;
2349 	blk64_t overhead, reserved, free;
2350 
2351 	FUSE2FS_CHECK_CONTEXT(ff);
2352 	fs = ff->fs;
2353 	dbg_printf("%s: path=%s\n", __func__, path);
2354 	buf->f_bsize = fs->blocksize;
2355 	buf->f_frsize = 0;
2356 
2357 	if (ff->minixdf)
2358 		overhead = 0;
2359 	else
2360 		overhead = fs->desc_blocks +
2361 			   (blk64_t)fs->group_desc_count *
2362 			   (fs->inode_blocks_per_group + 2);
2363 	reserved = ext2fs_r_blocks_count(fs->super);
2364 	if (!reserved)
2365 		reserved = ext2fs_blocks_count(fs->super) / 10;
2366 	free = ext2fs_free_blocks_count(fs->super);
2367 
2368 	buf->f_blocks = ext2fs_blocks_count(fs->super) - overhead;
2369 	buf->f_bfree = free;
2370 	if (free < reserved)
2371 		buf->f_bavail = 0;
2372 	else
2373 		buf->f_bavail = free - reserved;
2374 	buf->f_files = fs->super->s_inodes_count;
2375 	buf->f_ffree = fs->super->s_free_inodes_count;
2376 	buf->f_favail = fs->super->s_free_inodes_count;
2377 	f = (uint64_t *)fs->super->s_uuid;
2378 	fsid = *f;
2379 	f++;
2380 	fsid ^= *f;
2381 	buf->f_fsid = fsid;
2382 	buf->f_flag = 0;
2383 	if (fs->flags & EXT2_FLAG_RW)
2384 		buf->f_flag |= ST_RDONLY;
2385 	buf->f_namemax = EXT2_NAME_LEN;
2386 
2387 	return 0;
2388 }
2389 
2390 typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz,
2391 				     const void *raw_buf, size_t raw_sz);
2392 typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz,
2393 				     const void **raw_buf, size_t *raw_sz);
2394 struct xattr_translate {
2395 	const char *prefix;
2396 	xattr_xlate_get get;
2397 	xattr_xlate_set set;
2398 };
2399 
2400 #define XATTR_TRANSLATOR(p, g, s) \
2401 	{.prefix = (p), \
2402 	 .get = (xattr_xlate_get)(g), \
2403 	 .set = (xattr_xlate_set)(s)}
2404 
2405 static struct xattr_translate xattr_translators[] = {
2406 #ifdef TRANSLATE_LINUX_ACLS
2407 	XATTR_TRANSLATOR(ACL_EA_ACCESS, ext4_to_fuse_acl, fuse_to_ext4_acl),
2408 	XATTR_TRANSLATOR(ACL_EA_DEFAULT, ext4_to_fuse_acl, fuse_to_ext4_acl),
2409 #endif
2410 	XATTR_TRANSLATOR(NULL, NULL, NULL),
2411 };
2412 #undef XATTR_TRANSLATOR
2413 
op_getxattr(const char * path,const char * key,char * value,size_t len)2414 static int op_getxattr(const char *path, const char *key, char *value,
2415 		       size_t len)
2416 {
2417 	struct fuse_context *ctxt = fuse_get_context();
2418 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2419 	ext2_filsys fs;
2420 	struct ext2_xattr_handle *h;
2421 	struct xattr_translate *xt;
2422 	void *ptr, *cptr;
2423 	size_t plen, clen;
2424 	ext2_ino_t ino;
2425 	errcode_t err;
2426 	int ret = 0;
2427 
2428 	FUSE2FS_CHECK_CONTEXT(ff);
2429 	fs = ff->fs;
2430 	pthread_mutex_lock(&ff->bfl);
2431 	if (!ext2fs_has_feature_xattr(fs->super)) {
2432 		ret = -ENOTSUP;
2433 		goto out;
2434 	}
2435 
2436 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2437 	if (err || ino == 0) {
2438 		ret = translate_error(fs, 0, err);
2439 		goto out;
2440 	}
2441 	dbg_printf("%s: ino=%d\n", __func__, ino);
2442 
2443 	ret = check_inum_access(fs, ino, R_OK);
2444 	if (ret)
2445 		goto out;
2446 
2447 	err = ext2fs_xattrs_open(fs, ino, &h);
2448 	if (err) {
2449 		ret = translate_error(fs, ino, err);
2450 		goto out;
2451 	}
2452 
2453 	err = ext2fs_xattrs_read(h);
2454 	if (err) {
2455 		ret = translate_error(fs, ino, err);
2456 		goto out2;
2457 	}
2458 
2459 	err = ext2fs_xattr_get(h, key, &ptr, &plen);
2460 	if (err) {
2461 		ret = translate_error(fs, ino, err);
2462 		goto out2;
2463 	}
2464 
2465 	for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2466 		if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2467 			err = xt->get(&cptr, &clen, ptr, plen);
2468 			if (err)
2469 				goto out3;
2470 			ext2fs_free_mem(&ptr);
2471 			ptr = cptr;
2472 			plen = clen;
2473 		}
2474 	}
2475 
2476 	if (!len) {
2477 		ret = plen;
2478 	} else if (len < plen) {
2479 		ret = -ERANGE;
2480 	} else {
2481 		memcpy(value, ptr, plen);
2482 		ret = plen;
2483 	}
2484 
2485 out3:
2486 	ext2fs_free_mem(&ptr);
2487 out2:
2488 	err = ext2fs_xattrs_close(&h);
2489 	if (err)
2490 		ret = translate_error(fs, ino, err);
2491 out:
2492 	pthread_mutex_unlock(&ff->bfl);
2493 
2494 	return ret;
2495 }
2496 
count_buffer_space(char * name,char * value EXT2FS_ATTR ((unused)),size_t value_len EXT2FS_ATTR ((unused)),void * data)2497 static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)),
2498 			      size_t value_len EXT2FS_ATTR((unused)),
2499 			      void *data)
2500 {
2501 	unsigned int *x = data;
2502 
2503 	*x = *x + strlen(name) + 1;
2504 	return 0;
2505 }
2506 
copy_names(char * name,char * value EXT2FS_ATTR ((unused)),size_t value_len EXT2FS_ATTR ((unused)),void * data)2507 static int copy_names(char *name, char *value EXT2FS_ATTR((unused)),
2508 		      size_t value_len EXT2FS_ATTR((unused)), void *data)
2509 {
2510 	char **b = data;
2511 
2512 	strncpy(*b, name, strlen(name));
2513 	*b = *b + strlen(name) + 1;
2514 
2515 	return 0;
2516 }
2517 
op_listxattr(const char * path,char * names,size_t len)2518 static int op_listxattr(const char *path, char *names, size_t len)
2519 {
2520 	struct fuse_context *ctxt = fuse_get_context();
2521 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2522 	ext2_filsys fs;
2523 	struct ext2_xattr_handle *h;
2524 	unsigned int bufsz;
2525 	ext2_ino_t ino;
2526 	errcode_t err;
2527 	int ret = 0;
2528 
2529 	FUSE2FS_CHECK_CONTEXT(ff);
2530 	fs = ff->fs;
2531 	pthread_mutex_lock(&ff->bfl);
2532 	if (!ext2fs_has_feature_xattr(fs->super)) {
2533 		ret = -ENOTSUP;
2534 		goto out;
2535 	}
2536 
2537 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2538 	if (err || ino == 0) {
2539 		ret = translate_error(fs, ino, err);
2540 		goto out;
2541 	}
2542 	dbg_printf("%s: ino=%d\n", __func__, ino);
2543 
2544 	ret = check_inum_access(fs, ino, R_OK);
2545 	if (ret)
2546 		goto out;
2547 
2548 	err = ext2fs_xattrs_open(fs, ino, &h);
2549 	if (err) {
2550 		ret = translate_error(fs, ino, err);
2551 		goto out;
2552 	}
2553 
2554 	err = ext2fs_xattrs_read(h);
2555 	if (err) {
2556 		ret = translate_error(fs, ino, err);
2557 		goto out2;
2558 	}
2559 
2560 	/* Count buffer space needed for names */
2561 	bufsz = 0;
2562 	err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz);
2563 	if (err) {
2564 		ret = translate_error(fs, ino, err);
2565 		goto out2;
2566 	}
2567 
2568 	if (len == 0) {
2569 		ret = bufsz;
2570 		goto out2;
2571 	} else if (len < bufsz) {
2572 		ret = -ERANGE;
2573 		goto out2;
2574 	}
2575 
2576 	/* Copy names out */
2577 	memset(names, 0, len);
2578 	err = ext2fs_xattrs_iterate(h, copy_names, &names);
2579 	if (err) {
2580 		ret = translate_error(fs, ino, err);
2581 		goto out2;
2582 	}
2583 	ret = bufsz;
2584 out2:
2585 	err = ext2fs_xattrs_close(&h);
2586 	if (err)
2587 		ret = translate_error(fs, ino, err);
2588 out:
2589 	pthread_mutex_unlock(&ff->bfl);
2590 
2591 	return ret;
2592 }
2593 
op_setxattr(const char * path EXT2FS_ATTR ((unused)),const char * key,const char * value,size_t len,int flags EXT2FS_ATTR ((unused)))2594 static int op_setxattr(const char *path EXT2FS_ATTR((unused)),
2595 		       const char *key, const char *value,
2596 		       size_t len, int flags EXT2FS_ATTR((unused)))
2597 {
2598 	struct fuse_context *ctxt = fuse_get_context();
2599 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2600 	ext2_filsys fs;
2601 	struct ext2_xattr_handle *h;
2602 	struct xattr_translate *xt;
2603 	const void *cvalue;
2604 	size_t clen;
2605 	ext2_ino_t ino;
2606 	errcode_t err;
2607 	int ret = 0;
2608 
2609 	FUSE2FS_CHECK_CONTEXT(ff);
2610 	fs = ff->fs;
2611 	pthread_mutex_lock(&ff->bfl);
2612 	if (!ext2fs_has_feature_xattr(fs->super)) {
2613 		ret = -ENOTSUP;
2614 		goto out;
2615 	}
2616 
2617 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2618 	if (err || ino == 0) {
2619 		ret = translate_error(fs, 0, err);
2620 		goto out;
2621 	}
2622 	dbg_printf("%s: ino=%d\n", __func__, ino);
2623 
2624 	ret = check_inum_access(fs, ino, W_OK);
2625 	if (ret == -EACCES) {
2626 		ret = -EPERM;
2627 		goto out;
2628 	} else if (ret)
2629 		goto out;
2630 
2631 	err = ext2fs_xattrs_open(fs, ino, &h);
2632 	if (err) {
2633 		ret = translate_error(fs, ino, err);
2634 		goto out;
2635 	}
2636 
2637 	err = ext2fs_xattrs_read(h);
2638 	if (err) {
2639 		ret = translate_error(fs, ino, err);
2640 		goto out2;
2641 	}
2642 
2643 	cvalue = value;
2644 	clen = len;
2645 	for (xt = xattr_translators; xt->prefix != NULL; xt++) {
2646 		if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) {
2647 			err = xt->set(value, len, &cvalue, &clen);
2648 			if (err)
2649 				goto out3;
2650 		}
2651 	}
2652 
2653 	err = ext2fs_xattr_set(h, key, cvalue, clen);
2654 	if (err) {
2655 		ret = translate_error(fs, ino, err);
2656 		goto out3;
2657 	}
2658 
2659 	ret = update_ctime(fs, ino, NULL);
2660 out3:
2661 	if (cvalue != value)
2662 		ext2fs_free_mem(&cvalue);
2663 out2:
2664 	err = ext2fs_xattrs_close(&h);
2665 	if (!ret && err)
2666 		ret = translate_error(fs, ino, err);
2667 out:
2668 	pthread_mutex_unlock(&ff->bfl);
2669 
2670 	return ret;
2671 }
2672 
op_removexattr(const char * path,const char * key)2673 static int op_removexattr(const char *path, const char *key)
2674 {
2675 	struct fuse_context *ctxt = fuse_get_context();
2676 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2677 	ext2_filsys fs;
2678 	struct ext2_xattr_handle *h;
2679 	ext2_ino_t ino;
2680 	errcode_t err;
2681 	int ret = 0;
2682 
2683 	FUSE2FS_CHECK_CONTEXT(ff);
2684 	fs = ff->fs;
2685 	pthread_mutex_lock(&ff->bfl);
2686 	if (!ext2fs_has_feature_xattr(fs->super)) {
2687 		ret = -ENOTSUP;
2688 		goto out;
2689 	}
2690 
2691 	if (!fs_can_allocate(ff, 1)) {
2692 		ret = -ENOSPC;
2693 		goto out;
2694 	}
2695 
2696 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2697 	if (err || ino == 0) {
2698 		ret = translate_error(fs, 0, err);
2699 		goto out;
2700 	}
2701 	dbg_printf("%s: ino=%d\n", __func__, ino);
2702 
2703 	ret = check_inum_access(fs, ino, W_OK);
2704 	if (ret)
2705 		goto out;
2706 
2707 	err = ext2fs_xattrs_open(fs, ino, &h);
2708 	if (err) {
2709 		ret = translate_error(fs, ino, err);
2710 		goto out;
2711 	}
2712 
2713 	err = ext2fs_xattrs_read(h);
2714 	if (err) {
2715 		ret = translate_error(fs, ino, err);
2716 		goto out2;
2717 	}
2718 
2719 	err = ext2fs_xattr_remove(h, key);
2720 	if (err) {
2721 		ret = translate_error(fs, ino, err);
2722 		goto out2;
2723 	}
2724 
2725 	ret = update_ctime(fs, ino, NULL);
2726 out2:
2727 	err = ext2fs_xattrs_close(&h);
2728 	if (err)
2729 		ret = translate_error(fs, ino, err);
2730 out:
2731 	pthread_mutex_unlock(&ff->bfl);
2732 
2733 	return ret;
2734 }
2735 
2736 struct readdir_iter {
2737 	void *buf;
2738 	fuse_fill_dir_t func;
2739 };
2740 
op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR ((unused)),int entry EXT2FS_ATTR ((unused)),struct ext2_dir_entry * dirent,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * data)2741 static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)),
2742 			   int entry EXT2FS_ATTR((unused)),
2743 			   struct ext2_dir_entry *dirent,
2744 			   int offset EXT2FS_ATTR((unused)),
2745 			   int blocksize EXT2FS_ATTR((unused)),
2746 			   char *buf EXT2FS_ATTR((unused)), void *data)
2747 {
2748 	struct readdir_iter *i = data;
2749 	char namebuf[EXT2_NAME_LEN + 1];
2750 	int ret;
2751 
2752 	memcpy(namebuf, dirent->name, dirent->name_len & 0xFF);
2753 	namebuf[dirent->name_len & 0xFF] = 0;
2754 	ret = i->func(i->buf, namebuf, NULL, 0);
2755 	if (ret)
2756 		return DIRENT_ABORT;
2757 
2758 	return 0;
2759 }
2760 
op_readdir(const char * path EXT2FS_ATTR ((unused)),void * buf,fuse_fill_dir_t fill_func,off_t offset EXT2FS_ATTR ((unused)),struct fuse_file_info * fp)2761 static int op_readdir(const char *path EXT2FS_ATTR((unused)),
2762 		      void *buf, fuse_fill_dir_t fill_func,
2763 		      off_t offset EXT2FS_ATTR((unused)),
2764 		      struct fuse_file_info *fp)
2765 {
2766 	struct fuse_context *ctxt = fuse_get_context();
2767 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2768 	struct fuse2fs_file_handle *fh =
2769 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2770 	ext2_filsys fs;
2771 	errcode_t err;
2772 	struct readdir_iter i;
2773 	int ret = 0;
2774 
2775 	FUSE2FS_CHECK_CONTEXT(ff);
2776 	fs = ff->fs;
2777 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2778 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
2779 	pthread_mutex_lock(&ff->bfl);
2780 	i.buf = buf;
2781 	i.func = fill_func;
2782 	err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i);
2783 	if (err) {
2784 		ret = translate_error(fs, fh->ino, err);
2785 		goto out;
2786 	}
2787 
2788 	if (fs_writeable(fs)) {
2789 		ret = update_atime(fs, fh->ino);
2790 		if (ret)
2791 			goto out;
2792 	}
2793 out:
2794 	pthread_mutex_unlock(&ff->bfl);
2795 	return ret;
2796 }
2797 
op_access(const char * path,int mask)2798 static int op_access(const char *path, int mask)
2799 {
2800 	struct fuse_context *ctxt = fuse_get_context();
2801 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2802 	ext2_filsys fs;
2803 	errcode_t err;
2804 	ext2_ino_t ino;
2805 	int ret = 0;
2806 
2807 	FUSE2FS_CHECK_CONTEXT(ff);
2808 	fs = ff->fs;
2809 	dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask);
2810 	pthread_mutex_lock(&ff->bfl);
2811 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
2812 	if (err || ino == 0) {
2813 		ret = translate_error(fs, 0, err);
2814 		goto out;
2815 	}
2816 
2817 	ret = check_inum_access(fs, ino, mask);
2818 	if (ret)
2819 		goto out;
2820 
2821 out:
2822 	pthread_mutex_unlock(&ff->bfl);
2823 	return ret;
2824 }
2825 
op_create(const char * path,mode_t mode,struct fuse_file_info * fp)2826 static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
2827 {
2828 	struct fuse_context *ctxt = fuse_get_context();
2829 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2830 	ext2_filsys fs;
2831 	ext2_ino_t parent, child;
2832 	char *temp_path;
2833 	errcode_t err;
2834 	char *node_name, a;
2835 	int filetype;
2836 	struct ext2_inode_large inode;
2837 	int ret = 0;
2838 
2839 	FUSE2FS_CHECK_CONTEXT(ff);
2840 	fs = ff->fs;
2841 	dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode);
2842 	temp_path = strdup(path);
2843 	if (!temp_path) {
2844 		ret = -ENOMEM;
2845 		goto out;
2846 	}
2847 	node_name = strrchr(temp_path, '/');
2848 	if (!node_name) {
2849 		ret = -ENOMEM;
2850 		goto out;
2851 	}
2852 	node_name++;
2853 	a = *node_name;
2854 	*node_name = 0;
2855 
2856 	pthread_mutex_lock(&ff->bfl);
2857 	if (!fs_can_allocate(ff, 1)) {
2858 		ret = -ENOSPC;
2859 		goto out2;
2860 	}
2861 
2862 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path,
2863 			   &parent);
2864 	if (err) {
2865 		ret = translate_error(fs, 0, err);
2866 		goto out2;
2867 	}
2868 
2869 	ret = check_inum_access(fs, parent, W_OK);
2870 	if (ret)
2871 		goto out2;
2872 
2873 	*node_name = a;
2874 
2875 	filetype = ext2_file_type(mode);
2876 
2877 	err = ext2fs_new_inode(fs, parent, mode, 0, &child);
2878 	if (err) {
2879 		ret = translate_error(fs, parent, err);
2880 		goto out2;
2881 	}
2882 
2883 	dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child,
2884 		   node_name, parent);
2885 	err = ext2fs_link(fs, parent, node_name, child, filetype);
2886 	if (err == EXT2_ET_DIR_NO_SPACE) {
2887 		err = ext2fs_expand_dir(fs, parent);
2888 		if (err) {
2889 			ret = translate_error(fs, parent, err);
2890 			goto out2;
2891 		}
2892 
2893 		err = ext2fs_link(fs, parent, node_name, child,
2894 				     filetype);
2895 	}
2896 	if (err) {
2897 		ret = translate_error(fs, parent, err);
2898 		goto out2;
2899 	}
2900 
2901 	ret = update_mtime(fs, parent, NULL);
2902 	if (ret)
2903 		goto out2;
2904 
2905 	memset(&inode, 0, sizeof(inode));
2906 	inode.i_mode = mode;
2907 	inode.i_links_count = 1;
2908 	inode.i_extra_isize = sizeof(struct ext2_inode_large) -
2909 		EXT2_GOOD_OLD_INODE_SIZE;
2910 	inode.i_uid = ctxt->uid;
2911 	ext2fs_set_i_uid_high(inode, ctxt->uid >> 16);
2912 	inode.i_gid = ctxt->gid;
2913 	ext2fs_set_i_gid_high(inode, ctxt->gid >> 16);
2914 	if (ext2fs_has_feature_extents(fs->super)) {
2915 		ext2_extent_handle_t handle;
2916 
2917 		inode.i_flags &= ~EXT4_EXTENTS_FL;
2918 		ret = ext2fs_extent_open2(fs, child,
2919 					  (struct ext2_inode *)&inode, &handle);
2920 		if (ret)
2921 			return ret;
2922 		ext2fs_extent_free(handle);
2923 	}
2924 
2925 	err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode);
2926 	if (err) {
2927 		ret = translate_error(fs, child, err);
2928 		goto out2;
2929 	}
2930 
2931 	inode.i_generation = ff->next_generation++;
2932 	init_times(&inode);
2933 	err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode,
2934 				      sizeof(inode));
2935 	if (err) {
2936 		ret = translate_error(fs, child, err);
2937 		goto out2;
2938 	}
2939 
2940 	ext2fs_inode_alloc_stats2(fs, child, 1, 0);
2941 
2942 	ret = __op_open(ff, path, fp);
2943 	if (ret)
2944 		goto out2;
2945 out2:
2946 	pthread_mutex_unlock(&ff->bfl);
2947 out:
2948 	free(temp_path);
2949 	return ret;
2950 }
2951 
op_ftruncate(const char * path EXT2FS_ATTR ((unused)),off_t len,struct fuse_file_info * fp)2952 static int op_ftruncate(const char *path EXT2FS_ATTR((unused)),
2953 			off_t len, struct fuse_file_info *fp)
2954 {
2955 	struct fuse_context *ctxt = fuse_get_context();
2956 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
2957 	struct fuse2fs_file_handle *fh =
2958 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
2959 	ext2_filsys fs;
2960 	ext2_file_t efp;
2961 	errcode_t err;
2962 	int ret = 0;
2963 
2964 	FUSE2FS_CHECK_CONTEXT(ff);
2965 	fs = ff->fs;
2966 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
2967 	dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len);
2968 	pthread_mutex_lock(&ff->bfl);
2969 	if (!fs_writeable(fs)) {
2970 		ret = -EROFS;
2971 		goto out;
2972 	}
2973 
2974 	err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp);
2975 	if (err) {
2976 		ret = translate_error(fs, fh->ino, err);
2977 		goto out;
2978 	}
2979 
2980 	err = ext2fs_file_set_size2(efp, len);
2981 	if (err) {
2982 		ret = translate_error(fs, fh->ino, err);
2983 		goto out2;
2984 	}
2985 
2986 out2:
2987 	err = ext2fs_file_close(efp);
2988 	if (ret)
2989 		goto out;
2990 	if (err) {
2991 		ret = translate_error(fs, fh->ino, err);
2992 		goto out;
2993 	}
2994 
2995 	ret = update_mtime(fs, fh->ino, NULL);
2996 	if (ret)
2997 		goto out;
2998 
2999 out:
3000 	pthread_mutex_unlock(&ff->bfl);
3001 	return 0;
3002 }
3003 
op_fgetattr(const char * path EXT2FS_ATTR ((unused)),struct stat * statbuf,struct fuse_file_info * fp)3004 static int op_fgetattr(const char *path EXT2FS_ATTR((unused)),
3005 		       struct stat *statbuf,
3006 		       struct fuse_file_info *fp)
3007 {
3008 	struct fuse_context *ctxt = fuse_get_context();
3009 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3010 	ext2_filsys fs;
3011 	struct fuse2fs_file_handle *fh =
3012 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3013 	int ret = 0;
3014 
3015 	FUSE2FS_CHECK_CONTEXT(ff);
3016 	fs = ff->fs;
3017 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3018 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3019 	pthread_mutex_lock(&ff->bfl);
3020 	ret = stat_inode(fs, fh->ino, statbuf);
3021 	pthread_mutex_unlock(&ff->bfl);
3022 
3023 	return ret;
3024 }
3025 
op_utimens(const char * path,const struct timespec ctv[2])3026 static int op_utimens(const char *path, const struct timespec ctv[2])
3027 {
3028 	struct fuse_context *ctxt = fuse_get_context();
3029 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3030 	struct timespec tv[2];
3031 	ext2_filsys fs;
3032 	errcode_t err;
3033 	ext2_ino_t ino;
3034 	struct ext2_inode_large inode;
3035 	int ret = 0;
3036 
3037 	FUSE2FS_CHECK_CONTEXT(ff);
3038 	fs = ff->fs;
3039 	pthread_mutex_lock(&ff->bfl);
3040 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3041 	if (err) {
3042 		ret = translate_error(fs, 0, err);
3043 		goto out;
3044 	}
3045 	dbg_printf("%s: ino=%d\n", __func__, ino);
3046 
3047 	ret = check_inum_access(fs, ino, W_OK);
3048 	if (ret)
3049 		goto out;
3050 
3051 	memset(&inode, 0, sizeof(inode));
3052 	err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
3053 				     sizeof(inode));
3054 	if (err) {
3055 		ret = translate_error(fs, ino, err);
3056 		goto out;
3057 	}
3058 
3059 	tv[0] = ctv[0];
3060 	tv[1] = ctv[1];
3061 #ifdef UTIME_NOW
3062 	if (tv[0].tv_nsec == UTIME_NOW)
3063 		get_now(tv);
3064 	if (tv[1].tv_nsec == UTIME_NOW)
3065 		get_now(tv + 1);
3066 #endif /* UTIME_NOW */
3067 #ifdef UTIME_OMIT
3068 	if (tv[0].tv_nsec != UTIME_OMIT)
3069 		EXT4_INODE_SET_XTIME(i_atime, tv, &inode);
3070 	if (tv[1].tv_nsec != UTIME_OMIT)
3071 		EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode);
3072 #endif /* UTIME_OMIT */
3073 	ret = update_ctime(fs, ino, &inode);
3074 	if (ret)
3075 		goto out;
3076 
3077 	err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
3078 				      sizeof(inode));
3079 	if (err) {
3080 		ret = translate_error(fs, ino, err);
3081 		goto out;
3082 	}
3083 
3084 out:
3085 	pthread_mutex_unlock(&ff->bfl);
3086 	return ret;
3087 }
3088 
3089 #ifdef SUPPORT_I_FLAGS
ioctl_getflags(ext2_filsys fs,struct fuse2fs_file_handle * fh,void * data)3090 static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3091 			  void *data)
3092 {
3093 	errcode_t err;
3094 	struct ext2_inode_large inode;
3095 
3096 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3097 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3098 	memset(&inode, 0, sizeof(inode));
3099 	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3100 				     sizeof(inode));
3101 	if (err)
3102 		return translate_error(fs, fh->ino, err);
3103 
3104 	*(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE;
3105 	return 0;
3106 }
3107 
3108 #define FUSE2FS_MODIFIABLE_IFLAGS \
3109 	(EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \
3110 	 EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \
3111 	 EXT2_TOPDIR_FL)
3112 
ioctl_setflags(ext2_filsys fs,struct fuse2fs_file_handle * fh,void * data)3113 static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3114 			  void *data)
3115 {
3116 	errcode_t err;
3117 	struct ext2_inode_large inode;
3118 	int ret;
3119 	__u32 flags = *(__u32 *)data;
3120 	struct fuse_context *ctxt = fuse_get_context();
3121 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3122 
3123 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3124 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3125 	memset(&inode, 0, sizeof(inode));
3126 	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3127 				     sizeof(inode));
3128 	if (err)
3129 		return translate_error(fs, fh->ino, err);
3130 
3131 	if (!ff->fakeroot && ctxt->uid != 0 && inode_uid(inode) != ctxt->uid)
3132 		return -EPERM;
3133 
3134 	if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS)
3135 		return -EINVAL;
3136 
3137 	inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) |
3138 			(flags & FUSE2FS_MODIFIABLE_IFLAGS);
3139 
3140 	ret = update_ctime(fs, fh->ino, &inode);
3141 	if (ret)
3142 		return ret;
3143 
3144 	err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3145 				      sizeof(inode));
3146 	if (err)
3147 		return translate_error(fs, fh->ino, err);
3148 
3149 	return 0;
3150 }
3151 
ioctl_getversion(ext2_filsys fs,struct fuse2fs_file_handle * fh,void * data)3152 static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3153 			    void *data)
3154 {
3155 	errcode_t err;
3156 	struct ext2_inode_large inode;
3157 
3158 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3159 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3160 	memset(&inode, 0, sizeof(inode));
3161 	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3162 				     sizeof(inode));
3163 	if (err)
3164 		return translate_error(fs, fh->ino, err);
3165 
3166 	*(__u32 *)data = inode.i_generation;
3167 	return 0;
3168 }
3169 
ioctl_setversion(ext2_filsys fs,struct fuse2fs_file_handle * fh,void * data)3170 static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3171 			    void *data)
3172 {
3173 	errcode_t err;
3174 	struct ext2_inode_large inode;
3175 	int ret;
3176 	__u32 generation = *(__u32 *)data;
3177 	struct fuse_context *ctxt = fuse_get_context();
3178 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3179 
3180 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3181 	dbg_printf("%s: ino=%d\n", __func__, fh->ino);
3182 	memset(&inode, 0, sizeof(inode));
3183 	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3184 				     sizeof(inode));
3185 	if (err)
3186 		return translate_error(fs, fh->ino, err);
3187 
3188 	if (!ff->fakeroot && ctxt->uid != 0 && inode_uid(inode) != ctxt->uid)
3189 		return -EPERM;
3190 
3191 	inode.i_generation = generation;
3192 
3193 	ret = update_ctime(fs, fh->ino, &inode);
3194 	if (ret)
3195 		return ret;
3196 
3197 	err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3198 				      sizeof(inode));
3199 	if (err)
3200 		return translate_error(fs, fh->ino, err);
3201 
3202 	return 0;
3203 }
3204 #endif /* SUPPORT_I_FLAGS */
3205 
3206 #ifdef FITRIM
ioctl_fitrim(ext2_filsys fs,struct fuse2fs_file_handle * fh,void * data)3207 static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh,
3208 			void *data)
3209 {
3210 	struct fstrim_range *fr = data;
3211 	blk64_t start, end, max_blocks, b, cleared;
3212 	errcode_t err = 0;
3213 
3214 	start = fr->start / fs->blocksize;
3215 	end = (fr->start + fr->len - 1) / fs->blocksize;
3216 	dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end);
3217 
3218 	if (start < fs->super->s_first_data_block)
3219 		start = fs->super->s_first_data_block;
3220 	if (start >= ext2fs_blocks_count(fs->super))
3221 		start = ext2fs_blocks_count(fs->super) - 1;
3222 
3223 	if (end < fs->super->s_first_data_block)
3224 		end = fs->super->s_first_data_block;
3225 	if (end >= ext2fs_blocks_count(fs->super))
3226 		end = ext2fs_blocks_count(fs->super) - 1;
3227 
3228 	cleared = 0;
3229 	max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize;
3230 
3231 	fr->len = 0;
3232 	while (start <= end) {
3233 		err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
3234 							   start, end, &start);
3235 		if (err == ENOENT)
3236 			return 0;
3237 		else if (err)
3238 			return translate_error(fs, fh->ino, err);
3239 
3240 		b = start + max_blocks < end ? start + max_blocks : end;
3241 		err =  ext2fs_find_first_set_block_bitmap2(fs->block_map,
3242 							   start, b, &b);
3243 		if (err && err != ENOENT)
3244 			return translate_error(fs, fh->ino, err);
3245 		if (b - start >= fr->minlen) {
3246 			err = io_channel_discard(fs->io, start, b - start);
3247 			if (err)
3248 				return translate_error(fs, fh->ino, err);
3249 			cleared += b - start;
3250 			fr->len = cleared * fs->blocksize;
3251 		}
3252 		start = b + 1;
3253 	}
3254 
3255 	return err;
3256 }
3257 #endif /* FITRIM */
3258 
3259 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
op_ioctl(const char * path EXT2FS_ATTR ((unused)),int cmd,void * arg EXT2FS_ATTR ((unused)),struct fuse_file_info * fp,unsigned int flags EXT2FS_ATTR ((unused)),void * data)3260 static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd,
3261 		    void *arg EXT2FS_ATTR((unused)),
3262 		    struct fuse_file_info *fp,
3263 		    unsigned int flags EXT2FS_ATTR((unused)), void *data)
3264 {
3265 	struct fuse_context *ctxt = fuse_get_context();
3266 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3267 	struct fuse2fs_file_handle *fh =
3268 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3269 	ext2_filsys fs;
3270 	int ret = 0;
3271 
3272 	FUSE2FS_CHECK_CONTEXT(ff);
3273 	fs = ff->fs;
3274 	pthread_mutex_lock(&ff->bfl);
3275 	switch ((unsigned long) cmd) {
3276 #ifdef SUPPORT_I_FLAGS
3277 	case EXT2_IOC_GETFLAGS:
3278 		ret = ioctl_getflags(fs, fh, data);
3279 		break;
3280 	case EXT2_IOC_SETFLAGS:
3281 		ret = ioctl_setflags(fs, fh, data);
3282 		break;
3283 	case EXT2_IOC_GETVERSION:
3284 		ret = ioctl_getversion(fs, fh, data);
3285 		break;
3286 	case EXT2_IOC_SETVERSION:
3287 		ret = ioctl_setversion(fs, fh, data);
3288 		break;
3289 #endif
3290 #ifdef FITRIM
3291 	case FITRIM:
3292 		ret = ioctl_fitrim(fs, fh, data);
3293 		break;
3294 #endif
3295 	default:
3296 		dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd);
3297 		ret = -ENOTTY;
3298 	}
3299 	pthread_mutex_unlock(&ff->bfl);
3300 
3301 	return ret;
3302 }
3303 #endif /* FUSE 28 */
3304 
op_bmap(const char * path,size_t blocksize EXT2FS_ATTR ((unused)),uint64_t * idx)3305 static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)),
3306 		   uint64_t *idx)
3307 {
3308 	struct fuse_context *ctxt = fuse_get_context();
3309 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3310 	ext2_filsys fs;
3311 	ext2_ino_t ino;
3312 	errcode_t err;
3313 	int ret = 0;
3314 
3315 	FUSE2FS_CHECK_CONTEXT(ff);
3316 	fs = ff->fs;
3317 	pthread_mutex_lock(&ff->bfl);
3318 	err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino);
3319 	if (err) {
3320 		ret = translate_error(fs, 0, err);
3321 		goto out;
3322 	}
3323 	dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx);
3324 
3325 	err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx);
3326 	if (err) {
3327 		ret = translate_error(fs, ino, err);
3328 		goto out;
3329 	}
3330 
3331 out:
3332 	pthread_mutex_unlock(&ff->bfl);
3333 	return ret;
3334 }
3335 
3336 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3337 # ifdef SUPPORT_FALLOCATE
fallocate_helper(struct fuse_file_info * fp,int mode,off_t offset,off_t len)3338 static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset,
3339 			    off_t len)
3340 {
3341 	struct fuse_context *ctxt = fuse_get_context();
3342 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3343 	struct fuse2fs_file_handle *fh =
3344 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3345 	ext2_filsys fs;
3346 	struct ext2_inode_large inode;
3347 	blk64_t start, end;
3348 	__u64 fsize;
3349 	errcode_t err;
3350 	int flags;
3351 
3352 	FUSE2FS_CHECK_CONTEXT(ff);
3353 	fs = ff->fs;
3354 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3355 	start = offset / fs->blocksize;
3356 	end = (offset + len - 1) / fs->blocksize;
3357 	dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__,
3358 		   fh->ino, mode, offset / fs->blocksize, end);
3359 	if (!fs_can_allocate(ff, len / fs->blocksize))
3360 		return -ENOSPC;
3361 
3362 	memset(&inode, 0, sizeof(inode));
3363 	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3364 				     sizeof(inode));
3365 	if (err)
3366 		return err;
3367 	fsize = EXT2_I_SIZE(&inode);
3368 
3369 	/* Allocate a bunch of blocks */
3370 	flags = (mode & FL_KEEP_SIZE_FLAG ? 0 :
3371 			EXT2_FALLOCATE_INIT_BEYOND_EOF);
3372 	err = ext2fs_fallocate(fs, flags, fh->ino,
3373 			       (struct ext2_inode *)&inode,
3374 			       ~0ULL, start, end - start + 1);
3375 	if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL)
3376 		return translate_error(fs, fh->ino, err);
3377 
3378 	/* Update i_size */
3379 	if (!(mode & FL_KEEP_SIZE_FLAG)) {
3380 		if ((__u64) offset + len > fsize) {
3381 			err = ext2fs_inode_size_set(fs,
3382 						(struct ext2_inode *)&inode,
3383 						offset + len);
3384 			if (err)
3385 				return translate_error(fs, fh->ino, err);
3386 		}
3387 	}
3388 
3389 	err = update_mtime(fs, fh->ino, &inode);
3390 	if (err)
3391 		return err;
3392 
3393 	err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3394 				      sizeof(inode));
3395 	if (err)
3396 		return translate_error(fs, fh->ino, err);
3397 
3398 	return err;
3399 }
3400 
clean_block_middle(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode_large * inode,off_t offset,off_t len,char ** buf)3401 static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino,
3402 				  struct ext2_inode_large *inode, off_t offset,
3403 				  off_t len, char **buf)
3404 {
3405 	blk64_t blk;
3406 	off_t residue;
3407 	int retflags;
3408 	errcode_t err;
3409 
3410 	residue = offset % fs->blocksize;
3411 	if (residue == 0)
3412 		return 0;
3413 
3414 	if (!*buf) {
3415 		err = ext2fs_get_mem(fs->blocksize, buf);
3416 		if (err)
3417 			return err;
3418 	}
3419 
3420 	err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3421 			   offset / fs->blocksize, &retflags, &blk);
3422 	if (err)
3423 		return err;
3424 	if (!blk || (retflags & BMAP_RET_UNINIT))
3425 		return 0;
3426 
3427 	err = io_channel_read_blk(fs->io, blk, 1, *buf);
3428 	if (err)
3429 		return err;
3430 
3431 	memset(*buf + residue, 0, len);
3432 
3433 	return io_channel_write_blk(fs->io, blk, 1, *buf);
3434 }
3435 
clean_block_edge(ext2_filsys fs,ext2_ino_t ino,struct ext2_inode_large * inode,off_t offset,int clean_before,char ** buf)3436 static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino,
3437 				  struct ext2_inode_large *inode, off_t offset,
3438 				  int clean_before, char **buf)
3439 {
3440 	blk64_t blk;
3441 	int retflags;
3442 	off_t residue;
3443 	errcode_t err;
3444 
3445 	residue = offset % fs->blocksize;
3446 	if (residue == 0)
3447 		return 0;
3448 
3449 	if (!*buf) {
3450 		err = ext2fs_get_mem(fs->blocksize, buf);
3451 		if (err)
3452 			return err;
3453 	}
3454 
3455 	err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0,
3456 			   offset / fs->blocksize, &retflags, &blk);
3457 	if (err)
3458 		return err;
3459 
3460 	err = io_channel_read_blk(fs->io, blk, 1, *buf);
3461 	if (err)
3462 		return err;
3463 	if (!blk || (retflags & BMAP_RET_UNINIT))
3464 		return 0;
3465 
3466 	if (clean_before)
3467 		memset(*buf, 0, residue);
3468 	else
3469 		memset(*buf + residue, 0, fs->blocksize - residue);
3470 
3471 	return io_channel_write_blk(fs->io, blk, 1, *buf);
3472 }
3473 
punch_helper(struct fuse_file_info * fp,int mode,off_t offset,off_t len)3474 static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset,
3475 			off_t len)
3476 {
3477 	struct fuse_context *ctxt = fuse_get_context();
3478 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3479 	struct fuse2fs_file_handle *fh =
3480 		(struct fuse2fs_file_handle *)(uintptr_t)fp->fh;
3481 	ext2_filsys fs;
3482 	struct ext2_inode_large inode;
3483 	blk64_t start, end;
3484 	errcode_t err;
3485 	char *buf = NULL;
3486 
3487 	FUSE2FS_CHECK_CONTEXT(ff);
3488 	fs = ff->fs;
3489 	FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC);
3490 	dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len);
3491 
3492 	/* kernel ext4 punch requires this flag to be set */
3493 	if (!(mode & FL_KEEP_SIZE_FLAG))
3494 		return -EINVAL;
3495 
3496 	/* Punch out a bunch of blocks */
3497 	start = (offset + fs->blocksize - 1) / fs->blocksize;
3498 	end = (offset + len - fs->blocksize) / fs->blocksize;
3499 	dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__,
3500 		   fh->ino, mode, start, end);
3501 
3502 	memset(&inode, 0, sizeof(inode));
3503 	err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3504 				     sizeof(inode));
3505 	if (err)
3506 		return translate_error(fs, fh->ino, err);
3507 
3508 	/* Zero everything before the first block and after the last block */
3509 	if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize))
3510 		err = clean_block_middle(fs, fh->ino, &inode, offset,
3511 					 len, &buf);
3512 	else {
3513 		err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf);
3514 		if (!err)
3515 			err = clean_block_edge(fs, fh->ino, &inode,
3516 					       offset + len, 1, &buf);
3517 	}
3518 	if (buf)
3519 		ext2fs_free_mem(&buf);
3520 	if (err)
3521 		return translate_error(fs, fh->ino, err);
3522 
3523 	/* Unmap full blocks in the middle */
3524 	if (start <= end) {
3525 		err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode,
3526 				   NULL, start, end);
3527 		if (err)
3528 			return translate_error(fs, fh->ino, err);
3529 	}
3530 
3531 	err = update_mtime(fs, fh->ino, &inode);
3532 	if (err)
3533 		return err;
3534 
3535 	err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode,
3536 				      sizeof(inode));
3537 	if (err)
3538 		return translate_error(fs, fh->ino, err);
3539 
3540 	return 0;
3541 }
3542 
op_fallocate(const char * path EXT2FS_ATTR ((unused)),int mode,off_t offset,off_t len,struct fuse_file_info * fp)3543 static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode,
3544 			off_t offset, off_t len,
3545 			struct fuse_file_info *fp)
3546 {
3547 	struct fuse_context *ctxt = fuse_get_context();
3548 	struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data;
3549 	ext2_filsys fs = ff->fs;
3550 	int ret;
3551 
3552 	/* Catch unknown flags */
3553 	if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG))
3554 		return -EINVAL;
3555 
3556 	pthread_mutex_lock(&ff->bfl);
3557 	if (!fs_writeable(fs)) {
3558 		ret = -EROFS;
3559 		goto out;
3560 	}
3561 	if (mode & FL_PUNCH_HOLE_FLAG)
3562 		ret = punch_helper(fp, mode, offset, len);
3563 	else
3564 		ret = fallocate_helper(fp, mode, offset, len);
3565 out:
3566 	pthread_mutex_unlock(&ff->bfl);
3567 
3568 	return ret;
3569 }
3570 # endif /* SUPPORT_FALLOCATE */
3571 #endif /* FUSE 29 */
3572 
3573 static struct fuse_operations fs_ops = {
3574 	.init = op_init,
3575 	.destroy = op_destroy,
3576 	.getattr = op_getattr,
3577 	.readlink = op_readlink,
3578 	.mknod = op_mknod,
3579 	.mkdir = op_mkdir,
3580 	.unlink = op_unlink,
3581 	.rmdir = op_rmdir,
3582 	.symlink = op_symlink,
3583 	.rename = op_rename,
3584 	.link = op_link,
3585 	.chmod = op_chmod,
3586 	.chown = op_chown,
3587 	.truncate = op_truncate,
3588 	.open = op_open,
3589 	.read = op_read,
3590 	.write = op_write,
3591 	.statfs = op_statfs,
3592 	.release = op_release,
3593 	.fsync = op_fsync,
3594 	.setxattr = op_setxattr,
3595 	.getxattr = op_getxattr,
3596 	.listxattr = op_listxattr,
3597 	.removexattr = op_removexattr,
3598 	.opendir = op_open,
3599 	.readdir = op_readdir,
3600 	.releasedir = op_release,
3601 	.fsyncdir = op_fsync,
3602 	.access = op_access,
3603 	.create = op_create,
3604 	.ftruncate = op_ftruncate,
3605 	.fgetattr = op_fgetattr,
3606 	.utimens = op_utimens,
3607 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3608 # if defined(UTIME_NOW) || defined(UTIME_OMIT)
3609 	.flag_utime_omit_ok = 1,
3610 # endif
3611 #endif
3612 	.bmap = op_bmap,
3613 #ifdef SUPERFLUOUS
3614 	.lock = op_lock,
3615 	.poll = op_poll,
3616 #endif
3617 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8)
3618 	.ioctl = op_ioctl,
3619 	.flag_nullpath_ok = 1,
3620 #endif
3621 #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9)
3622 	.flag_nopath = 1,
3623 # ifdef SUPPORT_FALLOCATE
3624 	.fallocate = op_fallocate,
3625 # endif
3626 #endif
3627 };
3628 
get_random_bytes(void * p,size_t sz)3629 static int get_random_bytes(void *p, size_t sz)
3630 {
3631 	int fd;
3632 	ssize_t r;
3633 
3634 	fd = open("/dev/urandom", O_RDONLY);
3635 	if (fd < 0) {
3636 		perror("/dev/urandom");
3637 		return 0;
3638 	}
3639 
3640 	r = read(fd, p, sz);
3641 
3642 	close(fd);
3643 	return (size_t) r == sz;
3644 }
3645 
3646 enum {
3647 	FUSE2FS_VERSION,
3648 	FUSE2FS_HELP,
3649 	FUSE2FS_HELPFULL,
3650 };
3651 
3652 #define FUSE2FS_OPT(t, p, v) { t, offsetof(struct fuse2fs, p), v }
3653 
3654 static struct fuse_opt fuse2fs_opts[] = {
3655 	FUSE2FS_OPT("ro",		ro,			1),
3656 	FUSE2FS_OPT("errors=panic",	panic_on_error,		1),
3657 	FUSE2FS_OPT("minixdf",		minixdf,		1),
3658 	FUSE2FS_OPT("fakeroot",		fakeroot,		1),
3659 	FUSE2FS_OPT("fuse2fs_debug",	debug,			1),
3660 	FUSE2FS_OPT("no_default_opts",	no_default_opts,	1),
3661 	FUSE2FS_OPT("norecovery",	norecovery,		1),
3662 
3663 	FUSE_OPT_KEY("-V",             FUSE2FS_VERSION),
3664 	FUSE_OPT_KEY("--version",      FUSE2FS_VERSION),
3665 	FUSE_OPT_KEY("-h",             FUSE2FS_HELP),
3666 	FUSE_OPT_KEY("--help",         FUSE2FS_HELP),
3667 	FUSE_OPT_KEY("--helpfull",     FUSE2FS_HELPFULL),
3668 	FUSE_OPT_END
3669 };
3670 
3671 
fuse2fs_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)3672 static int fuse2fs_opt_proc(void *data, const char *arg,
3673 			    int key, struct fuse_args *outargs)
3674 {
3675 	struct fuse2fs *ff = data;
3676 
3677 	switch (key) {
3678 	case FUSE_OPT_KEY_NONOPT:
3679 		if (!ff->device) {
3680 			ff->device = strdup(arg);
3681 			return 0;
3682 		}
3683 		return 1;
3684 	case FUSE2FS_HELP:
3685 	case FUSE2FS_HELPFULL:
3686 		fprintf(stderr,
3687 	"usage: %s device/image mountpoint [options]\n"
3688 	"\n"
3689 	"general options:\n"
3690 	"    -o opt,[opt...]  mount options\n"
3691 	"    -h   --help      print help\n"
3692 	"    -V   --version   print version\n"
3693 	"\n"
3694 	"fuse2fs options:\n"
3695 	"    -o ro                  read-only mount\n"
3696 	"    -o errors=panic        dump core on error\n"
3697 	"    -o minixdf             minix-style df\n"
3698 	"    -o fakeroot            pretend to be root for permission checks\n"
3699 	"    -o no_default_opts     do not include default fuse options\n"
3700 	"    -o norecovery	    don't replay the journal (implies ro)\n"
3701 	"    -o fuse2fs_debug       enable fuse2fs debugging\n"
3702 	"\n",
3703 			outargs->argv[0]);
3704 		if (key == FUSE2FS_HELPFULL) {
3705 			fuse_opt_add_arg(outargs, "-ho");
3706 			fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3707 		} else {
3708 			fprintf(stderr, "Try --helpfull to get a list of "
3709 				"all flags, including the FUSE options.\n");
3710 		}
3711 		exit(1);
3712 
3713 	case FUSE2FS_VERSION:
3714 		fprintf(stderr, "fuse2fs %s (%s)\n", E2FSPROGS_VERSION,
3715 			E2FSPROGS_DATE);
3716 		fuse_opt_add_arg(outargs, "--version");
3717 		fuse_main(outargs->argc, outargs->argv, &fs_ops, NULL);
3718 		exit(0);
3719 	}
3720 	return 1;
3721 }
3722 
main(int argc,char * argv[])3723 int main(int argc, char *argv[])
3724 {
3725 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3726 	struct fuse2fs fctx;
3727 	errcode_t err;
3728 	char *logfile;
3729 	char extra_args[BUFSIZ];
3730 	int ret = 0;
3731 	int flags = EXT2_FLAG_64BITS | EXT2_FLAG_THREADS | EXT2_FLAG_EXCLUSIVE;
3732 
3733 	memset(&fctx, 0, sizeof(fctx));
3734 	fctx.magic = FUSE2FS_MAGIC;
3735 
3736 	fuse_opt_parse(&args, &fctx, fuse2fs_opts, fuse2fs_opt_proc);
3737 	if (fctx.device == NULL) {
3738 		fprintf(stderr, "Missing ext4 device/image\n");
3739 		fprintf(stderr, "See '%s -h' for usage\n", argv[0]);
3740 		exit(1);
3741 	}
3742 
3743 	if (fctx.norecovery)
3744 		fctx.ro = 1;
3745 	if (fctx.ro)
3746 		printf("%s", _("Mounting read-only.\n"));
3747 
3748 #ifdef ENABLE_NLS
3749 	setlocale(LC_MESSAGES, "");
3750 	setlocale(LC_CTYPE, "");
3751 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
3752 	textdomain(NLS_CAT_NAME);
3753 	set_com_err_gettext(gettext);
3754 #endif
3755 	add_error_table(&et_ext2_error_table);
3756 
3757 	/* Set up error logging */
3758 	logfile = getenv("FUSE2FS_LOGFILE");
3759 	if (logfile) {
3760 		fctx.err_fp = fopen(logfile, "a");
3761 		if (!fctx.err_fp) {
3762 			perror(logfile);
3763 			goto out;
3764 		}
3765 	} else
3766 		fctx.err_fp = stderr;
3767 
3768 	/* Will we allow users to allocate every last block? */
3769 	if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) {
3770 		printf(_("%s: Allowing users to allocate all blocks. "
3771 		       "This is dangerous!\n"), fctx.device);
3772 		fctx.alloc_all_blocks = 1;
3773 	}
3774 
3775 	/* Start up the fs (while we still can use stdout) */
3776 	ret = 2;
3777 	if (!fctx.ro)
3778 		flags |= EXT2_FLAG_RW;
3779 	err = ext2fs_open2(fctx.device, NULL, flags, 0, 0, unix_io_manager,
3780 			   &global_fs);
3781 	if (err) {
3782 		printf(_("%s: %s.\n"), fctx.device, error_message(err));
3783 		printf(_("Please run e2fsck -fy %s.\n"), fctx.device);
3784 		goto out;
3785 	}
3786 	fctx.fs = global_fs;
3787 	global_fs->priv_data = &fctx;
3788 
3789 	ret = 3;
3790 
3791 	if (ext2fs_has_feature_journal_needs_recovery(global_fs->super)) {
3792 		if (fctx.norecovery) {
3793 			printf(_("%s: mounting read-only without "
3794 				 "recovering journal\n"),
3795 			       fctx.device);
3796 		} else if (!fctx.ro) {
3797 			printf(_("%s: recovering journal\n"), fctx.device);
3798 			err = ext2fs_run_ext3_journal(&global_fs);
3799 			if (err) {
3800 				printf(_("%s: %s.\n"), fctx.device,
3801 				       error_message(err));
3802 				printf(_("Please run e2fsck -fy %s.\n"),
3803 				       fctx.device);
3804 				goto out;
3805 			}
3806 			ext2fs_clear_feature_journal_needs_recovery(global_fs->super);
3807 			ext2fs_mark_super_dirty(global_fs);
3808 		} else {
3809 			printf("%s", _("Journal needs recovery; running "
3810 			       "`e2fsck -E journal_only' is required.\n"));
3811 			goto out;
3812 		}
3813 	}
3814 
3815 	if (!fctx.ro) {
3816 		if (ext2fs_has_feature_journal(global_fs->super))
3817 			printf(_("%s: Writing to the journal is not supported.\n"),
3818 			       fctx.device);
3819 		err = ext2fs_read_inode_bitmap(global_fs);
3820 		if (err) {
3821 			translate_error(global_fs, 0, err);
3822 			goto out;
3823 		}
3824 		err = ext2fs_read_block_bitmap(global_fs);
3825 		if (err) {
3826 			translate_error(global_fs, 0, err);
3827 			goto out;
3828 		}
3829 	}
3830 
3831 	if (!(global_fs->super->s_state & EXT2_VALID_FS))
3832 		printf("%s", _("Warning: Mounting unchecked fs, running e2fsck "
3833 		       "is recommended.\n"));
3834 	if (global_fs->super->s_max_mnt_count > 0 &&
3835 	    global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count)
3836 		printf("%s", _("Warning: Maximal mount count reached, running "
3837 		       "e2fsck is recommended.\n"));
3838 	if (global_fs->super->s_checkinterval > 0 &&
3839 	    (time_t) (global_fs->super->s_lastcheck +
3840 		      global_fs->super->s_checkinterval) <= time(0))
3841 		printf("%s", _("Warning: Check time reached; running e2fsck "
3842 		       "is recommended.\n"));
3843 	if (global_fs->super->s_last_orphan)
3844 		printf("%s",
3845 		       _("Orphans detected; running e2fsck is recommended.\n"));
3846 
3847 	if (global_fs->super->s_state & EXT2_ERROR_FS) {
3848 		printf("%s",
3849 		       _("Errors detected; running e2fsck is required.\n"));
3850 		goto out;
3851 	}
3852 
3853 	/* Initialize generation counter */
3854 	get_random_bytes(&fctx.next_generation, sizeof(unsigned int));
3855 
3856 	/* Set up default fuse parameters */
3857 	snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino,"
3858 		 "fsname=%s,attr_timeout=0" FUSE_PLATFORM_OPTS,
3859 		 fctx.device);
3860 	if (fctx.no_default_opts == 0)
3861 		fuse_opt_add_arg(&args, extra_args);
3862 
3863 	if (fctx.fakeroot) {
3864 #ifdef HAVE_MOUNT_NODEV
3865 		fuse_opt_add_arg(&args,"-onodev");
3866 #endif
3867 #ifdef HAVE_MOUNT_NOSUID
3868 		fuse_opt_add_arg(&args,"-onosuid");
3869 #endif
3870 	}
3871 
3872 	if (fctx.debug) {
3873 		int	i;
3874 
3875 		printf("fuse arguments:");
3876 		for (i = 0; i < args.argc; i++)
3877 			printf(" '%s'", args.argv[i]);
3878 		printf("\n");
3879 	}
3880 
3881 	pthread_mutex_init(&fctx.bfl, NULL);
3882 	fuse_main(args.argc, args.argv, &fs_ops, &fctx);
3883 	pthread_mutex_destroy(&fctx.bfl);
3884 
3885 	ret = 0;
3886 out:
3887 	if (global_fs) {
3888 		err = ext2fs_close(global_fs);
3889 		if (err)
3890 			com_err(argv[0], err, "while closing fs");
3891 		global_fs = NULL;
3892 	}
3893 	return ret;
3894 }
3895 
__translate_error(ext2_filsys fs,errcode_t err,ext2_ino_t ino,const char * file,int line)3896 static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino,
3897 			     const char *file, int line)
3898 {
3899 	struct timespec now;
3900 	int ret = err;
3901 	struct fuse2fs *ff = fs->priv_data;
3902 	int is_err = 0;
3903 
3904 	/* Translate ext2 error to unix error code */
3905 	if (err < EXT2_ET_BASE)
3906 		goto no_translation;
3907 	switch (err) {
3908 	case EXT2_ET_NO_MEMORY:
3909 	case EXT2_ET_TDB_ERR_OOM:
3910 		ret = -ENOMEM;
3911 		break;
3912 	case EXT2_ET_INVALID_ARGUMENT:
3913 	case EXT2_ET_LLSEEK_FAILED:
3914 		ret = -EINVAL;
3915 		break;
3916 	case EXT2_ET_NO_DIRECTORY:
3917 		ret = -ENOTDIR;
3918 		break;
3919 	case EXT2_ET_FILE_NOT_FOUND:
3920 		ret = -ENOENT;
3921 		break;
3922 	case EXT2_ET_DIR_NO_SPACE:
3923 		is_err = 1;
3924 		/* fallthrough */
3925 	case EXT2_ET_TOOSMALL:
3926 	case EXT2_ET_BLOCK_ALLOC_FAIL:
3927 	case EXT2_ET_INODE_ALLOC_FAIL:
3928 	case EXT2_ET_EA_NO_SPACE:
3929 		ret = -ENOSPC;
3930 		break;
3931 	case EXT2_ET_SYMLINK_LOOP:
3932 		ret = -EMLINK;
3933 		break;
3934 	case EXT2_ET_FILE_TOO_BIG:
3935 		ret = -EFBIG;
3936 		break;
3937 	case EXT2_ET_TDB_ERR_EXISTS:
3938 	case EXT2_ET_FILE_EXISTS:
3939 		ret = -EEXIST;
3940 		break;
3941 	case EXT2_ET_MMP_FAILED:
3942 	case EXT2_ET_MMP_FSCK_ON:
3943 		ret = -EBUSY;
3944 		break;
3945 	case EXT2_ET_EA_KEY_NOT_FOUND:
3946 #ifdef ENODATA
3947 		ret = -ENODATA;
3948 #else
3949 		ret = -ENOENT;
3950 #endif
3951 		break;
3952 	/* Sometimes fuse returns a garbage file handle pointer to us... */
3953 	case EXT2_ET_MAGIC_EXT2_FILE:
3954 		ret = -EFAULT;
3955 		break;
3956 	case EXT2_ET_UNIMPLEMENTED:
3957 		ret = -EOPNOTSUPP;
3958 		break;
3959 	default:
3960 		is_err = 1;
3961 		ret = -EIO;
3962 		break;
3963 	}
3964 
3965 no_translation:
3966 	if (!is_err)
3967 		return ret;
3968 
3969 	if (ino)
3970 		fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n",
3971 			fs->device_name ? fs->device_name : "???",
3972 			error_message(err), ino, file, line);
3973 	else
3974 		fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n",
3975 			fs->device_name ? fs->device_name : "???",
3976 			error_message(err), file, line);
3977 	fflush(ff->err_fp);
3978 
3979 	/* Make a note in the error log */
3980 	get_now(&now);
3981 	fs->super->s_last_error_time = now.tv_sec;
3982 	fs->super->s_last_error_ino = ino;
3983 	fs->super->s_last_error_line = line;
3984 	fs->super->s_last_error_block = err; /* Yeah... */
3985 	strncpy((char *)fs->super->s_last_error_func, file,
3986 		sizeof(fs->super->s_last_error_func));
3987 	if (fs->super->s_first_error_time == 0) {
3988 		fs->super->s_first_error_time = now.tv_sec;
3989 		fs->super->s_first_error_ino = ino;
3990 		fs->super->s_first_error_line = line;
3991 		fs->super->s_first_error_block = err;
3992 		strncpy((char *)fs->super->s_first_error_func, file,
3993 			sizeof(fs->super->s_first_error_func));
3994 	}
3995 
3996 	fs->super->s_error_count++;
3997 	ext2fs_mark_super_dirty(fs);
3998 	ext2fs_flush(fs);
3999 	if (ff->panic_on_error)
4000 		abort();
4001 
4002 	return ret;
4003 }
4004