1 #include <posix/stdlib.h>
2
3 #include "nfs_add_on.h"
4 #include <sys/socket.h>
5
6 #include "rpc.h"
7 #include "pmap.h"
8 #include "nfs.h"
9 #include "mount.h"
10 #include <errno.h>
11 #include <string.h>
12 #include <KernelExport.h>
13 #include <driver_settings.h>
14 #include <sys/stat.h>
15 #include <dirent.h>
16 #include <SupportDefs.h>
17 #include <ByteOrder.h>
18 #include <netinet/udp.h>
19
20 #ifndef UDP_SIZE_MAX
21 #define UDP_SIZE_MAX 65515
22 #endif
23 #define B_UDP_MAX_SIZE UDP_SIZE_MAX
24
25 static status_t fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name);
26
27 /* *** configuration *** */
28
29 //#define NFS_FS_FLAGS B_FS_IS_SHARED
30 #define NFS_FS_FLAGS B_FS_IS_SHARED|B_FS_IS_PERSISTENT
31
32 /* port numbers: most NFS servers insist on the client port to be < 1024 (secure option) */
33 /* ports to bind() to; we start at conf_high_port, then go down */
34 static int16 conf_high_port = 1023;
35 static int16 conf_low_port = 900;
36
37 /* Allow open() to open directories too */
38 static bool conf_allow_dir_open = true;
39
40 /* Do we list ".." in readdir(rootid) ? (the VFS corrects the dirents anyway) */
41 /* this seems to be mandatory for Dano... BEntry::GetPath() needs that */
42 static bool conf_ls_root_parent = true;
43
44 /* timeout when waiting for an answer to a call */
45 static bigtime_t conf_call_timeout = 2000000;
46
47 /* number of retries when waiting for an anwser to a call */
48 static unsigned long conf_call_tries = 3;
49
50 /* don't check who the answers come from for requests */
51 bool conf_no_check_ip_xid = false;
52
53 static vint32 refcount = 0; /* we only want to read the config once ? */
54
55 static status_t
read_config(void)56 read_config(void)
57 {
58 void *handle;
59 const char *str, *endptr;
60
61 handle = load_driver_settings("nfs");
62 if (handle == NULL)
63 return ENOENT;
64
65 str = get_driver_parameter(handle, "high_port", NULL, NULL);
66 if (str) {
67 endptr = str + strlen(str);
68 conf_high_port = (int16)strtoul(str, (char **)&endptr, 10);
69 }
70 str = get_driver_parameter(handle, "low_port", NULL, NULL);
71 if (str) {
72 endptr = str + strlen(str);
73 conf_low_port = (int16)strtoul(str, (char **)&endptr, 10);
74 }
75
76 conf_allow_dir_open = get_driver_boolean_parameter(handle, "allow_dir_open", conf_allow_dir_open, true);
77 conf_ls_root_parent = get_driver_boolean_parameter(handle, "ls_root_parent", conf_ls_root_parent, true);
78 conf_no_check_ip_xid = get_driver_boolean_parameter(handle, "no_check_ip_xid", conf_no_check_ip_xid, true);
79
80 str = get_driver_parameter(handle, "call_timeout", NULL, NULL);
81 if (str) {
82 endptr = str + strlen(str);
83 conf_call_timeout = (bigtime_t)1000 * strtoul(str, (char **)&endptr, 10);
84 if (conf_call_timeout < 1000)
85 conf_call_timeout = 1000;
86 }
87
88 str = get_driver_parameter(handle, "call_tries", NULL, NULL);
89 if (str) {
90 endptr = str + strlen(str);
91 conf_call_tries = strtoul(str, (char **)&endptr, 10);
92 }
93
94 unload_driver_settings(handle);
95 return B_OK;
96 }
97
98
99 status_t
create_socket(fs_nspace * ns)100 create_socket(fs_nspace *ns)
101 {
102 struct sockaddr_in addr;
103 uint16 port=conf_high_port;
104
105 ns->s=socket(AF_INET,SOCK_DGRAM,0);
106
107 if (ns->s<0)
108 return errno;
109
110 do
111 {
112 addr.sin_family=AF_INET;
113 addr.sin_addr.s_addr=htonl(INADDR_ANY);
114 //addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
115 addr.sin_port=htons(port);
116 memset (addr.sin_zero,0,sizeof(addr.sin_zero));
117
118 if (bind(ns->s,(const struct sockaddr *)&addr,sizeof(addr))<0)
119 {
120 if (errno!=EADDRINUSE)
121 {
122 int result=errno;
123 close(ns->s);
124 return result;
125 }
126
127 port--;
128 if (port==conf_low_port)
129 {
130 close(ns->s);
131 return B_ERROR;
132 }
133 }
134 else
135 break;//return B_OK;
136 }
137 while (true);
138
139 // doesn't seem to help with autoincrementing port on source address...
140 addr.sin_addr = ns->mountAddr.sin_addr;
141 addr.sin_port = htons(111);
142 //kconnect(ns->s,(const struct sockaddr *)&addr,sizeof(addr));
143
144 return B_OK;
145 }
146
147
148 #if 0
149 static status_t
150 connect_socket(fs_nspace *ns)
151 {
152 uint16 port = conf_high_port;
153
154 struct sockaddr_in addr;
155 addr.sin_family = AF_INET;
156 addr.sin_addr.s_addr = htonl(INADDR_ANY);
157 //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
158 addr.sin_port = htons(port);
159 memset(addr.sin_zero,0,sizeof(addr.sin_zero));
160
161 if (kconnect(ns->s,(const struct sockaddr *)&ns->nfsAddr,sizeof(ns->nfsAddr))<0)
162 {
163 return -1;
164 }
165 return B_OK;
166 }
167 #endif
168
169
170 status_t
init_postoffice(fs_nspace * ns)171 init_postoffice(fs_nspace *ns)
172 {
173 status_t result;
174
175 ns->tid=spawn_kernel_thread ((thread_func)postoffice_func,"NFSv2 Postoffice",B_NORMAL_PRIORITY,ns);
176
177 if (ns->tid<B_OK)
178 return ns->tid;
179
180 ns->quit=false;
181
182 result=resume_thread (ns->tid);
183
184 if (result<B_OK)
185 {
186 kill_thread (ns->tid);
187
188 return result;
189 }
190
191 return B_OK;
192 }
193
194
195 void
shutdown_postoffice(fs_nspace * ns)196 shutdown_postoffice(fs_nspace *ns)
197 {
198 status_t result;
199
200 ns->quit=true;
201 close(ns->s);
202
203 wait_for_thread (ns->tid,&result);
204 }
205
206
207 status_t
postoffice_func(fs_nspace * ns)208 postoffice_func(fs_nspace *ns)
209 {
210 uint8 *buffer=(uint8 *)malloc(B_UDP_MAX_SIZE);
211
212 while (!ns->quit) {
213 struct sockaddr_in from;
214 socklen_t fromLen=sizeof(from);
215
216 ssize_t bytes = recvfrom(ns->s, buffer, B_UDP_MAX_SIZE, 0,
217 (struct sockaddr *)&from, &fromLen);
218
219 if (bytes >= 4) {
220 struct PendingCall *call;
221 int32 xid=B_BENDIAN_TO_HOST_INT32(*((int32 *)buffer));
222
223 call=RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls, xid,
224 &from);
225
226 if (call) {
227 call->buffer=(uint8 *)malloc(bytes);
228 memcpy(call->buffer, buffer, bytes);
229
230 while (release_sem (call->sem) == B_INTERRUPTED);
231 } else {
232 dprintf("nfs: postoffice: can't find pending call to remove "
233 "for xid %" B_PRId32 "\n", xid);
234 }
235 }
236 }
237
238 free (buffer);
239
240 return B_OK;
241 }
242
243
244 uint8 *
send_rpc_call(fs_nspace * ns,const struct sockaddr_in * addr,int32 prog,int32 vers,int32 proc,const struct XDROutPacket * packet)245 send_rpc_call(fs_nspace *ns, const struct sockaddr_in *addr, int32 prog,
246 int32 vers, int32 proc, const struct XDROutPacket *packet)
247 {
248 int32 xid;
249 size_t authSize;
250 struct PendingCall *pending;
251 int32 retries=conf_call_tries;
252 status_t result;
253 struct PendingCall *call;
254
255 struct XDROutPacket rpc_call;
256 XDROutPacketInit(&rpc_call);
257
258 xid=atomic_add(&ns->xid, 1);
259 #ifdef DEBUG_XID
260 //dbgprintxid(logfd1, xid);
261 #endif
262
263 XDROutPacketAddInt32(&rpc_call, xid);
264 XDROutPacketAddInt32(&rpc_call, RPC_CALL);
265 XDROutPacketAddInt32(&rpc_call, RPC_VERSION);
266 XDROutPacketAddInt32(&rpc_call, prog);
267 XDROutPacketAddInt32(&rpc_call, vers);
268 XDROutPacketAddInt32(&rpc_call, proc);
269
270 #if !defined(USE_SYSTEM_AUTHENTICATION)
271 XDROutPacketAddInt32(&rpc_call, RPC_AUTH_NONE);
272 XDROutPacketAddDynamic (&rpc_call, NULL, 0);
273 #else
274 XDROutPacketAddInt32(&rpc_call, RPC_AUTH_SYS);
275 authSize = 4 + 4 + ((strlen(ns->params.server) + 3) &~3) + 4 + 4 + 4;
276 XDROutPacketAddInt32(&rpc_call, authSize);
277 XDROutPacketAddInt32(&rpc_call, 0);
278 XDROutPacketAddString(&rpc_call, ns->params.server);
279 XDROutPacketAddInt32(&rpc_call, ns->params.uid);
280 XDROutPacketAddInt32(&rpc_call, ns->params.gid);
281 XDROutPacketAddInt32(&rpc_call, 0);
282 #endif
283
284 XDROutPacketAddInt32(&rpc_call, RPC_AUTH_NONE);
285 XDROutPacketAddDynamic (&rpc_call, NULL, 0);
286
287 XDROutPacketAppend (&rpc_call, packet);
288
289 pending = RPCPendingCallsAddPendingCall(&ns->pendingCalls, xid, addr);
290 #ifdef DEBUG_XID
291 checksemstate(xid, pending->sem, 0);
292 #endif
293
294 do {
295 ssize_t bytes;
296 do {
297 bytes = sendto(ns->s,(const void *)XDROutPacketBuffer(&rpc_call),
298 XDROutPacketLength(&rpc_call), 0,
299 (const struct sockaddr *)addr, sizeof(*addr));
300 }
301 while (bytes < 0 && errno == EINTR);
302
303 do {
304 result = acquire_sem_etc (pending->sem, 1, B_TIMEOUT,
305 (retries) ? (conf_call_timeout) : (2*conf_call_timeout));
306 }
307 while (result == B_INTERRUPTED);
308
309 retries--;
310 } while (result == B_TIMED_OUT && retries >= 0);
311
312 if (result >= B_OK) {
313 uint8 *buffer = pending->buffer;
314 pending->buffer = NULL;
315 SemaphorePoolPut(&ns->pendingCalls.fPool, pending->sem);
316
317 PendingCallDestroy(pending);
318 free(pending);
319
320 XDROutPacketDestroy(&rpc_call);
321 return buffer;
322 }
323
324 // we timed out
325
326 call = RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls, xid, addr);
327
328 dprintf("nfs: xid %" B_PRId32 " timed out, removing from queue", xid);
329
330 #if 0
331 if (call==NULL)
332 {
333 #if 1
334 //XXX:mmu_man:???
335 while (acquire_sem(pending->sem)==B_INTERRUPTED);
336 #else
337 status_t err;
338 /* NOTE(mmu_man): there can be a race condition here where the sem is returned
339 * to the pool without the correct value, compromising the next call using it.
340 * however it seems waiting forever can lead to lockups...
341 */
342 while ((err = acquire_sem_etc(pending->sem,1,B_TIMEOUT,5000000))==B_INTERRUPTED);
343 dprintf("nfs: acquire(pending->sem) = 0x%08lx\n", err);
344 if (err == B_TIMED_OUT)
345 dprintf("nfs: timed out waiting on sem\n");
346 #endif
347 }
348 #endif
349
350 /* mmu_man */
351 if (call) /* if the call has been found and removed (atomic op), the sem hasn't been released */
352 SemaphorePoolPut(&ns->pendingCalls.fPool, pending->sem);
353 else
354 delete_sem(pending->sem); /* else it's in an unknown state, forget it */
355
356 PendingCallDestroy(pending);
357 free(pending);
358
359 XDROutPacketDestroy (&rpc_call);
360 return NULL;
361 }
362
363
364 bool
is_successful_reply(struct XDRInPacket * reply)365 is_successful_reply(struct XDRInPacket *reply)
366 {
367 bool success = false;
368
369 int32 xid = XDRInPacketGetInt32(reply);
370 rpc_msg_type mtype=(rpc_msg_type)XDRInPacketGetInt32(reply);
371 rpc_reply_stat replyStat=(rpc_reply_stat)XDRInPacketGetInt32(reply);
372 (void)xid;
373 (void)mtype;
374
375 if (replyStat == RPC_MSG_DENIED) {
376 rpc_reject_stat rejectStat = (rpc_reject_stat)XDRInPacketGetInt32(reply);
377
378 if (rejectStat == RPC_RPC_MISMATCH) {
379 int32 low = XDRInPacketGetInt32(reply);
380 int32 high = XDRInPacketGetInt32(reply);
381
382 dprintf("nfs: RPC_MISMATCH (%" B_PRId32 ",%" B_PRId32 ")", low,
383 high);
384 } else {
385 rpc_auth_stat authStat = (rpc_auth_stat)XDRInPacketGetInt32(reply);
386
387 dprintf("nfs: RPC_AUTH_ERROR (%d)", authStat);
388 }
389 } else {
390 rpc_auth_flavor flavor = (rpc_auth_flavor)XDRInPacketGetInt32(reply);
391 char body[400];
392 size_t bodyLength;
393 XDRInPacketGetDynamic(reply, body, &bodyLength);
394
395 rpc_accept_stat acceptStat = (rpc_accept_stat)XDRInPacketGetInt32(reply);
396 (void)flavor;
397 (void)bodyLength;
398
399 if (acceptStat == RPC_PROG_MISMATCH) {
400 int32 low = XDRInPacketGetInt32(reply);
401 int32 high = XDRInPacketGetInt32(reply);
402
403 dprintf("nfs: RPC_PROG_MISMATCH (%" B_PRId32 ",%" B_PRId32 ")",
404 low, high);
405 } else if (acceptStat != RPC_SUCCESS)
406 dprintf("nfs: Accepted but failed (%d)", acceptStat);
407 else
408 success = true;
409 }
410
411 return success;
412 }
413
414
415 status_t
get_remote_address(fs_nspace * ns,int32 prog,int32 vers,int32 prot,struct sockaddr_in * addr)416 get_remote_address(fs_nspace *ns, int32 prog, int32 vers, int32 prot,
417 struct sockaddr_in *addr)
418 {
419 struct XDROutPacket call;
420 uint8 *replyBuf;
421
422 XDROutPacketInit(&call);
423
424 addr->sin_port = htons(PMAP_PORT);
425
426 XDROutPacketAddInt32(&call, prog);
427 XDROutPacketAddInt32(&call, vers);
428 XDROutPacketAddInt32(&call, prot);
429 XDROutPacketAddInt32(&call, 0);
430
431 replyBuf = send_rpc_call(ns, addr, PMAP_PROGRAM, PMAP_VERSION,
432 PMAPPROC_GETPORT, &call);
433
434 if (replyBuf) {
435 struct XDRInPacket reply;
436 XDRInPacketInit(&reply);
437
438 XDRInPacketSetTo(&reply,replyBuf,0);
439
440 if (is_successful_reply(&reply)) {
441 addr->sin_port = htons(XDRInPacketGetInt32(&reply));
442 memset(addr->sin_zero, 0, sizeof(addr->sin_zero));
443
444 XDRInPacketDestroy(&reply);
445 XDROutPacketDestroy(&call);
446 return B_OK;
447 }
448
449 XDRInPacketDestroy(&reply);
450 }
451
452 XDROutPacketDestroy (&call);
453 return EHOSTUNREACH;
454 }
455
456 status_t
nfs_mount(fs_nspace * ns,const char * path,nfs_fhandle * fhandle)457 nfs_mount(fs_nspace *ns, const char *path, nfs_fhandle *fhandle)
458 {
459 struct XDROutPacket call;
460 struct XDRInPacket reply;
461 uint8 *replyBuf;
462 int32 fhstatus;
463
464 XDROutPacketInit(&call);
465 XDRInPacketInit(&reply);
466
467 XDROutPacketAddString(&call,path);
468
469 replyBuf = send_rpc_call(ns, &ns->mountAddr, MOUNT_PROGRAM, MOUNT_VERSION,
470 MOUNTPROC_MNT, &call);
471
472 if (!replyBuf) {
473 XDRInPacketDestroy(&reply);
474 XDROutPacketDestroy(&call);
475 return EHOSTUNREACH;
476 }
477
478 XDRInPacketSetTo(&reply, replyBuf, 0);
479
480 if (!is_successful_reply(&reply)) {
481 XDRInPacketDestroy(&reply);
482 XDROutPacketDestroy(&call);
483 return B_ERROR;
484 }
485
486 fhstatus = XDRInPacketGetInt32(&reply);
487
488 if (fhstatus != NFS_OK) {
489 XDRInPacketDestroy(&reply);
490 XDROutPacketDestroy(&call);
491 return map_nfs_to_system_error(fhstatus);
492 }
493
494 fhstatus = XDRInPacketGetFixed(&reply, fhandle->opaque, NFS_FHSIZE);
495
496 XDRInPacketDestroy(&reply);
497 XDROutPacketDestroy(&call);
498
499 return map_nfs_to_system_error(fhstatus);
500 }
501
502
503 status_t
nfs_lookup(fs_nspace * ns,const nfs_fhandle * dir,const char * filename,nfs_fhandle * fhandle,struct stat * st)504 nfs_lookup (fs_nspace *ns, const nfs_fhandle *dir, const char *filename,
505 nfs_fhandle *fhandle, struct stat *st)
506 {
507 struct XDROutPacket call;
508 struct XDRInPacket reply;
509 int32 status;
510 uint8 *replyBuf;
511
512 XDROutPacketInit(&call);
513 XDRInPacketInit(&reply);
514
515 XDROutPacketAddFixed(&call, dir->opaque, NFS_FHSIZE);
516 XDROutPacketAddString(&call, filename);
517
518 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
519 NFSPROC_LOOKUP, &call);
520
521 if (!replyBuf) {
522 XDRInPacketDestroy(&reply);
523 XDROutPacketDestroy(&call);
524 return EHOSTUNREACH;
525 }
526
527 XDRInPacketSetTo(&reply, replyBuf, 0);
528
529 if (!is_successful_reply(&reply)) {
530 XDRInPacketDestroy(&reply);
531 XDROutPacketDestroy(&call);
532 return B_ERROR;
533 }
534
535 status = XDRInPacketGetInt32(&reply);
536
537 if (status != NFS_OK) {
538 XDRInPacketDestroy(&reply);
539 XDROutPacketDestroy(&call);
540 return map_nfs_to_system_error(status);
541 }
542
543 status = XDRInPacketGetFixed(&reply, fhandle->opaque, NFS_FHSIZE);
544
545 if (status != NFS_OK) {
546 XDRInPacketDestroy(&reply);
547 XDROutPacketDestroy(&call);
548 return map_nfs_to_system_error(status);
549 }
550
551 if (st)
552 get_nfs_attr(&reply, st);
553
554 XDRInPacketDestroy(&reply);
555 XDROutPacketDestroy(&call);
556 return B_OK;
557 }
558
559
560 status_t
nfs_getattr(fs_nspace * ns,const nfs_fhandle * fhandle,struct stat * st)561 nfs_getattr(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
562 {
563 struct XDROutPacket call;
564 struct XDRInPacket reply;
565 uint8 *replyBuf;
566 int32 status;
567
568 XDROutPacketInit(&call);
569 XDRInPacketInit(&reply);
570
571 XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE);
572
573 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
574 NFSPROC_GETATTR, &call);
575 if (replyBuf == NULL) {
576 XDRInPacketDestroy(&reply);
577 XDROutPacketDestroy(&call);
578 return EHOSTUNREACH;
579 }
580
581 XDRInPacketSetTo(&reply, replyBuf, 0);
582
583 if (!is_successful_reply(&reply)) {
584 XDRInPacketDestroy(&reply);
585 XDROutPacketDestroy(&call);
586 return B_ERROR;
587 }
588
589 status = XDRInPacketGetInt32(&reply);
590 if (status != NFS_OK) {
591 XDRInPacketDestroy(&reply);
592 XDROutPacketDestroy(&call);
593 return map_nfs_to_system_error(status);
594 }
595
596 get_nfs_attr(&reply, st);
597
598 XDRInPacketDestroy(&reply);
599 XDROutPacketDestroy(&call);
600 return B_OK;
601 }
602
603
604 status_t
nfs_truncate_file(fs_nspace * ns,const nfs_fhandle * fhandle,struct stat * st)605 nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
606 {
607 struct XDROutPacket call;
608 struct XDRInPacket reply;
609 uint8 *replyBuf;
610 int32 status;
611
612 XDROutPacketInit(&call);
613 XDRInPacketInit(&reply);
614
615 XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE);
616
617 XDROutPacketAddInt32(&call, -1);
618 XDROutPacketAddInt32(&call, -1);
619 XDROutPacketAddInt32(&call, -1);
620 XDROutPacketAddInt32(&call, 0);
621 XDROutPacketAddInt32(&call, time(NULL));
622 XDROutPacketAddInt32(&call, 0);
623 XDROutPacketAddInt32(&call, time(NULL));
624 XDROutPacketAddInt32(&call, 0);
625
626 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
627 NFSPROC_SETATTR, &call);
628 if (replyBuf == NULL) {
629 XDRInPacketDestroy(&reply);
630 XDROutPacketDestroy(&call);
631 return EHOSTUNREACH;
632 }
633
634 XDRInPacketSetTo(&reply, replyBuf, 0);
635
636 if (!is_successful_reply(&reply)) {
637 XDRInPacketDestroy(&reply);
638 XDROutPacketDestroy(&call);
639 return B_ERROR;
640 }
641
642 status = XDRInPacketGetInt32(&reply);
643 if (status != NFS_OK) {
644 XDRInPacketDestroy(&reply);
645 XDROutPacketDestroy(&call);
646 return map_nfs_to_system_error(status);
647 }
648
649 if (st)
650 get_nfs_attr(&reply,st);
651
652 XDRInPacketDestroy(&reply);
653 XDROutPacketDestroy(&call);
654 return B_OK;
655 }
656
657
658 void
get_nfs_attr(struct XDRInPacket * reply,struct stat * st)659 get_nfs_attr(struct XDRInPacket *reply, struct stat *st)
660 {
661 nfs_ftype ftype=(nfs_ftype)XDRInPacketGetInt32(reply);
662 (void) ftype;
663 st->st_mode=XDRInPacketGetInt32(reply);
664
665 st->st_dev=0; // just to be sure
666 st->st_nlink=XDRInPacketGetInt32(reply);
667 st->st_uid=XDRInPacketGetInt32(reply);
668 st->st_gid=XDRInPacketGetInt32(reply);
669 st->st_size=XDRInPacketGetInt32(reply);
670 st->st_blksize=XDRInPacketGetInt32(reply);
671 st->st_rdev=XDRInPacketGetInt32(reply);
672 st->st_blocks=XDRInPacketGetInt32(reply);
673 XDRInPacketGetInt32(reply); // fsid
674 st->st_ino=XDRInPacketGetInt32(reply);
675 st->st_atime=XDRInPacketGetInt32(reply);
676 XDRInPacketGetInt32(reply); // usecs
677 st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply);
678 XDRInPacketGetInt32(reply); // usecs
679 st->st_ctime=XDRInPacketGetInt32(reply);
680 XDRInPacketGetInt32(reply); // usecs
681 }
682
683
684 status_t
map_nfs_to_system_error(status_t nfsstatus)685 map_nfs_to_system_error(status_t nfsstatus)
686 {
687 switch (nfsstatus) {
688 case NFS_OK:
689 return B_OK;
690
691 case NFSERR_PERM:
692 return EPERM;
693
694 case NFSERR_NOENT:
695 return ENOENT;
696
697 case NFSERR_IO:
698 return EIO;
699
700 case NFSERR_NXIO:
701 return ENXIO;
702
703 case NFSERR_ACCES:
704 return EACCES;
705
706 case NFSERR_EXIST:
707 return EEXIST;
708
709 case NFSERR_NODEV:
710 return ENODEV;
711
712 case NFSERR_NOTDIR:
713 return ENOTDIR;
714
715 case NFSERR_ISDIR:
716 return EISDIR;
717
718 case NFSERR_FBIG:
719 return EFBIG;
720
721 case NFSERR_NOSPC:
722 return ENOSPC;
723
724 case NFSERR_ROFS:
725 return EROFS;
726
727 case NFSERR_NAMETOOLONG:
728 return ENAMETOOLONG;
729
730 case NFSERR_NOTEMPTY:
731 return ENOTEMPTY;
732
733 case NFSERR_STALE:
734 return C_ERROR_STALE;
735
736 default:
737 return B_ERROR;
738 }
739 }
740
741
742 nfs_fhandle
handle_from_vnid(fs_nspace * ns,ino_t vnid)743 handle_from_vnid(fs_nspace *ns, ino_t vnid)
744 {
745 fs_node *current;
746
747 while (acquire_sem(ns->sem) == B_INTERRUPTED);
748
749 current = ns->first;
750
751 while (current != NULL && current->vnid != vnid)
752 current = current->next;
753
754 while (release_sem(ns->sem) == B_INTERRUPTED);
755
756 return current->fhandle;
757 }
758
759
760 void
insert_node(fs_nspace * ns,fs_node * node)761 insert_node(fs_nspace *ns, fs_node *node)
762 {
763 fs_node *current;
764
765 while (acquire_sem(ns->sem) == B_INTERRUPTED);
766
767 current = ns->first;
768
769 while (current != NULL && current->vnid != node->vnid)
770 current = current->next;
771
772 if (current) {
773 free(node);
774 while (release_sem(ns->sem) == B_INTERRUPTED);
775 return;
776 }
777
778 node->next = ns->first;
779 ns->first = node;
780
781 while (release_sem (ns->sem) == B_INTERRUPTED);
782 }
783
784
785 void
remove_node(fs_nspace * ns,ino_t vnid)786 remove_node(fs_nspace *ns, ino_t vnid)
787 {
788 fs_node *current;
789 fs_node *previous;
790
791 while (acquire_sem(ns->sem) == B_INTERRUPTED);
792
793 current = ns->first;
794 previous = NULL;
795
796 while (current != NULL && current->vnid != vnid) {
797 previous = current;
798 current = current->next;
799 }
800
801 if (current) {
802 if (previous)
803 previous->next = current->next;
804 else
805 ns->first = current->next;
806
807 free(current);
808 }
809
810 while (release_sem(ns->sem) == B_INTERRUPTED);
811 }
812
813
814 // #pragma mark -
815
816
817 static status_t
fs_read_vnode(fs_volume * _volume,ino_t vnid,fs_vnode * _node,int * _type,uint32 * _flags,bool r)818 fs_read_vnode(fs_volume *_volume, ino_t vnid, fs_vnode *_node, int *_type,
819 uint32 *_flags, bool r)
820 {
821 fs_nspace *ns;
822 fs_node *current;
823
824 ns = _volume->private_volume;
825
826 if (!r) {
827 while (acquire_sem(ns->sem) == B_INTERRUPTED);
828 }
829
830 current = ns->first;
831
832 while (current != NULL && current->vnid != vnid)
833 current = current->next;
834
835 if (!current)
836 return EINVAL;
837
838 current->vnid = vnid;
839 _node->private_node = current;
840 _node->ops = &sNFSVnodeOps;
841 *_type = current->mode;
842 *_flags = 0;
843
844 if (!r) {
845 while (release_sem(ns->sem) == B_INTERRUPTED);
846 }
847
848 return B_OK;
849 }
850
851
852 static status_t
fs_release_vnode(fs_volume * _volume,fs_vnode * node,bool r)853 fs_release_vnode(fs_volume *_volume, fs_vnode *node, bool r)
854 {
855 (void) _volume;
856 (void) node;
857 (void) r;
858 return B_OK;
859 }
860
861
862 static status_t
fs_walk(fs_volume * _volume,fs_vnode * _base,const char * file,ino_t * vnid)863 fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid)
864 {
865 fs_node *dummy;
866 status_t result;
867 fs_nspace *ns;
868 fs_node *base;
869 //dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug
870
871 ns = _volume->private_volume;
872 base = _base->private_node;
873
874 if (!strcmp(".", file))
875 *vnid = base->vnid;
876 else {
877 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node));
878 struct stat st;
879
880 if ((result = nfs_lookup(ns, &base->fhandle, file, &newNode->fhandle,
881 &st)) < B_OK) {
882 free(newNode);
883 return result;
884 }
885
886 newNode->vnid = st.st_ino;
887 newNode->mode = st.st_mode;
888 *vnid = newNode->vnid;
889
890 insert_node(ns, newNode);
891 }
892
893 if ((result = get_vnode (_volume, *vnid, (void **)&dummy)) < B_OK)
894 return result;
895
896 return B_OK;
897 }
898
899
900 static status_t
fs_opendir(fs_volume * _volume,fs_vnode * _node,void ** _cookie)901 fs_opendir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
902 {
903 fs_nspace *ns;
904 fs_node *node;
905 nfs_cookie **cookie;
906
907 struct stat st;
908 status_t result;
909
910 ns = _volume->private_volume;
911 node = _node->private_node;
912 cookie = (nfs_cookie **)_cookie;
913
914 if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK)
915 return result;
916
917 if (!S_ISDIR(st.st_mode))
918 return ENOTDIR;
919
920 *cookie = (nfs_cookie *)malloc(sizeof(nfs_cookie));
921 memset((*cookie)->opaque,0,NFS_COOKIESIZE);
922
923 return B_OK;
924 }
925
926
927 static status_t
fs_closedir(fs_volume * _volume,fs_vnode * _node,void * cookie)928 fs_closedir(fs_volume *_volume, fs_vnode *_node, void *cookie)
929 {
930 (void) _volume;
931 (void) _node;
932 (void) cookie;
933 return B_OK;
934 }
935
936
937 static status_t
fs_rewinddir(fs_volume * _volume,fs_vnode * _node,void * _cookie)938 fs_rewinddir(fs_volume *_volume, fs_vnode *_node, void *_cookie)
939 {
940 nfs_cookie *cookie = (nfs_cookie *)_cookie;
941 (void) _volume;
942 (void) _node;
943 memset (cookie->opaque, 0, NFS_COOKIESIZE);
944
945 return B_OK;
946 }
947
948
949 static status_t
fs_readdir(fs_volume * _volume,fs_vnode * _node,void * _cookie,struct dirent * buf,size_t bufsize,uint32 * num)950 fs_readdir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
951 struct dirent *buf, size_t bufsize, uint32 *num)
952 {
953 nfs_cookie *cookie = (nfs_cookie *)_cookie;
954 uint32 max = *num;
955 int32 eof;
956
957 fs_nspace *ns;
958 fs_node *node;
959
960 size_t count = min_c(6000, max * 300);
961
962 *num = 0;
963
964 ns = _volume->private_volume;
965 node = _node->private_node;
966
967 do {
968 ino_t vnid;
969 char *filename;
970 uint8 *replyBuf;
971 struct XDROutPacket call;
972 struct XDRInPacket reply;
973 int32 status;
974
975 XDROutPacketInit(&call);
976 XDRInPacketInit(&reply);
977
978 XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE);
979 XDROutPacketAddFixed(&call, cookie->opaque, NFS_COOKIESIZE);
980 XDROutPacketAddInt32(&call, count);
981
982 replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
983 NFSPROC_READDIR, &call);
984
985 if (!replyBuf) {
986 XDRInPacketDestroy(&reply);
987 XDROutPacketDestroy(&call);
988 return B_ERROR;
989 }
990
991 XDRInPacketSetTo(&reply, replyBuf, 0);
992
993 if (!is_successful_reply(&reply)) {
994 XDRInPacketDestroy(&reply);
995 XDROutPacketDestroy(&call);
996 return B_ERROR;
997 }
998
999 status = XDRInPacketGetInt32(&reply);
1000
1001 if (status != NFS_OK) {
1002 XDRInPacketDestroy(&reply);
1003 XDROutPacketDestroy(&call);
1004 return map_nfs_to_system_error(status);
1005 }
1006
1007 while (XDRInPacketGetInt32(&reply) == 1) {
1008 nfs_cookie newCookie;
1009
1010 vnid=XDRInPacketGetInt32(&reply);
1011 filename=XDRInPacketGetString(&reply);
1012
1013 status = XDRInPacketGetFixed(&reply, newCookie.opaque,
1014 NFS_COOKIESIZE);
1015
1016 if (status != NFS_OK)
1017 return map_nfs_to_system_error(status);
1018
1019 //if (strcmp(".",filename)&&strcmp("..",filename))
1020 //if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename)))
1021 if (conf_ls_root_parent
1022 || ((ns->rootid != node->vnid) || strcmp("..", filename))) {
1023 status_t result;
1024 struct stat st;
1025
1026 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node));
1027 newNode->vnid = vnid;
1028
1029 if ((result = nfs_lookup(ns, &node->fhandle, filename,
1030 &newNode->fhandle, &st)) < B_OK) {
1031 free (filename);
1032 free(newNode);
1033 XDRInPacketDestroy (&reply);
1034 XDROutPacketDestroy (&call);
1035 return result;
1036 }
1037
1038 newNode->mode = st.st_mode;
1039 insert_node(ns,newNode);
1040
1041 if (bufsize < 2 * (sizeof(dev_t) + sizeof(ino_t))
1042 + sizeof(unsigned short) + strlen(filename) + 1) {
1043 XDRInPacketDestroy(&reply);
1044 XDROutPacketDestroy(&call);
1045 return B_OK;
1046 }
1047
1048 buf->d_dev = ns->nsid;
1049 buf->d_pdev = ns->nsid;
1050 buf->d_ino = vnid;
1051 buf->d_pino = node->vnid;
1052 buf->d_reclen = offsetof(struct dirent, d_name) + strlen(filename) + 1;
1053 strcpy(buf->d_name,filename);
1054 // if ((ns->rootid == node->vnid))//XXX:mmu_man:test
1055 // dprintf("nfs: dirent %d {d:%ld pd:%ld i:%lld pi:%lld '%s'}\n", *num, buf->d_dev, buf->d_pdev, buf->d_ino, buf->d_pino, buf->d_name);
1056
1057 bufsize -= buf->d_reclen;
1058 buf = (struct dirent *)((char *)buf + buf->d_reclen);
1059
1060 memcpy(cookie->opaque, newCookie.opaque, NFS_COOKIESIZE);
1061
1062 (*num)++;
1063 } else {
1064 memcpy(cookie->opaque, newCookie.opaque, NFS_COOKIESIZE);
1065 }
1066
1067 free (filename);
1068
1069 if ((*num) == max) {
1070 XDRInPacketDestroy(&reply);
1071 XDROutPacketDestroy(&call);
1072 return B_OK;
1073 }
1074 }
1075
1076 eof=XDRInPacketGetInt32(&reply);
1077
1078 XDRInPacketDestroy (&reply);
1079 XDROutPacketDestroy (&call);
1080 }
1081 while (eof == 0);
1082
1083 return B_OK;
1084 }
1085
1086
1087 static status_t
fs_free_dircookie(fs_volume * _volume,fs_vnode * _node,void * cookie)1088 fs_free_dircookie(fs_volume *_volume, fs_vnode *_node, void *cookie)
1089 {
1090 (void) _volume;
1091 (void) _node;
1092 free(cookie);
1093 return B_OK;
1094 }
1095
1096
1097 static status_t
fs_rstat(fs_volume * _volume,fs_vnode * _node,struct stat * st)1098 fs_rstat(fs_volume *_volume, fs_vnode *_node, struct stat *st)
1099 {
1100 fs_nspace *ns;
1101 fs_node *node;
1102 status_t result;
1103
1104 ns = _volume->private_volume;
1105 node = _node->private_node;
1106
1107 //dprintf("nfs: rstat()\n");//XXX:mmu_man:debug
1108 if ((result = nfs_getattr(ns, &node->fhandle, st)) < B_OK)
1109 return result;
1110
1111 st->st_dev = ns->nsid;
1112 //st->st_nlink = 1; //XXX:mmu_man:test
1113 return B_OK;
1114 }
1115
1116
1117 void
fs_nspaceInit(struct fs_nspace * nspace)1118 fs_nspaceInit(struct fs_nspace *nspace)
1119 {
1120 RPCPendingCallsInit(&nspace->pendingCalls);
1121 }
1122
1123
1124 void
fs_nspaceDestroy(struct fs_nspace * nspace)1125 fs_nspaceDestroy(struct fs_nspace *nspace)
1126 {
1127 RPCPendingCallsDestroy(&nspace->pendingCalls);
1128 }
1129
1130
1131 static status_t
parse_nfs_params(const char * str,struct mount_nfs_params * params)1132 parse_nfs_params(const char *str, struct mount_nfs_params *params)
1133 {
1134 const char *p, *e;
1135 long v;
1136 int i;
1137 // sprintf(buf, "nfs:%s:%s,uid=%u,gid=%u,hostname=%s",
1138 if (!str || !params)
1139 return EINVAL;
1140 if (strncmp(str, "nfs:", 4))
1141 return EINVAL;
1142 dprintf("nfs:ip!\n");
1143 p = str + 4;
1144 e = strchr(p, ':');
1145 if (!e)
1146 return EINVAL;
1147 params->server = malloc(e - p + 1);
1148 params->server[e - p] = '\0';
1149 strncpy(params->server, p, e - p);
1150 // hack
1151 params->serverIP = 0;
1152 v = strtol(p, (char **)&p, 10);
1153 dprintf("IP:%ld.", v);
1154 if (!p)
1155 return EINVAL;
1156 params->serverIP |= (v << 24);
1157 p++;
1158 v = strtol(p, (char **)&p, 10);
1159 dprintf("%ld.", v);
1160 if (!p)
1161 return EINVAL;
1162 params->serverIP |= (v << 16);
1163 p++;
1164 v = strtol(p, (char **)&p, 10);
1165 dprintf("%ld.", v);
1166 if (!p)
1167 return EINVAL;
1168 params->serverIP |= (v << 8);
1169 p++;
1170 v = strtol(p, (char **)&p, 10);
1171 dprintf("%ld\n", v);
1172 if (!p)
1173 return EINVAL;
1174 params->serverIP |= (v);
1175 if (*p++ != ':')
1176 return EINVAL;
1177
1178 e = strchr(p, ',');
1179 i = (e) ? (e - p) : ((int)strlen(p));
1180
1181 params->_export = malloc(i + 1);
1182 params->_export[i] = '\0';
1183 strncpy(params->_export, p, i);
1184
1185 p = strstr(str, "hostname=");
1186 if (!p)
1187 return EINVAL;
1188 dprintf("nfs:hn!\n");
1189 p += 9;
1190 e = strchr(p, ',');
1191 i = (e) ? (e - p) : ((int)strlen(p));
1192
1193 params->hostname = malloc(i + 1);
1194 params->hostname[i] = '\0';
1195 strncpy(params->hostname, p, i);
1196
1197 p = strstr(str, "uid=");
1198 dprintf("nfs:uid!\n");
1199 if (p) {
1200 p += 4;
1201 v = strtol(p, (char **)&p, 10);
1202 params->uid = v;
1203 }
1204 dprintf("nfs:gid!\n");
1205 p = strstr(str, "gid=");
1206 if (p) {
1207 p += 4;
1208 v = strtol(p, (char **)&p, 10);
1209 params->gid = v;
1210 }
1211 dprintf("nfs: ip:%08x server:'%s' export:'%s' hostname:'%s' uid=%d gid=%d \n",
1212 params->serverIP, params->server, params->_export,
1213 params->hostname, params->uid, params->gid);
1214 return B_OK;
1215 }
1216
1217
1218 static status_t
fs_mount(fs_volume * _vol,const char * devname,uint32 flags,const char * _parms,ino_t * vnid)1219 fs_mount(fs_volume *_vol, const char *devname, uint32 flags, const char *_parms, ino_t *vnid)
1220 {
1221 status_t result;
1222 fs_nspace *ns;
1223 fs_node *rootNode;
1224 struct stat st;
1225
1226 if (_parms == NULL)
1227 return EINVAL;
1228
1229 dprintf("nfs: mount(%" B_PRId32 ", %s, %08" B_PRIx32 ")\n", _vol->id,
1230 devname, flags);
1231 dprintf("nfs: nfs_params: %s\n", _parms);
1232
1233 // HAIKU: this should go to std_ops
1234 if (!refcount)
1235 read_config();
1236
1237
1238 result = ENOMEM;
1239 ns = (fs_nspace *)malloc(sizeof(fs_nspace));
1240 if (!ns)
1241 goto err_nspace;
1242 fs_nspaceInit(ns);
1243
1244 ns->nsid = _vol->id;
1245
1246 ns->params.server = NULL;
1247 ns->params._export = NULL;
1248 ns->params.hostname = NULL;
1249 if ((result = parse_nfs_params(_parms, &ns->params)) < 0)
1250 goto err_params;
1251 ns->xid = 0;
1252 ns->mountAddr.sin_family = AF_INET;
1253 ns->mountAddr.sin_addr.s_addr = htonl(ns->params.serverIP);
1254 memset(ns->mountAddr.sin_zero, 0, sizeof(ns->mountAddr.sin_zero));
1255
1256 if ((result = create_socket(ns)) < B_OK) {
1257 dprintf("nfs: could not create socket (%" B_PRId32 ")\n", result);
1258 goto err_socket;
1259 }
1260
1261 if ((result = init_postoffice(ns)) < B_OK) {
1262 dprintf("nfs: could not init_postoffice() (%" B_PRId32 ")\n", result);
1263 goto err_postoffice;
1264 }
1265
1266 if ((result = get_remote_address(ns, MOUNT_PROGRAM, MOUNT_VERSION,
1267 PMAP_IPPROTO_UDP, &ns->mountAddr)) < B_OK) {
1268 dprintf("could not get_remote_address() (%" B_PRId32 ")\n", result);
1269 goto err_sem;
1270 }
1271
1272 memcpy(&ns->nfsAddr, &ns->mountAddr, sizeof(ns->mountAddr));
1273 dprintf("nfs: mountd at %08x:%d\n", ns->mountAddr.sin_addr.s_addr, ntohs(ns->mountAddr.sin_port));
1274
1275 if ((result = get_remote_address(ns, NFS_PROGRAM, NFS_VERSION,
1276 PMAP_IPPROTO_UDP, &ns->nfsAddr)) < B_OK)
1277 goto err_sem;
1278 dprintf("nfs: nfsd at %08x:%d\n", ns->nfsAddr.sin_addr.s_addr, ntohs(ns->nfsAddr.sin_port));
1279 // result = connect_socket(ns);
1280 //dprintf("nfs: connect: %s\n", strerror(result));
1281
1282 if ((result = create_sem(1, "nfs_sem")) < B_OK)
1283 goto err_sem;
1284
1285 ns->sem = result;
1286
1287 set_sem_owner(ns->sem, B_SYSTEM_TEAM);
1288
1289 result = ENOMEM;
1290 rootNode = (fs_node *)malloc(sizeof(fs_node));
1291 if (!rootNode)
1292 goto err_rootvn;
1293 rootNode->next = NULL;
1294
1295 if ((result = nfs_mount(ns, ns->params._export, &rootNode->fhandle)) < B_OK)
1296 goto err_mount;
1297
1298 if ((result = nfs_getattr(ns, &rootNode->fhandle, &st)) < B_OK)
1299 goto err_publish;
1300
1301 ns->rootid = st.st_ino;
1302 rootNode->vnid = ns->rootid;
1303
1304 *vnid = ns->rootid;
1305
1306 _vol->private_volume = ns;
1307 _vol->ops = &sNFSVolumeOps;
1308
1309 // TODO: set right mode
1310 if ((result = publish_vnode(_vol, *vnid, rootNode, &sNFSVnodeOps,
1311 S_IFDIR, 0)) < B_OK)
1312 goto err_publish;
1313
1314 ns->first = rootNode;
1315
1316 return B_OK;
1317
1318 err_publish:
1319 // XXX: unmount ??
1320 err_mount:
1321 free(rootNode);
1322 err_rootvn:
1323 delete_sem (ns->sem);
1324 err_sem:
1325 shutdown_postoffice(ns);
1326 goto err_socket;
1327 err_postoffice:
1328 close(ns->s);
1329 err_socket:
1330 err_params:
1331 free(ns->params.hostname);
1332 free(ns->params._export);
1333 free(ns->params.server);
1334
1335 fs_nspaceDestroy(ns);
1336 free(ns);
1337 err_nspace:
1338
1339 if (result >= 0) {
1340 dprintf("nfs:bad error from mount!\n");
1341 result = EINVAL;
1342 }
1343 dprintf("nfs: error in nfs_mount: %s\n", strerror(result));
1344 return result;
1345 }
1346
1347
1348 static status_t
fs_unmount(fs_volume * _volume)1349 fs_unmount(fs_volume *_volume)
1350 {
1351 fs_nspace *ns = (fs_nspace *)_volume->private_volume;
1352 free(ns->params.hostname);
1353 free(ns->params._export);
1354 free(ns->params.server);
1355
1356 while (ns->first) {
1357 fs_node *next = ns->first->next;
1358 free(ns->first);
1359 ns->first = next;
1360 }
1361
1362 // We need to put the reference to our root node ourselves
1363 put_vnode(_volume, ns->rootid);
1364
1365 delete_sem(ns->sem);
1366 shutdown_postoffice(ns);
1367 fs_nspaceDestroy(ns);
1368 free(ns);
1369 return B_OK;
1370 }
1371
1372
1373 static status_t
fs_rfsstat(fs_volume * _volume,struct fs_info * info)1374 fs_rfsstat(fs_volume *_volume, struct fs_info *info)
1375 {
1376 fs_nspace *ns;
1377 struct XDROutPacket call;
1378 struct XDRInPacket reply;
1379 nfs_fhandle rootHandle;
1380 uint8 *replyBuf;
1381 int32 status;
1382
1383 ns = (fs_nspace *)_volume->private_volume;
1384
1385 rootHandle = handle_from_vnid (ns,ns->rootid);
1386 //dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug
1387
1388 XDROutPacketInit(&call);
1389 XDRInPacketInit(&reply);
1390
1391 XDROutPacketAddFixed(&call, rootHandle.opaque, NFS_FHSIZE);
1392
1393 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1394 NFSPROC_STATFS, &call);
1395 if (replyBuf == NULL) {
1396 XDRInPacketDestroy(&reply);
1397 XDROutPacketDestroy(&call);
1398 return EHOSTUNREACH;
1399 }
1400
1401 XDRInPacketSetTo(&reply, replyBuf, 0);
1402
1403 if (!is_successful_reply(&reply)) {
1404 XDRInPacketDestroy(&reply);
1405 XDROutPacketDestroy(&call);
1406 return B_ERROR;
1407 }
1408
1409 status = XDRInPacketGetInt32(&reply);
1410 if (status != NFS_OK) {
1411 XDRInPacketDestroy(&reply);
1412 XDROutPacketDestroy(&call);
1413 //dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status));
1414 return map_nfs_to_system_error(status);
1415 }
1416
1417 info->dev = ns->nsid;
1418 info->root = ns->rootid;
1419 info->flags = NFS_FS_FLAGS;
1420
1421 XDRInPacketGetInt32(&reply); // tsize
1422
1423 info->block_size = XDRInPacketGetInt32(&reply);
1424 info->io_size = 8192;
1425 info->total_blocks = XDRInPacketGetInt32(&reply);
1426 info->free_blocks = XDRInPacketGetInt32(&reply);
1427 info->total_nodes = 100;
1428 info->free_nodes = 100;
1429 strcpy(info->volume_name, "nfs://");
1430 strcat(info->volume_name, ns->params.server);
1431 strcat(info->volume_name, ns->params._export);
1432 strcpy(info->fsh_name, "nfs");
1433
1434 XDRInPacketDestroy(&reply);
1435 XDROutPacketDestroy(&call);
1436 return B_OK;
1437 }
1438
1439
1440 static status_t
fs_open(fs_volume * _volume,fs_vnode * _node,int omode,void ** _cookie)1441 fs_open(fs_volume *_volume, fs_vnode *_node, int omode, void **_cookie)
1442 {
1443 fs_nspace *ns;
1444 fs_node *node;
1445 struct stat st;
1446 status_t result;
1447 fs_file_cookie **cookie;
1448
1449 ns = _volume->private_volume;
1450 node = _node->private_node;
1451 cookie = (fs_file_cookie **)_cookie;
1452
1453 if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK)
1454 return result;
1455
1456 if (S_ISDIR(st.st_mode)) {
1457 /* permit opening of directories */
1458 if (conf_allow_dir_open) {
1459 *cookie = NULL;
1460 return B_OK;
1461 } else
1462 return EISDIR;
1463 }
1464
1465 *cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1466 (*cookie)->omode = omode;
1467 (*cookie)->original_size = st.st_size;
1468 (*cookie)->st = st;
1469
1470 return B_OK;
1471 }
1472
1473
1474 static status_t
fs_close(fs_volume * _volume,fs_vnode * _node,void * cookie)1475 fs_close(fs_volume *_volume, fs_vnode *_node, void *cookie)
1476 {
1477 (void) _volume;
1478 (void) _node;
1479 (void) cookie;
1480 /* //XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats
1481 if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY))
1482 return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL);
1483 */
1484 return B_OK;
1485 }
1486
1487
1488 static status_t
fs_free_cookie(fs_volume * _volume,fs_vnode * _node,void * cookie)1489 fs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie)
1490 {
1491 (void) _volume;
1492 (void) _node;
1493 free(cookie);
1494 return B_OK;
1495 }
1496
1497
1498 static status_t
fs_read(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,void * buf,size_t * len)1499 fs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
1500 void *buf, size_t *len)
1501 {
1502 fs_nspace *ns;
1503 fs_node *node;
1504 fs_file_cookie *cookie;
1505 size_t max = *len;
1506 *len = 0;
1507
1508 ns = _volume->private_volume;
1509 node = _node->private_node;
1510 cookie = (fs_file_cookie *)_cookie;
1511
1512 if (!cookie)
1513 return EISDIR; /* do not permit reading of directories */
1514
1515 while ((*len) < max) {
1516 size_t count = min_c(NFS_MAXDATA, max - (*len));
1517 struct XDROutPacket call;
1518 struct XDRInPacket reply;
1519 int32 status;
1520 uint8 *replyBuf;
1521 struct stat st;
1522 size_t readbytes;
1523
1524 XDROutPacketInit(&call);
1525 XDRInPacketInit(&reply);
1526
1527 XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE);
1528 XDROutPacketAddInt32(&call, pos);
1529 XDROutPacketAddInt32(&call, count);
1530 XDROutPacketAddInt32(&call, 0);
1531
1532 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1533 NFSPROC_READ, &call);
1534 if (replyBuf == NULL) {
1535 XDRInPacketDestroy(&reply);
1536 XDROutPacketDestroy(&call);
1537 return B_ERROR;
1538 }
1539
1540 XDRInPacketSetTo(&reply, replyBuf, 0);
1541
1542 if (!is_successful_reply(&reply)) {
1543 XDRInPacketDestroy(&reply);
1544 XDROutPacketDestroy(&call);
1545 return B_ERROR;
1546 }
1547
1548 status = XDRInPacketGetInt32(&reply);
1549 if (status != NFS_OK) {
1550 XDRInPacketDestroy(&reply);
1551 XDROutPacketDestroy(&call);
1552 return map_nfs_to_system_error(status);
1553 }
1554
1555 get_nfs_attr(&reply, &st);
1556 cookie->st = st;
1557
1558 status_t err = XDRInPacketGetDynamic(&reply, buf, &readbytes);
1559 if (err != B_OK)
1560 return err;
1561
1562 buf = (char *)buf + readbytes;
1563 (*len) += readbytes;
1564 pos += readbytes;
1565
1566 XDRInPacketDestroy(&reply);
1567 XDROutPacketDestroy(&call);
1568
1569 if (pos >= st.st_size)
1570 break;
1571 }
1572
1573 return B_OK;
1574 }
1575
1576
1577 static status_t
fs_write(fs_volume * _volume,fs_vnode * _node,void * _cookie,off_t pos,const void * buf,size_t * len)1578 fs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
1579 const void *buf, size_t *len)
1580 {
1581 fs_nspace *ns;
1582 fs_node *node;
1583 fs_file_cookie *cookie;
1584 size_t bytesWritten = 0;
1585
1586 ns = _volume->private_volume;
1587 node = _node->private_node;
1588 cookie = (fs_file_cookie *)_cookie;
1589
1590 if (!cookie)
1591 return EISDIR; /* do not permit reading of directories */
1592 if (cookie->omode & O_APPEND)
1593 pos += cookie->original_size;
1594
1595 while (bytesWritten < *len) {
1596 size_t count = min_c(NFS_MAXDATA,(*len) - bytesWritten);
1597
1598 struct XDROutPacket call;
1599 struct XDRInPacket reply;
1600 int32 status;
1601 uint8 *replyBuf;
1602 struct stat st;
1603
1604 XDROutPacketInit(&call);
1605 XDRInPacketInit(&reply);
1606
1607 XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE);
1608 XDROutPacketAddInt32(&call, 0);
1609 XDROutPacketAddInt32(&call, pos + bytesWritten);
1610 XDROutPacketAddInt32(&call, 0);
1611 status_t err = XDROutPacketAddDynamic(&call, (const char *)buf + bytesWritten, count);
1612 if (err != B_OK)
1613 return err;
1614
1615 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1616 NFSPROC_WRITE, &call);
1617
1618 if (!replyBuf) {
1619 XDRInPacketDestroy(&reply);
1620 XDROutPacketDestroy(&call);
1621 return B_ERROR;
1622 }
1623
1624 XDRInPacketSetTo(&reply, replyBuf, 0);
1625
1626 if (!is_successful_reply(&reply)) {
1627 XDRInPacketDestroy(&reply);
1628 XDROutPacketDestroy(&call);
1629 return B_ERROR;
1630 }
1631
1632 status = XDRInPacketGetInt32(&reply);
1633
1634 if (status != NFS_OK) {
1635 XDRInPacketDestroy(&reply);
1636 XDROutPacketDestroy(&call);
1637 return map_nfs_to_system_error(status);
1638 }
1639
1640 get_nfs_attr(&reply, &st);
1641
1642 cookie->st = st;
1643
1644 bytesWritten += count;
1645
1646 XDRInPacketDestroy(&reply);
1647 XDROutPacketDestroy(&call);
1648 }
1649
1650 return B_OK;
1651 }
1652
1653
1654 static status_t
fs_wstat(fs_volume * _volume,fs_vnode * _node,const struct stat * st,uint32 mask)1655 fs_wstat(fs_volume *_volume, fs_vnode *_node, const struct stat *st, uint32 mask)
1656 {
1657 fs_nspace *ns;
1658 fs_node *node;
1659 struct XDROutPacket call;
1660 struct XDRInPacket reply;
1661
1662 uint8 *replyBuf;
1663 int32 status;
1664
1665 ns = _volume->private_volume;
1666 node = _node->private_node;
1667
1668 XDROutPacketInit(&call);
1669 XDRInPacketInit(&reply);
1670
1671 XDROutPacketAddFixed(&call,node->fhandle.opaque,NFS_FHSIZE);
1672
1673 XDROutPacketAddInt32(&call, (mask & WSTAT_MODE) ? st->st_mode : UINT32_MAX);
1674 XDROutPacketAddInt32(&call, (mask & WSTAT_UID) ? st->st_uid : UINT32_MAX);
1675 XDROutPacketAddInt32(&call, (mask & WSTAT_GID) ? st->st_gid : UINT32_MAX);
1676 XDROutPacketAddInt32(&call, (mask & WSTAT_SIZE) ? st->st_size : UINT32_MAX);
1677 XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? st->st_atime : -1);
1678 XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? 0 : UINT32_MAX);
1679 XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? st->st_mtime : -1);
1680 XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? 0 : UINT32_MAX);
1681
1682 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1683 NFSPROC_SETATTR, &call);
1684
1685 if (!replyBuf) {
1686 XDRInPacketDestroy(&reply);
1687 XDROutPacketDestroy(&call);
1688 return EHOSTUNREACH;
1689 }
1690
1691 XDRInPacketSetTo(&reply, replyBuf, 0);
1692
1693 if (!is_successful_reply(&reply)) {
1694 XDRInPacketDestroy(&reply);
1695 XDROutPacketDestroy(&call);
1696 return B_ERROR;
1697 }
1698
1699 status = XDRInPacketGetInt32(&reply);
1700
1701 if (status != NFS_OK)
1702 return map_nfs_to_system_error(status);
1703
1704 XDRInPacketDestroy(&reply);
1705 XDROutPacketDestroy(&call);
1706
1707 return notify_stat_changed(_volume->id, -1, node->vnid, mask);
1708 }
1709
1710 static status_t
fs_wfsstat(fs_volume * _volume,const struct fs_info * info,uint32 mask)1711 fs_wfsstat(fs_volume *_volume, const struct fs_info *info, uint32 mask)
1712 {
1713 (void) _volume;
1714 (void) info;
1715 (void) mask;
1716 return B_OK;
1717 }
1718
1719 static status_t
fs_create(fs_volume * _volume,fs_vnode * _dir,const char * name,int omode,int perms,void ** _cookie,ino_t * vnid)1720 fs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int omode,
1721 int perms, void **_cookie, ino_t *vnid)
1722 {
1723 nfs_fhandle fhandle;
1724 struct stat st;
1725 fs_file_cookie **cookie;
1726
1727 fs_nspace *ns;
1728 fs_node *dir;
1729
1730 status_t result;
1731
1732 ns = _volume->private_volume;
1733 dir = _dir->private_node;
1734 cookie = (fs_file_cookie **)_cookie;
1735
1736 result = nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
1737
1738 if (result == B_OK) {
1739 void *dummy;
1740 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node));
1741 if (newNode == NULL)
1742 return B_NO_MEMORY;
1743
1744 newNode->fhandle = fhandle;
1745 newNode->vnid = st.st_ino;
1746 newNode->mode = st.st_mode;
1747 insert_node(ns, newNode);
1748
1749 *vnid = st.st_ino;
1750
1751 if ((result = get_vnode(_volume,*vnid,&dummy)) < B_OK)
1752 return result;
1753
1754 if (S_ISDIR(st.st_mode))
1755 return EISDIR;
1756
1757 if (omode & O_EXCL)
1758 return EEXIST;
1759
1760 if (omode & O_TRUNC)
1761 {
1762 if ((result = nfs_truncate_file(ns, &fhandle, NULL)) < B_OK)
1763 return result;
1764 }
1765
1766 *cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1767 if (*cookie == NULL)
1768 return B_NO_MEMORY;
1769
1770 (*cookie)->omode=omode;
1771 (*cookie)->original_size=st.st_size;
1772 (*cookie)->st=st;
1773
1774 return B_OK;
1775 } else if (result != ENOENT) {
1776 return result;
1777 } else {
1778 struct XDROutPacket call;
1779 struct XDRInPacket reply;
1780
1781 uint8 *replyBuf;
1782 int32 status;
1783
1784 fs_node *newNode;
1785
1786 if (!(omode & O_CREAT))
1787 return ENOENT;
1788
1789 XDROutPacketInit(&call);
1790 XDRInPacketInit(&reply);
1791
1792 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
1793 XDROutPacketAddString(&call, name);
1794 XDROutPacketAddInt32(&call, perms | S_IFREG);
1795 XDROutPacketAddInt32(&call, -1);
1796 XDROutPacketAddInt32(&call, -1);
1797 XDROutPacketAddInt32(&call, 0);
1798 XDROutPacketAddInt32(&call, time(NULL));
1799 XDROutPacketAddInt32(&call, 0);
1800 XDROutPacketAddInt32(&call, time(NULL));
1801 XDROutPacketAddInt32(&call, 0);
1802
1803 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1804 NFSPROC_CREATE, &call);
1805
1806 if (!replyBuf) {
1807 XDRInPacketDestroy(&reply);
1808 XDROutPacketDestroy(&call);
1809 return B_ERROR;
1810 }
1811
1812 XDRInPacketSetTo(&reply, replyBuf, 0);
1813
1814 if (!is_successful_reply(&reply)) {
1815 XDRInPacketDestroy(&reply);
1816 XDROutPacketDestroy(&call);
1817 return B_ERROR;
1818 }
1819
1820 status = XDRInPacketGetInt32(&reply);
1821
1822 if (status != NFS_OK) {
1823 XDRInPacketDestroy(&reply);
1824 XDROutPacketDestroy(&call);
1825 return map_nfs_to_system_error(status);
1826 }
1827
1828 status = XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE);
1829
1830 if (status != NFS_OK) {
1831 XDRInPacketDestroy(&reply);
1832 XDROutPacketDestroy(&call);
1833 return map_nfs_to_system_error(status);
1834 }
1835
1836 get_nfs_attr(&reply,&st);
1837
1838 newNode = (fs_node *)malloc(sizeof(fs_node));
1839 if (newNode == NULL) {
1840 XDRInPacketDestroy(&reply);
1841 XDROutPacketDestroy(&call);
1842 return B_NO_MEMORY;
1843 }
1844 newNode->fhandle = fhandle;
1845 newNode->vnid = st.st_ino;
1846 newNode->mode = st.st_mode;
1847
1848 insert_node (ns, newNode);
1849
1850 *vnid = st.st_ino;
1851 *cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1852 if (*cookie == NULL) {
1853 XDRInPacketDestroy(&reply);
1854 XDROutPacketDestroy(&call);
1855 return B_NO_MEMORY;
1856 }
1857 (*cookie)->omode = omode;
1858 (*cookie)->original_size = st.st_size;
1859 (*cookie)->st = st;
1860
1861 result = publish_vnode(_volume, *vnid, newNode, &sNFSVnodeOps,
1862 S_IFREG, 0);
1863 if (result < B_OK) {
1864 XDRInPacketDestroy(&reply);
1865 XDROutPacketDestroy(&call);
1866 return result;
1867 }
1868
1869 XDRInPacketDestroy(&reply);
1870 XDROutPacketDestroy(&call);
1871 return notify_entry_created(_volume->id, dir->vnid, name, *vnid);
1872 }
1873 }
1874
1875
1876 static status_t
fs_unlink(fs_volume * _volume,fs_vnode * _dir,const char * name)1877 fs_unlink(fs_volume *_volume, fs_vnode *_dir, const char *name)
1878 {
1879 status_t result;
1880 fs_nspace *ns;
1881 fs_node *dir;
1882 fs_node *newNode;
1883 fs_node *dummy;
1884
1885 struct XDROutPacket call;
1886 struct XDRInPacket reply;
1887
1888 struct stat st;
1889 nfs_fhandle fhandle;
1890 uint8 *replyBuf;
1891
1892 int32 status;
1893
1894 ns = _volume->private_volume;
1895 dir = _dir->private_node;
1896
1897 XDROutPacketInit(&call);
1898 XDRInPacketInit(&reply);
1899
1900 if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) {
1901 XDRInPacketDestroy(&reply);
1902 XDROutPacketDestroy(&call);
1903 return result;
1904 }
1905
1906 newNode = (fs_node *)malloc(sizeof(fs_node));
1907 if (newNode == NULL) {
1908 XDRInPacketDestroy(&reply);
1909 XDROutPacketDestroy(&call);
1910 return B_NO_MEMORY;
1911 }
1912 newNode->fhandle = fhandle;
1913 newNode->vnid = st.st_ino;
1914 newNode->mode = st.st_mode;
1915
1916 insert_node(ns, newNode);
1917
1918 if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) {
1919 XDRInPacketDestroy(&reply);
1920 XDROutPacketDestroy(&call);
1921 return result;
1922 }
1923
1924 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1925 XDRInPacketDestroy(&reply);
1926 XDROutPacketDestroy(&call);
1927 return EISDIR;
1928 }
1929
1930 if ((result=remove_vnode(_volume,st.st_ino)) < B_OK) {
1931 XDRInPacketDestroy(&reply);
1932 XDROutPacketDestroy(&call);
1933 return result;
1934 }
1935
1936 if ((result=put_vnode(_volume, st.st_ino)) < B_OK) {
1937 XDRInPacketDestroy(&reply);
1938 XDROutPacketDestroy(&call);
1939 return result;
1940 }
1941
1942 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
1943 XDROutPacketAddString(&call, name);
1944
1945 replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call);
1946
1947 if (!replyBuf) {
1948 XDRInPacketDestroy(&reply);
1949 XDROutPacketDestroy(&call);
1950 return EHOSTUNREACH;
1951 }
1952
1953 XDRInPacketSetTo(&reply, replyBuf, 0);
1954
1955 if (!is_successful_reply(&reply)) {
1956 XDRInPacketDestroy(&reply);
1957 XDROutPacketDestroy(&call);
1958 return B_ERROR;
1959 }
1960
1961 status = XDRInPacketGetInt32(&reply);
1962
1963 if (status != NFS_OK) {
1964 XDRInPacketDestroy(&reply);
1965 XDROutPacketDestroy(&call);
1966 return map_nfs_to_system_error(status);
1967 }
1968
1969 XDRInPacketDestroy(&reply);
1970 XDROutPacketDestroy(&call);
1971
1972 return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino);
1973 }
1974
1975
1976 static status_t
fs_remove_vnode(fs_volume * _volume,fs_vnode * _node,bool r)1977 fs_remove_vnode(fs_volume *_volume, fs_vnode *_node, bool r)
1978 {
1979 fs_nspace *ns = _volume->private_volume;
1980 fs_node *node = _node->private_node;
1981
1982 (void) r;
1983
1984 remove_node (ns, node->vnid);
1985
1986 return B_OK;
1987 }
1988
1989
1990 static status_t
fs_mkdir(fs_volume * _volume,fs_vnode * _dir,const char * name,int perms)1991 fs_mkdir(fs_volume *_volume, fs_vnode *_dir, const char *name, int perms)
1992 {
1993 fs_nspace *ns;
1994 fs_node *dir;
1995
1996 nfs_fhandle fhandle;
1997 struct stat st;
1998 fs_node *newNode;
1999
2000 status_t result;
2001 uint8 *replyBuf;
2002 int32 status;
2003
2004 struct XDROutPacket call;
2005 struct XDRInPacket reply;
2006
2007 ns = _volume->private_volume;
2008 dir = _dir->private_node;
2009
2010 XDROutPacketInit(&call);
2011 XDRInPacketInit(&reply);
2012
2013 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st);
2014
2015 if (result == B_OK) {
2016 //void *dummy;
2017
2018 XDRInPacketDestroy(&reply);
2019 XDROutPacketDestroy(&call);
2020 // XXX: either OK or not get_vnode !!! ??
2021 //if ((result=get_vnode(_volume,st.st_ino,&dummy))<B_OK)
2022 // return result;
2023 return EEXIST;
2024 } else if (result != ENOENT) {
2025 XDRInPacketDestroy(&reply);
2026 XDROutPacketDestroy(&call);
2027 return result;
2028 }
2029
2030 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
2031 XDROutPacketAddString(&call, name);
2032 XDROutPacketAddInt32(&call, perms | S_IFDIR);
2033 XDROutPacketAddInt32(&call, -1);
2034 XDROutPacketAddInt32(&call, -1);
2035 XDROutPacketAddInt32(&call, -1);
2036 XDROutPacketAddInt32(&call, time(NULL));
2037 XDROutPacketAddInt32(&call, 0);
2038 XDROutPacketAddInt32(&call, time(NULL));
2039 XDROutPacketAddInt32(&call, 0);
2040
2041 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2042 NFSPROC_MKDIR, &call);
2043
2044 if (!replyBuf) {
2045 XDRInPacketDestroy(&reply);
2046 XDROutPacketDestroy(&call);
2047 return B_ERROR;
2048 }
2049
2050 XDRInPacketSetTo(&reply, replyBuf, 0);
2051
2052 if (!is_successful_reply(&reply)) {
2053 XDRInPacketDestroy(&reply);
2054 XDROutPacketDestroy(&call);
2055 return B_ERROR;
2056 }
2057
2058 status = XDRInPacketGetInt32(&reply);
2059
2060 if (status != NFS_OK) {
2061 XDROutPacketDestroy(&call);
2062 return map_nfs_to_system_error(status);
2063 }
2064
2065 status = XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE);
2066
2067 if (status != NFS_OK) {
2068 XDROutPacketDestroy(&call);
2069 return map_nfs_to_system_error(status);
2070 }
2071
2072 get_nfs_attr(&reply, &st);
2073
2074 newNode=(fs_node *)malloc(sizeof(fs_node));
2075 if (newNode == NULL) {
2076 XDRInPacketDestroy(&reply);
2077 XDROutPacketDestroy(&call);
2078 return B_NO_MEMORY;
2079 }
2080 newNode->fhandle = fhandle;
2081 newNode->vnid = st.st_ino;
2082 newNode->mode = st.st_mode;
2083
2084 insert_node(ns, newNode);
2085
2086 XDRInPacketDestroy(&reply);
2087 XDROutPacketDestroy(&call);
2088
2089 return notify_entry_created(_volume->id, dir->vnid, name, st.st_ino);
2090 }
2091
2092 static status_t
fs_rename(fs_volume * _volume,fs_vnode * _olddir,const char * oldname,fs_vnode * _newdir,const char * newname)2093 fs_rename(fs_volume *_volume, fs_vnode *_olddir, const char *oldname,
2094 fs_vnode *_newdir, const char *newname)
2095 {
2096 struct stat st;
2097 nfs_fhandle fhandle;
2098 status_t result;
2099 struct XDROutPacket call;
2100 struct XDRInPacket reply;
2101 int32 status;
2102 uint8 *replyBuf;
2103 fs_nspace *ns;
2104 fs_node *olddir;
2105 fs_node *newdir;
2106
2107 ns = _volume->private_volume;
2108 olddir = _olddir->private_node;
2109 newdir = _newdir->private_node;
2110
2111 XDROutPacketInit(&call);
2112 XDRInPacketInit(&reply);
2113
2114 if ((result = nfs_lookup(ns, &newdir->fhandle, newname, &fhandle, &st))
2115 == B_OK) {
2116 if (S_ISREG(st.st_mode))
2117 result = fs_unlink (_volume,_newdir,newname);
2118 else
2119 result = fs_rmdir (_volume,_newdir,newname);
2120
2121 if (result < B_OK) {
2122 XDRInPacketDestroy (&reply);
2123 XDROutPacketDestroy (&call);
2124 return result;
2125 }
2126 }
2127
2128 if ((result = nfs_lookup(ns, &olddir->fhandle, oldname, &fhandle, &st))
2129 < B_OK) {
2130 XDRInPacketDestroy(&reply);
2131 XDROutPacketDestroy(&call);
2132 return result;
2133 }
2134
2135 XDROutPacketAddFixed(&call, olddir->fhandle.opaque, NFS_FHSIZE);
2136 XDROutPacketAddString(&call, oldname);
2137 XDROutPacketAddFixed(&call, newdir->fhandle.opaque, NFS_FHSIZE);
2138 XDROutPacketAddString(&call, newname);
2139
2140 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2141 NFSPROC_RENAME, &call);
2142
2143 if (!replyBuf) {
2144 XDRInPacketDestroy(&reply);
2145 XDROutPacketDestroy(&call);
2146 return EHOSTUNREACH;
2147 }
2148
2149 XDRInPacketSetTo(&reply, replyBuf, 0);
2150
2151 if (!is_successful_reply(&reply)) {
2152 XDRInPacketDestroy(&reply);
2153 XDROutPacketDestroy(&call);
2154 return B_ERROR;
2155 }
2156
2157 status = XDRInPacketGetInt32(&reply);
2158
2159 if (status != NFS_OK) {
2160 XDRInPacketDestroy(&reply);
2161 XDROutPacketDestroy(&call);
2162 return map_nfs_to_system_error(status);
2163 }
2164
2165 XDRInPacketDestroy (&reply);
2166 XDROutPacketDestroy (&call);
2167
2168 return notify_entry_moved(_volume->id, olddir->vnid, oldname, newdir->vnid,
2169 newname, st.st_ino);
2170 }
2171
2172
2173 static status_t
fs_rmdir(fs_volume * _volume,fs_vnode * _dir,const char * name)2174 fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name)
2175 {
2176 fs_nspace *ns;
2177 fs_node *dir;
2178
2179 status_t result;
2180 fs_node *newNode;
2181 fs_node *dummy;
2182 struct XDROutPacket call;
2183 struct XDRInPacket reply;
2184 int32 status;
2185 uint8 *replyBuf;
2186
2187 struct stat st;
2188 nfs_fhandle fhandle;
2189
2190 ns = _volume->private_volume;
2191 dir = _dir->private_node;
2192
2193 XDROutPacketInit(&call);
2194 XDRInPacketInit(&reply);
2195
2196 if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) {
2197 XDRInPacketDestroy(&reply);
2198 XDROutPacketDestroy(&call);
2199 return result;
2200 }
2201
2202 newNode = (fs_node *)malloc(sizeof(fs_node));
2203 if (newNode == NULL) {
2204 XDRInPacketDestroy(&reply);
2205 XDROutPacketDestroy(&call);
2206 return B_NO_MEMORY;
2207 }
2208 newNode->fhandle = fhandle;
2209 newNode->vnid = st.st_ino;
2210 newNode->mode = st.st_mode;
2211
2212 insert_node(ns, newNode);
2213
2214 if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) {
2215 XDRInPacketDestroy(&reply);
2216 XDROutPacketDestroy(&call);
2217 return result;
2218 }
2219
2220 if (!S_ISDIR(st.st_mode)) {
2221 XDRInPacketDestroy(&reply);
2222 XDROutPacketDestroy(&call);
2223 return ENOTDIR;
2224 }
2225
2226 if ((result = remove_vnode(_volume, st.st_ino)) < B_OK) {
2227 XDRInPacketDestroy(&reply);
2228 XDROutPacketDestroy(&call);
2229 return result;
2230 }
2231
2232 if ((result = put_vnode(_volume, st.st_ino)) < B_OK) {
2233 XDRInPacketDestroy(&reply);
2234 XDROutPacketDestroy(&call);
2235 return result;
2236 }
2237
2238 XDROutPacketAddFixed (&call, dir->fhandle.opaque, NFS_FHSIZE);
2239 XDROutPacketAddString(&call, name);
2240
2241 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2242 NFSPROC_RMDIR, &call);
2243
2244 if (!replyBuf) {
2245 XDRInPacketDestroy(&reply);
2246 XDROutPacketDestroy(&call);
2247 return EHOSTUNREACH;
2248 }
2249
2250 XDRInPacketSetTo (&reply,replyBuf,0);
2251
2252 if (!is_successful_reply(&reply)) {
2253 XDRInPacketDestroy(&reply);
2254 XDROutPacketDestroy(&call);
2255 return B_ERROR;
2256 }
2257
2258 status = XDRInPacketGetInt32(&reply);
2259
2260 if (status != NFS_OK) {
2261 XDRInPacketDestroy(&reply);
2262 XDROutPacketDestroy(&call);
2263 return map_nfs_to_system_error(status);
2264 }
2265
2266 XDRInPacketDestroy(&reply);
2267 XDROutPacketDestroy(&call);
2268 return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino);
2269 }
2270
2271
2272 static status_t
fs_readlink(fs_volume * _volume,fs_vnode * _node,char * buf,size_t * bufsize)2273 fs_readlink(fs_volume *_volume, fs_vnode *_node, char *buf, size_t *bufsize)
2274 {
2275 struct XDROutPacket call;
2276 uint8 *replyBuf;
2277 int32 status;
2278 size_t length;
2279 char data[NFS_MAXPATHLEN];
2280 struct XDRInPacket reply;
2281 fs_nspace *ns;
2282 fs_node *node;
2283
2284 ns = _volume->private_volume;
2285 node = _node->private_node;
2286
2287 XDROutPacketInit(&call);
2288 XDRInPacketInit(&reply);
2289
2290 XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE);
2291
2292 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2293 NFSPROC_READLINK, &call);
2294
2295 if (!replyBuf) {
2296 XDRInPacketDestroy(&reply);
2297 XDROutPacketDestroy(&call);
2298 return EHOSTUNREACH;
2299 }
2300
2301 XDRInPacketSetTo (&reply, replyBuf, 0);
2302
2303 if (!is_successful_reply(&reply)) {
2304 XDRInPacketDestroy(&reply);
2305 XDROutPacketDestroy(&call);
2306 return B_ERROR;
2307 }
2308
2309 status = XDRInPacketGetInt32(&reply);
2310
2311 if (status != NFS_OK) {
2312 XDRInPacketDestroy(&reply);
2313 XDROutPacketDestroy (&call);
2314 return map_nfs_to_system_error(status);
2315 }
2316
2317 XDRInPacketGetDynamic(&reply, data, &length);
2318
2319 memcpy(buf, data, min_c(length, *bufsize));
2320 *bufsize = length;
2321
2322 XDRInPacketDestroy(&reply);
2323 XDROutPacketDestroy(&call);
2324 return B_OK;
2325 }
2326
2327 static status_t
fs_symlink(fs_volume * _volume,fs_vnode * _dir,const char * name,const char * path,int mode)2328 fs_symlink(fs_volume *_volume, fs_vnode *_dir, const char *name,
2329 const char *path, int mode)
2330 {
2331 fs_nspace *ns;
2332 fs_node *dir;
2333 nfs_fhandle fhandle;
2334 struct stat st;
2335 struct XDROutPacket call;
2336 struct XDRInPacket reply;
2337 status_t result;
2338 uint8 *replyBuf;
2339 int32 status;
2340 fs_node *newNode;
2341
2342 ns = _volume->private_volume;
2343 dir = _dir->private_node;
2344
2345 XDROutPacketInit(&call);
2346 XDRInPacketInit(&reply);
2347
2348 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st);
2349
2350 if (result == B_OK) {
2351 void *dummy;
2352 if ((result = get_vnode(_volume, st.st_ino, &dummy)) < B_OK)
2353 return result;
2354
2355 XDRInPacketDestroy(&reply);
2356 XDROutPacketDestroy(&call);
2357 return EEXIST;
2358 } else if (result != ENOENT) {
2359 XDRInPacketDestroy(&reply);
2360 XDROutPacketDestroy(&call);
2361 return result;
2362 }
2363
2364 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
2365 XDROutPacketAddString(&call, name);
2366 XDROutPacketAddString(&call, path);
2367 XDROutPacketAddInt32(&call, S_IFLNK);
2368 XDROutPacketAddInt32(&call, -1);
2369 XDROutPacketAddInt32(&call, -1);
2370 XDROutPacketAddInt32(&call, -1);
2371 XDROutPacketAddInt32(&call, time(NULL));
2372 XDROutPacketAddInt32(&call, 0);
2373 XDROutPacketAddInt32(&call, time(NULL));
2374 XDROutPacketAddInt32(&call, 0);
2375
2376 replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2377 NFSPROC_SYMLINK, &call);
2378
2379 if (!replyBuf) {
2380 XDRInPacketDestroy(&reply);
2381 XDROutPacketDestroy(&call);
2382 return B_ERROR;
2383 }
2384
2385 XDRInPacketSetTo(&reply, replyBuf, 0);
2386
2387 if (!is_successful_reply(&reply)) {
2388 XDRInPacketDestroy(&reply);
2389 XDROutPacketDestroy(&call);
2390 return B_ERROR;
2391 }
2392
2393 status = XDRInPacketGetInt32(&reply);
2394 /* if (status!=NFS_OK)
2395 return map_nfs_to_system_error(status);
2396
2397 ignore status here, weird thing, nfsservers that is
2398 */
2399 (void)status;
2400
2401 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st);
2402
2403 if (result < B_OK) {
2404 XDRInPacketDestroy(&reply);
2405 XDROutPacketDestroy(&call);
2406 return result;
2407 }
2408
2409 newNode = (fs_node *)malloc(sizeof(fs_node));
2410 if (newNode == NULL) {
2411 XDRInPacketDestroy(&reply);
2412 XDROutPacketDestroy(&call);
2413 return B_NO_MEMORY;
2414 }
2415 newNode->fhandle = fhandle;
2416 newNode->vnid = st.st_ino;
2417
2418 insert_node(ns, newNode);
2419
2420 result = notify_entry_created (_volume->id, dir->vnid, name, st.st_ino);
2421
2422 XDRInPacketDestroy(&reply);
2423 XDROutPacketDestroy(&call);
2424 return result;
2425 }
2426
2427
2428 static status_t
fs_access(fs_volume * _volume,fs_vnode * node,int mode)2429 fs_access(fs_volume *_volume, fs_vnode *node, int mode)
2430 {
2431 (void) _volume;
2432 (void) node;
2433 (void) mode;
2434 /* XXX */
2435 return B_OK;
2436 }
2437
2438
2439 static status_t
nfs_std_ops(int32 op,...)2440 nfs_std_ops(int32 op, ...)
2441 {
2442 switch (op) {
2443 case B_MODULE_INIT:
2444 return B_OK;
2445 case B_MODULE_UNINIT:
2446 return B_OK;
2447
2448 default:
2449 return B_ERROR;
2450 }
2451 }
2452
2453
2454 fs_volume_ops sNFSVolumeOps = {
2455 &fs_unmount,
2456 &fs_rfsstat,
2457 &fs_wfsstat,
2458 NULL, // no sync!
2459 &fs_read_vnode,
2460
2461 /* index directory & index operations */
2462 NULL, // &fs_open_index_dir
2463 NULL, // &fs_close_index_dir
2464 NULL, // &fs_free_index_dir_cookie
2465 NULL, // &fs_read_index_dir
2466 NULL, // &fs_rewind_index_dir
2467
2468 NULL, // &fs_create_index
2469 NULL, // &fs_remove_index
2470 NULL, // &fs_stat_index
2471
2472 /* query operations */
2473 NULL, // &fs_open_query,
2474 NULL, // &fs_close_query,
2475 NULL, // &fs_free_query_cookie,
2476 NULL, // &fs_read_query,
2477 NULL, // &fs_rewind_query,
2478 };
2479
2480
2481 fs_vnode_ops sNFSVnodeOps = {
2482 /* vnode operations */
2483 &fs_walk,
2484 NULL, // fs_get_vnode_name
2485 &fs_release_vnode,
2486 &fs_remove_vnode,
2487
2488 /* VM file access */
2489 NULL, // &fs_can_page
2490 NULL, // &fs_read_pages
2491 NULL, // &fs_write_pages
2492
2493 NULL, // io()
2494 NULL, // cancel_io()
2495
2496 NULL, // &fs_get_file_map,
2497
2498 NULL, // &fs_ioctl
2499 NULL, // &fs_setflags,
2500 NULL, // &fs_select
2501 NULL, // &fs_deselect
2502 NULL, // &fs_fsync
2503
2504 &fs_readlink,
2505 &fs_symlink,
2506
2507 NULL, // &fs_link,
2508 &fs_unlink,
2509 &fs_rename,
2510
2511 &fs_access,
2512 &fs_rstat,
2513 &fs_wstat,
2514 NULL, // fs_preallocate()
2515
2516 /* file operations */
2517 &fs_create,
2518 &fs_open,
2519 &fs_close,
2520 &fs_free_cookie,
2521 &fs_read,
2522 &fs_write,
2523
2524 /* directory operations */
2525 &fs_mkdir,
2526 &fs_rmdir,
2527 &fs_opendir,
2528 &fs_closedir,
2529 &fs_free_dircookie,
2530 &fs_readdir,
2531 &fs_rewinddir,
2532
2533 /* attribute directory operations */
2534 NULL, // &fs_open_attrdir,
2535 NULL, // &fs_close_attrdir,
2536 NULL, // &fs_free_attrdircookie,
2537 NULL, // &fs_read_attrdir,
2538 NULL, // &fs_rewind_attrdir,
2539
2540 /* attribute operations */
2541 NULL, // &fs_create_attr
2542 NULL, // &fs_open_attr_h,
2543 NULL, // &fs_close_attr_h,
2544 NULL, // &fs_free_attr_cookie_h,
2545 NULL, // &fs_read_attr_h,
2546 NULL, // &fs_write_attr_h,
2547
2548 NULL, // &fs_read_attr_stat_h,
2549 NULL, // &fs_write_attr_stat
2550 NULL, // &fs_rename_attr
2551 NULL, // &fs_remove_attr
2552 };
2553
2554 file_system_module_info sNFSFileSystem = {
2555 {
2556 "file_systems/nfs" B_CURRENT_FS_API_VERSION,
2557 0,
2558 nfs_std_ops,
2559 },
2560 "nfs", // short name
2561 "Network File System v2", // pretty name
2562 B_DISK_SYSTEM_SUPPORTS_WRITING, // DDM flags
2563
2564 // scanning
2565 NULL, // fs_identify_partition,
2566 NULL, // fs_scan_partition,
2567 NULL, // fs_free_identify_partition_cookie,
2568 NULL, // free_partition_content_cookie()
2569
2570 &fs_mount,
2571 };
2572
2573 module_info *modules[] = {
2574 (module_info *)&sNFSFileSystem,
2575 NULL,
2576 };
2577