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