Commit | Line | Data |
---|---|---|
c6bd90a2 RS |
1 | /* |
2 | Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2013 | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 3 of the License, or | |
7 | (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | /* A FUSE filesystem based on libnfs. */ | |
18 | ||
19 | #define FUSE_USE_VERSION 26 | |
20 | #define _FILE_OFFSET_BITS 64 | |
21 | ||
22 | #include <fuse.h> | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <errno.h> | |
27 | #include <fcntl.h> | |
28 | #include <getopt.h> | |
29 | ||
30 | #include <nfsc/libnfs.h> | |
31 | ||
32 | #define discard_const(ptr) ((void *)((intptr_t)(ptr))) | |
33 | ||
c6bd90a2 RS |
34 | struct nfs_context *nfs = NULL; |
35 | ||
36 | static int fuse_nfs_getattr(const char *path, struct stat *stbuf) | |
37 | { | |
38 | int ret = 0; | |
39 | ||
40 | memset(stbuf, 0, sizeof(struct stat)); | |
41 | ret = nfs_stat(nfs, path, stbuf); | |
42 | ||
43 | return ret; | |
44 | } | |
45 | ||
46 | static int fuse_nfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | |
47 | off_t offset, struct fuse_file_info *fi) | |
48 | { | |
49 | struct nfsdir *nfsdir; | |
50 | struct nfsdirent *nfsdirent; | |
51 | ||
52 | int ret = 0; | |
53 | ||
54 | ret = nfs_opendir(nfs, path, &nfsdir); | |
55 | if (ret < 0) { | |
56 | return ret; | |
57 | } | |
58 | while ((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) { | |
59 | filler(buf, nfsdirent->name, NULL, 0); | |
60 | } | |
61 | ||
62 | return ret; | |
63 | } | |
64 | ||
65 | static int fuse_nfs_open(const char *path, struct fuse_file_info *fi) | |
66 | { | |
67 | int ret = 0; | |
68 | struct nfsfh *nfsfh; | |
69 | ||
70 | fi->fh = 0; | |
71 | ret = nfs_open(nfs, path, fi->flags, &nfsfh); | |
72 | if (ret < 0) { | |
73 | return ret; | |
74 | } | |
75 | ||
76 | fi->fh = (uint64_t)nfsfh; | |
77 | ||
78 | return ret; | |
79 | } | |
80 | ||
81 | static int fuse_nfs_release(const char *path, struct fuse_file_info *fi) | |
82 | { | |
83 | struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; | |
84 | ||
85 | nfs_close(nfs, nfsfh); | |
86 | return 0; | |
87 | } | |
88 | ||
89 | static int fuse_nfs_read(const char *path, char *buf, size_t size, | |
90 | off_t offset, struct fuse_file_info *fi) | |
91 | { | |
92 | int ret = 0; | |
93 | struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; | |
94 | ||
95 | ret = nfs_pread(nfs, nfsfh, offset, size, buf); | |
96 | ||
97 | return ret; | |
98 | } | |
99 | ||
100 | static int fuse_nfs_write(const char *path, const char *buf, size_t size, | |
101 | off_t offset, struct fuse_file_info *fi) | |
102 | { | |
103 | int ret = 0; | |
104 | struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; | |
105 | ||
106 | ret = nfs_pwrite(nfs, nfsfh, offset, size, discard_const(buf)); | |
107 | ||
108 | return ret; | |
109 | } | |
110 | ||
111 | static int fuse_nfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) | |
112 | { | |
113 | int ret = 0; | |
114 | struct nfsfh *nfsfh; | |
115 | ||
116 | ret = nfs_creat(nfs, path, mode, &nfsfh); | |
117 | if (ret < 0) { | |
118 | return ret; | |
119 | } | |
120 | ||
121 | fi->fh = (uint64_t)nfsfh; | |
122 | ||
c6bd90a2 RS |
123 | return ret; |
124 | } | |
125 | ||
126 | static int fuse_nfs_utime(const char *path, struct utimbuf *times) | |
127 | { | |
128 | int ret = 0; | |
129 | ||
130 | ret = nfs_utime(nfs, path, times); | |
131 | if (ret < 0) { | |
132 | return ret; | |
133 | } | |
134 | ||
135 | return ret; | |
136 | } | |
137 | ||
138 | static int fuse_nfs_unlink(const char *path) | |
139 | { | |
140 | int ret = 0; | |
141 | ||
142 | ret = nfs_unlink(nfs, path); | |
143 | if (ret < 0) { | |
144 | return ret; | |
145 | } | |
146 | ||
147 | return ret; | |
148 | } | |
149 | ||
150 | static int fuse_nfs_rmdir(const char *path) | |
151 | { | |
152 | int ret = 0; | |
153 | ||
154 | ret = nfs_rmdir(nfs, path); | |
155 | if (ret < 0) { | |
156 | return ret; | |
157 | } | |
158 | ||
159 | return ret; | |
160 | } | |
161 | ||
162 | static int fuse_nfs_mkdir(const char *path, mode_t mode) | |
163 | { | |
164 | int ret = 0; | |
165 | ||
166 | ret = nfs_mkdir(nfs, path); | |
167 | if (ret < 0) { | |
168 | return ret; | |
169 | } | |
170 | ret = nfs_chmod(nfs, path, mode); | |
171 | if (ret < 0) { | |
172 | return ret; | |
173 | } | |
174 | ||
175 | return ret; | |
176 | } | |
177 | ||
178 | static struct fuse_operations nfs_oper = { | |
179 | .create = fuse_nfs_create, | |
180 | .getattr = fuse_nfs_getattr, | |
181 | .mkdir = fuse_nfs_mkdir, | |
182 | .open = fuse_nfs_open, | |
183 | .read = fuse_nfs_read, | |
184 | .readdir = fuse_nfs_readdir, | |
185 | .release = fuse_nfs_release, | |
186 | .rmdir = fuse_nfs_rmdir, | |
187 | .unlink = fuse_nfs_unlink, | |
188 | .utime = fuse_nfs_utime, | |
189 | .write = fuse_nfs_write, | |
190 | }; | |
191 | ||
192 | void print_usage(char *name) | |
193 | { | |
194 | printf("Usage: %s [-?|--help] [-n|--nfs-share=nfs-url] mountpoint\n", | |
195 | name); | |
196 | exit(0); | |
197 | } | |
198 | ||
199 | int main(int argc, char *argv[]) | |
200 | { | |
201 | int ret = 0; | |
202 | static struct option long_opts[] = { | |
203 | { "help", no_argument, 0, '?' }, | |
204 | { "nfs-share", required_argument, 0, 'n' }, | |
205 | { "mountpoint", required_argument, 0, 'm' }, | |
206 | { NULL, 0, 0, 0 } | |
207 | }; | |
208 | int c; | |
209 | int opt_idx = 0; | |
210 | char *url = NULL; | |
211 | char *mnt = NULL; | |
212 | char *server = NULL, *export = NULL, *strp; | |
8ca7b275 | 213 | int fuse_nfs_argc = 5; |
c6bd90a2 RS |
214 | char *fuse_nfs_argv[16] = { |
215 | "fuse-nfs", | |
216 | "<export>", | |
c6bd90a2 RS |
217 | "-oallow_other", |
218 | "-odefault_permissions", | |
219 | "-omax_write=32768", | |
220 | NULL, | |
221 | NULL, | |
222 | NULL, | |
223 | NULL, | |
224 | NULL, | |
225 | NULL, | |
226 | NULL, | |
227 | NULL, | |
228 | NULL, | |
229 | NULL, | |
8ca7b275 | 230 | NULL, |
c6bd90a2 RS |
231 | }; |
232 | ||
233 | while ((c = getopt_long(argc, argv, "?hm:n:", long_opts, | |
234 | &opt_idx)) > 0) { | |
235 | switch (c) { | |
236 | case 'h': | |
237 | case '?': | |
238 | print_usage(argv[0]); | |
239 | return 0; | |
240 | case 'm': | |
241 | mnt = strdup(optarg); | |
242 | break; | |
243 | case 'n': | |
244 | url = strdup(optarg); | |
245 | break; | |
246 | } | |
247 | } | |
248 | ||
249 | if (url == NULL) { | |
250 | fprintf(stderr, "-n was not specified.\n"); | |
251 | ret = 10; | |
252 | goto finished; | |
253 | } | |
254 | if (mnt == NULL) { | |
255 | fprintf(stderr, "-m was not specified.\n"); | |
256 | ret = 10; | |
257 | goto finished; | |
258 | } | |
259 | ||
260 | ||
261 | if (strncmp(url, "nfs://", 6)) { | |
262 | fprintf(stderr, "Invalid URL specified.\n"); | |
263 | ret = 10; | |
264 | goto finished; | |
265 | } | |
266 | server = strdup(url + 6); | |
267 | if (server == NULL) { | |
268 | fprintf(stderr, "Failed to strdup server string\n"); | |
269 | ret = 10; | |
270 | goto finished; | |
271 | } | |
272 | if (server[0] == '/' || server[0] == '\0') { | |
273 | fprintf(stderr, "Invalid server string.\n"); | |
274 | ret = 10; | |
275 | goto finished; | |
276 | } | |
277 | strp = strchr(server, '/'); | |
278 | if (strp == NULL) { | |
279 | fprintf(stderr, "Invalid URL specified.\n"); | |
280 | ret = 10; | |
281 | goto finished; | |
282 | } | |
283 | export = strdup(strp); | |
284 | if (export == NULL) { | |
285 | fprintf(stderr, "Failed to strdup server string\n"); | |
286 | ret = 10; | |
287 | goto finished; | |
288 | } | |
289 | if (export[0] != '/') { | |
290 | fprintf(stderr, "Invalid export.\n"); | |
291 | ret = 10; | |
292 | goto finished; | |
293 | } | |
294 | *strp = 0; | |
295 | ||
296 | nfs = nfs_init_context(); | |
297 | if (nfs == NULL) { | |
298 | printf("failed to init context\n"); | |
299 | goto finished; | |
300 | } | |
301 | ||
302 | ret = nfs_mount(nfs, server, export); | |
303 | if (ret != 0) { | |
304 | printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs)); | |
305 | goto finished; | |
306 | } | |
307 | ||
308 | ||
309 | fuse_nfs_argv[1] = mnt; | |
310 | return fuse_main(fuse_nfs_argc, fuse_nfs_argv, &nfs_oper, NULL); | |
311 | ||
312 | finished: | |
313 | if (nfs != NULL) { | |
314 | nfs_destroy_context(nfs); | |
315 | } | |
316 | free(server); | |
317 | free(export); | |
318 | free(url); | |
319 | free(mnt); | |
320 | return ret; | |
321 | } |