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