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