xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/nfs/dfs_nfs.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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 
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 
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 
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 
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 
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 
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 
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 
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") */
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 
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 
549 int nfs_ioctl(struct dfs_fd *file, int cmd, void *args)
550 {
551     return -ENOSYS;
552 }
553 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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