xref: /aosp_15_r20/external/erofs-utils/fuse/main.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker  * Created by Li Guifu <[email protected]>
4*33b1fccfSAndroid Build Coastguard Worker  * Lowlevel added by Li Yiyan <[email protected]>
5*33b1fccfSAndroid Build Coastguard Worker  */
6*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
7*33b1fccfSAndroid Build Coastguard Worker #include <string.h>
8*33b1fccfSAndroid Build Coastguard Worker #include <signal.h>
9*33b1fccfSAndroid Build Coastguard Worker #include <libgen.h>
10*33b1fccfSAndroid Build Coastguard Worker #include "macosx.h"
11*33b1fccfSAndroid Build Coastguard Worker #include "erofs/config.h"
12*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
13*33b1fccfSAndroid Build Coastguard Worker #include "erofs/dir.h"
14*33b1fccfSAndroid Build Coastguard Worker #include "erofs/inode.h"
15*33b1fccfSAndroid Build Coastguard Worker 
16*33b1fccfSAndroid Build Coastguard Worker #include <float.h>
17*33b1fccfSAndroid Build Coastguard Worker #include <fuse.h>
18*33b1fccfSAndroid Build Coastguard Worker #include <fuse_lowlevel.h>
19*33b1fccfSAndroid Build Coastguard Worker 
20*33b1fccfSAndroid Build Coastguard Worker #define EROFSFUSE_TIMEOUT DBL_MAX
21*33b1fccfSAndroid Build Coastguard Worker 
22*33b1fccfSAndroid Build Coastguard Worker struct erofsfuse_readdir_context {
23*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dir_context ctx;
24*33b1fccfSAndroid Build Coastguard Worker 
25*33b1fccfSAndroid Build Coastguard Worker 	fuse_req_t req;
26*33b1fccfSAndroid Build Coastguard Worker 	void *buf;
27*33b1fccfSAndroid Build Coastguard Worker 	int is_plus;
28*33b1fccfSAndroid Build Coastguard Worker 	size_t index;
29*33b1fccfSAndroid Build Coastguard Worker 	size_t buf_rem;
30*33b1fccfSAndroid Build Coastguard Worker 	size_t offset;
31*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_file_info *fi;
32*33b1fccfSAndroid Build Coastguard Worker };
33*33b1fccfSAndroid Build Coastguard Worker 
34*33b1fccfSAndroid Build Coastguard Worker struct erofsfuse_lookupdir_context {
35*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_dir_context ctx;
36*33b1fccfSAndroid Build Coastguard Worker 
37*33b1fccfSAndroid Build Coastguard Worker 	const char *target_name;
38*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_entry_param *ent;
39*33b1fccfSAndroid Build Coastguard Worker };
40*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_to_nid(fuse_ino_t ino)41*33b1fccfSAndroid Build Coastguard Worker static inline erofs_nid_t erofsfuse_to_nid(fuse_ino_t ino)
42*33b1fccfSAndroid Build Coastguard Worker {
43*33b1fccfSAndroid Build Coastguard Worker 	if (ino == FUSE_ROOT_ID)
44*33b1fccfSAndroid Build Coastguard Worker 		return g_sbi.root_nid;
45*33b1fccfSAndroid Build Coastguard Worker 	return (erofs_nid_t)(ino - FUSE_ROOT_ID);
46*33b1fccfSAndroid Build Coastguard Worker }
47*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_to_ino(erofs_nid_t nid)48*33b1fccfSAndroid Build Coastguard Worker static inline fuse_ino_t erofsfuse_to_ino(erofs_nid_t nid)
49*33b1fccfSAndroid Build Coastguard Worker {
50*33b1fccfSAndroid Build Coastguard Worker 	if (nid == g_sbi.root_nid)
51*33b1fccfSAndroid Build Coastguard Worker 		return FUSE_ROOT_ID;
52*33b1fccfSAndroid Build Coastguard Worker 	return (nid + FUSE_ROOT_ID);
53*33b1fccfSAndroid Build Coastguard Worker }
54*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_fill_stat(struct erofs_inode * vi,struct stat * stbuf)55*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_fill_stat(struct erofs_inode *vi, struct stat *stbuf)
56*33b1fccfSAndroid Build Coastguard Worker {
57*33b1fccfSAndroid Build Coastguard Worker 	if (S_ISBLK(vi->i_mode) || S_ISCHR(vi->i_mode))
58*33b1fccfSAndroid Build Coastguard Worker 		stbuf->st_rdev = vi->u.i_rdev;
59*33b1fccfSAndroid Build Coastguard Worker 
60*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_mode = vi->i_mode;
61*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_nlink = vi->i_nlink;
62*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_size = vi->i_size;
63*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_blocks = roundup(vi->i_size, erofs_blksiz(&g_sbi)) >> 9;
64*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_uid = vi->i_uid;
65*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_gid = vi->i_gid;
66*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_ctime = vi->i_mtime;
67*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_mtime = stbuf->st_ctime;
68*33b1fccfSAndroid Build Coastguard Worker 	stbuf->st_atime = stbuf->st_ctime;
69*33b1fccfSAndroid Build Coastguard Worker }
70*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_add_dentry(struct erofs_dir_context * ctx)71*33b1fccfSAndroid Build Coastguard Worker static int erofsfuse_add_dentry(struct erofs_dir_context *ctx)
72*33b1fccfSAndroid Build Coastguard Worker {
73*33b1fccfSAndroid Build Coastguard Worker 	size_t entsize = 0;
74*33b1fccfSAndroid Build Coastguard Worker 	char dname[EROFS_NAME_LEN + 1];
75*33b1fccfSAndroid Build Coastguard Worker 	struct erofsfuse_readdir_context *readdir_ctx = (void *)ctx;
76*33b1fccfSAndroid Build Coastguard Worker 
77*33b1fccfSAndroid Build Coastguard Worker 	if (readdir_ctx->index < readdir_ctx->offset) {
78*33b1fccfSAndroid Build Coastguard Worker 		readdir_ctx->index++;
79*33b1fccfSAndroid Build Coastguard Worker 		return 0;
80*33b1fccfSAndroid Build Coastguard Worker 	}
81*33b1fccfSAndroid Build Coastguard Worker 
82*33b1fccfSAndroid Build Coastguard Worker 	strncpy(dname, ctx->dname, ctx->de_namelen);
83*33b1fccfSAndroid Build Coastguard Worker 	dname[ctx->de_namelen] = '\0';
84*33b1fccfSAndroid Build Coastguard Worker 
85*33b1fccfSAndroid Build Coastguard Worker 	if (!readdir_ctx->is_plus) { /* fuse 3 still use non-plus readdir */
86*33b1fccfSAndroid Build Coastguard Worker 		struct stat st = { 0 };
87*33b1fccfSAndroid Build Coastguard Worker 
88*33b1fccfSAndroid Build Coastguard Worker 		st.st_mode = erofs_ftype_to_mode(ctx->de_ftype, 0);
89*33b1fccfSAndroid Build Coastguard Worker 		st.st_ino = erofsfuse_to_ino(ctx->de_nid);
90*33b1fccfSAndroid Build Coastguard Worker 		entsize = fuse_add_direntry(readdir_ctx->req, readdir_ctx->buf,
91*33b1fccfSAndroid Build Coastguard Worker 					 readdir_ctx->buf_rem, dname, &st,
92*33b1fccfSAndroid Build Coastguard Worker 					 readdir_ctx->index + 1);
93*33b1fccfSAndroid Build Coastguard Worker 	} else {
94*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
95*33b1fccfSAndroid Build Coastguard Worker 		int ret;
96*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_inode vi = {
97*33b1fccfSAndroid Build Coastguard Worker 			.sbi = &g_sbi,
98*33b1fccfSAndroid Build Coastguard Worker 			.nid = ctx->de_nid
99*33b1fccfSAndroid Build Coastguard Worker 		};
100*33b1fccfSAndroid Build Coastguard Worker 
101*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_read_inode_from_disk(&vi);
102*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
103*33b1fccfSAndroid Build Coastguard Worker 			return ret;
104*33b1fccfSAndroid Build Coastguard Worker 
105*33b1fccfSAndroid Build Coastguard Worker 		struct fuse_entry_param param = {
106*33b1fccfSAndroid Build Coastguard Worker 			.ino = erofsfuse_to_ino(ctx->de_nid),
107*33b1fccfSAndroid Build Coastguard Worker 			.attr.st_ino = erofsfuse_to_ino(ctx->de_nid),
108*33b1fccfSAndroid Build Coastguard Worker 			.generation = 0,
109*33b1fccfSAndroid Build Coastguard Worker 
110*33b1fccfSAndroid Build Coastguard Worker 			.attr_timeout = EROFSFUSE_TIMEOUT,
111*33b1fccfSAndroid Build Coastguard Worker 			.entry_timeout = EROFSFUSE_TIMEOUT,
112*33b1fccfSAndroid Build Coastguard Worker 		};
113*33b1fccfSAndroid Build Coastguard Worker 		erofsfuse_fill_stat(&vi, &(param.attr));
114*33b1fccfSAndroid Build Coastguard Worker 
115*33b1fccfSAndroid Build Coastguard Worker 		entsize = fuse_add_direntry_plus(readdir_ctx->req,
116*33b1fccfSAndroid Build Coastguard Worker 					      readdir_ctx->buf,
117*33b1fccfSAndroid Build Coastguard Worker 					      readdir_ctx->buf_rem, dname,
118*33b1fccfSAndroid Build Coastguard Worker 					      &param, readdir_ctx->index + 1);
119*33b1fccfSAndroid Build Coastguard Worker #else
120*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
121*33b1fccfSAndroid Build Coastguard Worker #endif
122*33b1fccfSAndroid Build Coastguard Worker 	}
123*33b1fccfSAndroid Build Coastguard Worker 
124*33b1fccfSAndroid Build Coastguard Worker 	if (entsize > readdir_ctx->buf_rem)
125*33b1fccfSAndroid Build Coastguard Worker 		return 1;
126*33b1fccfSAndroid Build Coastguard Worker 	readdir_ctx->index++;
127*33b1fccfSAndroid Build Coastguard Worker 	readdir_ctx->buf += entsize;
128*33b1fccfSAndroid Build Coastguard Worker 	readdir_ctx->buf_rem -= entsize;
129*33b1fccfSAndroid Build Coastguard Worker 	return 0;
130*33b1fccfSAndroid Build Coastguard Worker }
131*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_lookup_dentry(struct erofs_dir_context * ctx)132*33b1fccfSAndroid Build Coastguard Worker static int erofsfuse_lookup_dentry(struct erofs_dir_context *ctx)
133*33b1fccfSAndroid Build Coastguard Worker {
134*33b1fccfSAndroid Build Coastguard Worker 	struct erofsfuse_lookupdir_context *lookup_ctx = (void *)ctx;
135*33b1fccfSAndroid Build Coastguard Worker 
136*33b1fccfSAndroid Build Coastguard Worker 	if (lookup_ctx->ent->ino != 0 ||
137*33b1fccfSAndroid Build Coastguard Worker 	    strlen(lookup_ctx->target_name) != ctx->de_namelen)
138*33b1fccfSAndroid Build Coastguard Worker 		return 0;
139*33b1fccfSAndroid Build Coastguard Worker 
140*33b1fccfSAndroid Build Coastguard Worker 	if (!strncmp(lookup_ctx->target_name, ctx->dname, ctx->de_namelen)) {
141*33b1fccfSAndroid Build Coastguard Worker 		int ret;
142*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_inode vi = {
143*33b1fccfSAndroid Build Coastguard Worker 			.sbi = &g_sbi,
144*33b1fccfSAndroid Build Coastguard Worker 			.nid = (erofs_nid_t)ctx->de_nid,
145*33b1fccfSAndroid Build Coastguard Worker 		};
146*33b1fccfSAndroid Build Coastguard Worker 
147*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_read_inode_from_disk(&vi);
148*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
149*33b1fccfSAndroid Build Coastguard Worker 			return ret;
150*33b1fccfSAndroid Build Coastguard Worker 
151*33b1fccfSAndroid Build Coastguard Worker 		lookup_ctx->ent->ino = erofsfuse_to_ino(ctx->de_nid);
152*33b1fccfSAndroid Build Coastguard Worker 		lookup_ctx->ent->attr.st_ino = erofsfuse_to_ino(ctx->de_nid);
153*33b1fccfSAndroid Build Coastguard Worker 
154*33b1fccfSAndroid Build Coastguard Worker 		erofsfuse_fill_stat(&vi, &(lookup_ctx->ent->attr));
155*33b1fccfSAndroid Build Coastguard Worker 	}
156*33b1fccfSAndroid Build Coastguard Worker 	return 0;
157*33b1fccfSAndroid Build Coastguard Worker }
158*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_readdir_general(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi,int plus)159*33b1fccfSAndroid Build Coastguard Worker static inline void erofsfuse_readdir_general(fuse_req_t req, fuse_ino_t ino,
160*33b1fccfSAndroid Build Coastguard Worker 					     size_t size, off_t off,
161*33b1fccfSAndroid Build Coastguard Worker 					     struct fuse_file_info *fi,
162*33b1fccfSAndroid Build Coastguard Worker 					     int plus)
163*33b1fccfSAndroid Build Coastguard Worker {
164*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
165*33b1fccfSAndroid Build Coastguard Worker 	char *buf = NULL;
166*33b1fccfSAndroid Build Coastguard Worker 	struct erofsfuse_readdir_context ctx = { 0 };
167*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *vi = (struct erofs_inode *)fi->fh;
168*33b1fccfSAndroid Build Coastguard Worker 
169*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("readdir(%llu): size: %zu, off: %lu, plus: %d", ino | 0ULL,
170*33b1fccfSAndroid Build Coastguard Worker 		  size, off, plus);
171*33b1fccfSAndroid Build Coastguard Worker 
172*33b1fccfSAndroid Build Coastguard Worker 	buf = malloc(size);
173*33b1fccfSAndroid Build Coastguard Worker 	if (!buf) {
174*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOMEM);
175*33b1fccfSAndroid Build Coastguard Worker 		return;
176*33b1fccfSAndroid Build Coastguard Worker 	}
177*33b1fccfSAndroid Build Coastguard Worker 	ctx.ctx.dir = vi;
178*33b1fccfSAndroid Build Coastguard Worker 	ctx.ctx.cb = erofsfuse_add_dentry;
179*33b1fccfSAndroid Build Coastguard Worker 
180*33b1fccfSAndroid Build Coastguard Worker 	ctx.fi = fi;
181*33b1fccfSAndroid Build Coastguard Worker 	ctx.buf = buf;
182*33b1fccfSAndroid Build Coastguard Worker 	ctx.buf_rem = size;
183*33b1fccfSAndroid Build Coastguard Worker 	ctx.req = req;
184*33b1fccfSAndroid Build Coastguard Worker 	ctx.index = 0;
185*33b1fccfSAndroid Build Coastguard Worker 	ctx.offset = off;
186*33b1fccfSAndroid Build Coastguard Worker 	ctx.is_plus = plus;
187*33b1fccfSAndroid Build Coastguard Worker 
188*33b1fccfSAndroid Build Coastguard Worker #ifdef NDEBUG
189*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iterate_dir(&ctx.ctx, false);
190*33b1fccfSAndroid Build Coastguard Worker #else
191*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iterate_dir(&ctx.ctx, true);
192*33b1fccfSAndroid Build Coastguard Worker #endif
193*33b1fccfSAndroid Build Coastguard Worker 
194*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) /* if buffer insufficient, return 1 */
195*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
196*33b1fccfSAndroid Build Coastguard Worker 	else
197*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_buf(req, buf, size - ctx.buf_rem);
198*33b1fccfSAndroid Build Coastguard Worker 
199*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
200*33b1fccfSAndroid Build Coastguard Worker }
201*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_readdir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)202*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
203*33b1fccfSAndroid Build Coastguard Worker 			      off_t off, struct fuse_file_info *fi)
204*33b1fccfSAndroid Build Coastguard Worker {
205*33b1fccfSAndroid Build Coastguard Worker 	erofsfuse_readdir_general(req, ino, size, off, fi, 0);
206*33b1fccfSAndroid Build Coastguard Worker }
207*33b1fccfSAndroid Build Coastguard Worker 
208*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
erofsfuse_readdirplus(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)209*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
210*33b1fccfSAndroid Build Coastguard Worker 				  off_t off, struct fuse_file_info *fi)
211*33b1fccfSAndroid Build Coastguard Worker {
212*33b1fccfSAndroid Build Coastguard Worker 	erofsfuse_readdir_general(req, ino, size, off, fi, 1);
213*33b1fccfSAndroid Build Coastguard Worker }
214*33b1fccfSAndroid Build Coastguard Worker #endif
215*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_init(void * userdata,struct fuse_conn_info * conn)216*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_init(void *userdata, struct fuse_conn_info *conn)
217*33b1fccfSAndroid Build Coastguard Worker {
218*33b1fccfSAndroid Build Coastguard Worker 	erofs_info("Using FUSE protocol %d.%d", conn->proto_major,
219*33b1fccfSAndroid Build Coastguard Worker 		   conn->proto_minor);
220*33b1fccfSAndroid Build Coastguard Worker }
221*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_open(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)222*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_open(fuse_req_t req, fuse_ino_t ino,
223*33b1fccfSAndroid Build Coastguard Worker 			   struct fuse_file_info *fi)
224*33b1fccfSAndroid Build Coastguard Worker {
225*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
226*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *vi;
227*33b1fccfSAndroid Build Coastguard Worker 
228*33b1fccfSAndroid Build Coastguard Worker 	if (fi->flags & (O_WRONLY | O_RDWR)) {
229*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, EROFS);
230*33b1fccfSAndroid Build Coastguard Worker 		return;
231*33b1fccfSAndroid Build Coastguard Worker 	}
232*33b1fccfSAndroid Build Coastguard Worker 
233*33b1fccfSAndroid Build Coastguard Worker 	vi = (struct erofs_inode *)malloc(sizeof(struct erofs_inode));
234*33b1fccfSAndroid Build Coastguard Worker 	if (!vi) {
235*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOMEM);
236*33b1fccfSAndroid Build Coastguard Worker 		return;
237*33b1fccfSAndroid Build Coastguard Worker 	}
238*33b1fccfSAndroid Build Coastguard Worker 
239*33b1fccfSAndroid Build Coastguard Worker 	vi->sbi = &g_sbi;
240*33b1fccfSAndroid Build Coastguard Worker 	vi->nid = erofsfuse_to_nid(ino);
241*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(vi);
242*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
243*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
244*33b1fccfSAndroid Build Coastguard Worker 		goto out;
245*33b1fccfSAndroid Build Coastguard Worker 	}
246*33b1fccfSAndroid Build Coastguard Worker 
247*33b1fccfSAndroid Build Coastguard Worker 	if (!S_ISREG(vi->i_mode)) {
248*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, EISDIR);
249*33b1fccfSAndroid Build Coastguard Worker 	} else {
250*33b1fccfSAndroid Build Coastguard Worker 		fi->fh = (uint64_t)vi;
251*33b1fccfSAndroid Build Coastguard Worker 		fi->keep_cache = 1;
252*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_open(req, fi);
253*33b1fccfSAndroid Build Coastguard Worker 		return;
254*33b1fccfSAndroid Build Coastguard Worker 	}
255*33b1fccfSAndroid Build Coastguard Worker 
256*33b1fccfSAndroid Build Coastguard Worker out:
257*33b1fccfSAndroid Build Coastguard Worker 	free(vi);
258*33b1fccfSAndroid Build Coastguard Worker }
259*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_getattr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)260*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_getattr(fuse_req_t req, fuse_ino_t ino,
261*33b1fccfSAndroid Build Coastguard Worker 			      struct fuse_file_info *fi)
262*33b1fccfSAndroid Build Coastguard Worker {
263*33b1fccfSAndroid Build Coastguard Worker 	int ret;
264*33b1fccfSAndroid Build Coastguard Worker 	struct stat stbuf = { 0 };
265*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode vi = { .sbi = &g_sbi, .nid = erofsfuse_to_nid(ino) };
266*33b1fccfSAndroid Build Coastguard Worker 
267*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(&vi);
268*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
269*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
270*33b1fccfSAndroid Build Coastguard Worker 
271*33b1fccfSAndroid Build Coastguard Worker 	erofsfuse_fill_stat(&vi, &stbuf);
272*33b1fccfSAndroid Build Coastguard Worker 	stbuf.st_ino = ino;
273*33b1fccfSAndroid Build Coastguard Worker 
274*33b1fccfSAndroid Build Coastguard Worker 	fuse_reply_attr(req, &stbuf, EROFSFUSE_TIMEOUT);
275*33b1fccfSAndroid Build Coastguard Worker }
276*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_opendir(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)277*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_opendir(fuse_req_t req, fuse_ino_t ino,
278*33b1fccfSAndroid Build Coastguard Worker 			      struct fuse_file_info *fi)
279*33b1fccfSAndroid Build Coastguard Worker {
280*33b1fccfSAndroid Build Coastguard Worker 	int ret;
281*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *vi;
282*33b1fccfSAndroid Build Coastguard Worker 
283*33b1fccfSAndroid Build Coastguard Worker 	vi = (struct erofs_inode *)malloc(sizeof(struct erofs_inode));
284*33b1fccfSAndroid Build Coastguard Worker 	if (!vi) {
285*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOMEM);
286*33b1fccfSAndroid Build Coastguard Worker 		return;
287*33b1fccfSAndroid Build Coastguard Worker 	}
288*33b1fccfSAndroid Build Coastguard Worker 
289*33b1fccfSAndroid Build Coastguard Worker 	vi->sbi = &g_sbi;
290*33b1fccfSAndroid Build Coastguard Worker 	vi->nid = erofsfuse_to_nid(ino);
291*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(vi);
292*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
293*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
294*33b1fccfSAndroid Build Coastguard Worker 		goto out;
295*33b1fccfSAndroid Build Coastguard Worker 	}
296*33b1fccfSAndroid Build Coastguard Worker 
297*33b1fccfSAndroid Build Coastguard Worker 	if (!S_ISDIR(vi->i_mode)) {
298*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOTDIR);
299*33b1fccfSAndroid Build Coastguard Worker 		goto out;
300*33b1fccfSAndroid Build Coastguard Worker 	}
301*33b1fccfSAndroid Build Coastguard Worker 
302*33b1fccfSAndroid Build Coastguard Worker 	fi->fh = (uint64_t)vi;
303*33b1fccfSAndroid Build Coastguard Worker 	fuse_reply_open(req, fi);
304*33b1fccfSAndroid Build Coastguard Worker 	return;
305*33b1fccfSAndroid Build Coastguard Worker 
306*33b1fccfSAndroid Build Coastguard Worker out:
307*33b1fccfSAndroid Build Coastguard Worker 	free(vi);
308*33b1fccfSAndroid Build Coastguard Worker }
309*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_release(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)310*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_release(fuse_req_t req, fuse_ino_t ino,
311*33b1fccfSAndroid Build Coastguard Worker 			      struct fuse_file_info *fi)
312*33b1fccfSAndroid Build Coastguard Worker {
313*33b1fccfSAndroid Build Coastguard Worker 	free((struct erofs_inode *)fi->fh);
314*33b1fccfSAndroid Build Coastguard Worker 	fi->fh = 0;
315*33b1fccfSAndroid Build Coastguard Worker 	fuse_reply_err(req, 0);
316*33b1fccfSAndroid Build Coastguard Worker }
317*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_lookup(fuse_req_t req,fuse_ino_t parent,const char * name)318*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_lookup(fuse_req_t req, fuse_ino_t parent,
319*33b1fccfSAndroid Build Coastguard Worker 			     const char *name)
320*33b1fccfSAndroid Build Coastguard Worker {
321*33b1fccfSAndroid Build Coastguard Worker 	int ret;
322*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *vi;
323*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_entry_param fentry = { 0 };
324*33b1fccfSAndroid Build Coastguard Worker 	struct erofsfuse_lookupdir_context ctx = { 0 };
325*33b1fccfSAndroid Build Coastguard Worker 
326*33b1fccfSAndroid Build Coastguard Worker 	vi = (struct erofs_inode *)malloc(sizeof(struct erofs_inode));
327*33b1fccfSAndroid Build Coastguard Worker 	if (!vi) {
328*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOMEM);
329*33b1fccfSAndroid Build Coastguard Worker 		return;
330*33b1fccfSAndroid Build Coastguard Worker 	}
331*33b1fccfSAndroid Build Coastguard Worker 
332*33b1fccfSAndroid Build Coastguard Worker 	vi->sbi = &g_sbi;
333*33b1fccfSAndroid Build Coastguard Worker 	vi->nid = erofsfuse_to_nid(parent);
334*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(vi);
335*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
336*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
337*33b1fccfSAndroid Build Coastguard Worker 		goto out;
338*33b1fccfSAndroid Build Coastguard Worker 	}
339*33b1fccfSAndroid Build Coastguard Worker 
340*33b1fccfSAndroid Build Coastguard Worker 	memset(&fentry, 0, sizeof(fentry));
341*33b1fccfSAndroid Build Coastguard Worker 	fentry.ino = 0;
342*33b1fccfSAndroid Build Coastguard Worker 	fentry.attr_timeout = fentry.entry_timeout = EROFSFUSE_TIMEOUT;
343*33b1fccfSAndroid Build Coastguard Worker 	ctx.ctx.dir = vi;
344*33b1fccfSAndroid Build Coastguard Worker 	ctx.ctx.cb = erofsfuse_lookup_dentry;
345*33b1fccfSAndroid Build Coastguard Worker 
346*33b1fccfSAndroid Build Coastguard Worker 	ctx.ent = &fentry;
347*33b1fccfSAndroid Build Coastguard Worker 	ctx.target_name = name;
348*33b1fccfSAndroid Build Coastguard Worker 
349*33b1fccfSAndroid Build Coastguard Worker #ifdef NDEBUG
350*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iterate_dir(&ctx.ctx, false);
351*33b1fccfSAndroid Build Coastguard Worker #else
352*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_iterate_dir(&ctx.ctx, true);
353*33b1fccfSAndroid Build Coastguard Worker #endif
354*33b1fccfSAndroid Build Coastguard Worker 
355*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
356*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
357*33b1fccfSAndroid Build Coastguard Worker 		goto out;
358*33b1fccfSAndroid Build Coastguard Worker 	}
359*33b1fccfSAndroid Build Coastguard Worker 	fuse_reply_entry(req, &fentry);
360*33b1fccfSAndroid Build Coastguard Worker 
361*33b1fccfSAndroid Build Coastguard Worker out:
362*33b1fccfSAndroid Build Coastguard Worker 	free(vi);
363*33b1fccfSAndroid Build Coastguard Worker }
364*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_read(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)365*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
366*33b1fccfSAndroid Build Coastguard Worker 			   off_t off, struct fuse_file_info *fi)
367*33b1fccfSAndroid Build Coastguard Worker {
368*33b1fccfSAndroid Build Coastguard Worker 	int ret;
369*33b1fccfSAndroid Build Coastguard Worker 	char *buf = NULL;
370*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *vi = (struct erofs_inode *)fi->fh;
371*33b1fccfSAndroid Build Coastguard Worker 
372*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("read(%llu): size = %zu, off = %lu", ino | 0ULL, size, off);
373*33b1fccfSAndroid Build Coastguard Worker 
374*33b1fccfSAndroid Build Coastguard Worker 	buf = malloc(size);
375*33b1fccfSAndroid Build Coastguard Worker 	if (!buf) {
376*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOMEM);
377*33b1fccfSAndroid Build Coastguard Worker 		return;
378*33b1fccfSAndroid Build Coastguard Worker 	}
379*33b1fccfSAndroid Build Coastguard Worker 
380*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_pread(vi, buf, size, off);
381*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
382*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
383*33b1fccfSAndroid Build Coastguard Worker 		goto out;
384*33b1fccfSAndroid Build Coastguard Worker 	}
385*33b1fccfSAndroid Build Coastguard Worker 	if (off >= vi->i_size)
386*33b1fccfSAndroid Build Coastguard Worker 		ret = 0;
387*33b1fccfSAndroid Build Coastguard Worker 	else if (off + size > vi->i_size)
388*33b1fccfSAndroid Build Coastguard Worker 		ret = vi->i_size - off;
389*33b1fccfSAndroid Build Coastguard Worker 	else
390*33b1fccfSAndroid Build Coastguard Worker 		ret = size;
391*33b1fccfSAndroid Build Coastguard Worker 
392*33b1fccfSAndroid Build Coastguard Worker 	fuse_reply_buf(req, buf, ret);
393*33b1fccfSAndroid Build Coastguard Worker 
394*33b1fccfSAndroid Build Coastguard Worker out:
395*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
396*33b1fccfSAndroid Build Coastguard Worker }
397*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_readlink(fuse_req_t req,fuse_ino_t ino)398*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_readlink(fuse_req_t req, fuse_ino_t ino)
399*33b1fccfSAndroid Build Coastguard Worker {
400*33b1fccfSAndroid Build Coastguard Worker 	int ret;
401*33b1fccfSAndroid Build Coastguard Worker 	char *buf = NULL;
402*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode vi = { .sbi = &g_sbi, .nid = erofsfuse_to_nid(ino) };
403*33b1fccfSAndroid Build Coastguard Worker 
404*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(&vi);
405*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
406*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
407*33b1fccfSAndroid Build Coastguard Worker 		return;
408*33b1fccfSAndroid Build Coastguard Worker 	}
409*33b1fccfSAndroid Build Coastguard Worker 
410*33b1fccfSAndroid Build Coastguard Worker 	buf = malloc(vi.i_size + 1);
411*33b1fccfSAndroid Build Coastguard Worker 	if (!buf) {
412*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, ENOMEM);
413*33b1fccfSAndroid Build Coastguard Worker 		return;
414*33b1fccfSAndroid Build Coastguard Worker 	}
415*33b1fccfSAndroid Build Coastguard Worker 
416*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_pread(&vi, buf, vi.i_size, 0);
417*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
418*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
419*33b1fccfSAndroid Build Coastguard Worker 		goto out;
420*33b1fccfSAndroid Build Coastguard Worker 	}
421*33b1fccfSAndroid Build Coastguard Worker 
422*33b1fccfSAndroid Build Coastguard Worker 	buf[vi.i_size] = '\0';
423*33b1fccfSAndroid Build Coastguard Worker 	fuse_reply_readlink(req, buf);
424*33b1fccfSAndroid Build Coastguard Worker 
425*33b1fccfSAndroid Build Coastguard Worker out:
426*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
427*33b1fccfSAndroid Build Coastguard Worker }
428*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_getxattr(fuse_req_t req,fuse_ino_t ino,const char * name,size_t size,uint32_t position)429*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
430*33b1fccfSAndroid Build Coastguard Worker 			       size_t size
431*33b1fccfSAndroid Build Coastguard Worker #ifdef __APPLE__
432*33b1fccfSAndroid Build Coastguard Worker 			       , uint32_t position)
433*33b1fccfSAndroid Build Coastguard Worker #else
434*33b1fccfSAndroid Build Coastguard Worker 			       )
435*33b1fccfSAndroid Build Coastguard Worker #endif
436*33b1fccfSAndroid Build Coastguard Worker {
437*33b1fccfSAndroid Build Coastguard Worker 	int ret;
438*33b1fccfSAndroid Build Coastguard Worker 	char *buf = NULL;
439*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode vi = { .sbi = &g_sbi, .nid = erofsfuse_to_nid(ino) };
440*33b1fccfSAndroid Build Coastguard Worker 
441*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("getattr(%llu): name = %s, size = %zu", ino | 0ULL, name, size);
442*33b1fccfSAndroid Build Coastguard Worker 
443*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(&vi);
444*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
445*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
446*33b1fccfSAndroid Build Coastguard Worker 		return;
447*33b1fccfSAndroid Build Coastguard Worker 	}
448*33b1fccfSAndroid Build Coastguard Worker 
449*33b1fccfSAndroid Build Coastguard Worker 	if (size != 0) {
450*33b1fccfSAndroid Build Coastguard Worker 		buf = malloc(size);
451*33b1fccfSAndroid Build Coastguard Worker 		if (!buf) {
452*33b1fccfSAndroid Build Coastguard Worker 			fuse_reply_err(req, ENOMEM);
453*33b1fccfSAndroid Build Coastguard Worker 			return;
454*33b1fccfSAndroid Build Coastguard Worker 		}
455*33b1fccfSAndroid Build Coastguard Worker 	}
456*33b1fccfSAndroid Build Coastguard Worker 
457*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_getxattr(&vi, name, buf, size);
458*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
459*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
460*33b1fccfSAndroid Build Coastguard Worker 	else if (size == 0)
461*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_xattr(req, ret);
462*33b1fccfSAndroid Build Coastguard Worker 	else
463*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_buf(req, buf, ret);
464*33b1fccfSAndroid Build Coastguard Worker 
465*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
466*33b1fccfSAndroid Build Coastguard Worker }
467*33b1fccfSAndroid Build Coastguard Worker 
erofsfuse_listxattr(fuse_req_t req,fuse_ino_t ino,size_t size)468*33b1fccfSAndroid Build Coastguard Worker static void erofsfuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
469*33b1fccfSAndroid Build Coastguard Worker {
470*33b1fccfSAndroid Build Coastguard Worker 	int ret;
471*33b1fccfSAndroid Build Coastguard Worker 	char *buf = NULL;
472*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode vi = { .sbi = &g_sbi, .nid = erofsfuse_to_nid(ino) };
473*33b1fccfSAndroid Build Coastguard Worker 
474*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("listxattr(%llu): size = %zu", ino | 0ULL, size);
475*33b1fccfSAndroid Build Coastguard Worker 
476*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_inode_from_disk(&vi);
477*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0) {
478*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
479*33b1fccfSAndroid Build Coastguard Worker 		return;
480*33b1fccfSAndroid Build Coastguard Worker 	}
481*33b1fccfSAndroid Build Coastguard Worker 
482*33b1fccfSAndroid Build Coastguard Worker 	if (size != 0) {
483*33b1fccfSAndroid Build Coastguard Worker 		buf = malloc(size);
484*33b1fccfSAndroid Build Coastguard Worker 		if (!buf) {
485*33b1fccfSAndroid Build Coastguard Worker 			fuse_reply_err(req, ENOMEM);
486*33b1fccfSAndroid Build Coastguard Worker 			return;
487*33b1fccfSAndroid Build Coastguard Worker 		}
488*33b1fccfSAndroid Build Coastguard Worker 	}
489*33b1fccfSAndroid Build Coastguard Worker 
490*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_listxattr(&vi, buf, size);
491*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
492*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_err(req, -ret);
493*33b1fccfSAndroid Build Coastguard Worker 	else if (size == 0)
494*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_xattr(req, ret);
495*33b1fccfSAndroid Build Coastguard Worker 	else
496*33b1fccfSAndroid Build Coastguard Worker 		fuse_reply_buf(req, buf, ret);
497*33b1fccfSAndroid Build Coastguard Worker 
498*33b1fccfSAndroid Build Coastguard Worker 	free(buf);
499*33b1fccfSAndroid Build Coastguard Worker }
500*33b1fccfSAndroid Build Coastguard Worker 
501*33b1fccfSAndroid Build Coastguard Worker static struct fuse_lowlevel_ops erofsfuse_lops = {
502*33b1fccfSAndroid Build Coastguard Worker 	.getxattr = erofsfuse_getxattr,
503*33b1fccfSAndroid Build Coastguard Worker 	.opendir = erofsfuse_opendir,
504*33b1fccfSAndroid Build Coastguard Worker 	.releasedir = erofsfuse_release,
505*33b1fccfSAndroid Build Coastguard Worker 	.release = erofsfuse_release,
506*33b1fccfSAndroid Build Coastguard Worker 	.lookup = erofsfuse_lookup,
507*33b1fccfSAndroid Build Coastguard Worker 	.listxattr = erofsfuse_listxattr,
508*33b1fccfSAndroid Build Coastguard Worker 	.readlink = erofsfuse_readlink,
509*33b1fccfSAndroid Build Coastguard Worker 	.getattr = erofsfuse_getattr,
510*33b1fccfSAndroid Build Coastguard Worker 	.readdir = erofsfuse_readdir,
511*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
512*33b1fccfSAndroid Build Coastguard Worker 	.readdirplus = erofsfuse_readdirplus,
513*33b1fccfSAndroid Build Coastguard Worker #endif
514*33b1fccfSAndroid Build Coastguard Worker 	.open = erofsfuse_open,
515*33b1fccfSAndroid Build Coastguard Worker 	.read = erofsfuse_read,
516*33b1fccfSAndroid Build Coastguard Worker 	.init = erofsfuse_init,
517*33b1fccfSAndroid Build Coastguard Worker };
518*33b1fccfSAndroid Build Coastguard Worker 
519*33b1fccfSAndroid Build Coastguard Worker static struct options {
520*33b1fccfSAndroid Build Coastguard Worker 	const char *disk;
521*33b1fccfSAndroid Build Coastguard Worker 	const char *mountpoint;
522*33b1fccfSAndroid Build Coastguard Worker 	u64 offset;
523*33b1fccfSAndroid Build Coastguard Worker 	unsigned int debug_lvl;
524*33b1fccfSAndroid Build Coastguard Worker 	bool show_help;
525*33b1fccfSAndroid Build Coastguard Worker 	bool show_version;
526*33b1fccfSAndroid Build Coastguard Worker 	bool odebug;
527*33b1fccfSAndroid Build Coastguard Worker } fusecfg;
528*33b1fccfSAndroid Build Coastguard Worker 
529*33b1fccfSAndroid Build Coastguard Worker #define OPTION(t, p) { t, offsetof(struct options, p), 1 }
530*33b1fccfSAndroid Build Coastguard Worker static const struct fuse_opt option_spec[] = {
531*33b1fccfSAndroid Build Coastguard Worker 	OPTION("--offset=%lu", offset),
532*33b1fccfSAndroid Build Coastguard Worker 	OPTION("--dbglevel=%u", debug_lvl),
533*33b1fccfSAndroid Build Coastguard Worker 	OPTION("--help", show_help),
534*33b1fccfSAndroid Build Coastguard Worker 	OPTION("--version", show_version),
535*33b1fccfSAndroid Build Coastguard Worker 	FUSE_OPT_KEY("--device=", 1),
536*33b1fccfSAndroid Build Coastguard Worker 	FUSE_OPT_END
537*33b1fccfSAndroid Build Coastguard Worker };
538*33b1fccfSAndroid Build Coastguard Worker 
usage(void)539*33b1fccfSAndroid Build Coastguard Worker static void usage(void)
540*33b1fccfSAndroid Build Coastguard Worker {
541*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION < 3
542*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
543*33b1fccfSAndroid Build Coastguard Worker 
544*33b1fccfSAndroid Build Coastguard Worker #else
545*33b1fccfSAndroid Build Coastguard Worker 	fuse_lowlevel_version();
546*33b1fccfSAndroid Build Coastguard Worker #endif
547*33b1fccfSAndroid Build Coastguard Worker 	fputs("usage: [options] IMAGE MOUNTPOINT\n\n"
548*33b1fccfSAndroid Build Coastguard Worker 	      "Options:\n"
549*33b1fccfSAndroid Build Coastguard Worker 	      "    --offset=#             skip # bytes at the beginning of IMAGE\n"
550*33b1fccfSAndroid Build Coastguard Worker 	      "    --dbglevel=#           set output message level to # (maximum 9)\n"
551*33b1fccfSAndroid Build Coastguard Worker 	      "    --device=#             specify an extra device to be used together\n"
552*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION < 3
553*33b1fccfSAndroid Build Coastguard Worker 	      "    --help                 display this help and exit\n"
554*33b1fccfSAndroid Build Coastguard Worker 	      "    --version              display erofsfuse version\n"
555*33b1fccfSAndroid Build Coastguard Worker #endif
556*33b1fccfSAndroid Build Coastguard Worker 	      "\n", stderr);
557*33b1fccfSAndroid Build Coastguard Worker 
558*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
559*33b1fccfSAndroid Build Coastguard Worker 	fputs("\nFUSE options:\n", stderr);
560*33b1fccfSAndroid Build Coastguard Worker 	fuse_cmdline_help();
561*33b1fccfSAndroid Build Coastguard Worker #else
562*33b1fccfSAndroid Build Coastguard Worker 	fuse_opt_add_arg(&args, ""); /* progname */
563*33b1fccfSAndroid Build Coastguard Worker 	fuse_opt_add_arg(&args, "-ho"); /* progname */
564*33b1fccfSAndroid Build Coastguard Worker 	fuse_parse_cmdline(&args, NULL, NULL, NULL);
565*33b1fccfSAndroid Build Coastguard Worker #endif
566*33b1fccfSAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
567*33b1fccfSAndroid Build Coastguard Worker }
568*33b1fccfSAndroid Build Coastguard Worker 
optional_opt_func(void * data,const char * arg,int key,struct fuse_args * outargs)569*33b1fccfSAndroid Build Coastguard Worker static int optional_opt_func(void *data, const char *arg, int key,
570*33b1fccfSAndroid Build Coastguard Worker 			     struct fuse_args *outargs)
571*33b1fccfSAndroid Build Coastguard Worker {
572*33b1fccfSAndroid Build Coastguard Worker 	int ret;
573*33b1fccfSAndroid Build Coastguard Worker 
574*33b1fccfSAndroid Build Coastguard Worker 	switch (key) {
575*33b1fccfSAndroid Build Coastguard Worker 	case 1:
576*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_blob_open_ro(&g_sbi, arg + sizeof("--device=") - 1);
577*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
578*33b1fccfSAndroid Build Coastguard Worker 			return -1;
579*33b1fccfSAndroid Build Coastguard Worker 		++g_sbi.extra_devices;
580*33b1fccfSAndroid Build Coastguard Worker 		return 0;
581*33b1fccfSAndroid Build Coastguard Worker 	case FUSE_OPT_KEY_NONOPT:
582*33b1fccfSAndroid Build Coastguard Worker 		if (fusecfg.mountpoint)
583*33b1fccfSAndroid Build Coastguard Worker 			return -1; /* Too many args */
584*33b1fccfSAndroid Build Coastguard Worker 
585*33b1fccfSAndroid Build Coastguard Worker 		if (!fusecfg.disk) {
586*33b1fccfSAndroid Build Coastguard Worker 			fusecfg.disk = strdup(arg);
587*33b1fccfSAndroid Build Coastguard Worker 			return 0;
588*33b1fccfSAndroid Build Coastguard Worker 		}
589*33b1fccfSAndroid Build Coastguard Worker 		if (!fusecfg.mountpoint)
590*33b1fccfSAndroid Build Coastguard Worker 			fusecfg.mountpoint = strdup(arg);
591*33b1fccfSAndroid Build Coastguard Worker 	case FUSE_OPT_KEY_OPT:
592*33b1fccfSAndroid Build Coastguard Worker 		if (!strcmp(arg, "-d"))
593*33b1fccfSAndroid Build Coastguard Worker 			fusecfg.odebug = true;
594*33b1fccfSAndroid Build Coastguard Worker 		if (!strcmp(arg, "-h"))
595*33b1fccfSAndroid Build Coastguard Worker 			fusecfg.show_help = true;
596*33b1fccfSAndroid Build Coastguard Worker 		if (!strcmp(arg, "-V"))
597*33b1fccfSAndroid Build Coastguard Worker 			fusecfg.show_version = true;
598*33b1fccfSAndroid Build Coastguard Worker 	}
599*33b1fccfSAndroid Build Coastguard Worker 	return 1; // keep arg
600*33b1fccfSAndroid Build Coastguard Worker }
601*33b1fccfSAndroid Build Coastguard Worker 
602*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)
603*33b1fccfSAndroid Build Coastguard Worker #include <execinfo.h>
604*33b1fccfSAndroid Build Coastguard Worker 
signal_handle_sigsegv(int signal)605*33b1fccfSAndroid Build Coastguard Worker static void signal_handle_sigsegv(int signal)
606*33b1fccfSAndroid Build Coastguard Worker {
607*33b1fccfSAndroid Build Coastguard Worker 	void *array[10];
608*33b1fccfSAndroid Build Coastguard Worker 	size_t nptrs;
609*33b1fccfSAndroid Build Coastguard Worker 	char **strings;
610*33b1fccfSAndroid Build Coastguard Worker 	size_t i;
611*33b1fccfSAndroid Build Coastguard Worker 
612*33b1fccfSAndroid Build Coastguard Worker 	erofs_dump("========================================\n");
613*33b1fccfSAndroid Build Coastguard Worker 	erofs_dump("Segmentation Fault.  Starting backtrace:\n");
614*33b1fccfSAndroid Build Coastguard Worker 	nptrs = backtrace(array, 10);
615*33b1fccfSAndroid Build Coastguard Worker 	strings = backtrace_symbols(array, nptrs);
616*33b1fccfSAndroid Build Coastguard Worker 	if (strings) {
617*33b1fccfSAndroid Build Coastguard Worker 		for (i = 0; i < nptrs; i++)
618*33b1fccfSAndroid Build Coastguard Worker 			erofs_dump("%s\n", strings[i]);
619*33b1fccfSAndroid Build Coastguard Worker 		free(strings);
620*33b1fccfSAndroid Build Coastguard Worker 	}
621*33b1fccfSAndroid Build Coastguard Worker 	erofs_dump("========================================\n");
622*33b1fccfSAndroid Build Coastguard Worker 	abort();
623*33b1fccfSAndroid Build Coastguard Worker }
624*33b1fccfSAndroid Build Coastguard Worker #endif
625*33b1fccfSAndroid Build Coastguard Worker 
626*33b1fccfSAndroid Build Coastguard Worker #define EROFSFUSE_MOUNT_MSG	\
627*33b1fccfSAndroid Build Coastguard Worker 	erofs_warn("%s mounted on %s with offset %u",	\
628*33b1fccfSAndroid Build Coastguard Worker 		   fusecfg.disk, fusecfg.mountpoint, fusecfg.offset);
629*33b1fccfSAndroid Build Coastguard Worker 
main(int argc,char * argv[])630*33b1fccfSAndroid Build Coastguard Worker int main(int argc, char *argv[])
631*33b1fccfSAndroid Build Coastguard Worker {
632*33b1fccfSAndroid Build Coastguard Worker 	int ret;
633*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_session *se;
634*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
635*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
636*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_cmdline_opts opts = {};
637*33b1fccfSAndroid Build Coastguard Worker #else
638*33b1fccfSAndroid Build Coastguard Worker 	struct fuse_chan *ch;
639*33b1fccfSAndroid Build Coastguard Worker 	struct {
640*33b1fccfSAndroid Build Coastguard Worker 		char *mountpoint;
641*33b1fccfSAndroid Build Coastguard Worker 		int mt, foreground;
642*33b1fccfSAndroid Build Coastguard Worker 	} opts = {};
643*33b1fccfSAndroid Build Coastguard Worker #endif
644*33b1fccfSAndroid Build Coastguard Worker 
645*33b1fccfSAndroid Build Coastguard Worker 	erofs_init_configure();
646*33b1fccfSAndroid Build Coastguard Worker 	fusecfg.debug_lvl = cfg.c_dbg_lvl;
647*33b1fccfSAndroid Build Coastguard Worker 	printf("erofsfuse %s\n", cfg.c_version);
648*33b1fccfSAndroid Build Coastguard Worker 
649*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)
650*33b1fccfSAndroid Build Coastguard Worker 	if (signal(SIGSEGV, signal_handle_sigsegv) == SIG_ERR) {
651*33b1fccfSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to initialize signals\n");
652*33b1fccfSAndroid Build Coastguard Worker 		ret = -errno;
653*33b1fccfSAndroid Build Coastguard Worker 		goto err;
654*33b1fccfSAndroid Build Coastguard Worker 	}
655*33b1fccfSAndroid Build Coastguard Worker #endif
656*33b1fccfSAndroid Build Coastguard Worker 
657*33b1fccfSAndroid Build Coastguard Worker 	/* parse options */
658*33b1fccfSAndroid Build Coastguard Worker 	ret = fuse_opt_parse(&args, &fusecfg, option_spec, optional_opt_func);
659*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
660*33b1fccfSAndroid Build Coastguard Worker 		goto err;
661*33b1fccfSAndroid Build Coastguard Worker 
662*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
663*33b1fccfSAndroid Build Coastguard Worker 	ret = fuse_parse_cmdline(&args, &opts);
664*33b1fccfSAndroid Build Coastguard Worker #else
665*33b1fccfSAndroid Build Coastguard Worker 	ret = (fuse_parse_cmdline(&args, &opts.mountpoint, &opts.mt,
666*33b1fccfSAndroid Build Coastguard Worker 				  &opts.foreground) < 0);
667*33b1fccfSAndroid Build Coastguard Worker #endif
668*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
669*33b1fccfSAndroid Build Coastguard Worker 		goto err_fuse_free_args;
670*33b1fccfSAndroid Build Coastguard Worker 
671*33b1fccfSAndroid Build Coastguard Worker 	if (fusecfg.show_help || fusecfg.show_version || !opts.mountpoint)
672*33b1fccfSAndroid Build Coastguard Worker 		usage();
673*33b1fccfSAndroid Build Coastguard Worker 	cfg.c_dbg_lvl = fusecfg.debug_lvl;
674*33b1fccfSAndroid Build Coastguard Worker 
675*33b1fccfSAndroid Build Coastguard Worker 	if (fusecfg.odebug && cfg.c_dbg_lvl < EROFS_DBG)
676*33b1fccfSAndroid Build Coastguard Worker 		cfg.c_dbg_lvl = EROFS_DBG;
677*33b1fccfSAndroid Build Coastguard Worker 
678*33b1fccfSAndroid Build Coastguard Worker 	g_sbi.bdev.offset = fusecfg.offset;
679*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_dev_open(&g_sbi, fusecfg.disk, O_RDONLY);
680*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
681*33b1fccfSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to open: %s\n", fusecfg.disk);
682*33b1fccfSAndroid Build Coastguard Worker 		goto err_fuse_free_args;
683*33b1fccfSAndroid Build Coastguard Worker 	}
684*33b1fccfSAndroid Build Coastguard Worker 
685*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_read_superblock(&g_sbi);
686*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
687*33b1fccfSAndroid Build Coastguard Worker 		fprintf(stderr, "failed to read erofs super block\n");
688*33b1fccfSAndroid Build Coastguard Worker 		goto err_dev_close;
689*33b1fccfSAndroid Build Coastguard Worker 	}
690*33b1fccfSAndroid Build Coastguard Worker 
691*33b1fccfSAndroid Build Coastguard Worker #if FUSE_MAJOR_VERSION >= 3
692*33b1fccfSAndroid Build Coastguard Worker 	se = fuse_session_new(&args, &erofsfuse_lops, sizeof(erofsfuse_lops),
693*33b1fccfSAndroid Build Coastguard Worker 			      NULL);
694*33b1fccfSAndroid Build Coastguard Worker 	if (!se)
695*33b1fccfSAndroid Build Coastguard Worker 		goto err_super_put;
696*33b1fccfSAndroid Build Coastguard Worker 
697*33b1fccfSAndroid Build Coastguard Worker 	if (fuse_session_mount(se, opts.mountpoint) >= 0) {
698*33b1fccfSAndroid Build Coastguard Worker 		EROFSFUSE_MOUNT_MSG
699*33b1fccfSAndroid Build Coastguard Worker 		if (fuse_daemonize(opts.foreground) >= 0) {
700*33b1fccfSAndroid Build Coastguard Worker 			if (fuse_set_signal_handlers(se) >= 0) {
701*33b1fccfSAndroid Build Coastguard Worker 				if (opts.singlethread) {
702*33b1fccfSAndroid Build Coastguard Worker 					ret = fuse_session_loop(se);
703*33b1fccfSAndroid Build Coastguard Worker 				} else {
704*33b1fccfSAndroid Build Coastguard Worker #if FUSE_USE_VERSION == 30
705*33b1fccfSAndroid Build Coastguard Worker 					ret = fuse_session_loop_mt(se, opts.clone_fd);
706*33b1fccfSAndroid Build Coastguard Worker #elif FUSE_USE_VERSION == 32
707*33b1fccfSAndroid Build Coastguard Worker 					struct fuse_loop_config config = {
708*33b1fccfSAndroid Build Coastguard Worker 						.clone_fd = opts.clone_fd,
709*33b1fccfSAndroid Build Coastguard Worker 						.max_idle_threads = opts.max_idle_threads
710*33b1fccfSAndroid Build Coastguard Worker 					};
711*33b1fccfSAndroid Build Coastguard Worker 					ret = fuse_session_loop_mt(se, &config);
712*33b1fccfSAndroid Build Coastguard Worker #else
713*33b1fccfSAndroid Build Coastguard Worker #error "FUSE_USE_VERSION not supported"
714*33b1fccfSAndroid Build Coastguard Worker #endif
715*33b1fccfSAndroid Build Coastguard Worker 				}
716*33b1fccfSAndroid Build Coastguard Worker 				fuse_remove_signal_handlers(se);
717*33b1fccfSAndroid Build Coastguard Worker 			}
718*33b1fccfSAndroid Build Coastguard Worker 			fuse_session_unmount(se);
719*33b1fccfSAndroid Build Coastguard Worker 			fuse_session_destroy(se);
720*33b1fccfSAndroid Build Coastguard Worker 		}
721*33b1fccfSAndroid Build Coastguard Worker 	}
722*33b1fccfSAndroid Build Coastguard Worker #else
723*33b1fccfSAndroid Build Coastguard Worker 	ch = fuse_mount(opts.mountpoint, &args);
724*33b1fccfSAndroid Build Coastguard Worker 	if (!ch)
725*33b1fccfSAndroid Build Coastguard Worker 		goto err_super_put;
726*33b1fccfSAndroid Build Coastguard Worker 	EROFSFUSE_MOUNT_MSG
727*33b1fccfSAndroid Build Coastguard Worker 	se = fuse_lowlevel_new(&args, &erofsfuse_lops, sizeof(erofsfuse_lops),
728*33b1fccfSAndroid Build Coastguard Worker 			       NULL);
729*33b1fccfSAndroid Build Coastguard Worker 	if (se) {
730*33b1fccfSAndroid Build Coastguard Worker 		if (fuse_daemonize(opts.foreground) != -1) {
731*33b1fccfSAndroid Build Coastguard Worker 			if (fuse_set_signal_handlers(se) != -1) {
732*33b1fccfSAndroid Build Coastguard Worker 				fuse_session_add_chan(se, ch);
733*33b1fccfSAndroid Build Coastguard Worker 				if (opts.mt)
734*33b1fccfSAndroid Build Coastguard Worker 					ret = fuse_session_loop_mt(se);
735*33b1fccfSAndroid Build Coastguard Worker 				else
736*33b1fccfSAndroid Build Coastguard Worker 					ret = fuse_session_loop(se);
737*33b1fccfSAndroid Build Coastguard Worker 				fuse_remove_signal_handlers(se);
738*33b1fccfSAndroid Build Coastguard Worker 				fuse_session_remove_chan(ch);
739*33b1fccfSAndroid Build Coastguard Worker 			}
740*33b1fccfSAndroid Build Coastguard Worker 		}
741*33b1fccfSAndroid Build Coastguard Worker 		fuse_session_destroy(se);
742*33b1fccfSAndroid Build Coastguard Worker 	}
743*33b1fccfSAndroid Build Coastguard Worker 	fuse_unmount(opts.mountpoint, ch);
744*33b1fccfSAndroid Build Coastguard Worker #endif
745*33b1fccfSAndroid Build Coastguard Worker 
746*33b1fccfSAndroid Build Coastguard Worker err_super_put:
747*33b1fccfSAndroid Build Coastguard Worker 	erofs_put_super(&g_sbi);
748*33b1fccfSAndroid Build Coastguard Worker err_dev_close:
749*33b1fccfSAndroid Build Coastguard Worker 	erofs_blob_closeall(&g_sbi);
750*33b1fccfSAndroid Build Coastguard Worker 	erofs_dev_close(&g_sbi);
751*33b1fccfSAndroid Build Coastguard Worker err_fuse_free_args:
752*33b1fccfSAndroid Build Coastguard Worker 	free(opts.mountpoint);
753*33b1fccfSAndroid Build Coastguard Worker 	fuse_opt_free_args(&args);
754*33b1fccfSAndroid Build Coastguard Worker err:
755*33b1fccfSAndroid Build Coastguard Worker 	erofs_exit_configure();
756*33b1fccfSAndroid Build Coastguard Worker 	return ret ? EXIT_FAILURE : EXIT_SUCCESS;
757*33b1fccfSAndroid Build Coastguard Worker }
758