New version: 1.9.3
[deb_libnfs.git] / examples / fuse_nfs.c
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 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
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;
213 int fuse_nfs_argc = 5;
214 char *fuse_nfs_argv[16] = {
215 "fuse-nfs",
216 "<export>",
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,
230 NULL,
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 }