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