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