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