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