1 /*
2 * Copyright (c) 2014 Dave Vasilevsky <dave@vasilevsky.ca>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 #include "squashfuse.h"
26 #include "fuseprivate.h"
27
28 #include "nonstd.h"
29
30 #include <errno.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36
37 typedef struct sqfs_hl sqfs_hl;
38 struct sqfs_hl {
39 sqfs fs;
40 sqfs_inode root;
41 };
42
sqfs_hl_lookup(sqfs ** fs,sqfs_inode * inode,const char * path)43 static sqfs_err sqfs_hl_lookup(sqfs **fs, sqfs_inode *inode,
44 const char *path) {
45 bool found;
46
47 sqfs_hl *hl = fuse_get_context()->private_data;
48 *fs = &hl->fs;
49 if (inode)
50 *inode = hl->root; /* copy */
51
52 if (path) {
53 sqfs_err err = sqfs_lookup_path(*fs, inode, path, &found);
54 if (err)
55 return err;
56 if (!found)
57 return SQFS_ERR;
58 }
59 return SQFS_OK;
60 }
61
62
sqfs_hl_op_destroy(void * user_data)63 static void sqfs_hl_op_destroy(void *user_data) {
64 sqfs_hl *hl = (sqfs_hl*)user_data;
65 sqfs_destroy(&hl->fs);
66 free(hl);
67 }
68
sqfs_hl_op_init(struct fuse_conn_info * conn)69 static void *sqfs_hl_op_init(struct fuse_conn_info *conn) {
70 return fuse_get_context()->private_data;
71 }
72
sqfs_hl_op_getattr(const char * path,struct stat * st)73 static int sqfs_hl_op_getattr(const char *path, struct stat *st) {
74 sqfs *fs;
75 sqfs_inode inode;
76 if (sqfs_hl_lookup(&fs, &inode, path))
77 return -ENOENT;
78
79 if (sqfs_stat(fs, &inode, st))
80 return -ENOENT;
81
82 return 0;
83 }
84
sqfs_hl_op_opendir(const char * path,struct fuse_file_info * fi)85 static int sqfs_hl_op_opendir(const char *path, struct fuse_file_info *fi) {
86 sqfs *fs;
87 sqfs_inode *inode;
88
89 inode = malloc(sizeof(*inode));
90 if (!inode)
91 return -ENOMEM;
92
93 if (sqfs_hl_lookup(&fs, inode, path)) {
94 free(inode);
95 return -ENOENT;
96 }
97
98 if (!S_ISDIR(inode->base.mode)) {
99 free(inode);
100 return -ENOTDIR;
101 }
102
103 fi->fh = (intptr_t)inode;
104 return 0;
105 }
106
sqfs_hl_op_releasedir(const char * path,struct fuse_file_info * fi)107 static int sqfs_hl_op_releasedir(const char *path,
108 struct fuse_file_info *fi) {
109 free((sqfs_inode*)(intptr_t)fi->fh);
110 fi->fh = 0;
111 return 0;
112 }
113
sqfs_hl_op_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)114 static int sqfs_hl_op_readdir(const char *path, void *buf,
115 fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
116 sqfs_err err;
117 sqfs *fs;
118 sqfs_inode *inode;
119 sqfs_dir dir;
120 sqfs_name namebuf;
121 sqfs_dir_entry entry;
122 struct stat st;
123
124 sqfs_hl_lookup(&fs, NULL, NULL);
125 inode = (sqfs_inode*)(intptr_t)fi->fh;
126
127 if (sqfs_dir_open(fs, inode, &dir, offset))
128 return -EINVAL;
129
130 memset(&st, 0, sizeof(st));
131 sqfs_dentry_init(&entry, namebuf);
132 while (sqfs_dir_next(fs, &dir, &entry, &err)) {
133 sqfs_off_t doff = sqfs_dentry_next_offset(&entry);
134 st.st_mode = sqfs_dentry_mode(&entry);
135 if (filler(buf, sqfs_dentry_name(&entry), &st, doff))
136 return 0;
137 }
138 if (err)
139 return -EIO;
140 return 0;
141 }
142
sqfs_hl_op_open(const char * path,struct fuse_file_info * fi)143 static int sqfs_hl_op_open(const char *path, struct fuse_file_info *fi) {
144 sqfs *fs;
145 sqfs_inode *inode;
146
147 if (fi->flags & (O_WRONLY | O_RDWR))
148 return -EROFS;
149
150 inode = malloc(sizeof(*inode));
151 if (!inode)
152 return -ENOMEM;
153
154 if (sqfs_hl_lookup(&fs, inode, path)) {
155 free(inode);
156 return -ENOENT;
157 }
158
159 if (!S_ISREG(inode->base.mode)) {
160 free(inode);
161 return -EISDIR;
162 }
163
164 fi->fh = (intptr_t)inode;
165 fi->keep_cache = 1;
166 return 0;
167 }
168
sqfs_hl_op_create(const char * unused_path,mode_t unused_mode,struct fuse_file_info * unused_fi)169 static int sqfs_hl_op_create(const char* unused_path, mode_t unused_mode,
170 struct fuse_file_info *unused_fi) {
171 return -EROFS;
172 }
sqfs_hl_op_release(const char * path,struct fuse_file_info * fi)173 static int sqfs_hl_op_release(const char *path, struct fuse_file_info *fi) {
174 free((sqfs_inode*)(intptr_t)fi->fh);
175 fi->fh = 0;
176 return 0;
177 }
178
sqfs_hl_op_read(const char * path,char * buf,size_t size,off_t off,struct fuse_file_info * fi)179 static int sqfs_hl_op_read(const char *path, char *buf, size_t size,
180 off_t off, struct fuse_file_info *fi) {
181 sqfs *fs;
182 sqfs_hl_lookup(&fs, NULL, NULL);
183 sqfs_inode *inode = (sqfs_inode*)(intptr_t)fi->fh;
184
185 off_t osize = size;
186 if (sqfs_read_range(fs, inode, off, &osize, buf))
187 return -EIO;
188 return osize;
189 }
190
sqfs_hl_op_readlink(const char * path,char * buf,size_t size)191 static int sqfs_hl_op_readlink(const char *path, char *buf, size_t size) {
192 sqfs *fs;
193 sqfs_inode inode;
194 if (sqfs_hl_lookup(&fs, &inode, path))
195 return -ENOENT;
196
197 if (!S_ISLNK(inode.base.mode)) {
198 return -EINVAL;
199 } else if (sqfs_readlink(fs, &inode, buf, &size)) {
200 return -EIO;
201 }
202 return 0;
203 }
204
sqfs_hl_op_listxattr(const char * path,char * buf,size_t size)205 static int sqfs_hl_op_listxattr(const char *path, char *buf, size_t size) {
206 sqfs *fs;
207 sqfs_inode inode;
208 int ferr;
209
210 if (sqfs_hl_lookup(&fs, &inode, path))
211 return -ENOENT;
212
213 ferr = sqfs_listxattr(fs, &inode, buf, &size);
214 if (ferr)
215 return -ferr;
216 return size;
217 }
218
sqfs_hl_op_getxattr(const char * path,const char * name,char * value,size_t size,uint32_t position)219 static int sqfs_hl_op_getxattr(const char *path, const char *name,
220 char *value, size_t size
221 #ifdef FUSE_XATTR_POSITION
222 , uint32_t position
223 #endif
224 ) {
225 sqfs *fs;
226 sqfs_inode inode;
227 size_t real = size;
228
229 #ifdef FUSE_XATTR_POSITION
230 if (position != 0) /* We don't support resource forks */
231 return -EINVAL;
232 #endif
233
234 if (sqfs_hl_lookup(&fs, &inode, path))
235 return -ENOENT;
236
237 if ((sqfs_xattr_lookup(fs, &inode, name, value, &real)))
238 return -EIO;
239 if (real == 0)
240 return -sqfs_enoattr();
241 if (size != 0 && size < real)
242 return -ERANGE;
243 return real;
244 }
245
sqfs_hl_open(const char * path,size_t offset)246 static sqfs_hl *sqfs_hl_open(const char *path, size_t offset) {
247 sqfs_hl *hl;
248
249 hl = malloc(sizeof(*hl));
250 if (!hl) {
251 perror("Can't allocate memory");
252 } else {
253 memset(hl, 0, sizeof(*hl));
254 if (sqfs_open_image(&hl->fs, path, offset) == SQFS_OK) {
255 if (sqfs_inode_get(&hl->fs, &hl->root, sqfs_inode_root(&hl->fs)))
256 fprintf(stderr, "Can't find the root of this filesystem!\n");
257 else
258 return hl;
259 sqfs_destroy(&hl->fs);
260 }
261
262 free(hl);
263 }
264 return NULL;
265 }
266
main(int argc,char * argv[])267 int main(int argc, char *argv[]) {
268 struct fuse_args args;
269 sqfs_opts opts;
270 sqfs_hl *hl;
271 int ret;
272
273 struct fuse_opt fuse_opts[] = {
274 {"offset=%zu", offsetof(sqfs_opts, offset), 0},
275 FUSE_OPT_END
276 };
277
278 struct fuse_operations sqfs_hl_ops;
279 memset(&sqfs_hl_ops, 0, sizeof(sqfs_hl_ops));
280 sqfs_hl_ops.init = sqfs_hl_op_init;
281 sqfs_hl_ops.destroy = sqfs_hl_op_destroy;
282 sqfs_hl_ops.getattr = sqfs_hl_op_getattr;
283 sqfs_hl_ops.opendir = sqfs_hl_op_opendir;
284 sqfs_hl_ops.releasedir = sqfs_hl_op_releasedir;
285 sqfs_hl_ops.readdir = sqfs_hl_op_readdir;
286 sqfs_hl_ops.open = sqfs_hl_op_open;
287 sqfs_hl_ops.create = sqfs_hl_op_create;
288 sqfs_hl_ops.release = sqfs_hl_op_release;
289 sqfs_hl_ops.read = sqfs_hl_op_read;
290 sqfs_hl_ops.readlink = sqfs_hl_op_readlink;
291 sqfs_hl_ops.listxattr = sqfs_hl_op_listxattr;
292 sqfs_hl_ops.getxattr = sqfs_hl_op_getxattr;
293
294 args.argc = argc;
295 args.argv = argv;
296 args.allocated = 0;
297
298 opts.progname = argv[0];
299 opts.image = NULL;
300 opts.mountpoint = 0;
301 opts.offset = 0;
302 if (fuse_opt_parse(&args, &opts, fuse_opts, sqfs_opt_proc) == -1)
303 sqfs_usage(argv[0], true);
304 if (!opts.image)
305 sqfs_usage(argv[0], true);
306
307 hl = sqfs_hl_open(opts.image, opts.offset);
308 if (!hl)
309 return -1;
310
311 fuse_opt_add_arg(&args, "-s"); /* single threaded */
312 ret = fuse_main(args.argc, args.argv, &sqfs_hl_ops, hl);
313 fuse_opt_free_args(&args);
314 return ret;
315 }
316