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 | ||
34 | FILE *fh=NULL; | |
35 | ||
36 | struct nfs_context *nfs = NULL; | |
37 | ||
38 | static int fuse_nfs_getattr(const char *path, struct stat *stbuf) | |
39 | { | |
40 | int ret = 0; | |
41 | ||
42 | memset(stbuf, 0, sizeof(struct stat)); | |
43 | ret = nfs_stat(nfs, path, stbuf); | |
44 | ||
45 | return ret; | |
46 | } | |
47 | ||
48 | static int fuse_nfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | |
49 | off_t offset, struct fuse_file_info *fi) | |
50 | { | |
51 | struct nfsdir *nfsdir; | |
52 | struct nfsdirent *nfsdirent; | |
53 | ||
54 | int ret = 0; | |
55 | ||
56 | ret = nfs_opendir(nfs, path, &nfsdir); | |
57 | if (ret < 0) { | |
58 | return ret; | |
59 | } | |
60 | while ((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) { | |
61 | filler(buf, nfsdirent->name, NULL, 0); | |
62 | } | |
63 | ||
64 | return ret; | |
65 | } | |
66 | ||
67 | static int fuse_nfs_open(const char *path, struct fuse_file_info *fi) | |
68 | { | |
69 | int ret = 0; | |
70 | struct nfsfh *nfsfh; | |
71 | ||
72 | fi->fh = 0; | |
73 | ret = nfs_open(nfs, path, fi->flags, &nfsfh); | |
74 | if (ret < 0) { | |
75 | return ret; | |
76 | } | |
77 | ||
78 | fi->fh = (uint64_t)nfsfh; | |
79 | ||
80 | return ret; | |
81 | } | |
82 | ||
83 | static int fuse_nfs_release(const char *path, struct fuse_file_info *fi) | |
84 | { | |
85 | struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; | |
86 | ||
87 | nfs_close(nfs, nfsfh); | |
88 | return 0; | |
89 | } | |
90 | ||
91 | static int fuse_nfs_read(const char *path, char *buf, size_t size, | |
92 | off_t offset, struct fuse_file_info *fi) | |
93 | { | |
94 | int ret = 0; | |
95 | struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; | |
96 | ||
97 | ret = nfs_pread(nfs, nfsfh, offset, size, buf); | |
98 | ||
99 | return ret; | |
100 | } | |
101 | ||
102 | static int fuse_nfs_write(const char *path, const char *buf, size_t size, | |
103 | off_t offset, struct fuse_file_info *fi) | |
104 | { | |
105 | int ret = 0; | |
106 | struct nfsfh *nfsfh = (struct nfsfh *)fi->fh; | |
107 | ||
108 | ret = nfs_pwrite(nfs, nfsfh, offset, size, discard_const(buf)); | |
109 | ||
110 | return ret; | |
111 | } | |
112 | ||
113 | static int fuse_nfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) | |
114 | { | |
115 | int ret = 0; | |
116 | struct nfsfh *nfsfh; | |
117 | ||
118 | ret = nfs_creat(nfs, path, mode, &nfsfh); | |
119 | if (ret < 0) { | |
120 | return ret; | |
121 | } | |
122 | ||
123 | fi->fh = (uint64_t)nfsfh; | |
124 | ||
125 | //nfs_chown | |
126 | ||
127 | return ret; | |
128 | } | |
129 | ||
130 | static int fuse_nfs_utime(const char *path, struct utimbuf *times) | |
131 | { | |
132 | int ret = 0; | |
133 | ||
134 | ret = nfs_utime(nfs, path, times); | |
135 | if (ret < 0) { | |
136 | return ret; | |
137 | } | |
138 | ||
139 | return ret; | |
140 | } | |
141 | ||
142 | static int fuse_nfs_unlink(const char *path) | |
143 | { | |
144 | int ret = 0; | |
145 | ||
146 | ret = nfs_unlink(nfs, path); | |
147 | if (ret < 0) { | |
148 | return ret; | |
149 | } | |
150 | ||
151 | return ret; | |
152 | } | |
153 | ||
154 | static int fuse_nfs_rmdir(const char *path) | |
155 | { | |
156 | int ret = 0; | |
157 | ||
158 | ret = nfs_rmdir(nfs, path); | |
159 | if (ret < 0) { | |
160 | return ret; | |
161 | } | |
162 | ||
163 | return ret; | |
164 | } | |
165 | ||
166 | static int fuse_nfs_mkdir(const char *path, mode_t mode) | |
167 | { | |
168 | int ret = 0; | |
169 | ||
170 | ret = nfs_mkdir(nfs, path); | |
171 | if (ret < 0) { | |
172 | return ret; | |
173 | } | |
174 | ret = nfs_chmod(nfs, path, mode); | |
175 | if (ret < 0) { | |
176 | return ret; | |
177 | } | |
178 | ||
179 | return ret; | |
180 | } | |
181 | ||
182 | static struct fuse_operations nfs_oper = { | |
183 | .create = fuse_nfs_create, | |
184 | .getattr = fuse_nfs_getattr, | |
185 | .mkdir = fuse_nfs_mkdir, | |
186 | .open = fuse_nfs_open, | |
187 | .read = fuse_nfs_read, | |
188 | .readdir = fuse_nfs_readdir, | |
189 | .release = fuse_nfs_release, | |
190 | .rmdir = fuse_nfs_rmdir, | |
191 | .unlink = fuse_nfs_unlink, | |
192 | .utime = fuse_nfs_utime, | |
193 | .write = fuse_nfs_write, | |
194 | }; | |
195 | ||
196 | void print_usage(char *name) | |
197 | { | |
198 | printf("Usage: %s [-?|--help] [-n|--nfs-share=nfs-url] mountpoint\n", | |
199 | name); | |
200 | exit(0); | |
201 | } | |
202 | ||
203 | int main(int argc, char *argv[]) | |
204 | { | |
205 | int ret = 0; | |
206 | static struct option long_opts[] = { | |
207 | { "help", no_argument, 0, '?' }, | |
208 | { "nfs-share", required_argument, 0, 'n' }, | |
209 | { "mountpoint", required_argument, 0, 'm' }, | |
210 | { NULL, 0, 0, 0 } | |
211 | }; | |
212 | int c; | |
213 | int opt_idx = 0; | |
214 | char *url = NULL; | |
215 | char *mnt = NULL; | |
216 | char *server = NULL, *export = NULL, *strp; | |
8ca7b275 | 217 | int fuse_nfs_argc = 5; |
c6bd90a2 RS |
218 | char *fuse_nfs_argv[16] = { |
219 | "fuse-nfs", | |
220 | "<export>", | |
c6bd90a2 RS |
221 | "-oallow_other", |
222 | "-odefault_permissions", | |
223 | "-omax_write=32768", | |
224 | NULL, | |
225 | NULL, | |
226 | NULL, | |
227 | NULL, | |
228 | NULL, | |
229 | NULL, | |
230 | NULL, | |
231 | NULL, | |
232 | NULL, | |
233 | NULL, | |
8ca7b275 | 234 | NULL, |
c6bd90a2 RS |
235 | }; |
236 | ||
237 | while ((c = getopt_long(argc, argv, "?hm:n:", long_opts, | |
238 | &opt_idx)) > 0) { | |
239 | switch (c) { | |
240 | case 'h': | |
241 | case '?': | |
242 | print_usage(argv[0]); | |
243 | return 0; | |
244 | case 'm': | |
245 | mnt = strdup(optarg); | |
246 | break; | |
247 | case 'n': | |
248 | url = strdup(optarg); | |
249 | break; | |
250 | } | |
251 | } | |
252 | ||
253 | if (url == NULL) { | |
254 | fprintf(stderr, "-n was not specified.\n"); | |
255 | ret = 10; | |
256 | goto finished; | |
257 | } | |
258 | if (mnt == NULL) { | |
259 | fprintf(stderr, "-m was not specified.\n"); | |
260 | ret = 10; | |
261 | goto finished; | |
262 | } | |
263 | ||
264 | ||
265 | if (strncmp(url, "nfs://", 6)) { | |
266 | fprintf(stderr, "Invalid URL specified.\n"); | |
267 | ret = 10; | |
268 | goto finished; | |
269 | } | |
270 | server = strdup(url + 6); | |
271 | if (server == NULL) { | |
272 | fprintf(stderr, "Failed to strdup server string\n"); | |
273 | ret = 10; | |
274 | goto finished; | |
275 | } | |
276 | if (server[0] == '/' || server[0] == '\0') { | |
277 | fprintf(stderr, "Invalid server string.\n"); | |
278 | ret = 10; | |
279 | goto finished; | |
280 | } | |
281 | strp = strchr(server, '/'); | |
282 | if (strp == NULL) { | |
283 | fprintf(stderr, "Invalid URL specified.\n"); | |
284 | ret = 10; | |
285 | goto finished; | |
286 | } | |
287 | export = strdup(strp); | |
288 | if (export == NULL) { | |
289 | fprintf(stderr, "Failed to strdup server string\n"); | |
290 | ret = 10; | |
291 | goto finished; | |
292 | } | |
293 | if (export[0] != '/') { | |
294 | fprintf(stderr, "Invalid export.\n"); | |
295 | ret = 10; | |
296 | goto finished; | |
297 | } | |
298 | *strp = 0; | |
299 | ||
300 | nfs = nfs_init_context(); | |
301 | if (nfs == NULL) { | |
302 | printf("failed to init context\n"); | |
303 | goto finished; | |
304 | } | |
305 | ||
306 | ret = nfs_mount(nfs, server, export); | |
307 | if (ret != 0) { | |
308 | printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs)); | |
309 | goto finished; | |
310 | } | |
311 | ||
312 | ||
313 | fuse_nfs_argv[1] = mnt; | |
314 | return fuse_main(fuse_nfs_argc, fuse_nfs_argv, &nfs_oper, NULL); | |
315 | ||
316 | finished: | |
317 | if (nfs != NULL) { | |
318 | nfs_destroy_context(nfs); | |
319 | } | |
320 | free(server); | |
321 | free(export); | |
322 | free(url); | |
323 | free(mnt); | |
324 | return ret; | |
325 | } |