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