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