1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9
10 #include <stdio.h>
11 #include <rtthread.h>
12 #include <dfs_fs.h>
13 #include <dfs.h>
14 #include <dfs_file.h>
15
16 #include <rpc/rpc.h>
17
18 #include "mount.h"
19 #include "nfs.h"
20
21 #define NAME_MAX 64
22 #define DFS_NFS_MAX_MTU 1024
23
24 #ifdef _WIN32
25 #define strtok_r strtok_s
26 #endif
27
28 struct nfs_file
29 {
30 nfs_fh3 handle; /* handle */
31 size_t offset; /* current offset */
32
33 size_t size; /* total size */
34 bool_t eof; /* end of file */
35 };
36
37 struct nfs_dir
38 {
39 nfs_fh3 handle;
40 cookie3 cookie;
41 cookieverf3 cookieverf;
42 entry3 *entry;
43 bool_t eof;
44 READDIR3res res;
45 };
46
47 #define HOST_LENGTH 32
48 #define EXPORT_PATH_LENGTH 32
49
50 struct nfs_filesystem
51 {
52 nfs_fh3 root_handle;
53 nfs_fh3 current_handle;
54 CLIENT *nfs_client;
55 CLIENT *mount_client;
56
57 char host[HOST_LENGTH];
58 char export[EXPORT_PATH_LENGTH];
59 void *data; /* nfs_file or nfs_dir */
60 };
61
62 typedef struct nfs_filesystem nfs_filesystem;
63 typedef struct nfs_file nfs_file;
64 typedef struct nfs_dir nfs_dir;
65
66 nfs_dir *nfs_opendir(nfs_filesystem *nfs, const char *path);
67
nfs_parse_host_export(const char * host_export,char * host,size_t host_len,char * export,size_t export_len)68 static int nfs_parse_host_export(const char *host_export,
69 char *host,
70 size_t host_len,
71 char *export,
72 size_t export_len)
73 {
74 int index;
75
76 for (index = 0; index < host_len; index ++)
77 {
78 /* it's end of string, failed */
79 if (host_export[index] == 0)
80 return -1;
81
82 /* copy to host buffer */
83 if (host_export[index] != ':')
84 host[index] = host_export[index];
85 else
86 break;
87 }
88
89 /* host buffer is not enough, failed */
90 if (index == host_len)
91 return -1;
92
93 /* make NULL */
94 host_len = index;
95 host[host_len] = '\0';
96
97 host_len ++;
98
99 /* copy export path */
100 for (index = host_len; index < host_len + export_len; index ++)
101 {
102 if (host_export[index] == 0)
103 {
104 export[index - host_len] = '\0';
105
106 return 0;
107 }
108
109 export[index - host_len] = host_export[index];
110 }
111
112 return -1;
113 }
114
copy_handle(nfs_fh3 * dest,const nfs_fh3 * source)115 static void copy_handle(nfs_fh3 *dest, const nfs_fh3 *source)
116 {
117 dest->data.data_len = source->data.data_len;
118 dest->data.data_val = rt_malloc(dest->data.data_len);
119 if (dest->data.data_val == NULL)
120 {
121 dest->data.data_len = 0;
122
123 return;
124 }
125
126 memcpy(dest->data.data_val, source->data.data_val, dest->data.data_len);
127 }
128
get_handle(nfs_filesystem * nfs,const char * name)129 static nfs_fh3 *get_handle(nfs_filesystem *nfs, const char *name)
130 {
131 nfs_fh3 *handle = NULL;
132 char *file;
133 char *path;
134 char *init;
135
136 init = path = rt_malloc(strlen(name)+1);
137 if (init == NULL)
138 return NULL;
139
140 memcpy(init, name, strlen(name)+1);
141
142 handle = rt_malloc(sizeof(nfs_fh3));
143 if (handle == NULL)
144 {
145 rt_free(init);
146
147 return NULL;
148 }
149
150 if (path[0] == '/')
151 {
152 path ++;
153 copy_handle(handle, &nfs->root_handle);
154 }
155 else
156 {
157 copy_handle(handle, &nfs->current_handle);
158 }
159
160 while ((file = strtok_r(NULL, "/", &path)) != NULL)
161 {
162 LOOKUP3args args;
163 LOOKUP3res res;
164 memset(&res, 0, sizeof(res));
165 copy_handle(&args.what.dir, handle);
166 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
167 args.what.name = file;
168
169 if (nfsproc3_lookup_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
170 {
171 rt_kprintf("Lookup failed\n");
172 rt_free(init);
173 rt_free(handle);
174 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&args.what.dir);
175
176 return NULL;
177 }
178 else if (res.status != NFS3_OK)
179 {
180 rt_kprintf("Lookup failed: %d\n", res.status);
181 rt_free(init);
182 rt_free(handle);
183 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&args.what.dir);
184 xdr_free((xdrproc_t)xdr_LOOKUP3res, (char *)&res);
185
186 return NULL;
187 }
188 copy_handle(handle, &res.LOOKUP3res_u.resok.object);
189 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&args.what.dir);
190 xdr_free((xdrproc_t)xdr_LOOKUP3res, (char *)&res);
191 }
192
193 rt_free(init);
194
195 return handle;
196 }
197
get_dir_handle(nfs_filesystem * nfs,const char * name)198 static nfs_fh3 *get_dir_handle(nfs_filesystem *nfs, const char *name)
199 {
200 nfs_fh3 *handle = NULL;
201 char *file;
202 char *path;
203 char *init;
204
205 init = path = rt_malloc(strlen(name)+1);
206 if (init == NULL)
207 return NULL;
208 memcpy(init, name, strlen(name)+1);
209
210 handle = rt_malloc(sizeof(nfs_fh3));
211 if (handle == NULL)
212 {
213 rt_free(init);
214
215 return NULL;
216 }
217
218 if (path[0] == '/')
219 {
220 path ++;
221 copy_handle(handle, &nfs->root_handle);
222 }
223 else
224 {
225 copy_handle(handle, &nfs->current_handle);
226 }
227
228 while ((file = strtok_r(NULL, "/", &path)) != NULL && path[0] != 0)
229 {
230 LOOKUP3args args;
231 LOOKUP3res res;
232 memset(&res, 0, sizeof(res));
233 copy_handle(&args.what.dir, handle);
234 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
235 args.what.name = file;
236
237 if (nfsproc3_lookup_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
238 {
239 rt_kprintf("Lookup failed\n");
240 rt_free(init);
241 rt_free(handle);
242 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&args.what.dir);
243
244 return NULL;
245 }
246 else if (res.status != NFS3_OK)
247 {
248 rt_kprintf("Lookup failed: %d\n", res.status);
249 rt_free(init);
250 rt_free(handle);
251 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&args.what.dir);
252 xdr_free((xdrproc_t)xdr_LOOKUP3res, (char *)&res);
253
254 return NULL;
255 }
256 copy_handle(handle, &res.LOOKUP3res_u.resok.object);
257 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&args.what.dir);
258 xdr_free((xdrproc_t)xdr_LOOKUP3res, (char *)&res);
259 }
260
261 rt_free(init);
262
263 return handle;
264 }
265
nfs_get_filesize(nfs_filesystem * nfs,nfs_fh3 * handle)266 static size_t nfs_get_filesize(nfs_filesystem *nfs, nfs_fh3 *handle)
267 {
268 GETATTR3args args;
269 GETATTR3res res;
270 fattr3 *info;
271 size_t size;
272
273 args.object = *handle;
274
275 memset(&res, '\0', sizeof(res));
276
277 if ((nfsproc3_getattr_3(args, &res, nfs->nfs_client)!=RPC_SUCCESS) ||
278 res.status != NFS3_OK)
279 {
280 rt_kprintf("GetAttr failed: %d\n", res.status);
281
282 return 0;
283 }
284
285 info = &res.GETATTR3res_u.resok.obj_attributes;
286 size = info->size;
287 xdr_free((xdrproc_t)xdr_GETATTR3res, (char *)&res);
288
289 return size;
290 }
291
nfs_is_directory(nfs_filesystem * nfs,const char * name)292 rt_bool_t nfs_is_directory(nfs_filesystem *nfs, const char *name)
293 {
294 GETATTR3args args;
295 GETATTR3res res;
296 fattr3 *info;
297 nfs_fh3 *handle;
298 rt_bool_t result;
299
300 result = RT_FALSE;
301 handle = get_handle(nfs, name);
302 if (handle == NULL)
303 return RT_FALSE;
304
305 args.object = *handle;
306
307 memset(&res, '\0', sizeof(res));
308
309 if (nfsproc3_getattr_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
310 {
311 rt_kprintf("GetAttr failed\n");
312
313 return RT_FALSE;
314 }
315 else if (res.status != NFS3_OK)
316 {
317 rt_kprintf("Getattr failed: %d\n", res.status);
318
319 return RT_FALSE;
320 }
321
322 info=&res.GETATTR3res_u.resok.obj_attributes;
323
324 if (info->type == NFS3DIR)
325 result = RT_TRUE;
326
327 xdr_free((xdrproc_t)xdr_GETATTR3res, (char *)&res);
328 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
329 rt_free(handle);
330
331 return result;
332 }
333
nfs_create(nfs_filesystem * nfs,const char * name,mode_t mode)334 int nfs_create(nfs_filesystem *nfs, const char *name, mode_t mode)
335 {
336 CREATE3args args;
337 CREATE3res res;
338 int ret = 0;
339 nfs_fh3 *handle;
340
341 if (nfs->nfs_client == NULL)
342 {
343 return -1;
344 }
345
346 handle = get_dir_handle(nfs, name);
347 if (handle == NULL)
348 {
349 return -1;
350 }
351 args.where.dir = *handle;
352 args.where.name = strrchr(name, '/') + 1;
353 if (args.where.name == NULL)
354 {
355 args.where.name = (char *)name;
356 }
357 args.how.mode = GUARDED;
358
359 args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
360 args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = mode;
361 args.how.createhow3_u.obj_attributes.uid.set_it = FALSE;
362 args.how.createhow3_u.obj_attributes.gid.set_it = FALSE;
363 args.how.createhow3_u.obj_attributes.size.set_it = FALSE;
364 args.how.createhow3_u.obj_attributes.atime.set_it = DONT_CHANGE;
365 args.how.createhow3_u.obj_attributes.mtime.set_it = DONT_CHANGE;
366
367 memset(&res, 0, sizeof(res));
368
369 if (nfsproc3_create_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
370 {
371 rt_kprintf("Create failed\n");
372 ret = -1;
373 }
374 else if (res.status != NFS3_OK)
375 {
376 rt_kprintf("Create failed: %d\n", res.status);
377 ret = -1;
378 }
379 xdr_free((xdrproc_t)xdr_CREATE3res, (char *)&res);
380 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
381 rt_free(handle);
382
383 return ret;
384 }
385
nfs_mkdir(nfs_filesystem * nfs,const char * name,mode_t mode)386 int nfs_mkdir(nfs_filesystem *nfs, const char *name, mode_t mode)
387 {
388 MKDIR3args args;
389 MKDIR3res res;
390 int ret = 0;
391 nfs_fh3 *handle;
392
393 if (nfs->nfs_client == NULL)
394 return -1;
395
396 handle = get_dir_handle(nfs, name);
397 if (handle == NULL)
398 return -1;
399
400 args.where.dir = *handle;
401 args.where.name = strrchr(name, '/') + 1;
402 if (args.where.name == NULL)
403 {
404 args.where.name = (char *)name;
405 }
406
407 args.attributes.mode.set_it = TRUE;
408 args.attributes.mode.set_mode3_u.mode = mode;
409 args.attributes.uid.set_it = FALSE;
410 args.attributes.gid.set_it = FALSE;
411 args.attributes.size.set_it = FALSE;
412 args.attributes.atime.set_it = DONT_CHANGE;
413 args.attributes.mtime.set_it = DONT_CHANGE;
414
415 memset(&res, 0, sizeof(res));
416
417 if (nfsproc3_mkdir_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
418 {
419 rt_kprintf("Mkdir failed\n");
420 ret = -1;
421 }
422 else if (res.status != NFS3_OK)
423 {
424 rt_kprintf("Mkdir failed: %d\n", res.status);
425 ret = -1;
426 }
427 xdr_free((xdrproc_t)xdr_MKDIR3res, (char *)&res);
428 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
429 rt_free(handle);
430
431 return ret;
432 }
433
434 /* mount(NULL, "/mnt", "nfs", 0, "192.168.1.1:/export") */
nfs_mount(struct dfs_filesystem * fs,unsigned long rwflag,const void * data)435 int nfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
436 {
437 mountres3 res;
438 nfs_filesystem *nfs;
439
440 nfs = (nfs_filesystem *)rt_malloc(sizeof(nfs_filesystem));
441 memset(nfs, 0, sizeof(nfs_filesystem));
442
443 if (nfs_parse_host_export((const char *)data, nfs->host, HOST_LENGTH,
444 nfs->export, EXPORT_PATH_LENGTH) < 0)
445 {
446 rt_kprintf("host or export path error\n");
447 goto __return;
448 }
449
450 nfs->mount_client=clnt_create((char *)nfs->host, MOUNT_PROGRAM, MOUNT_V3, "udp");
451 if (nfs->mount_client == NULL)
452 {
453 rt_kprintf("create mount client failed\n");
454 goto __return;
455 }
456
457 memset(&res, '\0', sizeof(mountres3));
458 if (mountproc3_mnt_3((char *)nfs->export, &res, nfs->mount_client) != RPC_SUCCESS)
459 {
460 rt_kprintf("nfs mount failed\n");
461 goto __return;
462 }
463 else if (res.fhs_status != MNT3_OK)
464 {
465 rt_kprintf("nfs mount failed\n");
466 goto __return;
467 }
468 nfs->nfs_client=clnt_create((char *)nfs->host, NFS_PROGRAM, NFS_V3, "udp");
469 if (nfs->nfs_client == NULL)
470 {
471 rt_kprintf("creat nfs client failed\n");
472 goto __return;
473 }
474 copy_handle(&nfs->root_handle, (nfs_fh3 *)&res.mountres3_u.mountinfo.fhandle);
475 copy_handle(&nfs->current_handle, &nfs->root_handle);
476
477 nfs->nfs_client->cl_auth = authnone_create();
478 fs->data = nfs;
479
480 return 0;
481
482 __return:
483 if (nfs != NULL)
484 {
485 if (nfs->mount_client != NULL)
486 {
487 clnt_destroy(nfs->mount_client);
488 }
489 if (nfs->nfs_client != NULL)
490 {
491 if (nfs->nfs_client->cl_auth != NULL)
492 {
493 auth_destroy(nfs->nfs_client->cl_auth);
494 }
495 clnt_destroy(nfs->nfs_client);
496 }
497 rt_free(nfs);
498 }
499
500 return -1;
501 }
502
nfs_unmount(struct dfs_filesystem * fs)503 int nfs_unmount(struct dfs_filesystem *fs)
504 {
505 nfs_filesystem *nfs;
506
507 RT_ASSERT(fs != NULL);
508 RT_ASSERT(fs->data != NULL);
509 nfs = (nfs_filesystem *)fs->data;
510
511 if (nfs->mount_client != NULL &&
512 mountproc3_umnt_3((char *)nfs->export, NULL, nfs->mount_client) != RPC_SUCCESS)
513 {
514 rt_kprintf("unmount failed\n");
515
516 return -1;
517 }
518
519 /* destroy nfs client */
520 if (nfs->nfs_client != NULL)
521 {
522 if (nfs->nfs_client->cl_auth != NULL)
523 {
524 auth_destroy(nfs->nfs_client->cl_auth);
525 nfs->nfs_client->cl_auth = NULL;
526 }
527 clnt_destroy(nfs->nfs_client);
528 nfs->nfs_client = NULL;
529 }
530
531 /* destroy mount client */
532 if (nfs->mount_client != NULL)
533 {
534 if (nfs->mount_client->cl_auth != NULL)
535 {
536 auth_destroy(nfs->mount_client->cl_auth);
537 nfs->mount_client->cl_auth = NULL;
538 }
539 clnt_destroy(nfs->mount_client);
540 nfs->mount_client = NULL;
541 }
542
543 rt_free(nfs);
544 fs->data = NULL;
545
546 return 0;
547 }
548
nfs_ioctl(struct dfs_fd * file,int cmd,void * args)549 int nfs_ioctl(struct dfs_fd *file, int cmd, void *args)
550 {
551 return -ENOSYS;
552 }
553
nfs_read(struct dfs_fd * file,void * buf,size_t count)554 int nfs_read(struct dfs_fd *file, void *buf, size_t count)
555 {
556 READ3args args;
557 READ3res res;
558 ssize_t bytes, total=0;
559 nfs_file *fd;
560 nfs_filesystem *nfs;
561
562 if (file->type == FT_DIRECTORY)
563 return -EISDIR;
564
565
566 RT_ASSERT(file->data != NULL);
567 struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem*)(file->data));
568 nfs = (struct nfs_filesystem *)(dfs_nfs->data);
569 fd = (nfs_file *)(nfs->data);
570 RT_ASSERT(fd != NULL);
571
572 if (nfs->nfs_client == NULL)
573 return -1;
574
575 /* end of file */
576 if (fd->eof == TRUE)
577 return 0;
578
579 args.file = fd->handle;
580 do {
581 args.offset = fd->offset;
582 args.count = count > DFS_NFS_MAX_MTU ? DFS_NFS_MAX_MTU : count;
583 count -= args.count;
584
585 memset(&res, 0, sizeof(res));
586 if (nfsproc3_read_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
587 {
588 rt_kprintf("Read failed\n");
589 total = 0;
590 break;
591 }
592 else if (res.status != NFS3_OK)
593 {
594 rt_kprintf("Read failed: %d\n", res.status);
595 total = 0;
596 break;
597 }
598 else
599 {
600 bytes = res.READ3res_u.resok.count;
601 total += bytes;
602 fd->offset += bytes;
603 /* update current position */
604 file->pos = fd->offset;
605 memcpy(buf, res.READ3res_u.resok.data.data_val, bytes);
606 buf = (void *)((char *)buf + args.count);
607 if (res.READ3res_u.resok.eof)
608 {
609 /* something should probably be here */
610 fd->eof = TRUE;
611 break;
612 }
613 }
614 xdr_free((xdrproc_t)xdr_READ3res, (char *)&res);
615 } while(count > 0);
616
617 xdr_free((xdrproc_t)xdr_READ3res, (char *)&res);
618
619 return total;
620 }
621
nfs_write(struct dfs_fd * file,const void * buf,size_t count)622 int nfs_write(struct dfs_fd *file, const void *buf, size_t count)
623 {
624 WRITE3args args;
625 WRITE3res res;
626 ssize_t bytes, total=0;
627 nfs_file *fd;
628 nfs_filesystem *nfs;
629
630 if (file->type == FT_DIRECTORY)
631 return -EISDIR;
632
633 RT_ASSERT(file->data != NULL);
634 struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem*)(file->data));
635 nfs = (struct nfs_filesystem *)(dfs_nfs->data);
636 fd = (nfs_file *)(nfs->data);
637 RT_ASSERT(fd != NULL);
638
639 if (nfs->nfs_client == NULL)
640 return -1;
641
642 args.file = fd->handle;
643 args.stable = FILE_SYNC;
644
645 do {
646 args.offset = fd->offset;
647
648 memset(&res, 0, sizeof(res));
649 args.data.data_val=(void *)buf;
650 args.count = count > DFS_NFS_MAX_MTU ? DFS_NFS_MAX_MTU : count;
651 args.data.data_len = args.count;
652 count -= args.count;
653 buf = (const void *)((char *)buf + args.count);
654
655 if (nfsproc3_write_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
656 {
657 rt_kprintf("Write failed\n");
658 total = 0;
659 break;
660 }
661 else if (res.status != NFS3_OK)
662 {
663 rt_kprintf("Write failed: %d\n", res.status);
664 total = 0;
665 break;
666 }
667 else
668 {
669 bytes = res.WRITE3res_u.resok.count;
670 fd->offset += bytes;
671 total += bytes;
672 /* update current position */
673 file->pos = fd->offset;
674 /* update file size */
675 if (fd->size < fd->offset) fd->size = fd->offset;
676 file->size = fd->size;
677 }
678 xdr_free((xdrproc_t)xdr_WRITE3res, (char *)&res);
679 } while (count > 0);
680
681 xdr_free((xdrproc_t)xdr_WRITE3res, (char *)&res);
682
683 return total;
684 }
685
nfs_lseek(struct dfs_fd * file,off_t offset)686 int nfs_lseek(struct dfs_fd *file, off_t offset)
687 {
688 nfs_file *fd;
689 nfs_filesystem *nfs;
690
691 if (file->type == FT_DIRECTORY)
692 return -EISDIR;
693
694 RT_ASSERT(file->data != NULL);
695 struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem*)(file->data));
696 nfs = (struct nfs_filesystem *)(dfs_nfs->data);
697 fd = (nfs_file *)(nfs->data);
698 RT_ASSERT(fd != NULL);
699
700 if (offset <= fd->size)
701 {
702 fd->offset = offset;
703
704 return offset;
705 }
706
707 return -EIO;
708 }
709
nfs_close(struct dfs_fd * file)710 int nfs_close(struct dfs_fd *file)
711 {
712 nfs_filesystem *nfs;
713 RT_ASSERT(file->data != NULL);
714 struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem*)(file->data));
715 nfs = (struct nfs_filesystem *)(dfs_nfs->data);
716
717 if (file->type == FT_DIRECTORY)
718 {
719 struct nfs_dir *dir;
720
721 dir = (struct nfs_dir *)nfs->data;
722 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&dir->handle);
723 xdr_free((xdrproc_t)xdr_READDIR3res, (char *)&dir->res);
724 rt_free(dir);
725 }
726 else if (file->type == FT_REGULAR)
727 {
728 struct nfs_file *fd;
729
730 fd = (struct nfs_file *)nfs->data;
731
732 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)&fd->handle);
733 rt_free(fd);
734 }
735
736 nfs->data = NULL;
737 return 0;
738 }
739
nfs_open(struct dfs_fd * file)740 int nfs_open(struct dfs_fd *file)
741 {
742 nfs_filesystem *nfs;
743 RT_ASSERT(file->data != NULL);
744 struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem*)(file->data));
745 nfs = (struct nfs_filesystem *)(dfs_nfs->data);
746
747
748 if (file->flags & O_DIRECTORY)
749 {
750 nfs_dir *dir;
751
752 if (file->flags & O_CREAT)
753 {
754 if (nfs_mkdir(nfs, file->path, 0755) < 0)
755 return -EAGAIN;
756 }
757
758 /* open directory */
759 dir = nfs_opendir(nfs, file->path);
760 if (dir == NULL) return -ENOENT;
761 nfs->data = dir;
762 }
763 else
764 {
765 nfs_file *fp;
766 nfs_fh3 *handle;
767
768 /* create file */
769 if (file->flags & O_CREAT)
770 {
771 if (nfs_create(nfs, file->path, 0664) < 0)
772 return -EAGAIN;
773 }
774
775 /* open file (get file handle ) */
776 fp = rt_malloc(sizeof(nfs_file));
777 if (fp == NULL)
778 return -ENOMEM;
779
780 handle = get_handle(nfs, file->path);
781 if (handle == NULL)
782 {
783 rt_free(fp);
784
785 return -ENOENT;
786 }
787
788 /* get size of file */
789 fp->size = nfs_get_filesize(nfs, handle);
790 fp->offset = 0;
791 fp->eof = FALSE;
792
793 copy_handle(&fp->handle, handle);
794 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
795 rt_free(handle);
796
797 if (file->flags & O_APPEND)
798 {
799 fp->offset = fp->size;
800 }
801
802 /* set private file */
803 nfs->data = fp;
804 file->size = fp->size;
805 }
806
807 return 0;
808 }
809
nfs_stat(struct dfs_filesystem * fs,const char * path,struct stat * st)810 int nfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
811 {
812 GETATTR3args args;
813 GETATTR3res res;
814 fattr3 *info;
815 nfs_fh3 *handle;
816 nfs_filesystem *nfs;
817
818 RT_ASSERT(fs != NULL);
819 RT_ASSERT(fs->data != NULL);
820 nfs = (nfs_filesystem *)fs->data;
821
822 handle = get_handle(nfs, path);
823 if (handle == NULL)
824 return -1;
825
826 args.object = *handle;
827
828 memset(&res, '\0', sizeof(res));
829
830 if (nfsproc3_getattr_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
831 {
832 rt_kprintf("GetAttr failed\n");
833 return -1;
834 }
835 else if (res.status != NFS3_OK)
836 {
837 rt_kprintf("Getattr failed: %d\n", res.status);
838 return -1;
839 }
840
841 info = &res.GETATTR3res_u.resok.obj_attributes;
842
843 st->st_dev = 0;
844
845 st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH;
846 if (info->type == NFS3DIR)
847 {
848 st->st_mode &= ~S_IFREG;
849 st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
850 }
851
852 st->st_size = info->size;
853 st->st_mtime = info->mtime.seconds;
854
855 xdr_free((xdrproc_t)xdr_GETATTR3res, (char *)&res);
856 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
857 rt_free(handle);
858
859 return 0;
860 }
861
nfs_opendir(nfs_filesystem * nfs,const char * path)862 nfs_dir *nfs_opendir(nfs_filesystem *nfs, const char *path)
863 {
864 nfs_dir *dir;
865 nfs_fh3 *handle;
866
867 dir = rt_malloc(sizeof(nfs_dir));
868 if (dir == NULL)
869 {
870 return NULL;
871 }
872
873 handle = get_handle(nfs, path);
874 if (handle == NULL)
875 {
876 rt_free(dir);
877 return NULL;
878 }
879
880 copy_handle(&dir->handle, handle);
881 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
882 rt_free(handle);
883
884 dir->cookie = 0;
885 memset(&dir->cookieverf, '\0', sizeof(cookieverf3));
886 dir->entry = NULL;
887 dir->eof = FALSE;
888 memset(&dir->res, '\0', sizeof(dir->res));
889
890 return dir;
891 }
892
nfs_readdir(nfs_filesystem * nfs,nfs_dir * dir)893 char *nfs_readdir(nfs_filesystem *nfs, nfs_dir *dir)
894 {
895 static char name[NAME_MAX];
896
897 if (nfs->nfs_client == NULL || dir == NULL)
898 return NULL;
899
900 if (dir->entry == NULL)
901 {
902 READDIR3args args;
903
904 xdr_free((xdrproc_t)xdr_READDIR3res, (char *)&dir->res);
905 memset(&dir->res, '\0', sizeof(dir->res));
906
907 args.dir = dir->handle;
908 args.cookie = dir->cookie;
909 memcpy(&args.cookieverf, &dir->cookieverf, sizeof(cookieverf3));
910 args.count = 1024;
911
912 if (nfsproc3_readdir_3(args, &dir->res, nfs->nfs_client) != RPC_SUCCESS)
913 {
914 rt_kprintf("Readdir failed\n");
915
916 return NULL;
917 }
918 else if (dir->res.status != NFS3_OK)
919 {
920 rt_kprintf("Readdir failed: %d\n", dir->res.status);
921
922 return NULL;
923 }
924
925 memcpy(&dir->cookieverf, &dir->res.READDIR3res_u.resok.cookieverf, sizeof(cookieverf3));
926 dir->eof = dir->res.READDIR3res_u.resok.reply.eof;
927 dir->entry = dir->res.READDIR3res_u.resok.reply.entries;
928 }
929 if (dir->eof == TRUE && dir->entry == NULL)
930 return NULL;
931
932 dir->cookie = dir->entry->cookie;
933 strncpy(name, dir->entry->name, NAME_MAX-1);
934 dir->entry = dir->entry->nextentry;
935 name[NAME_MAX - 1] = '\0';
936
937 return name;
938 }
939
nfs_unlink(struct dfs_filesystem * fs,const char * path)940 int nfs_unlink(struct dfs_filesystem *fs, const char *path)
941 {
942 int ret = 0;
943 nfs_filesystem *nfs;
944
945 RT_ASSERT(fs != NULL);
946 RT_ASSERT(fs->data != NULL);
947 nfs = (nfs_filesystem *)fs->data;
948
949 if (nfs_is_directory(nfs, path) == RT_FALSE)
950 {
951 /* remove file */
952 REMOVE3args args;
953 REMOVE3res res;
954 nfs_fh3 *handle;
955
956 handle = get_dir_handle(nfs, path);
957 if (handle == NULL)
958 return -1;
959
960 args.object.dir = *handle;
961 args.object.name = strrchr(path, '/') + 1;
962 if (args.object.name == NULL)
963 {
964 args.object.name = (char *)path;
965 }
966
967 memset(&res, 0, sizeof(res));
968
969 if (nfsproc3_remove_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
970 {
971 rt_kprintf("Remove failed\n");
972 ret = -1;
973 }
974 else if (res.status != NFS3_OK)
975 {
976 rt_kprintf("Remove failed: %d\n", res.status);
977 ret = -1;
978 }
979 xdr_free((xdrproc_t)xdr_REMOVE3res, (char *)&res);
980 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
981 rt_free(handle);
982 }
983 else
984 {
985 /* remove directory */
986 RMDIR3args args;
987 RMDIR3res res;
988 nfs_fh3 *handle;
989
990 handle = get_dir_handle(nfs, path);
991 if (handle == NULL)
992 return -1;
993
994 args.object.dir = *handle;
995 args.object.name = strrchr(path, '/') + 1;
996 if (args.object.name == NULL)
997 {
998 args.object.name = (char *)path;
999 }
1000
1001 memset(&res, 0, sizeof(res));
1002
1003 if (nfsproc3_rmdir_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
1004 {
1005 rt_kprintf("Rmdir failed\n");
1006 ret = -1;
1007 }
1008 else if (res.status != NFS3_OK)
1009 {
1010 rt_kprintf("Rmdir failed: %d\n", res.status);
1011 ret = -1;
1012 }
1013
1014 xdr_free((xdrproc_t)xdr_RMDIR3res, (char *)&res);
1015 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)handle);
1016 rt_free(handle);
1017 }
1018
1019 return ret;
1020 }
1021
nfs_rename(struct dfs_filesystem * fs,const char * src,const char * dest)1022 int nfs_rename(struct dfs_filesystem *fs, const char *src, const char *dest)
1023 {
1024 RENAME3args args;
1025 RENAME3res res;
1026 nfs_fh3 *sHandle;
1027 nfs_fh3 *dHandle;
1028 int ret = 0;
1029 nfs_filesystem *nfs;
1030
1031 RT_ASSERT(fs != NULL);
1032 RT_ASSERT(fs->data != NULL);
1033 nfs = (nfs_filesystem *)fs->data;
1034
1035 if (nfs->nfs_client == NULL)
1036 return -1;
1037
1038 sHandle = get_dir_handle(nfs, src);
1039 if (sHandle == NULL)
1040 return -1;
1041
1042 dHandle = get_dir_handle(nfs, dest);
1043 if (dHandle == NULL)
1044 return -1;
1045
1046 args.from.dir = *sHandle;
1047 args.from.name = strrchr(src, '/') + 1;
1048 if (args.from.name == NULL)
1049 args.from.name = (char *)src;
1050
1051 args.to.dir = *dHandle;
1052 args.to.name = strrchr(src, '/') + 1;
1053 if (args.to.name == NULL)
1054 args.to.name = (char *)dest;
1055
1056 memset(&res, '\0', sizeof(res));
1057
1058 if (nfsproc3_rename_3(args, &res, nfs->nfs_client) != RPC_SUCCESS)
1059 {
1060 rt_kprintf("Rename failed\n");
1061 ret = -1;
1062 }
1063 else if (res.status != NFS3_OK)
1064 {
1065 rt_kprintf("Rename failed: %d\n", res.status);
1066 ret = -1;
1067 }
1068
1069 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)sHandle);
1070 xdr_free((xdrproc_t)xdr_nfs_fh3, (char *)dHandle);
1071 xdr_free((xdrproc_t)xdr_RENAME3res, (char *)&res);
1072
1073 return ret;
1074 }
1075
nfs_getdents(struct dfs_fd * file,struct dirent * dirp,uint32_t count)1076 int nfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
1077 {
1078 nfs_dir *dir;
1079 rt_uint32_t index;
1080 struct dirent *d;
1081 nfs_filesystem *nfs;
1082 char *name;
1083
1084
1085 RT_ASSERT(file->data != NULL);
1086 struct dfs_filesystem *dfs_nfs = ((struct dfs_filesystem*)(file->data));
1087 nfs = (struct nfs_filesystem *)(dfs_nfs->data);
1088 dir = (nfs_dir *)(nfs->data);
1089 RT_ASSERT(dir != NULL);
1090
1091 /* make integer count */
1092 count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
1093 if (count == 0)
1094 return -EINVAL;
1095
1096 index = 0;
1097 while (1)
1098 {
1099 d = dirp + index;
1100
1101 name = nfs_readdir(nfs, dir);
1102 if (name == NULL)
1103 break;
1104
1105 d->d_type = DT_REG;
1106
1107 d->d_namlen = rt_strlen(name);
1108 d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
1109 rt_strncpy(d->d_name, name, rt_strlen(name) + 1);
1110
1111 index ++;
1112 if (index * sizeof(struct dirent) >= count)
1113 break;
1114 }
1115
1116 return index * sizeof(struct dirent);
1117 }
1118
1119 static const struct dfs_file_ops nfs_fops =
1120 {
1121 nfs_open,
1122 nfs_close,
1123 nfs_ioctl,
1124 nfs_read,
1125 nfs_write,
1126 NULL, /* flush */
1127 nfs_lseek,
1128 nfs_getdents,
1129 NULL, /* poll */
1130 };
1131
1132 static const struct dfs_filesystem_ops _nfs =
1133 {
1134 "nfs",
1135 DFS_FS_FLAG_DEFAULT,
1136 &nfs_fops,
1137 nfs_mount,
1138 nfs_unmount,
1139 NULL, /* mkfs */
1140 NULL, /* statfs */
1141 nfs_unlink,
1142 nfs_stat,
1143 nfs_rename,
1144 };
1145
nfs_init(void)1146 int nfs_init(void)
1147 {
1148 /* register nfs file system */
1149 dfs_register(&_nfs);
1150
1151 return RT_EOK;
1152 }
1153 INIT_COMPONENT_EXPORT(nfs_init);
1154
1155