• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/nfs/nfs_vfsops.c
3  *
4  *   Copyright (C) 2012-2013, 2015, 2017-2018 Gregory Nutt. All rights reserved.
5  *   Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved.
6  *   Author: Jose Pablo Rojas Vargas <jrojas@nx-engineering.com>
7  *           Gregory Nutt <gnutt@nuttx.org>
8  *
9  * Leveraged from OpenBSD:
10  *
11  *   Copyright (c) 1989, 1993, 1995
12  *   The Regents of the University of California.  All rights reserved.
13  *
14  * This code is derived from software contributed to Berkeley by
15  * Rick Macklem at The University of Guelph.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  *
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  ****************************************************************************/
43 
44 /****************************************************************************
45  * Included Files
46  ****************************************************************************/
47 
48 #include <sys/mount.h>
49 #include <sys/socket.h>
50 #include <sys/statfs.h>
51 #include <sys/stat.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <fcntl.h>
55 #include <semaphore.h>
56 #include <assert.h>
57 #include <errno.h>
58 #include <pthread.h>
59 #include <unistd.h>
60 #include "lwip/opt.h"
61 #include "lwip/sockets.h"
62 #include "vfs_config.h"
63 #include "dirent.h"
64 #include "fs/fs.h"
65 #include "fs/dirent_fs.h"
66 #include "nfs.h"
67 #include "nfs_node.h"
68 #include "xdr_subs.h"
69 #include "los_tables.h"
70 #include "vnode.h"
71 #include "los_vm_filemap.h"
72 #include "user_copy.h"
73 
74 /****************************************************************************
75  * Pre-processor Definitions
76  ****************************************************************************/
77 /****************************************************************************
78  * Public Data
79  ****************************************************************************/
80 
81 uint32_t nfs_true;
82 uint32_t nfs_false;
83 uint32_t nfs_xdrneg1;
84 NFSMOUNT_HOOK g_NFSMOUNT_HOOK = (NFSMOUNT_HOOK)(UINTPTR)NULL;
85 
86 #ifdef CONFIG_NFS_STATISTICS
87 struct nfsstats nfsstats;
88 #endif
89 
90 #define USE_GUARDED_CREATE 1
91 
92 #ifdef LOSCFG_FS_NFS
93 /****************************************************************************
94  * Private Type Definitions
95  ****************************************************************************/
96 
97 #define NFS_DIR_ENTRY_MALLOC(entry)                                           \
98   do                                                                          \
99     {                                                                         \
100       entry = (struct entry3 *)malloc(sizeof(struct entry3));                 \
101       if (entry == NULL)                                                      \
102         {                                                                     \
103           nfs_debug_info("malloc failed\n");                                           \
104           error = ENOMEM;                                                     \
105           goto errout_with_memory;                                            \
106         }                                                                     \
107       (void)memset_s(entry, sizeof(struct entry3), 0, sizeof(struct entry3)); \
108     }                                                                         \
109   while (0)
110 
111 #define NFS_DIR_ENTRY_FREE(entry)  \
112   do                               \
113     {                              \
114       free(entry->contents);       \
115       entry->contents = NULL;      \
116       free(entry);                 \
117       entry = NULL;                \
118     }                              \
119   while (0)
120 
121 #define FILENAME_MAX_LEN 50
122 struct MountOps nfs_mount_operations;
123 struct VnodeOps nfs_vops;
124 struct file_operations_vfs nfs_fops;
125 struct nfs_statinfo_s
126 {
127   uint16_t ns_mode;    /* File access mode */
128   uint8_t  ns_type;    /* File type */
129   uint64_t ns_size;    /* File size */
130   time_t   ns_atime;   /* Time of last access */
131   time_t   ns_mtime;   /* Time of last modification */
132   time_t   ns_ctime;   /* Time of last status change */
133 };
134 extern void nfs_stat_common(struct nfs_statinfo_s *info, struct stat *buf);
135 
type_to_mode(int type,mode_t permission)136 static mode_t type_to_mode(int type, mode_t permission)
137 {
138   switch (type)
139     {
140     case VNODE_TYPE_DIR:
141       return permission | S_IFDIR;
142     case VNODE_TYPE_REG:
143       return permission | S_IFREG;
144     case VNODE_TYPE_BLK:
145       return permission | S_IFBLK;
146     case VNODE_TYPE_CHR:
147       return permission | S_IFCHR;
148     case VNODE_TYPE_FIFO:
149       return permission | S_IFIFO;
150     default:
151       break;
152     }
153   return permission;
154 }
155 
nfs_2_vfs(int result)156 static int nfs_2_vfs(int result)
157 {
158   int status;
159 
160   if ((result < NFS_OK) || (result > NFSERR_NOTEMPTY))
161     {
162       return result;
163     }
164 
165   /* Nfs errno to Libc errno */
166   switch (result)
167     {
168     case NFSERR_NAMETOL:
169       status = ENAMETOOLONG;
170       break;
171     case NFSERR_NOTEMPTY:
172       status = ENOTEMPTY;
173       break;
174     default:
175       status = result;
176       break;
177     }
178 
179   return status;
180 }
181 
182 /****************************************************************************
183  * Name: nfs_fileupdate
184  *
185  * Description:
186  *   This is to update the file attributes like size, type. This sends a LOOKUP msg of nfs
187  *   to get latest file attributes.
188  *
189  * Returned Value:
190  *   0 on success; a positive errno value on failure.
191  *
192  ****************************************************************************/
nfs_fileupdate(struct nfsmount * nmp,char * filename,struct file_handle * parent_fhandle,struct nfsnode * np)193 static int nfs_fileupdate(struct nfsmount *nmp, char *filename,
194     struct file_handle *parent_fhandle, struct nfsnode *np)
195 {
196   struct file_handle fhandle;
197   int                error;
198   struct nfs_fattr   fattr;
199 
200   /* Find the NFS node associate with the path */
201 
202   fhandle.length = parent_fhandle->length;
203   (void)memcpy_s(&(fhandle.handle), fhandle.length, &(parent_fhandle->handle), parent_fhandle->length);
204   error = nfs_lookup(nmp, filename, &fhandle, &fattr, NULL);
205 
206   if (error != OK)
207     {
208       nfs_debug_error("nfs_lookup failed returned: %d\n", error);
209       return error;
210     }
211 
212   /* Update the file handle */
213 
214   error = memcpy_s(&(np->n_fhandle), NFSX_V3FHMAX, &(fhandle.handle), fhandle.length);
215   if (error != EOK)
216     {
217       return ENOBUFS;
218     }
219 
220   np->n_fhsize = fhandle.length;
221 
222   /* Save the file attributes */
223 
224   nfs_attrupdate(np, &fattr);
225 
226   return OK;
227 }
228 
vfs_nfs_reclaim(struct Vnode * node)229 int vfs_nfs_reclaim(struct Vnode *node)
230 {
231   struct nfsnode  *prev = NULL;
232   struct nfsnode  *curr = NULL;
233   struct nfsmount *nmp = NULL;
234   struct nfsnode  *np = NULL;
235   if (node->data == NULL)
236     {
237       return OK;
238     }
239   nmp = (struct nfsmount *)(node->originMount->data);
240   nfs_mux_take(nmp);
241   np = (struct nfsnode*)(node->data);
242   int ret;
243 
244   if (np->n_crefs > 1)
245     {
246       np->n_crefs--;
247       ret = OK;
248     }
249 
250   /* There are no more references to the file structure.  Now we need to
251    * free up all resources associated with the open file.
252    *
253    * First, find our file structure in the list of file structures
254    * containted in the mount structure.
255    */
256 
257   else
258     {
259       /* Assume file structure will not be found.  This should never happen. */
260 
261       ret = -EINVAL;
262 
263       for (prev = NULL, curr = nmp->nm_head;
264           curr;
265           prev = curr, curr = curr->n_next)
266         {
267           /* Check if this node is ours */
268 
269           if (np == curr)
270             {
271               /* Yes.. remove it from the list of file structures */
272 
273               if (prev)
274                 {
275                   /* Remove from mid-list */
276 
277                   prev->n_next = np->n_next;
278                 }
279               else
280                 {
281                   /* Remove from the head of the list */
282 
283                   nmp->nm_head = np->n_next;
284                 }
285 
286               /* Then deallocate the file structure and return success */
287 
288               free(np->n_name);
289               free(np);
290               ret = OK;
291               break;
292             }
293         }
294     }
295 
296   nfs_mux_release(nmp);
297   return ret;
298 }
299 
vfs_nfs_stat_internal(struct nfsmount * nmp,struct nfsnode * nfs_node)300 static int vfs_nfs_stat_internal(struct nfsmount *nmp, struct nfsnode *nfs_node)
301 {
302   int ret;
303   struct timespec ts;
304   struct rpc_call_fs attr_call;
305   struct rpc_reply_getattr attr_reply;
306   attr_call.fs.fsroot.length = txdr_unsigned(nfs_node->n_fhsize);
307   memcpy_s(&(attr_call.fs.fsroot.handle), sizeof(nfsfh_t), &(nfs_node->n_fhandle), sizeof(nfsfh_t));
308   ret = nfs_request(nmp, NFSPROC_GETATTR, &attr_call,
309       sizeof(struct file_handle), &attr_reply,
310       sizeof(struct rpc_reply_getattr));
311   if (ret != OK)
312     {
313       return ret;
314     }
315   /* Extract the file mode, file type, and file size. */
316 
317   nfs_node->n_mode  = fxdr_unsigned(uint16_t, attr_reply.attr.fa_mode);
318   nfs_node->n_type  = fxdr_unsigned(uint8_t, attr_reply.attr.fa_type);
319   nfs_node->n_size  = fxdr_hyper(&attr_reply.attr.fa_size);
320 
321   /* Extract time values as type time_t in units of seconds */
322 
323   fxdr_nfsv3time(&attr_reply.attr.fa_mtime, &ts);
324   nfs_node->n_timestamp.tv_sec = ts.tv_sec;
325   nfs_node->n_timestamp.tv_nsec = ts.tv_nsec;
326 
327   fxdr_nfsv3time(&attr_reply.attr.fa_atime, &ts);
328   nfs_node->n_atime = ts.tv_sec;
329 
330   fxdr_nfsv3time(&attr_reply.attr.fa_ctime, &ts);
331   nfs_node->n_ctime = ts.tv_sec;
332 
333   return OK;
334 }
335 
336 /****************************************************************************
337  * Name: nfs_decode_args
338  *
339  * Returned Value:
340  *   None
341  *
342  ****************************************************************************/
343 
nfs_decode_args(struct nfs_mount_parameters * nprmt,struct nfs_args * argp)344 static void nfs_decode_args(struct nfs_mount_parameters *nprmt,
345                             struct nfs_args *argp)
346 {
347   int maxio;
348 
349   /* Get the selected timeout value */
350 
351   if ((argp->flags & NFSMNT_TIMEO) != 0 && argp->timeo > 0)
352     {
353       uint32_t tmp = ((uint32_t)argp->timeo * NFS_HZ + 5) / 10;
354       if (tmp < NFS_MINTIMEO)
355         {
356           tmp = NFS_MINTIMEO;
357         }
358       else if (tmp > NFS_MAXTIMEO)
359         {
360           tmp = NFS_MAXTIMEO;
361         }
362 
363       nprmt->timeo = tmp;
364     }
365 
366   /* Get the selected retransmission count */
367 
368   if ((argp->flags & NFSMNT_RETRANS) != 0 && argp->retrans > 1)
369     {
370       if  (argp->retrans < NFS_MAXREXMIT)
371         {
372           nprmt->retry = argp->retrans;
373         }
374       else
375         {
376           nprmt->retry = NFS_MAXREXMIT;
377         }
378     }
379 
380   if ((argp->flags & NFSMNT_SOFT) == 0)
381     {
382       nprmt->retry = NFS_MAXREXMIT + 1;  /* Past clip limit */
383     }
384 
385   /* Get the maximum amount of data that can be transferred in one packet */
386 
387   if ((argp->sotype == SOCK_DGRAM) != 0)
388     {
389       maxio = NFS_MAXDGRAMDATA;
390     }
391   else
392     {
393       nfs_debug_error("Only SOCK_DRAM is supported\n");
394       maxio = NFS_MAXDATA;
395     }
396 
397   /* Get the maximum amount of data that can be transferred in one write transfer */
398 
399   if ((argp->flags & NFSMNT_WSIZE) != 0 && argp->wsize > 0)
400     {
401       nprmt->wsize = argp->wsize;
402 
403       /* Round down to multiple of blocksize */
404 
405       nprmt->wsize &= ~(NFS_FABLKSIZE - 1);
406       if (nprmt->wsize <= 0)
407         {
408           nprmt->wsize = NFS_FABLKSIZE;
409         }
410     }
411 
412   if (nprmt->wsize > maxio)
413     {
414       nprmt->wsize = maxio;
415     }
416 
417   if (nprmt->wsize > MAXBSIZE)
418     {
419       nprmt->wsize = MAXBSIZE;
420     }
421 
422   /* Get the maximum amount of data that can be transferred in one read transfer */
423 
424   if ((argp->flags & NFSMNT_RSIZE) != 0 && argp->rsize > 0)
425     {
426       nprmt->rsize = argp->rsize;
427 
428       /* Round down to multiple of blocksize */
429 
430       nprmt->rsize &= ~(NFS_FABLKSIZE - 1);
431       if (nprmt->rsize <= 0)
432         {
433           nprmt->rsize = NFS_FABLKSIZE;
434         }
435     }
436 
437   if (nprmt->rsize > maxio)
438     {
439       nprmt->rsize = maxio;
440     }
441 
442   if (nprmt->rsize > MAXBSIZE)
443     {
444       nprmt->rsize = MAXBSIZE;
445     }
446 
447   /* Get the maximum amount of data that can be transferred in directory transfer */
448 
449   if ((argp->flags & NFSMNT_READDIRSIZE) != 0 && argp->readdirsize > 0)
450     {
451       nprmt->readdirsize = argp->readdirsize;
452 
453       /* Round down to multiple of blocksize */
454 
455       nprmt->readdirsize &= ~(NFS_DIRBLKSIZ - 1);
456       if (nprmt->readdirsize < NFS_DIRBLKSIZ)
457         {
458           nprmt->readdirsize = NFS_DIRBLKSIZ;
459         }
460     }
461   else if (argp->flags & NFSMNT_RSIZE)
462     {
463       nprmt->readdirsize = nprmt->rsize;
464     }
465 
466   if (nprmt->readdirsize > maxio)
467     {
468       nprmt->readdirsize = maxio;
469     }
470 }
471 
472 /****************************************************************************
473  * Name: nfs_bind
474  *
475  * Description:
476  *  This implements a portion of the mount operation. This function allocates
477  *  and initializes the mountpoint private data and gets mount information
478  *  from the NFS server.  The final binding of the private data (containing
479  *  NFS server mount information) to the  mountpoint is performed by mount().
480  *
481  * Returned Value:
482  *   0 on success; a negated errno value on failure.
483  *
484  ****************************************************************************/
485 
nfs_bind(struct Vnode * blkdriver,const void * data,void ** handle,const char * relpath)486 int nfs_bind(struct Vnode *blkdriver, const void *data,
487                     void **handle, const char *relpath)
488 {
489   struct nfs_args        *argp = (struct nfs_args *)data;
490   struct nfsmount        *nmp = NULL;
491   struct rpcclnt             *rpc = NULL;
492   struct rpc_call_fs          getattr;
493   struct rpc_reply_getattr    resok;
494   struct nfs_mount_parameters nprmt;
495   uint32_t                    buflen;
496   uint32_t                    pathlen;
497   uint32_t                    tmp;
498   int                         error = 0;
499   pthread_mutexattr_t attr;
500 
501   DEBUGASSERT(data && handle);
502 
503   /* Set default values of the parameters.  These may be overridden by
504    * settings in the argp->flags.
505    */
506 
507   nprmt.timeo       = NFS_TIMEO;
508   nprmt.retry       = NFS_RETRANS;
509   nprmt.wsize       = NFS_WSIZE;
510   nprmt.rsize       = NFS_RSIZE;
511   nprmt.readdirsize = NFS_READDIRSIZE;
512 
513   nfs_decode_args(&nprmt, argp);
514 
515   /* Determine the size of a buffer that will hold one RPC data transfer.
516    * First, get the maximum size of a read and a write transfer.
517    */
518 
519   pathlen = strlen(argp->path);
520   if (pathlen >= NFS_MOUNT_PATH_MAX_SIZE) {
521       return -ENAMETOOLONG;
522   }
523 
524   buflen = SIZEOF_rpc_call_write(nprmt.wsize);
525   tmp    = SIZEOF_rpc_reply_read(nprmt.rsize);
526 
527   /* The buffer size will be the maximum of those two sizes */
528 
529   if (tmp > buflen)
530     {
531       buflen = tmp;
532     }
533 
534   /* But don't let the buffer size exceed the MSS of the socket type.
535    *
536    * In the case where there are multiple network devices with different
537    * link layer protocols, each network device may support a different
538    * UDP MSS value.  Here we arbitrarily select the minimum MSS for
539    * that case.
540    */
541 
542   /* Create an instance of the mountpt state structure */
543 
544   nmp = (struct nfsmount *)malloc(SIZEOF_nfsmount(buflen));
545   if (!nmp)
546     {
547       nfs_debug_error("Failed to allocate mountpoint structure\n");
548       return -ENOMEM;
549     }
550 
551   (void)memset_s(nmp, SIZEOF_nfsmount(buflen), 0, SIZEOF_nfsmount(buflen));
552 
553   /* Save the allocated I/O buffer size */
554 
555   nmp->nm_buflen = (uint16_t)buflen;
556 
557   nmp->nm_so = -1;
558 
559   /* Initialize the allocated mountpt state structure. */
560 
561   (void)pthread_mutexattr_init(&attr);
562   (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
563   error = pthread_mutex_init(&nmp->nm_mux, &attr);
564   if (error)
565     {
566       free(nmp);
567       return -error;
568     }
569 
570   /* Initialize NFS */
571 
572   nfs_true = txdr_unsigned(TRUE);
573   nfs_false = txdr_unsigned(FALSE);
574   nfs_xdrneg1 = txdr_unsigned(-1);
575 
576   rpcclnt_init();
577 
578   /* Set initial values of other fields */
579 
580   nmp->nm_timeo       = nprmt.timeo;
581   nmp->nm_retry       = nprmt.retry;
582   nmp->nm_wsize       = nprmt.wsize;
583   nmp->nm_rsize       = nprmt.rsize;
584   nmp->nm_readdirsize = nprmt.readdirsize;
585   nmp->nm_fhsize      = NFSX_V3FHMAX;
586 
587   (void)strncpy_s(nmp->nm_path, sizeof(nmp->nm_path), argp->path, pathlen);
588   (void)memcpy_s(&nmp->nm_nam, sizeof(struct sockaddr), &argp->addr, argp->addrlen);
589 
590   /* Set up the sockets and per-host congestion */
591 
592   nmp->nm_sotype  = argp->sotype;
593 
594   if (nmp->nm_sotype == SOCK_DGRAM || nmp->nm_sotype == SOCK_STREAM)
595     {
596       /* Connection-less... connect now */
597 
598       /* Create an instance of the rpc state structure */
599 
600       rpc = (struct rpcclnt *)malloc(sizeof(struct rpcclnt));
601       if (!rpc)
602         {
603           nfs_debug_error("Failed to allocate rpc structure\n");
604           error = ENOMEM;
605           goto bad;
606         }
607 
608       (void)memset_s(rpc, sizeof(struct rpcclnt), 0, sizeof(struct rpcclnt));
609 
610       nfs_debug_info("Connecting\n");
611 
612       /* Translate nfsmnt flags -> rpcclnt flags */
613 
614       rpc->rc_path       = nmp->nm_path;
615       rpc->rc_name       = &nmp->nm_nam;
616       rpc->rc_sotype     = nmp->nm_sotype;
617       rpc->rc_retry      = nmp->nm_retry;
618       rpc->rc_so         = -1;
619 
620       nmp->nm_rpcclnt    = rpc;
621 
622       error = rpcclnt_connect(nmp->nm_rpcclnt);
623       if (error != OK)
624         {
625           nfs_debug_error("nfs_connect failed: %d\n", error);
626           goto bad;
627         }
628     }
629 
630   nmp->nm_mounted        = true;
631   nmp->nm_so             = nmp->nm_rpcclnt->rc_so;
632   nmp->nm_head           = NULL;
633   nmp->nm_dir            = NULL;
634   nmp->nm_fhsize         = nmp->nm_rpcclnt->rc_fhsize;
635   (void)memcpy_s(&nmp->nm_fh, sizeof(nfsfh_t), &nmp->nm_rpcclnt->rc_fh, sizeof(nfsfh_t));
636 
637   /* Get the file attributes */
638 
639   getattr.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
640   (void)memcpy_s(&getattr.fs.fsroot.handle, sizeof(nfsfh_t), &nmp->nm_fh, sizeof(nfsfh_t));
641 
642   error = nfs_request(nmp, NFSPROC_GETATTR,
643                       (void *)&getattr, /* sizeof(struct FS3args) */
644                       (sizeof(getattr.fs.fsroot.length) + nmp->nm_fhsize),
645                       (void *)&resok, sizeof(struct rpc_reply_getattr));
646   if (error)
647     {
648       nfs_debug_error("nfs_request failed: %d\n", error);
649       goto bad;
650     }
651 
652   /* Save the file attributes */
653 
654   (void)memcpy_s(&nmp->nm_fattr, sizeof(struct nfs_fattr), &resok.attr, sizeof(struct nfs_fattr));
655 
656   /* Mounted! */
657 
658   *handle = (void *)nmp;
659 
660   nfs_debug_info("Successfully mounted\n");
661   return OK;
662 
663 bad:
664   if (nmp)
665     {
666       /* Disconnect from the server */
667 
668       if (nmp->nm_rpcclnt)
669         {
670           rpcclnt_disconnect(nmp->nm_rpcclnt);
671           free(nmp->nm_rpcclnt);
672           nmp->nm_rpcclnt = NULL;
673         }
674 
675       /* Free connection-related resources */
676 
677       (void)pthread_mutex_destroy(&nmp->nm_mux);
678 
679       free(nmp);
680       nmp = NULL;
681     }
682 
683   return -error; /*lint !e438*/
684 }
685 
686 
filetype_to_vnodetype(uint32_t filetype)687 static enum VnodeType filetype_to_vnodetype(uint32_t filetype)
688 {
689   if (filetype < 0 || filetype > 7)
690     {
691       return VNODE_TYPE_UNKNOWN;
692     }
693 
694   enum VnodeType transfer_table[8] =
695     {
696       VNODE_TYPE_UNKNOWN,
697       VNODE_TYPE_REG,
698       VNODE_TYPE_DIR,
699       VNODE_TYPE_BLK,
700       VNODE_TYPE_CHR,
701       VNODE_TYPE_LNK,
702       VNODE_TYPE_UNKNOWN,
703       VNODE_TYPE_FIFO
704     };
705 
706   return transfer_table[filetype];
707 }
708 
nfs_mount(const char * server_ip_and_path,const char * mount_path,unsigned int uid,unsigned int gid)709 int nfs_mount(const char *server_ip_and_path, const char *mount_path,
710               unsigned int uid, unsigned int gid)
711 {
712   struct nfs_args         nfs_args = {0};
713   char                    *server_ip_addr = NULL;
714   char                    *server_nfs_path = NULL;
715   int                     found_colon = 0;
716   unsigned int            pos;
717   int                     ret = -1;
718   struct sockaddr_in      *nfs_srv_addr = NULL;
719   size_t len;
720 
721   rpcclnt_setuidgid(uid, gid);
722 
723   len = strlen(server_ip_and_path);
724   for (pos = 0; pos < len; pos++)
725     {
726       if (*(server_ip_and_path + pos) == ':')
727         {
728           found_colon = 1;
729           break;
730         }
731     }
732 
733   if (!found_colon)
734     {
735       set_errno(ENOENT);
736       goto nfs_mount_out;
737     }
738 
739   server_ip_addr = (char *)malloc(pos + 1);
740   if (server_ip_addr == NULL)
741     {
742       nfs_debug_info("malloc failure\n");
743       set_errno(ENOMEM);
744       goto nfs_mount_out;
745     }
746 
747   ret = strncpy_s(server_ip_addr, pos + 1, server_ip_and_path, pos);
748   if (ret != EOK)
749     {
750       set_errno(ENOBUFS);
751       goto nfs_free_node_out;
752     }
753   *(server_ip_addr + pos) = '\0';
754   server_nfs_path = (char *)(server_ip_and_path + pos + 1);
755 
756   (void)memset_s(&nfs_args, sizeof(nfs_args), 0, sizeof(nfs_args));
757 
758   if (g_NFSMOUNT_HOOK != NULL)
759     {
760       g_NFSMOUNT_HOOK(&nfs_args);
761     }
762 
763   nfs_args.path = server_nfs_path; /* server nfs dir */
764 
765   nfs_srv_addr = (struct sockaddr_in *)&nfs_args.addr;
766   nfs_srv_addr->sin_family = AF_INET;
767   ret = inet_pton(AF_INET, server_ip_addr, &nfs_srv_addr->sin_addr.s_addr);
768   if (ret != 1)
769     {
770       ret = -1;
771       set_errno(ECONNREFUSED);
772       goto nfs_free_node_out;
773     }
774   nfs_srv_addr->sin_port = htons(PMAPPORT);
775 
776   nfs_args.addrlen = sizeof(nfs_args.addr);
777 #if (NFS_PROTO_TYPE == NFS_IPPROTO_TCP)
778   nfs_args.sotype = SOCK_STREAM;
779 #elif (NFS_PROTO_TYPE == NFS_IPPROTO_UDP)
780   nfs_args.sotype = SOCK_DGRAM;
781 #endif
782 
783   PRINTK("Mount nfs on %s:%s, uid:%d, gid:%d\n", server_ip_addr, server_nfs_path, uid, gid);
784   ret = mount((const char *)NULL, mount_path, "nfs", 0, &nfs_args);
785 
786 nfs_free_node_out:
787   free(server_ip_addr);
788 
789 nfs_mount_out:
790   if (ret)
791     {
792       perror("mount nfs error");
793       return -1;
794     }
795   PRINTK("Mount nfs finished.\n");
796   return 0;
797 }
798 
vfs_nfs_mount(struct Mount * mnt,struct Vnode * device,const void * data)799 int vfs_nfs_mount(struct Mount *mnt, struct Vnode *device, const void *data)
800 {
801   struct nfsmount *nmp = NULL;
802   struct Vnode *vp = NULL;
803 
804   int ret = VnodeAlloc(&nfs_vops, &vp);
805   if (ret != OK)
806     {
807       return -EADDRNOTAVAIL;
808     }
809 
810   struct nfsnode *root = zalloc(sizeof(struct nfsnode));
811   if (root == NULL)
812     {
813       (void)VnodeFree(vp);
814       return -EADDRNOTAVAIL;
815     }
816 
817   ret = nfs_bind(NULL, data, (void **)(&nmp), NULL);
818   if (ret != OK || nmp == NULL)
819     {
820       (void)VnodeFree(vp);
821       free(root);
822       return -EAGAIN;
823     }
824   vp->originMount = mnt;
825   vp->fop = &nfs_fops;
826   vp->data = root;
827   root->n_fhsize = nmp->nm_fhsize;
828   (void)memcpy_s(&(root->n_fhandle), root->n_fhsize, &(nmp->nm_fh), nmp->nm_fhsize);
829   root->n_pfhsize = 0;
830   mnt->vnodeCovered = vp;
831   mnt->data = nmp;
832   root->n_next = nmp->nm_head;
833   nmp->nm_head = root;
834 
835   ret = vfs_nfs_stat_internal(nmp, root);
836   if (ret == OK)
837     {
838       vp->type = root->n_type;
839     }
840   nmp->nm_permission = mnt->vnodeBeCovered->mode & 0777;
841   nmp->nm_gid = mnt->vnodeBeCovered->gid;
842   nmp->nm_uid = mnt->vnodeBeCovered->uid;
843   vp->mode = type_to_mode(vp->type, nmp->nm_permission);
844   vp->gid = nmp->nm_gid;
845   vp->uid = nmp->nm_uid;
846   return OK;
847 }
848 
vfs_nfs_lookup(struct Vnode * parent,const char * path,int len,struct Vnode ** vpp)849 int vfs_nfs_lookup(struct Vnode *parent, const char *path, int len, struct Vnode **vpp)
850 {
851   int ret;
852   struct nfs_fattr obj_attributes;
853   struct nfsmount *nmp;
854   char filename[len + 1];
855   struct file_handle fhandle;
856   struct nfsnode *parent_nfs_node = NULL;
857   struct nfsnode *nfs_node = NULL;
858   nmp = (struct nfsmount *)(parent->originMount->data);
859   nfs_mux_take(nmp);
860   parent_nfs_node = (struct nfsnode *)parent->data;
861   fhandle.length = parent_nfs_node->n_fhsize;
862   (void)memcpy_s(&(fhandle.handle), fhandle.length, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize);
863   filename[len] = '\0';
864   (void)memcpy_s(filename, (len + 1), path, len);
865 
866   ret = nfs_lookup(nmp, filename, &fhandle, &obj_attributes, NULL);
867   if (ret != OK)
868     {
869       nfs_mux_release(nmp);
870       return -ENOENT;
871     }
872 
873   /* Initialize the file private data.
874    *
875    * Copy the file handle.
876    */
877   nfs_node = zalloc(sizeof(struct nfsnode));
878   nfs_node->n_fhsize = (uint8_t)fhandle.length;
879   memcpy_s(&(nfs_node->n_fhandle), nfs_node->n_fhsize, &(fhandle.handle), fhandle.length);
880   nfs_node->n_pfhsize = parent_nfs_node->n_fhsize;
881   (void)memcpy_s(&(nfs_node->n_pfhandle), NFSX_V3FHMAX, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize);
882   nfs_node->n_name = zalloc(sizeof(filename));
883   memcpy_s(nfs_node->n_name, (len + 1), filename, sizeof(filename));
884   nfs_node->n_next = nmp->nm_head;
885   nmp->nm_head = nfs_node;
886 
887   /* Save the file attributes */
888   nfs_attrupdate(nfs_node, &obj_attributes);
889 
890   (void)VnodeAlloc(&nfs_vops, vpp);
891   (*vpp)->parent = parent;
892   (*vpp)->fop = &nfs_fops;
893   (*vpp)->originMount = parent->originMount;
894   (*vpp)->data = nfs_node;
895   (*vpp)->type = filetype_to_vnodetype(nfs_node->n_type);
896   (*vpp)->mode = type_to_mode((*vpp)->type, nmp->nm_permission);
897   (*vpp)->gid = nmp->nm_gid;
898   (*vpp)->uid = nmp->nm_uid;
899   nfs_mux_release(nmp);
900   return OK;
901 }
902 
vfs_nfs_stat(struct Vnode * node,struct stat * buf)903 int vfs_nfs_stat(struct Vnode *node, struct stat *buf)
904 {
905   struct nfsnode *nfs_node = NULL;
906   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
907   nfs_mux_take(nmp);
908   nfs_node = (struct nfsnode *)node->data;
909   buf->st_mode = node->mode;
910   buf->st_gid = node->gid;
911   buf->st_uid = node->uid;
912   buf->st_size    = (off_t)nfs_node->n_size;
913   buf->st_blksize = 0;
914   buf->st_blocks  = 0;
915   buf->st_mtime   = nfs_node->n_timestamp.tv_sec;
916   buf->st_atime   = nfs_node->n_atime;
917   buf->st_ctime   = nfs_node->n_ctime;
918 
919   /* Adapt to kstat member "long tv_sec" */
920   buf->__st_mtim32.tv_sec   = (long)nfs_node->n_timestamp.tv_sec;
921   buf->__st_atim32.tv_sec   = (long)nfs_node->n_atime;
922   buf->__st_ctim32.tv_sec   = (long)nfs_node->n_ctime;
923 
924   nfs_mux_release(nmp);
925   return OK;
926 }
927 
vfs_nfs_opendir(struct Vnode * node,struct fs_dirent_s * dir)928 int vfs_nfs_opendir(struct Vnode *node, struct fs_dirent_s *dir)
929 {
930   int ret;
931   struct nfsdir_s *nfs_dir = NULL;
932   struct nfsnode *nfs_node = NULL;
933   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
934   if (node->type != VNODE_TYPE_DIR) {
935       return -ENOTDIR;
936   }
937   nfs_mux_take(nmp);
938   nfs_node = (struct nfsnode *)node->data;
939   ret = nfs_checkmount(nmp);
940   if (ret != OK) {
941       ret = -ret;
942       nfs_debug_error("nfs_checkmount failed: %d\n", ret);
943       goto errout_with_mutex;
944   }
945   nfs_dir = (struct nfsdir_s *)malloc(sizeof(struct nfsdir_s));
946   if (!nfs_dir) {
947       ret = -ENOMEM;
948       goto errout_with_mutex;
949   }
950   nfs_dir->nfs_fhsize = nfs_node->n_fhsize;
951   nfs_dir->nfs_cookie[0] = 0;
952   nfs_dir->nfs_cookie[1] = 0;
953   (void)memcpy_s(nfs_dir->nfs_fhandle, DIRENT_NFS_MAXHANDLE, &(nfs_node->n_fhandle), DIRENT_NFS_MAXHANDLE);
954   dir->u.fs_dir = (fs_dir_s)nfs_dir;
955   ret = OK;
956 
957   nfs_dir->nfs_next = nmp->nm_dir;
958   nmp->nm_dir = nfs_dir;
959   nfs_dir->nfs_dir = dir;
960   nfs_dir->nfs_entries = NULL;
961 
962 errout_with_mutex:
963   nfs_mux_release(nmp);
964   return ret;
965 }
966 
vfs_nfs_readdir(struct Vnode * node,struct fs_dirent_s * dir)967 int vfs_nfs_readdir(struct Vnode *node, struct fs_dirent_s *dir)
968 {
969   struct nfsmount *nmp;
970   struct file_handle fhandle;
971   struct nfs_fattr obj_attributes;
972   struct nfsdir_s *nfs_dir = NULL;
973   struct entry3   *entry = NULL;
974   struct entry3   *entry_pos = NULL;
975 
976   /* Use 2 cookies */
977 
978   uint32_t cookies[2];
979   uint32_t tmp;
980   uint32_t *ptr = NULL;
981   size_t d_name_size;
982   int reqlen;
983   int error = 0;
984   int i = 0;
985 
986   /* Sanity checks */
987 
988   /* Recover our private data from the vnode instance */
989 
990   nmp = (struct nfsmount *)(node->originMount->data);
991 
992   /* Make sure that the mount is still healthy */
993 
994   nfs_mux_take(nmp);
995   error = nfs_checkmount(nmp);
996   if (error != OK)
997     {
998       nfs_debug_error("nfs_checkmount failed: %d\n", error);
999       goto errout_with_mutex;
1000     }
1001 
1002   /* Request a block directory entries, copying directory information from
1003    * the dirent structure.
1004    */
1005   nfs_dir = (struct nfsdir_s *)dir->u.fs_dir;
1006   cookies[0] = 0;
1007   cookies[1] = 0;
1008 
1009   if (nfs_dir && nfs_dir->nfs_entries && (nfs_dir->nfs_entries->file_id[0] == (uint32_t)EOF))
1010     {
1011       error = ENOENT;
1012       free(nfs_dir->nfs_entries);
1013       nfs_dir->nfs_entries = NULL;
1014       goto errout_with_mutex;
1015     }
1016   while (i < dir->read_cnt)
1017     {
1018       if (!nfs_dir->nfs_entries)
1019         {
1020           entry_pos = nfs_dir->nfs_entries;
1021           do
1022             {
1023               ptr     = (uint32_t *)&nmp->nm_msgbuffer.readdir.readdir;
1024               reqlen  = 0;
1025 
1026               /* Copy the variable length, directory file handle */
1027 
1028               *ptr++  = txdr_unsigned((uint32_t)nfs_dir->nfs_fhsize);
1029               reqlen += sizeof(uint32_t);
1030 
1031               (void)memcpy_s(ptr, nfs_dir->nfs_fhsize, nfs_dir->nfs_fhandle, nfs_dir->nfs_fhsize);
1032               reqlen += (int)nfs_dir->nfs_fhsize;
1033               ptr    += uint32_increment((int)nfs_dir->nfs_fhsize);
1034 
1035               /* Cookie and cookie verifier */
1036 
1037               ptr[0] = cookies[0];
1038               ptr[1] = cookies[1];
1039               ptr    += 2;
1040               reqlen += 2 * sizeof(uint32_t);
1041 
1042               (void)memcpy_s(ptr, DIRENT_NFS_VERFLEN, nfs_dir->nfs_verifier, DIRENT_NFS_VERFLEN);
1043               ptr    += uint32_increment(DIRENT_NFS_VERFLEN);
1044               reqlen += DIRENT_NFS_VERFLEN;
1045 
1046               /* Number of directory entries (We currently only process one entry at a time) */
1047 
1048               *ptr    = txdr_unsigned((uint32_t)nmp->nm_readdirsize);
1049               reqlen += sizeof(uint32_t);
1050 
1051               /* And read the directory */
1052 
1053               nfs_statistics(NFSPROC_READDIR);
1054               error = nfs_request(nmp, NFSPROC_READDIR,
1055                                   (void *)&nmp->nm_msgbuffer.readdir, reqlen,
1056                                   (void *)nmp->nm_iobuffer, nmp->nm_buflen);
1057 
1058               if (error != OK)
1059                 {
1060                   nfs_debug_error("nfs_request failed: %d\n", error);
1061                   goto errout_with_mutex;
1062                 }
1063 
1064               /* A new group of entries was successfully read.  Process the
1065                * information contained in the response header.  This information
1066                * includes:
1067                *
1068                * 1) Attributes follow indication - 4 bytes
1069                * 2) Directory attributes         - sizeof(struct nfs_fattr)
1070                * 3) Cookie verifier              - NFSX_V3COOKIEVERF bytes
1071                * 4) Values follows indication    - 4 bytes
1072                */
1073 
1074               ptr = (uint32_t *)&((struct rpc_reply_readdir *)nmp->nm_iobuffer)->readdir;
1075 
1076               /* Check if attributes follow, if 0 so Skip over the attributes */
1077 
1078               tmp = *ptr++;
1079               if (tmp != 0)
1080                 {
1081                   /* Attributes are not currently used */
1082 
1083                   ptr += uint32_increment(sizeof(struct nfs_fattr));
1084                 }
1085 
1086               /* Save the verification cookie */
1087 
1088               (void)memcpy_s(nfs_dir->nfs_verifier, DIRENT_NFS_VERFLEN, ptr, DIRENT_NFS_VERFLEN);
1089               ptr += uint32_increment(DIRENT_NFS_VERFLEN);
1090 
1091               /* Check if values follow.  If no values follow, then the EOF indication
1092                * will appear next.
1093                */
1094 
1095               tmp = *ptr++;
1096               if (tmp == 0)
1097                 {
1098                   /* No values follow, then the reply should consist only of a 4-byte
1099                    * end-of-directory indication.
1100                    */
1101 
1102                   tmp = *ptr++;
1103                   if (tmp != 0)
1104                     {
1105                       error = ENOENT;
1106                     }
1107 
1108                   /* What would it mean if there were not data and we not at the end of
1109                    * file?
1110                    */
1111 
1112                   else
1113                     {
1114                       error = EAGAIN;
1115                     }
1116                   goto errout_with_mutex;
1117                 }
1118 
1119               /* If we are not at the end of the directory listing, then a set of entries
1120                * will follow the header.  Each entry is of the form:
1121                *
1122                *    File ID (8 bytes)
1123                *    Name length (4 bytes)
1124                *    Name string (varaiable size but in multiples of 4 bytes)
1125                *    Cookie (8 bytes)
1126                *    next entry (4 bytes)
1127                */
1128 
1129                do
1130                 {
1131                   NFS_DIR_ENTRY_MALLOC(entry);
1132 
1133                   /* There is an entry. Skip over the file ID and point to the length */
1134 
1135                   entry->file_id[0] = *ptr++;
1136                   entry->file_id[1] = *ptr++; /*lint !e662 !e661*/
1137 
1138                   /* Get the length and point to the name */
1139 
1140                   tmp    = *ptr++; /*lint !e662 !e661*/
1141                   entry->name_len = fxdr_unsigned(uint32_t, tmp);
1142                   entry->contents = (uint8_t *)malloc(entry->name_len + 1);
1143                   if (!entry->contents)
1144                     {
1145                       free(entry);
1146                       entry = NULL;
1147                       goto errout_with_memory;
1148                     }
1149                   (void)memset_s(entry->contents, entry->name_len + 1, 0, entry->name_len + 1);
1150 
1151                   error = strncpy_s((char *)entry->contents, entry->name_len + 1, (const char *)ptr, entry->name_len);
1152                   if (error != EOK)
1153                     {
1154                       free(entry->contents);
1155                       entry->contents = NULL;
1156                       free(entry);
1157                       entry = NULL;
1158                       error = ENOBUFS;
1159                       goto errout_with_memory;
1160                     }
1161                   /* Increment the pointer past the name (allowing for padding). ptr
1162                    * now points to the cookie.
1163                    */
1164 
1165                   ptr += uint32_increment(entry->name_len);
1166 
1167                   /* Save the cookie and increment the pointer to the next entry */
1168 
1169                   entry->cookie[0] = *ptr++;
1170                   entry->cookie[1] = *ptr++;
1171 
1172                   /* Get the file attributes associated with this name and return
1173                    * the file type.
1174                    */
1175 
1176                   if (strcmp((char *)entry->contents, ".") == 0 || strcmp((char *)entry->contents, "..") == 0)
1177                     {
1178                       NFS_DIR_ENTRY_FREE(entry);
1179                       continue;
1180                     }
1181 
1182                   if (!nfs_dir->nfs_entries)
1183                     {
1184                       entry_pos = entry;
1185                       nfs_dir->nfs_entries = entry;
1186                     }
1187                   else
1188                     {
1189                       entry_pos->next = entry;
1190                       entry_pos = entry;
1191                     }
1192                 }
1193               while (*ptr++);
1194               if (entry_pos)
1195                 {
1196                   cookies[0] = entry_pos->cookie[0];
1197                   cookies[1] = entry_pos->cookie[1];
1198                 }
1199             }
1200           while (!(*ptr));
1201 
1202           if (!nfs_dir->nfs_entries)
1203             {
1204               error = ENOENT;
1205               goto errout_with_mutex;
1206             }
1207 
1208           NFS_DIR_ENTRY_MALLOC(entry);
1209 
1210           /* There is an entry. Skip over the file ID and point to the length */
1211 
1212           entry->file_id[0] = (uint32_t)EOF;
1213           if (!entry_pos)
1214             {
1215               error = ENOENT;
1216               NFS_DIR_ENTRY_FREE(entry);
1217               goto errout_with_mutex;
1218             }
1219           entry_pos->next = entry;
1220           entry_pos = entry;
1221         }
1222 
1223       entry_pos = nfs_dir->nfs_entries;
1224       if (nfs_dir->nfs_entries->file_id[0] == (uint32_t)EOF)
1225         {
1226           error = ENOENT;
1227           goto errout_with_mutex;
1228         }
1229 
1230       d_name_size = sizeof(dir->fd_dir[i].d_name);
1231       error = memcpy_s(dir->fd_dir[i].d_name, d_name_size, (const char *)entry_pos->contents, (size_t)entry_pos->name_len);
1232       if (error != EOK)
1233         {
1234           error = ENOBUFS;
1235           goto errout_with_memory;
1236         }
1237       if (entry_pos->name_len >= d_name_size)
1238         {
1239           dir->fd_dir[i].d_name[d_name_size - 1] = '\0';
1240         }
1241       else
1242         {
1243           dir->fd_dir[i].d_name[entry_pos->name_len] = '\0';
1244         }
1245 
1246       nfs_dir->nfs_entries = entry_pos->next;
1247       NFS_DIR_ENTRY_FREE(entry_pos);
1248 
1249       fhandle.length = (uint32_t)nfs_dir->nfs_fhsize;
1250       (void)memcpy_s(&fhandle.handle, DIRENT_NFS_MAXHANDLE, nfs_dir->nfs_fhandle, DIRENT_NFS_MAXHANDLE);
1251 
1252       error = nfs_lookup(nmp, dir->fd_dir[i].d_name, &fhandle, &obj_attributes, NULL);
1253       if (error != OK)
1254       {
1255         nfs_debug_error("nfs_lookup failed: %d\n", error);
1256         goto errout_with_memory;
1257       }
1258 
1259       /* Set the dirent file type */
1260 
1261       tmp = fxdr_unsigned(uint32_t, obj_attributes.fa_type);
1262       switch (tmp)
1263         {
1264         default:
1265         case NFNON:        /* Unknown type */
1266         case NFSOCK:       /* Socket */
1267         case NFLNK:        /* Symbolic link */
1268           break;
1269 
1270         case NFREG:        /* Regular file */
1271           dir->fd_dir[i].d_type = DT_REG;
1272           break;
1273 
1274         case NFDIR:        /* Directory */
1275           dir->fd_dir[i].d_type = DT_DIR;
1276           break;
1277 
1278         case NFBLK:        /* Block special device file */
1279           dir->fd_dir[i].d_type = DT_BLK;
1280           break;
1281 
1282         case NFFIFO:       /* Named FIFO */
1283         case NFCHR:        /* Character special device file */
1284           dir->fd_dir[i].d_type = DT_CHR;
1285           break;
1286         }
1287       dir->fd_position++;
1288       dir->fd_dir[i].d_off = dir->fd_position;
1289       dir->fd_dir[i].d_reclen = (uint16_t)sizeof(struct dirent);
1290       i++;
1291     }
1292   nfs_mux_release(nmp);
1293   return i;
1294 
1295 errout_with_memory:
1296   for (entry_pos = nfs_dir->nfs_entries; entry_pos != NULL; entry_pos = nfs_dir->nfs_entries)
1297     {
1298       nfs_dir->nfs_entries = entry_pos->next;
1299       NFS_DIR_ENTRY_FREE(entry_pos);
1300     }
1301 errout_with_mutex:
1302   nfs_mux_release(nmp);
1303   if (error == ENOENT && i > 0)
1304     {
1305       return i;
1306     }
1307   return -error;
1308 }
1309 extern int nfs_getfilename(char *dstpath, unsigned int dstpathLen, const char *srcpath, unsigned int maxlen);
1310 extern int nfs_rename(struct Vnode *mountpt, const char *oldrelpath, const char *newrelpath);
vfs_nfs_rename(struct Vnode * from_vnode,struct Vnode * to_parent,const char * from_name,const char * to_name)1311 int vfs_nfs_rename(struct Vnode *from_vnode, struct Vnode *to_parent,
1312                    const char *from_name, const char *to_name)
1313 {
1314   int error;
1315   int reqlen;
1316   int namelen;
1317   uint32_t *ptr = NULL;
1318   struct Vnode *to_vnode = NULL;
1319   struct Vnode *from_parent = from_vnode->parent;
1320   struct nfsnode *from_node = NULL;
1321   struct nfsnode *to_node = NULL;
1322   struct nfsmount *nmp = (struct nfsmount *)(to_parent->originMount->data);
1323 
1324   nfs_mux_take(nmp);
1325   error = nfs_checkmount(nmp);
1326   if (error != OK)
1327     {
1328       nfs_debug_error("nfs_checkmount failed: %d\n", error);
1329       goto errout_with_mutex;
1330     }
1331 
1332   from_node = (struct nfsnode *)from_parent->data;
1333   to_node = (struct nfsnode *)to_parent->data;
1334 
1335   ptr    = (uint32_t *)&nmp->nm_msgbuffer.renamef.rename;
1336   reqlen = 0;
1337 
1338   /* Copy the variable length, 'from' directory file handle */
1339 
1340   *ptr++  = txdr_unsigned(from_node->n_fhsize);
1341   reqlen += sizeof(uint32_t);
1342 
1343   (void)memcpy_s(ptr, from_node->n_fhsize, &from_node->n_fhandle, from_node->n_fhsize);
1344   reqlen += (int)from_node->n_fhsize;
1345   ptr    += uint32_increment(from_node->n_fhsize);
1346 
1347   /* Copy the variable-length 'from' object name */
1348 
1349   namelen = strlen(from_name);
1350 
1351   *ptr++  = txdr_unsigned(namelen);
1352   reqlen += sizeof(uint32_t);
1353 
1354   (void)memcpy_s(ptr, namelen, from_name, namelen);
1355   reqlen += uint32_alignup(namelen);
1356   ptr    += uint32_increment(namelen);
1357 
1358   /* Copy the variable length, 'to' directory file handle */
1359 
1360   *ptr++  = txdr_unsigned(to_node->n_fhsize);
1361   reqlen += sizeof(uint32_t);
1362 
1363   (void)memcpy_s(ptr, to_node->n_fhsize, &to_node->n_fhandle, to_node->n_fhsize);
1364   ptr    += uint32_increment(to_node->n_fhsize);
1365   reqlen += (int)to_node->n_fhsize;
1366 
1367   /* Copy the variable-length 'to' object name */
1368 
1369   namelen = strlen(to_name);
1370 
1371   *ptr++  = txdr_unsigned(namelen);
1372   reqlen += sizeof(uint32_t);
1373 
1374   (void)memcpy_s(ptr, namelen, to_name, namelen);
1375   reqlen += uint32_alignup(namelen);
1376 
1377   /* Perform the RENAME RPC */
1378 
1379   nfs_statistics(NFSPROC_RENAME);
1380   error = nfs_request(nmp, NFSPROC_RENAME,
1381       (void *)&nmp->nm_msgbuffer.renamef, reqlen,
1382       (void *)nmp->nm_iobuffer, nmp->nm_buflen);
1383   if (error != OK)
1384     {
1385       nfs_debug_error("nfs_request returned: %d\n", error);
1386       goto errout_with_mutex;
1387     }
1388 
1389   error = vfs_nfs_lookup(to_parent, to_name, strlen(to_name), &to_vnode);
1390   if (error != OK)
1391     {
1392       error = -error;
1393       nfs_debug_error("nfs_rename not finish\n");
1394       goto errout_with_mutex;
1395     }
1396   vfs_nfs_reclaim(from_vnode);
1397   from_vnode->data = to_vnode->data;
1398   from_vnode->parent = to_parent;
1399   to_vnode->data = NULL;
1400   VnodeFree(to_vnode);
1401 
1402 errout_with_mutex:
1403   nfs_mux_release(nmp);
1404   return -error;
1405 }
1406 
vfs_nfs_mkdir(struct Vnode * parent,const char * dirname,mode_t mode,struct Vnode ** vpp)1407 int vfs_nfs_mkdir(struct Vnode *parent, const char *dirname, mode_t mode, struct Vnode **vpp)
1408 {
1409   struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data);
1410   struct nfsnode *parent_nfs_node = NULL;
1411   struct nfs_fattr obj_attributes;
1412   struct nfsnode *target_node = NULL;
1413   struct file_handle fhandle;
1414   uint32_t          *ptr = NULL;
1415   uint32_t               tmp;
1416   int                    namelen;
1417   int                    reqlen;
1418   int                    error;
1419 
1420   /* Sanity checks */
1421 
1422   DEBUGASSERT(parent && parent->data);
1423 
1424   /* Check if the mount is still healthy */
1425 
1426   nfs_mux_take(nmp);
1427   error = nfs_checkmount(nmp);
1428   if (error != OK)
1429     {
1430       nfs_debug_error("nfs_checkmount: %d\n", error);
1431       goto errout_with_mutex;
1432     }
1433 
1434   parent_nfs_node = (struct nfsnode *)parent->data;
1435 
1436   /* Format the MKDIR call message arguments */
1437 
1438   ptr    = (uint32_t *)&nmp->nm_msgbuffer.mkdir.mkdir;
1439   reqlen = 0;
1440 
1441   /* Copy the variable length, directory file handle */
1442 
1443   *ptr++  = txdr_unsigned(parent_nfs_node->n_fhsize);
1444   reqlen += sizeof(uint32_t);
1445 
1446   memcpy_s(ptr, parent_nfs_node->n_fhsize, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize);
1447   ptr    += uint32_increment(parent_nfs_node->n_fhsize);
1448   reqlen += (int)parent_nfs_node->n_fhsize;
1449 
1450   /* Copy the variable-length directory name */
1451 
1452   namelen = strlen(dirname);
1453 
1454   *ptr++  = txdr_unsigned(namelen);
1455   reqlen += sizeof(uint32_t);
1456 
1457   (void)memcpy_s(ptr, namelen, dirname, namelen);
1458   ptr    += uint32_increment(namelen);
1459   reqlen += uint32_alignup(namelen);
1460 
1461   /* Set the mode.  NOTE: Here we depend on the fact that the NuttX and NFS
1462    * bit settings are the same (at least for the bits of interest).
1463    */
1464 
1465   *ptr++  = nfs_true; /* True: mode value follows */
1466   reqlen += sizeof(uint32_t);
1467 
1468   if (!mode)
1469     {
1470       mode = (NFSMODE_IXOTH | NFSMODE_IROTH |
1471               NFSMODE_IXGRP | NFSMODE_IRGRP |
1472               NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR);
1473     }
1474   tmp = mode & (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH |
1475                 NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP |
1476                 NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR);
1477   *ptr++  = txdr_unsigned(tmp);
1478   reqlen += sizeof(uint32_t);
1479 
1480   /* Set the user ID to zero */
1481 
1482   *ptr++  = nfs_true;             /* True: Uid value follows */
1483   *ptr++  = 0;                    /* UID = 0 (nobody) */
1484   reqlen += 2*sizeof(uint32_t);
1485 
1486   /* Set the group ID to one */
1487 
1488   *ptr++  = nfs_true;            /* True: Gid value follows */
1489   *ptr++  = htonl(1);            /* GID = 1 (nogroup) */
1490   reqlen += 2*sizeof(uint32_t);
1491 
1492   /* No size */
1493 
1494   *ptr++  = nfs_false; /* False: No size value follows */
1495   reqlen += sizeof(uint32_t);
1496 
1497   /* Don't change times */
1498 
1499   *ptr++  = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change atime */
1500   *ptr++  = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change mtime */
1501   reqlen += 2*sizeof(uint32_t);
1502 
1503   /* Perform the MKDIR RPC */
1504 
1505   nfs_statistics(NFSPROC_MKDIR);
1506   error = nfs_request(nmp, NFSPROC_MKDIR,
1507       (void *)&nmp->nm_msgbuffer.mkdir, reqlen,
1508       (void *)nmp->nm_iobuffer, nmp->nm_buflen);
1509   if (error)
1510     {
1511       nfs_debug_error("nfs_request failed: %d\n", error);
1512       goto errout_with_mutex;
1513     }
1514 
1515   fhandle.length = parent_nfs_node->n_fhsize;
1516   memcpy_s(&(fhandle.handle), DIRENT_NFS_MAXHANDLE, &(parent_nfs_node->n_fhandle), fhandle.length);
1517   error = nfs_lookup(nmp, dirname, &fhandle, &obj_attributes, NULL);
1518   if (error)
1519     {
1520       error = ENOENT;
1521       goto errout_with_mutex;
1522     }
1523 
1524   /* Initialize the file private data.
1525    *
1526    * Copy the file handle.
1527    */
1528   target_node = zalloc(sizeof(struct nfsnode));
1529   target_node->n_fhsize = (uint8_t)fhandle.length;
1530   memcpy_s(&(target_node->n_fhandle), target_node->n_fhsize, &(fhandle.handle), fhandle.length);
1531   target_node->n_pfhsize = parent_nfs_node->n_fhsize;
1532   (void)memcpy_s(&(target_node->n_pfhandle), NFSX_V3FHMAX, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize);
1533   target_node->n_name = zalloc(sizeof (dirname));
1534   memcpy_s(target_node->n_name, sizeof(dirname), dirname, sizeof (dirname));
1535   target_node->n_next = nmp->nm_head;
1536   nmp->nm_head = target_node;
1537 
1538   /* Save the file attributes */
1539   nfs_attrupdate(target_node, &obj_attributes);
1540   (void)VnodeAlloc(&nfs_vops, vpp);
1541   (*vpp)->parent = parent;
1542   (*vpp)->fop = &nfs_fops;
1543   (*vpp)->originMount = parent->originMount;
1544   (*vpp)->data = target_node;
1545   (*vpp)->type = filetype_to_vnodetype(target_node->n_type);
1546   (*vpp)->mode = type_to_mode((*vpp)->type, nmp->nm_permission);
1547   (*vpp)->gid = nmp->nm_gid;
1548   (*vpp)->uid = nmp->nm_uid;
1549 
1550 errout_with_mutex:
1551   nfs_mux_release(nmp);
1552   return -error;
1553 }
1554 
vfs_nfs_write(struct file * filep,const char * buffer,size_t buflen)1555 int vfs_nfs_write(struct file *filep, const char *buffer, size_t buflen)
1556 {
1557   struct nfsmount       *nmp;
1558   struct nfsnode        *np;
1559   loff_t                f_pos;
1560   size_t                writesize;
1561   size_t                bufsize;
1562   size_t                byteswritten;
1563   size_t                reqlen;
1564   uint32_t              *ptr = NULL;
1565   uint32_t              tmp;
1566   int                   committed = NFSV3WRITE_UNSTABLE;
1567   int                   error;
1568   char                  *temp_buffer = NULL;
1569   struct file_handle    parent_fhandle;
1570 
1571   struct Vnode *node = filep->f_vnode;
1572   nmp = (struct nfsmount *)(node->originMount->data);
1573   DEBUGASSERT(nmp != NULL);
1574 
1575   /* Make sure that the mount is still healthy */
1576 
1577   nfs_mux_take(nmp);
1578   np  = (struct nfsnode *)node->data;
1579   error = nfs_checkmount(nmp);
1580   if (error != OK)
1581     {
1582       nfs_debug_error("nfs_checkmount failed: %d\n", error);
1583       goto errout_with_mutex;
1584     }
1585 
1586   parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize;
1587   (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX,
1588       &(((struct nfsnode *)node->data)->n_pfhandle),
1589       ((struct nfsnode *)node->data)->n_pfhsize);
1590 
1591   if (filep->f_oflags & O_APPEND)
1592     {
1593       if (nfs_fileupdate(nmp, np->n_name, &parent_fhandle, np) == OK)
1594         {
1595           f_pos = np->n_size;
1596         }
1597       else
1598         {
1599           error = EAGAIN;
1600           goto errout_with_mutex;
1601         }
1602     }
1603   else
1604     {
1605       f_pos = filep->f_pos;
1606     }
1607 
1608   /* Check if the file size would exceed the range of off_t */
1609 
1610   if (np->n_size + buflen < np->n_size)
1611     {
1612       error = EFBIG;
1613       goto errout_with_mutex;
1614     }
1615 
1616   /* Allocate memory for data */
1617 
1618   bufsize = (buflen < nmp->nm_wsize) ? buflen : nmp->nm_wsize;
1619   temp_buffer = malloc(bufsize);
1620   if (temp_buffer == NULL)
1621     {
1622       error = ENOMEM;
1623       goto errout_with_mutex;
1624     }
1625 
1626   /* Now loop until we send the entire user buffer */
1627 
1628   writesize = 0;
1629   for (byteswritten = 0; byteswritten < buflen; )
1630     {
1631       /* Make sure that the attempted write size does not exceed the RPC
1632        * maximum.
1633        */
1634 
1635       writesize = buflen - byteswritten;
1636       if (writesize > nmp->nm_wsize)
1637         {
1638           writesize = nmp->nm_wsize;
1639         }
1640 
1641       /* Make sure that the attempted read size does not exceed the IO
1642        * buffer size.
1643        */
1644 
1645       bufsize = SIZEOF_rpc_call_write(writesize);
1646       if (bufsize > nmp->nm_buflen)
1647         {
1648           writesize -= (bufsize - nmp->nm_buflen);
1649         }
1650 
1651       /* Copy a chunk of the user data into the temporary buffer */
1652 
1653       if (LOS_CopyToKernel(temp_buffer, writesize, buffer, writesize) != 0)
1654         {
1655           error = EINVAL;
1656           goto errout_with_memfree;
1657         }
1658 
1659       /* Initialize the request.  Here we need an offset pointer to the write
1660        * arguments, skipping over the RPC header.  Write is unique among the
1661        * RPC calls in that the entry RPC calls messasge lies in the I/O buffer
1662        */
1663 
1664       ptr     = (uint32_t *)&((struct rpc_call_write *)
1665           nmp->nm_iobuffer)->write;
1666       reqlen  = 0;
1667 
1668       /* Copy the variable length, file handle */
1669 
1670       *ptr++  = txdr_unsigned((uint32_t)np->n_fhsize);
1671       reqlen += sizeof(uint32_t);
1672 
1673       (void)memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize);
1674       reqlen += (int)np->n_fhsize;
1675       ptr    += uint32_increment((int)np->n_fhsize);
1676 
1677       /* Copy the file offset */
1678 
1679       txdr_hyper((uint64_t)f_pos, ptr);
1680       ptr    += 2;
1681       reqlen += 2*sizeof(uint32_t);
1682 
1683       /* Copy the count and stable values */
1684 
1685       *ptr++  = txdr_unsigned(writesize);
1686       *ptr++  = txdr_unsigned((uint32_t)committed);
1687       reqlen += 2*sizeof(uint32_t);
1688 
1689       /* Copy a chunk of the user data into the I/O buffer from temporary buffer */
1690 
1691       *ptr++  = txdr_unsigned(writesize);
1692       reqlen += sizeof(uint32_t);
1693       error = memcpy_s(ptr, writesize, temp_buffer, writesize);
1694       if (error != EOK)
1695         {
1696           error = ENOBUFS;
1697           goto errout_with_memfree;
1698         }
1699       reqlen += uint32_alignup(writesize);
1700 
1701       /* Perform the write */
1702 
1703       nfs_statistics(NFSPROC_WRITE);
1704       error = nfs_request(nmp, NFSPROC_WRITE,
1705           (void *)nmp->nm_iobuffer, reqlen,
1706           (void *)&nmp->nm_msgbuffer.write,
1707           sizeof(struct rpc_reply_write));
1708       if (error)
1709         {
1710           goto errout_with_memfree;
1711         }
1712 
1713       /* Get a pointer to the WRITE reply data */
1714 
1715       ptr = (uint32_t *)&nmp->nm_msgbuffer.write.write;
1716 
1717       /* Parse file_wcc.  First, check if WCC attributes follow. */
1718 
1719       tmp = *ptr++;
1720       if (tmp != 0)
1721         {
1722           /* Yes.. WCC attributes follow.  But we just skip over them. */
1723 
1724           ptr += uint32_increment(sizeof(struct wcc_attr));
1725         }
1726 
1727       /* Check if normal file attributes follow */
1728 
1729       tmp = *ptr++;
1730       if (tmp != 0)
1731         {
1732           /* Yes.. Update the cached file status in the file structure. */
1733 
1734           nfs_attrupdate(np, (struct nfs_fattr *)ptr);
1735           ptr += uint32_increment(sizeof(struct nfs_fattr));
1736         }
1737 
1738       /* Get the count of bytes actually written */
1739 
1740       tmp = fxdr_unsigned(uint32_t, *ptr);
1741       ptr++;
1742 
1743       if (tmp < 1 || tmp > writesize)
1744         {
1745           error = EIO;
1746           goto errout_with_memfree;
1747         }
1748 
1749       writesize = tmp;
1750       f_pos += writesize;
1751       filep->f_pos = f_pos;
1752       np->n_fpos = f_pos;
1753 
1754       /* Update the read state data */
1755 
1756       if (filep->f_pos > (loff_t)np->n_size)
1757         {
1758           np->n_size = f_pos;
1759         }
1760       byteswritten += writesize;
1761       buffer       += writesize;
1762   }
1763 
1764   free(temp_buffer);
1765   nfs_mux_release(nmp);
1766   return byteswritten;
1767 errout_with_memfree:
1768   free(temp_buffer);
1769 errout_with_mutex:
1770   nfs_mux_release(nmp);
1771   return -error;
1772 }
1773 
vfs_nfs_writepage(struct Vnode * node,char * buffer,off_t pos,size_t buflen)1774 ssize_t vfs_nfs_writepage(struct Vnode *node, char *buffer, off_t pos, size_t buflen)
1775 {
1776   struct nfsmount       *nmp;
1777   struct nfsnode        *np;
1778   loff_t                f_pos = pos;
1779   size_t                writesize;
1780   size_t                bufsize;
1781   size_t                byteswritten;
1782   size_t                reqlen;
1783   uint32_t              *ptr = NULL;
1784   uint32_t              tmp;
1785   int                   committed = NFSV3WRITE_UNSTABLE;
1786   int                   error;
1787   char                  *temp_buffer = NULL;
1788   struct file_handle    parent_fhandle;
1789 
1790   nmp = (struct nfsmount *)(node->originMount->data);
1791   DEBUGASSERT(nmp != NULL);
1792 
1793   /* Make sure that the mount is still healthy */
1794 
1795   nfs_mux_take(nmp);
1796   np  = (struct nfsnode *)node->data;
1797   error = nfs_checkmount(nmp);
1798   if (error != OK)
1799     {
1800       nfs_debug_error("nfs_checkmount failed: %d\n", error);
1801       goto errout_with_mutex;
1802     }
1803 
1804   parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize;
1805   (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX,
1806       &(((struct nfsnode *)node->data)->n_pfhandle),
1807       ((struct nfsnode *)node->data)->n_pfhsize);
1808 
1809   /* Check if the file size would exceed the range of off_t */
1810 
1811   if (np->n_size + buflen < np->n_size)
1812     {
1813       error = EFBIG;
1814       goto errout_with_mutex;
1815     }
1816 
1817   /* writepage cannot exceed the file range */
1818 
1819   if (f_pos >= np->n_size)
1820     {
1821       error = ERANGE;
1822       goto errout_with_mutex;
1823     }
1824 
1825   buflen = min(buflen, np->n_size - f_pos);
1826 
1827   /* Allocate memory for data */
1828 
1829   bufsize = (buflen < nmp->nm_wsize) ? buflen : nmp->nm_wsize;
1830   temp_buffer = malloc(bufsize);
1831   if (temp_buffer == NULL)
1832     {
1833       error = ENOMEM;
1834       goto errout_with_mutex;
1835     }
1836 
1837   /* Now loop until we send the entire user buffer */
1838 
1839   writesize = 0;
1840   for (byteswritten = 0; byteswritten < buflen; )
1841     {
1842       /* Make sure that the attempted write size does not exceed the RPC
1843        * maximum.
1844        */
1845 
1846       writesize = buflen - byteswritten;
1847       if (writesize > nmp->nm_wsize)
1848         {
1849           writesize = nmp->nm_wsize;
1850         }
1851 
1852       /* Make sure that the attempted read size does not exceed the IO
1853        * buffer size.
1854        */
1855 
1856       bufsize = SIZEOF_rpc_call_write(writesize);
1857       if (bufsize > nmp->nm_buflen)
1858         {
1859           writesize -= (bufsize - nmp->nm_buflen);
1860         }
1861 
1862       /* Copy a chunk of the user data into the temporary buffer */
1863 
1864       if (LOS_CopyToKernel(temp_buffer, writesize, buffer, writesize) != 0)
1865         {
1866           error = EINVAL;
1867           goto errout_with_memfree;
1868         }
1869 
1870       /* Initialize the request.  Here we need an offset pointer to the write
1871        * arguments, skipping over the RPC header.  Write is unique among the
1872        * RPC calls in that the entry RPC calls messasge lies in the I/O buffer
1873        */
1874 
1875       ptr     = (uint32_t *)&((struct rpc_call_write *)
1876           nmp->nm_iobuffer)->write;
1877       reqlen  = 0;
1878 
1879       /* Copy the variable length, file handle */
1880 
1881       *ptr++  = txdr_unsigned((uint32_t)np->n_fhsize);
1882       reqlen += sizeof(uint32_t);
1883 
1884       (void)memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize);
1885       reqlen += (int)np->n_fhsize;
1886       ptr    += uint32_increment((int)np->n_fhsize);
1887 
1888       /* Copy the file offset */
1889 
1890       txdr_hyper((uint64_t)f_pos, ptr);
1891       ptr    += 2;
1892       reqlen += 2*sizeof(uint32_t);
1893 
1894       /* Copy the count and stable values */
1895 
1896       *ptr++  = txdr_unsigned(writesize);
1897       *ptr++  = txdr_unsigned((uint32_t)committed);
1898       reqlen += 2*sizeof(uint32_t);
1899 
1900       /* Copy a chunk of the user data into the I/O buffer from temporary buffer */
1901 
1902       *ptr++  = txdr_unsigned(writesize);
1903       reqlen += sizeof(uint32_t);
1904       error = memcpy_s(ptr, writesize, temp_buffer, writesize);
1905       if (error != EOK)
1906         {
1907           error = ENOBUFS;
1908           goto errout_with_memfree;
1909         }
1910       reqlen += uint32_alignup(writesize);
1911 
1912       /* Perform the write */
1913 
1914       nfs_statistics(NFSPROC_WRITE);
1915       error = nfs_request(nmp, NFSPROC_WRITE,
1916           (void *)nmp->nm_iobuffer, reqlen,
1917           (void *)&nmp->nm_msgbuffer.write,
1918           sizeof(struct rpc_reply_write));
1919       if (error)
1920         {
1921           goto errout_with_memfree;
1922         }
1923 
1924       /* Get a pointer to the WRITE reply data */
1925 
1926       ptr = (uint32_t *)&nmp->nm_msgbuffer.write.write;
1927 
1928       /* Parse file_wcc.  First, check if WCC attributes follow. */
1929 
1930       tmp = *ptr++;
1931       if (tmp != 0)
1932         {
1933           /* Yes.. WCC attributes follow.  But we just skip over them. */
1934 
1935           ptr += uint32_increment(sizeof(struct wcc_attr));
1936         }
1937 
1938       /* Check if normal file attributes follow */
1939 
1940       tmp = *ptr++;
1941       if (tmp != 0)
1942         {
1943           /* Yes.. Update the cached file status in the file structure. */
1944 
1945           nfs_attrupdate(np, (struct nfs_fattr *)ptr);
1946           ptr += uint32_increment(sizeof(struct nfs_fattr));
1947         }
1948 
1949       /* Get the count of bytes actually written */
1950 
1951       tmp = fxdr_unsigned(uint32_t, *ptr);
1952       ptr++;
1953 
1954       if (tmp < 1 || tmp > writesize)
1955         {
1956           error = EIO;
1957           goto errout_with_memfree;
1958         }
1959 
1960       writesize = tmp;
1961       f_pos += writesize;
1962       np->n_fpos = f_pos;
1963 
1964       byteswritten += writesize;
1965       buffer       += writesize;
1966   }
1967 
1968   free(temp_buffer);
1969   nfs_mux_release(nmp);
1970   return byteswritten;
1971 errout_with_memfree:
1972   free(temp_buffer);
1973 errout_with_mutex:
1974   nfs_mux_release(nmp);
1975   return -error;
1976 }
1977 
vfs_nfs_seek(struct file * filep,off_t offset,int whence)1978 off_t vfs_nfs_seek(struct file *filep, off_t offset, int whence)
1979 {
1980   struct Vnode *node = filep->f_vnode;
1981   struct nfsnode  *np = NULL;
1982   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
1983   int                        error;
1984   off_t                      position;
1985 
1986   /* Make sure that the mount is still healthy */
1987 
1988   nfs_mux_take(nmp);
1989   np = (struct nfsnode *)node->data;
1990   error = nfs_checkmount(nmp);
1991   if (error != OK)
1992     {
1993       nfs_debug_info("nfs_checkmount failed: %d\n", error);
1994       goto errout_with_mutex;
1995     }
1996 
1997 
1998   switch (whence)
1999     {
2000     case SEEK_SET: /* The offset is set to offset bytes. */
2001       position = offset;
2002       break;
2003 
2004     case SEEK_CUR: /* The offset is set to its current location plus offset bytes. */
2005       position = offset + filep->f_pos;
2006       break;
2007 
2008     case SEEK_END: /* The offset is set to the size of the file plus offset bytes. */
2009       position = offset + np->n_size;
2010       break;
2011 
2012     default:
2013       error = EINVAL;
2014       goto errout_with_mutex;
2015     }
2016 
2017   /* Attempts to set the position beyound the end of file will
2018    * work if the file is open for write access.
2019    */
2020 
2021   if ((position > (off_t)np->n_size) && ((np->n_oflags & O_WRONLY) == 0) &&
2022       ((np->n_oflags & O_RDWR) == 0))
2023   {
2024       position = np->n_size;
2025   }
2026 
2027   /* position less than 0 should be reset to 0 */
2028 
2029   if (position < 0)
2030   {
2031       position = 0;
2032   }
2033 
2034   np->n_fpos = (loff_t)position;
2035   filep->f_pos = np->n_fpos;
2036   if (position > (off_t)np->n_size)
2037   {
2038       np->n_size = (loff_t)position;
2039   }
2040   nfs_mux_release(nmp);
2041   return (off_t)filep->f_pos;
2042 
2043 errout_with_mutex:
2044   nfs_mux_release(nmp);
2045   return -error;
2046 }
2047 
vfs_nfs_readpage(struct Vnode * node,char * buffer,off_t pos)2048 ssize_t vfs_nfs_readpage(struct Vnode *node, char *buffer, off_t pos)
2049 {
2050   struct nfsnode            *np;
2051   struct rpc_reply_read     *read_response = NULL;
2052   size_t                     readsize;
2053   size_t                     tmp;
2054   size_t                     bytesread;
2055   size_t                     reqlen;
2056   uint32_t                  *ptr = NULL;
2057   int                        error = 0;
2058   struct file_handle         parent_fhandle;
2059   int                        buflen = PAGE_SIZE;
2060   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
2061 
2062   DEBUGASSERT(nmp != NULL);
2063 
2064   /* Make sure that the mount is still healthy */
2065 
2066   nfs_mux_take(nmp);
2067   np  = (struct nfsnode *)node->data;
2068   error = nfs_checkmount(nmp);
2069   if (error != OK)
2070     {
2071       nfs_debug_error("nfs_checkmount failed: %d\n", error);
2072       goto errout_with_mutex;
2073     }
2074 
2075 
2076   parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize;
2077   (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX,
2078       &(((struct nfsnode *)node->data)->n_pfhandle),
2079       ((struct nfsnode *)node->data)->n_pfhsize);
2080   error = nfs_fileupdate(nmp, np->n_name, &parent_fhandle, np);
2081   if (error != OK)
2082     {
2083       nfs_debug_info("nfs_fileupdate failed: %d\n", error);
2084       goto errout_with_mutex;
2085     }
2086 
2087   /* Get the number of bytes left in the file and truncate read count so that
2088    * it does not exceed the number of bytes left in the file.
2089    */
2090 
2091   if (pos >= np->n_size) {
2092       error = EFAULT;
2093       nfs_debug_info("readpage out of file range: %d\n", error);
2094       goto errout_with_mutex;
2095   }
2096 
2097   tmp = np->n_size - pos;
2098   if (buflen > tmp)
2099     {
2100       buflen = tmp;
2101     }
2102 
2103   /* Now loop until we fill the user buffer (or hit the end of the file) */
2104 
2105   for (bytesread = 0; bytesread < buflen; )
2106     {
2107       /* Make sure that the attempted read size does not exceed the RPC maximum */
2108 
2109       readsize = buflen - bytesread;
2110       if (readsize > nmp->nm_rsize)
2111         {
2112           readsize = nmp->nm_rsize;
2113         }
2114 
2115       /* Make sure that the attempted read size does not exceed the IO buffer size */
2116 
2117       tmp = SIZEOF_rpc_reply_read(readsize);
2118       if (tmp > nmp->nm_buflen)
2119         {
2120           readsize -= (tmp - nmp->nm_buflen);
2121         }
2122 
2123       /* Initialize the request */
2124 
2125       ptr     = (uint32_t *)&nmp->nm_msgbuffer.read.read;
2126       reqlen  = 0;
2127 
2128       /* Copy the variable length, file handle */
2129 
2130       *ptr++  = txdr_unsigned((uint32_t)np->n_fhsize);
2131       reqlen += sizeof(uint32_t);
2132 
2133       memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize);
2134       reqlen += (int)np->n_fhsize;
2135       ptr    += uint32_increment((int)np->n_fhsize);
2136 
2137       /* Copy the file offset */
2138 
2139       txdr_hyper((uint64_t)pos, ptr);
2140       ptr += 2;
2141       reqlen += 2*sizeof(uint32_t);
2142 
2143       /* Set the readsize */
2144 
2145       *ptr = txdr_unsigned(readsize);
2146       reqlen += sizeof(uint32_t);
2147 
2148       /* Perform the read */
2149 
2150       nfs_statistics(NFSPROC_READ);
2151       error = nfs_request(nmp, NFSPROC_READ,
2152           (void *)&nmp->nm_msgbuffer.read, reqlen,
2153           (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2154       if (error)
2155         {
2156           nfs_debug_error("nfs_request failed: %d\n", error);
2157           goto errout_with_mutex;
2158         }
2159 
2160       /* The read was successful.  Get a pointer to the beginning of the NFS
2161        * response data.
2162        */
2163 
2164       read_response = (struct rpc_reply_read *)nmp->nm_iobuffer;
2165       readsize = fxdr_unsigned(uint32_t, read_response->read.hdr.count);
2166 
2167       /* Copy the read data into the user buffer */
2168 
2169       if (LOS_CopyFromKernel(buffer, buflen, (const void *)read_response->read.data, readsize) != 0)
2170         {
2171           error = EINVAL;
2172           goto errout_with_mutex;
2173         }
2174 
2175       /* Update the read state data */
2176 
2177       pos          += readsize;
2178       np->n_fpos   += readsize;
2179       bytesread    += readsize;
2180       buffer       += readsize;
2181 
2182       /* Check if we hit the end of file */
2183 
2184       if (read_response->read.hdr.eof != 0)
2185         {
2186           break;
2187         }
2188     }
2189 
2190   nfs_mux_release(nmp);
2191   return bytesread;
2192 
2193 errout_with_mutex:
2194   nfs_mux_release(nmp);
2195   return -error;
2196 }
2197 
vfs_nfs_read(struct file * filep,char * buffer,size_t buflen)2198 ssize_t vfs_nfs_read(struct file *filep, char *buffer, size_t buflen)
2199 {
2200   struct nfsnode            *np;
2201   struct rpc_reply_read     *read_response = NULL;
2202   size_t                     readsize;
2203   size_t                     tmp;
2204   size_t                     bytesread;
2205   size_t                     reqlen;
2206   uint32_t                  *ptr = NULL;
2207   int                        error = 0;
2208   struct file_handle         parent_fhandle;
2209 
2210   struct Vnode *node = filep->f_vnode;
2211   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
2212 
2213   DEBUGASSERT(nmp != NULL);
2214 
2215   /* Make sure that the mount is still healthy */
2216 
2217   nfs_mux_take(nmp);
2218   np  = (struct nfsnode *)node->data;
2219   error = nfs_checkmount(nmp);
2220   if (error != OK)
2221     {
2222       nfs_debug_error("nfs_checkmount failed: %d\n", error);
2223       goto errout_with_mutex;
2224     }
2225 
2226 
2227   parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize;
2228   (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX,
2229       &(((struct nfsnode *)node->data)->n_pfhandle),
2230       ((struct nfsnode *)node->data)->n_pfhsize);
2231   error = nfs_fileupdate(nmp, np->n_name, &parent_fhandle, np);
2232   if (error != OK)
2233     {
2234       nfs_debug_info("nfs_fileupdate failed: %d\n", error);
2235       goto errout_with_mutex;
2236     }
2237 
2238   /* Get the number of bytes left in the file and truncate read count so that
2239    * it does not exceed the number of bytes left in the file.
2240    */
2241 
2242   tmp = np->n_size - filep->f_pos;
2243   if (buflen > tmp)
2244     {
2245       buflen = tmp;
2246     }
2247 
2248   /* Now loop until we fill the user buffer (or hit the end of the file) */
2249 
2250   for (bytesread = 0; bytesread < buflen; )
2251     {
2252       /* Make sure that the attempted read size does not exceed the RPC maximum */
2253 
2254       readsize = buflen - bytesread;
2255       if (readsize > nmp->nm_rsize)
2256         {
2257           readsize = nmp->nm_rsize;
2258         }
2259 
2260       /* Make sure that the attempted read size does not exceed the IO buffer size */
2261 
2262       tmp = SIZEOF_rpc_reply_read(readsize);
2263       if (tmp > nmp->nm_buflen)
2264         {
2265           readsize -= (tmp - nmp->nm_buflen);
2266         }
2267 
2268       /* Initialize the request */
2269 
2270       ptr     = (uint32_t *)&nmp->nm_msgbuffer.read.read;
2271       reqlen  = 0;
2272 
2273       /* Copy the variable length, file handle */
2274 
2275       *ptr++  = txdr_unsigned((uint32_t)np->n_fhsize);
2276       reqlen += sizeof(uint32_t);
2277 
2278       memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize);
2279       reqlen += (int)np->n_fhsize;
2280       ptr    += uint32_increment((int)np->n_fhsize);
2281 
2282       /* Copy the file offset */
2283 
2284       txdr_hyper((uint64_t)filep->f_pos, ptr);
2285       ptr += 2;
2286       reqlen += 2*sizeof(uint32_t);
2287 
2288       /* Set the readsize */
2289 
2290       *ptr = txdr_unsigned(readsize);
2291       reqlen += sizeof(uint32_t);
2292 
2293       /* Perform the read */
2294 
2295       nfs_statistics(NFSPROC_READ);
2296       error = nfs_request(nmp, NFSPROC_READ,
2297           (void *)&nmp->nm_msgbuffer.read, reqlen,
2298           (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2299       if (error)
2300         {
2301           nfs_debug_error("nfs_request failed: %d\n", error);
2302           goto errout_with_mutex;
2303         }
2304 
2305       /* The read was successful.  Get a pointer to the beginning of the NFS
2306        * response data.
2307        */
2308 
2309       read_response = (struct rpc_reply_read *)nmp->nm_iobuffer;
2310       readsize = fxdr_unsigned(uint32_t, read_response->read.hdr.count);
2311 
2312       /* Copy the read data into the user buffer */
2313 
2314       if (LOS_CopyFromKernel(buffer, buflen, (const void *)read_response->read.data, readsize) != 0)
2315         {
2316           error = EINVAL;
2317           goto errout_with_mutex;
2318         }
2319 
2320       /* Update the read state data */
2321 
2322       filep->f_pos += readsize;
2323       np->n_fpos   += readsize;
2324       bytesread    += readsize;
2325       buffer       += readsize;
2326 
2327       /* Check if we hit the end of file */
2328 
2329       if (read_response->read.hdr.eof != 0)
2330         {
2331           break;
2332         }
2333     }
2334 
2335   nfs_mux_release(nmp);
2336   return bytesread;
2337 
2338 errout_with_mutex:
2339   nfs_mux_release(nmp);
2340   return -error;
2341 }
2342 
vfs_nfs_create(struct Vnode * parent,const char * filename,int mode,struct Vnode ** vpp)2343 int vfs_nfs_create(struct Vnode *parent, const char *filename, int mode, struct Vnode **vpp)
2344 {
2345   uint32_t           *ptr = NULL;
2346   uint32_t            tmp;
2347   int                 namelen;
2348   int                 reqlen;
2349   int                 error;
2350   struct nfsnode *parent_nfs_node = (struct nfsnode *)parent->data;
2351   struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data);
2352   struct nfsnode *np = zalloc(sizeof(struct nfsnode));
2353   nfs_mux_take(nmp);
2354   error = nfs_checkmount(nmp);
2355   if (error != OK)
2356     {
2357       nfs_debug_error("nfs_checkmount failed: %d\n", error);
2358       goto errout_with_mutex;
2359     }
2360   ptr    = (uint32_t *)&nmp->nm_msgbuffer.create.create;
2361   reqlen = 0;
2362 
2363   /* Copy the variable length, directory file handle */
2364 
2365   *ptr++  = txdr_unsigned(parent_nfs_node->n_fhsize);
2366   reqlen += sizeof(uint32_t);
2367 
2368   (void)memcpy_s(ptr, parent_nfs_node->n_fhsize, &parent_nfs_node->n_fhandle, parent_nfs_node->n_fhsize);
2369   reqlen += (int)parent_nfs_node->n_fhsize;
2370   ptr    += uint32_increment(parent_nfs_node->n_fhsize);
2371 
2372   /* Copy the variable-length file name */
2373 
2374   namelen = strlen(filename);
2375 
2376   *ptr++  = txdr_unsigned(namelen);
2377   reqlen += sizeof(uint32_t);
2378 
2379   (void)memcpy_s(ptr, namelen, filename, namelen);
2380   ptr    += uint32_increment(namelen);
2381   reqlen += uint32_alignup(namelen);
2382 
2383   /* Set the creation mode */
2384 
2385 #ifdef USE_GUARDED_CREATE
2386   *ptr++  = htonl(NFSV3CREATE_GUARDED);
2387 #else
2388   *ptr++  = htonl(NFSV3CREATE_EXCLUSIVE);
2389 #endif
2390 
2391   reqlen += sizeof(uint32_t);
2392 
2393   /* Mode information is not provided if EXCLUSIVE creation is used.
2394    * in this case, we must call SETATTR after successfully creating
2395    * the file.
2396    */
2397 
2398   /* Set the mode.  NOTE: Here we depend on the fact that the NuttX and NFS
2399    * bit settings are the same (at least for the bits of interest).
2400    */
2401 
2402   *ptr++  = nfs_true; /* True: mode value follows */
2403   reqlen += sizeof(uint32_t);
2404 
2405   tmp = mode & (NFSMODE_IWOTH | NFSMODE_IROTH | NFSMODE_IWGRP |
2406       NFSMODE_IRGRP | NFSMODE_IWUSR | NFSMODE_IRUSR);
2407   *ptr++  = txdr_unsigned(tmp);
2408   reqlen += sizeof(uint32_t);
2409 
2410   /* Set the user ID to zero */
2411 
2412   *ptr++  = nfs_true;             /* True: Uid value follows */
2413   *ptr++  = 0;                    /* UID = 0 (nobody) */
2414   reqlen += 2*sizeof(uint32_t);
2415 
2416   /* Set the group ID to one */
2417 
2418   *ptr++  = nfs_true;            /* True: Gid value follows */
2419   *ptr++  = htonl(1);            /* GID = 1 (nogroup) */
2420   reqlen += 2*sizeof(uint32_t);
2421 
2422   /* Set the size to zero */
2423 
2424   *ptr++  = nfs_true;            /* True: Size value follows */
2425   *ptr++  = 0;                   /* Size = 0 */
2426   *ptr++  = 0;
2427   reqlen += 3*sizeof(uint32_t);
2428 
2429   /* Don't change times */
2430 
2431   *ptr++  = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change atime */
2432   *ptr++  = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change mtime */
2433   reqlen += 2*sizeof(uint32_t);
2434 
2435   /* Send the NFS request.  Note there is special logic here to handle version 3
2436    * exclusive open semantics.
2437    */
2438 
2439   do
2440     {
2441       nfs_statistics(NFSPROC_CREATE);
2442       error = nfs_request(nmp, NFSPROC_CREATE,
2443           (void *)&nmp->nm_msgbuffer.create, reqlen,
2444           (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2445     }
2446   while (0);
2447 
2448   /* Check for success */
2449 
2450   if (error != OK)
2451     {
2452       *vpp = NULL;
2453       goto errout_with_mutex;
2454     }
2455 
2456   /* Parse the returned data */
2457 
2458   ptr = (uint32_t *)&((struct rpc_reply_create *)
2459       nmp->nm_iobuffer)->create;
2460 
2461   /* Save the file handle in the file data structure */
2462 
2463   tmp = *ptr++;  /* handle_follows */
2464   if (!tmp)
2465     {
2466       nfs_debug_error("no file handle follows\n");
2467       error = EINVAL;
2468       goto errout_with_mutex;
2469     }
2470 
2471   tmp = *ptr++;
2472   tmp = fxdr_unsigned(uint32_t, tmp);
2473   DEBUGASSERT(tmp <= NFSX_V3FHMAX);
2474 
2475   np->n_fhsize      = (uint8_t)tmp;
2476   (void)memcpy_s(&np->n_fhandle, tmp, ptr, tmp);
2477   ptr += uint32_increment(tmp);
2478 
2479   /* Save the attributes in the file data structure */
2480 
2481   tmp = *ptr;  /* handle_follows */
2482   if (!tmp)
2483     {
2484       nfs_debug_info("WARNING: no file attributes\n");
2485     }
2486   else
2487     {
2488       /* Initialize the file attributes */
2489 
2490       nfs_attrupdate(np, (struct nfs_fattr *)ptr);
2491     }
2492 
2493   /* Any following dir_wcc data is ignored for now */
2494   np->n_crefs = 1;
2495 
2496   /* Attach the private data to the struct file instance */
2497 
2498   /* Then insert the new instance at the head of the list in the mountpoint
2499    * tructure. It needs to be there (1) to handle error conditions that effect
2500    * all files, and (2) to inform the umount logic that we are busy.  We
2501    * cannot unmount the file system if this list is not empty!
2502    */
2503 
2504   np->n_next   = nmp->nm_head;
2505   nmp->nm_head = np;
2506 
2507   np->n_pfhsize     = parent_nfs_node->n_fhsize;
2508   (void)memcpy_s(&(np->n_pfhandle), NFSX_V3FHMAX, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize);
2509 
2510   np->n_flags |= (NFSNODE_OPEN | NFSNODE_MODIFIED);
2511   np->n_name = zalloc(namelen + 1);
2512   memcpy_s(np->n_name, (namelen + 1), filename, (namelen + 1));
2513 
2514   (void)VnodeAlloc(&nfs_vops, vpp);
2515   (*vpp)->parent = parent;
2516   (*vpp)->fop = &nfs_fops;
2517   (*vpp)->originMount = parent->originMount;
2518   (*vpp)->data = np;
2519   (*vpp)->type = filetype_to_vnodetype(np->n_type);
2520   (*vpp)->mode = type_to_mode((*vpp)->type, nmp->nm_permission);
2521   (*vpp)->gid = nmp->nm_gid;
2522   (*vpp)->uid = nmp->nm_uid;
2523 
2524   nfs_mux_release(nmp);
2525   return OK;
2526 
2527 errout_with_mutex:
2528   if (np)
2529     {
2530       free(np);
2531     }
2532   nfs_mux_release(nmp);
2533   return -error;
2534 }
2535 
vfs_nfs_unlink(struct Vnode * parent,struct Vnode * target,const char * filename)2536 int vfs_nfs_unlink(struct Vnode *parent, struct Vnode *target, const char *filename)
2537 {
2538   struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data);
2539   struct nfsnode  *parent_node = NULL;
2540   struct nfsnode  *target_node = NULL;
2541   int reqlen;
2542   int namelen;
2543   uint32_t *ptr = NULL;
2544   int error;
2545 
2546   nfs_mux_take(nmp);
2547   error = nfs_checkmount(nmp);
2548   if (error != OK)
2549     {
2550       nfs_debug_error("nfs_checkmount failed: %d\n", error);
2551       goto errout_with_mutex;
2552     }
2553 
2554   parent_node = (struct nfsnode*)(parent->data);
2555   target_node = (struct nfsnode*)(target->data);
2556 
2557   if (target_node->n_type == NFDIR)
2558     {
2559       nfs_debug_error("try to remove a directory\n");
2560       error = EISDIR;
2561       goto errout_with_mutex;
2562     }
2563 
2564   /* Create the REMOVE RPC call arguments */
2565 
2566   ptr    = (uint32_t *)&nmp->nm_msgbuffer.removef.remove;
2567   reqlen = 0;
2568 
2569   /* Copy the variable length, directory file handle */
2570 
2571   *ptr++  = txdr_unsigned(parent_node->n_fhsize);
2572   reqlen += sizeof(uint32_t);
2573 
2574   (void)memcpy_s(ptr, parent_node->n_fhsize, &parent_node->n_fhandle, parent_node->n_fhsize);
2575   reqlen += (int)parent_node->n_fhsize;
2576   ptr    += uint32_increment(parent_node->n_fhsize);
2577 
2578   /* Copy the variable-length file name */
2579 
2580   namelen = strlen(filename);
2581 
2582   *ptr++  = txdr_unsigned(namelen);
2583   reqlen += sizeof(uint32_t);
2584 
2585   (void)memcpy_s(ptr, namelen, filename, namelen);
2586   reqlen += uint32_alignup(namelen);
2587 
2588   /* Perform the REMOVE RPC call */
2589 
2590   nfs_statistics(NFSPROC_REMOVE);
2591   error = nfs_request(nmp, NFSPROC_REMOVE,
2592       (void *)&nmp->nm_msgbuffer.removef, reqlen,
2593       (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2594 
2595 errout_with_mutex:
2596   nfs_mux_release(nmp);
2597   return -error;
2598 }
2599 
vfs_nfs_rmdir(struct Vnode * parent,struct Vnode * target,const char * dirname)2600 int vfs_nfs_rmdir(struct Vnode *parent, struct Vnode *target, const char *dirname)
2601 {
2602   struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data);
2603   struct nfsnode  *parent_node = NULL;
2604   struct nfsnode  *target_node = NULL;
2605   int reqlen;
2606   int namelen;
2607   uint32_t *ptr = NULL;
2608   int error;
2609   nfs_mux_take(nmp);
2610   error = nfs_checkmount(nmp);
2611   if (error != OK)
2612     {
2613       nfs_debug_error("nfs_checkmount failed: %d\n", error);
2614       goto errout_with_mutex;
2615     }
2616 
2617   parent_node = (struct nfsnode*)(parent->data);
2618   target_node = (struct nfsnode*)(target->data);
2619 
2620   if (target_node->n_type != NFDIR)
2621     {
2622       nfs_debug_error("try to remove a non-dir\n");
2623       return -ENOTDIR;
2624     }
2625 
2626   /* Set up the RMDIR call message arguments */
2627 
2628   ptr    = (uint32_t *)&nmp->nm_msgbuffer.rmdir.rmdir;
2629   reqlen = 0;
2630 
2631   /* Copy the variable length, directory file handle */
2632 
2633   *ptr++  = txdr_unsigned(parent_node->n_fhsize);
2634   reqlen += sizeof(uint32_t);
2635 
2636   (void)memcpy_s(ptr, parent_node->n_fhsize, &parent_node->n_fhandle, parent_node->n_fhsize);
2637   reqlen += (int)parent_node->n_fhsize;
2638   ptr    += uint32_increment(parent_node->n_fhsize);
2639 
2640   /* Copy the variable-length directory name */
2641 
2642   namelen = strlen(dirname);
2643 
2644   *ptr++  = txdr_unsigned(namelen);
2645   reqlen += sizeof(uint32_t);
2646 
2647   (void)memcpy_s(ptr, namelen, dirname, namelen);
2648   reqlen += uint32_alignup(namelen);
2649 
2650   /* Perform the RMDIR RPC */
2651 
2652   nfs_statistics(NFSPROC_RMDIR);
2653   error = nfs_request(nmp, NFSPROC_RMDIR,
2654       (void *)&nmp->nm_msgbuffer.rmdir, reqlen,
2655       (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2656 
2657 errout_with_mutex:
2658   nfs_mux_release(nmp);
2659   return -nfs_2_vfs(error);
2660 }
2661 
2662 
vfs_nfs_close(struct Vnode * node)2663 int vfs_nfs_close(struct Vnode *node)
2664 {
2665   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
2666   struct nfsnode  *np = NULL;
2667   nfs_mux_take(nmp);
2668   np = (struct nfsnode*)(node->data);
2669   /* Decrement the reference count.  If the reference count would not
2670    * decrement to zero, then that is all we have to do.
2671    */
2672 
2673   if (np->n_crefs > 1)
2674     {
2675       np->n_crefs--;
2676     }
2677   nfs_mux_release(nmp);
2678   return OK;
2679 }
2680 
vfs_nfs_close_file(struct file * filep)2681 int vfs_nfs_close_file(struct file *filep)
2682 {
2683   struct Vnode *node = (struct Vnode *)filep->f_vnode;
2684   return vfs_nfs_close(node);
2685 }
2686 
vfs_nfs_closedir(struct Vnode * node,struct fs_dirent_s * dir)2687 int vfs_nfs_closedir(struct Vnode *node, struct fs_dirent_s *dir)
2688 {
2689   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
2690   struct nfsdir_s  *prev = NULL;
2691   struct nfsdir_s  *curr = NULL;
2692   struct nfsdir_s      *nfs_dir;
2693   struct entry3        *entry_pos = NULL;
2694   int                  ret;
2695 
2696   /* Sanity checks */
2697   nfs_dir = (struct nfsdir_s *)(dir->u.fs_dir);
2698 
2699   DEBUGASSERT(nmp != NULL);
2700 
2701   /* Get exclusive access to the mount structure. */
2702   nfs_mux_take(nmp);
2703 
2704 
2705   for (entry_pos = nfs_dir->nfs_entries; entry_pos != NULL; entry_pos = nfs_dir->nfs_entries)
2706     {
2707       nfs_dir->nfs_entries = entry_pos->next;
2708       NFS_DIR_ENTRY_FREE(entry_pos);
2709     }
2710 
2711   /* Assume file structure will not be found.  This should never happen. */
2712 
2713   ret = EINVAL;
2714 
2715   for (prev = (struct nfsdir_s  *)NULL, curr = nmp->nm_dir;
2716       curr;
2717       prev = curr, curr = curr->nfs_next)
2718     {
2719       /* Check if this node is ours */
2720 
2721       if (nfs_dir == curr)
2722         {
2723           /* Yes.. remove it from the list of file structures */
2724 
2725           if (prev)
2726             {
2727               /* Remove from mid-list */
2728 
2729               prev->nfs_next = nfs_dir->nfs_next;
2730             }
2731           else
2732             {
2733               /* Remove from the head of the list */
2734 
2735               nmp->nm_dir= nfs_dir->nfs_next;
2736             }
2737 
2738           /* Then deallocate the file structure and return success */
2739 
2740           free(nfs_dir);
2741           nfs_dir = NULL;
2742           ret = OK;
2743           break;
2744         }
2745     }
2746   nfs_mux_release(nmp);
2747 
2748   return -ret; /*lint !e438*/
2749 }
2750 
2751 /****************************************************************************
2752  * Name: nfs_fsinfo
2753  *
2754  * Description:
2755  *   Return information about root directory.
2756  *
2757  * Returned Value:
2758  *   0 on success; positive errno value on failure
2759  *
2760  * Assumptions:
2761  *   The caller has exclusive access to the NFS mount structure
2762  *
2763  ****************************************************************************/
2764 
nfs_fsinfo(struct nfsmount * nmp)2765 int nfs_fsinfo(struct nfsmount *nmp)
2766 {
2767   struct rpc_call_fs fsinfo;
2768   struct rpc_reply_fsinfo fsp;
2769   struct nfs_fsinfo *rep_info = NULL;
2770   uint32_t pref;
2771   uint32_t max;
2772   int error = 0;
2773 
2774   fsinfo.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
2775   fsinfo.fs.fsroot.handle = nmp->nm_fh;
2776 
2777   /* Request FSINFO from the server */
2778 
2779   nfs_statistics(NFSPROC_FSINFO);
2780   error = nfs_request(nmp, NFSPROC_FSINFO,
2781                       (void *)&fsinfo, sizeof(struct FS3args),
2782                       (void *)&fsp, sizeof(struct rpc_reply_fsinfo));
2783   if (error)
2784     {
2785       return error;
2786     }
2787 
2788   if (txdr_unsigned(fsp.fsinfo.obj_attributes.obj_attribute_follow) == 1)
2789     {
2790       rep_info = (struct nfs_fsinfo *)&fsp.fsinfo.fs_rtmax;
2791     }
2792   else
2793     {
2794       rep_info = (struct nfs_fsinfo *)((void *)(&fsp.fsinfo.obj_attributes.attributes));
2795     }
2796 
2797   /* Save the root file system attributes */
2798   pref = fxdr_unsigned(uint32_t, rep_info->fs_wtpref);
2799   if (pref < nmp->nm_wsize)
2800     {
2801       nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1);
2802     }
2803 
2804   max = fxdr_unsigned(uint32_t, rep_info->fs_wtmax);
2805   if (max < nmp->nm_wsize)
2806     {
2807       nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1);
2808       if (nmp->nm_wsize == 0)
2809         {
2810           nmp->nm_wsize = max;
2811         }
2812     }
2813 
2814   pref = fxdr_unsigned(uint32_t, rep_info->fs_rtpref);
2815   if (pref < nmp->nm_rsize)
2816     {
2817       nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1);
2818     }
2819 
2820   max = fxdr_unsigned(uint32_t, rep_info->fs_rtmax);
2821   if (max < nmp->nm_rsize)
2822     {
2823       nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1);
2824       if (nmp->nm_rsize == 0)
2825         {
2826           nmp->nm_rsize = max;
2827         }
2828     }
2829 
2830   pref = fxdr_unsigned(uint32_t, rep_info->fs_dtpref);
2831   if (pref < nmp->nm_readdirsize)
2832     {
2833       nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & ~(NFS_DIRBLKSIZ - 1);
2834     }
2835 
2836   if (max < nmp->nm_readdirsize)
2837     {
2838       nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1);
2839       if (nmp->nm_readdirsize == 0)
2840         {
2841           nmp->nm_readdirsize = max;
2842         }
2843     }
2844 
2845   return OK;
2846 }
2847 
vfs_nfs_statfs(struct Mount * mountpt,struct statfs * sbp)2848 int vfs_nfs_statfs(struct Mount *mountpt, struct statfs *sbp)
2849 {
2850   struct nfsmount *nmp;
2851   struct rpc_call_fs *fsstat = NULL;
2852   struct rpc_reply_fsstat *sfp = NULL;
2853   struct nfs_statfs_ctx  *stfp = NULL;
2854   int error = 0;
2855   uint64_t tquad;
2856 
2857   /* Get the mountpoint private data from the vnode structure */
2858 
2859   nmp = (struct nfsmount *)mountpt->data;
2860 
2861   /* Check if the mount is still healthy */
2862 
2863   nfs_mux_take(nmp);
2864   error = nfs_checkmount(nmp);
2865   if (error != OK)
2866     {
2867       nfs_debug_error("nfs_checkmount failed: %d\n", error);
2868       goto errout_with_mutex;
2869     }
2870 
2871   /* Fill in the statfs info */
2872 
2873   sbp->f_type = NFS_SUPER_MAGIC;
2874 
2875   error = nfs_fsinfo(nmp);
2876   if (error)
2877     {
2878       nfs_debug_error("nfs_fsinfo failed: %d\n", error);
2879       goto errout_with_mutex;
2880     }
2881 
2882   fsstat = &nmp->nm_msgbuffer.fsstat;
2883   fsstat->fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize);
2884   (void)memcpy_s(&fsstat->fs.fsroot.handle, sizeof(nfsfh_t), &nmp->nm_fh, sizeof(nfsfh_t));
2885 
2886   nfs_statistics(NFSPROC_FSSTAT);
2887   error = nfs_request(nmp, NFSPROC_FSSTAT,
2888                       (void *)fsstat, sizeof(struct FS3args),
2889                       (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2890   if (error)
2891     {
2892       goto errout_with_mutex;
2893     }
2894 
2895   sfp                   = (struct rpc_reply_fsstat *)nmp->nm_iobuffer;
2896   if (txdr_unsigned(sfp->fsstat.attributes_follow) == 1)
2897     {
2898       stfp = (struct nfs_statfs_ctx *)&sfp->fsstat.sf_tbytes;
2899     }
2900   else
2901     {
2902       stfp = (struct nfs_statfs_ctx *)&sfp->fsstat.obj_attributes;
2903     }
2904 
2905   sbp->f_bsize          = NFS_FABLKSIZE;
2906   tquad                 = fxdr_hyper(&stfp->sf_tbytes); /*lint !e571*/
2907   sbp->f_blocks         = tquad / (uint64_t) NFS_FABLKSIZE;
2908   tquad                 = fxdr_hyper(&stfp->sf_fbytes); /*lint !e571*/
2909   sbp->f_bfree          = tquad / (uint64_t) NFS_FABLKSIZE;
2910   tquad                 = fxdr_hyper(&stfp->sf_abytes); /*lint !e571*/
2911   sbp->f_bavail         = tquad / (uint64_t) NFS_FABLKSIZE;
2912   tquad                 = fxdr_hyper(&stfp->sf_tfiles); /*lint !e571*/
2913   sbp->f_files          = tquad;
2914   tquad                 = fxdr_hyper(&stfp->sf_ffiles); /*lint !e571*/
2915   sbp->f_ffree          = tquad;
2916   sbp->f_namelen        = NAME_MAX;
2917   sbp->f_flags          = mountpt->mountFlags;
2918 
2919 errout_with_mutex:
2920   nfs_mux_release(nmp);
2921   return -error;
2922 }
2923 
vfs_nfs_rewinddir(struct Vnode * node,struct fs_dirent_s * dir)2924 static int vfs_nfs_rewinddir(struct Vnode *node, struct fs_dirent_s *dir)
2925 {
2926   struct nfsdir_s *nfs_dir = NULL;
2927   struct entry3   *entry_pos = NULL;
2928 
2929   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
2930   nfs_mux_take(nmp);
2931   /* Reset the NFS-specific portions of dirent structure, retaining only the
2932    * file handle.
2933    */
2934 
2935   nfs_dir = (struct nfsdir_s *)dir->u.fs_dir;
2936   (void)memset_s(nfs_dir->nfs_verifier, DIRENT_NFS_VERFLEN, 0, DIRENT_NFS_VERFLEN);
2937   nfs_dir->nfs_cookie[0] = 0;
2938   nfs_dir->nfs_cookie[1] = 0;
2939   for (entry_pos = nfs_dir->nfs_entries; entry_pos != NULL; entry_pos = nfs_dir->nfs_entries)
2940     {
2941       nfs_dir->nfs_entries = entry_pos->next;
2942       NFS_DIR_ENTRY_FREE(entry_pos);
2943     }
2944   free(nfs_dir->nfs_entries);
2945   nfs_dir->nfs_entries = NULL;
2946   nfs_mux_release(nmp);
2947   return OK;
2948 }
2949 
vfs_nfs_truncate(struct Vnode * node,off_t length)2950 int vfs_nfs_truncate(struct Vnode *node, off_t length)
2951 {
2952   uint32_t *ptr;
2953   int reqlen;
2954   int error;
2955 
2956   struct nfsmount *nmp = NULL;
2957   struct nfsnode  *np = NULL;
2958 
2959   nmp = (struct nfsmount *)(node->originMount->data);
2960   nfs_mux_take(nmp);
2961   np = (struct nfsnode*)(node->data);
2962 
2963   /* Create the SETATTR RPC call arguments */
2964 
2965   ptr    = (uint32_t *)&nmp->nm_msgbuffer.setattr.setattr;
2966   reqlen = 0;
2967 
2968   /* Copy the variable length, directory file handle */
2969 
2970   *ptr++  = txdr_unsigned(np->n_fhsize);
2971   reqlen += sizeof(uint32_t);
2972 
2973   (void)memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize);
2974   reqlen += (int)np->n_fhsize;
2975   ptr    += uint32_increment(np->n_fhsize);
2976 
2977   /* Copy the variable-length attributes */
2978 
2979   *ptr++  = nfs_false;                        /* Don't change mode */
2980   *ptr++  = nfs_false;                        /* Don't change uid */
2981   *ptr++  = nfs_false;                        /* Don't change gid */
2982   *ptr++  = nfs_true;                         /* Use the following size */
2983   *ptr++  = length;                           /* Truncate to the specified length */
2984   *ptr++  = 0;
2985   *ptr++  = htonl(NFSV3SATTRTIME_TOSERVER);   /* Use the server's time */
2986   *ptr++  = htonl(NFSV3SATTRTIME_TOSERVER);   /* Use the server's time */
2987   *ptr++  = nfs_false;                        /* No guard value */
2988   reqlen += 9 * sizeof(uint32_t);
2989 
2990   /* Perform the SETATTR RPC */
2991 
2992   nfs_statistics(NFSPROC_SETATTR);
2993   error = nfs_request(nmp, NFSPROC_SETATTR,
2994                       (void *)&nmp->nm_msgbuffer.setattr, reqlen,
2995                       (void *)nmp->nm_iobuffer, nmp->nm_buflen);
2996   if (error != OK)
2997     {
2998       nfs_mux_release(nmp);
2999       nfs_debug_error("nfs_request failed: %d\n", error);
3000       return -error;
3001     }
3002 
3003   /* Indicate that the file now has zero length */
3004 
3005   np->n_size = length;
3006   nfs_mux_release(nmp);
3007   return OK;
3008 }
3009 
vfs_nfs_unmount(struct Mount * mnt,struct Vnode ** blkDriver)3010 static int vfs_nfs_unmount(struct Mount *mnt, struct Vnode **blkDriver)
3011 {
3012   (void)blkDriver;
3013   struct nfsmount *nmp = (struct nfsmount *)mnt->data;
3014   int error;
3015 
3016   DEBUGASSERT(nmp);
3017 
3018   /* Get exclusive access to the mount structure */
3019 
3020   nfs_mux_take(nmp);
3021 
3022   /* Are there any open files?  We can tell if there are open files by looking
3023    * at the list of file structures in the mount structure.  If this list
3024    * not empty, then there are open files and we cannot unmount now (or a
3025    * crash is sure to follow).
3026    * The root of nfs is the head of the nfsnode list, it will be released later,
3027    * so now skip checking it.
3028    */
3029   if (nmp->nm_head == NULL)
3030     {
3031       error = ENODEV;
3032       goto errout_with_mutex;
3033     }
3034 
3035   if (nmp->nm_head->n_next != NULL || nmp->nm_dir != NULL)
3036     {
3037       nfs_debug_error("There are open files: %p or directories: %p\n", nmp->nm_head, nmp->nm_dir);
3038 
3039       /* This implementation currently only supports unmounting if there are
3040        * no open file references.
3041        */
3042 
3043       error = EBUSY;
3044       goto errout_with_mutex;
3045     }
3046 
3047   /* No open file... Umount the file system. */
3048 
3049   error = rpcclnt_umount(nmp->nm_rpcclnt);
3050   if (error)
3051     {
3052       nfs_debug_error("rpcclnt_umount failed: %d\n", error);
3053       goto errout_with_mutex;
3054     }
3055 
3056   /* Disconnect from the server */
3057 
3058   rpcclnt_disconnect(nmp->nm_rpcclnt);
3059 
3060   /* And free any allocated resources */
3061 
3062   nfs_mux_release(nmp);
3063   (void)pthread_mutex_destroy(&nmp->nm_mux);
3064   free(nmp->nm_rpcclnt);
3065   nmp->nm_rpcclnt = NULL;
3066   free(nmp);
3067   nmp = NULL;
3068 
3069   return -error;
3070 
3071 errout_with_mutex:
3072   nfs_mux_release(nmp);
3073   return -error;
3074 }
3075 
nfs_check_timestamp(struct timespec * origin,struct timespec * new)3076 static int nfs_check_timestamp(struct timespec *origin, struct timespec *new)
3077 {
3078   return (origin->tv_sec == new->tv_sec) && (origin->tv_nsec == new->tv_nsec);
3079 }
3080 
vfs_nfs_open(struct file * filep)3081 static int vfs_nfs_open(struct file *filep)
3082 {
3083   int ret;
3084   struct timespec ts;
3085   struct rpc_call_fs attr_call;
3086   struct rpc_reply_getattr attr_reply;
3087   struct Vnode *node = filep->f_vnode;
3088   struct nfsnode *nfs_node = NULL;
3089   struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data);
3090   struct file_handle parent_fhandle = {0};
3091 
3092   nfs_mux_take(nmp);
3093   nfs_node = (struct nfsnode *)node->data;
3094   attr_call.fs.fsroot.length = txdr_unsigned(nfs_node->n_fhsize);
3095   memcpy_s(&(attr_call.fs.fsroot.handle), sizeof(nfsfh_t), &(nfs_node->n_fhandle), sizeof(nfsfh_t));
3096 
3097   ret = nfs_request(nmp, NFSPROC_GETATTR, &attr_call,
3098       sizeof(struct file_handle), &attr_reply,
3099       sizeof(struct rpc_reply_getattr));
3100   if (ret != OK)
3101     {
3102       if (ret == NFSERR_STALE)
3103       {
3104         /* If the file handle is stale, update it */
3105         OsFileCacheRemove(&(node->mapping));
3106         parent_fhandle.length = ((struct nfsnode *)node->parent->data)->n_fhsize;
3107         memcpy_s(&(parent_fhandle.handle), parent_fhandle.length,
3108             &(((struct nfsnode *)node->parent->data)->n_fhandle),
3109             ((struct nfsnode *)node->parent->data)->n_fhsize);
3110         ret = nfs_fileupdate(nmp, nfs_node->n_name, &parent_fhandle, nfs_node);
3111       }
3112       nfs_mux_release(nmp);
3113       return ret;
3114     }
3115 
3116   /* Extract time values as timestamp */
3117 
3118   fxdr_nfsv3time(&attr_reply.attr.fa_mtime, &ts);
3119   if (!nfs_check_timestamp(&(nfs_node->n_timestamp), &ts))
3120     {
3121       OsFileCacheRemove(&(node->mapping));
3122       nfs_node->n_timestamp.tv_sec = ts.tv_sec;
3123       nfs_node->n_timestamp.tv_nsec = ts.tv_nsec;
3124     }
3125 
3126   nfs_mux_release(nmp);
3127 
3128   return OK;
3129 }
3130 
3131 struct MountOps nfs_mount_operations =
3132 {
3133   .Mount = vfs_nfs_mount,
3134   .Unmount = vfs_nfs_unmount,
3135   .Statfs= vfs_nfs_statfs,
3136 };
3137 
3138 struct VnodeOps nfs_vops =
3139 {
3140   .Lookup = vfs_nfs_lookup,
3141   .Getattr = vfs_nfs_stat,
3142   .Opendir = vfs_nfs_opendir,
3143   .Readdir = vfs_nfs_readdir,
3144   .Rename = vfs_nfs_rename,
3145   .Mkdir = vfs_nfs_mkdir,
3146   .Create = vfs_nfs_create,
3147   .ReadPage = vfs_nfs_readpage,
3148   .WritePage = vfs_nfs_writepage,
3149   .Unlink =  vfs_nfs_unlink,
3150   .Rmdir = vfs_nfs_rmdir,
3151   .Reclaim = vfs_nfs_reclaim,
3152   .Closedir = vfs_nfs_closedir,
3153   .Close = vfs_nfs_close,
3154   .Rewinddir = vfs_nfs_rewinddir,
3155   .Truncate = vfs_nfs_truncate,
3156 };
3157 
3158 struct file_operations_vfs nfs_fops =
3159 {
3160   .open = vfs_nfs_open,
3161   .seek = vfs_nfs_seek,
3162   .write = vfs_nfs_write,
3163   .read = vfs_nfs_read,
3164   .mmap = OsVfsFileMmap,
3165   .close = vfs_nfs_close_file,
3166 };
3167 FSMAP_ENTRY(nfs_fsmap, "nfs", nfs_mount_operations, FALSE, FALSE);
3168 #endif
3169