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