Add a simple FUSE filesystem based on libnfs.
[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 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;
217 int fuse_nfs_argc = 6;
218 char *fuse_nfs_argv[16] = {
219 "fuse-nfs",
220 "<export>",
221 "-odebug",
222 "-oallow_other",
223 "-odefault_permissions",
224 "-omax_write=32768",
225 NULL,
226 NULL,
227 NULL,
228 NULL,
229 NULL,
230 NULL,
231 NULL,
232 NULL,
233 NULL,
234 NULL,
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 }