xref: /haiku/src/add-ons/kernel/file_systems/nfs/nfs_add_on.c (revision 9918c8295480d70f55fafb98008e23109b598871)
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 		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 *
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
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 = 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 (%" B_PRId32 ",%" B_PRId32 ")",
403 				low, high);
404 		} else if (acceptStat != RPC_SUCCESS)
405 			dprintf("nfs: Accepted but failed (%d)", acceptStat);
406 		else
407 			success = true;
408 	}
409 
410 	return success;
411 }
412 
413 
414 status_t
415 get_remote_address(fs_nspace *ns, int32 prog, int32 vers, int32 prot,
416 	struct sockaddr_in *addr)
417 {
418 	struct XDROutPacket call;
419 	uint8 *replyBuf;
420 
421 	XDROutPacketInit(&call);
422 
423 	addr->sin_port = htons(PMAP_PORT);
424 
425 	XDROutPacketAddInt32(&call, prog);
426 	XDROutPacketAddInt32(&call, vers);
427 	XDROutPacketAddInt32(&call, prot);
428 	XDROutPacketAddInt32(&call, 0);
429 
430 	replyBuf = send_rpc_call(ns, addr, PMAP_PROGRAM, PMAP_VERSION,
431 		PMAPPROC_GETPORT, &call);
432 
433 	if (replyBuf) {
434 		struct XDRInPacket reply;
435 		XDRInPacketInit(&reply);
436 
437 		XDRInPacketSetTo(&reply,replyBuf,0);
438 
439 		if (is_successful_reply(&reply)) {
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
456 nfs_mount(fs_nspace *ns, const char *path, nfs_fhandle *fhandle)
457 {
458 	struct XDROutPacket call;
459 	struct XDRInPacket reply;
460 	uint8 *replyBuf;
461 	int32 fhstatus;
462 
463 	XDROutPacketInit(&call);
464 	XDRInPacketInit(&reply);
465 
466 	XDROutPacketAddString(&call,path);
467 
468 	replyBuf = send_rpc_call(ns, &ns->mountAddr, MOUNT_PROGRAM, MOUNT_VERSION,
469 		MOUNTPROC_MNT, &call);
470 
471 	if (!replyBuf) {
472 		XDRInPacketDestroy(&reply);
473 		XDROutPacketDestroy(&call);
474 		return EHOSTUNREACH;
475 	}
476 
477 	XDRInPacketSetTo(&reply, replyBuf, 0);
478 
479 	if (!is_successful_reply(&reply)) {
480 		XDRInPacketDestroy(&reply);
481 		XDROutPacketDestroy(&call);
482 		return B_ERROR;
483 	}
484 
485 	fhstatus = XDRInPacketGetInt32(&reply);
486 
487 	if (fhstatus != NFS_OK) {
488 		XDRInPacketDestroy(&reply);
489 		XDROutPacketDestroy(&call);
490 		return map_nfs_to_system_error(fhstatus);
491 	}
492 
493 	fhstatus = XDRInPacketGetFixed(&reply, fhandle->opaque, NFS_FHSIZE);
494 
495 	XDRInPacketDestroy(&reply);
496 	XDROutPacketDestroy(&call);
497 
498 	return map_nfs_to_system_error(fhstatus);
499 }
500 
501 
502 status_t
503 nfs_lookup (fs_nspace *ns, const nfs_fhandle *dir, const char *filename,
504 	nfs_fhandle *fhandle, struct stat *st)
505 {
506 	struct XDROutPacket call;
507 	struct XDRInPacket reply;
508 	int32 status;
509 	uint8 *replyBuf;
510 
511 	XDROutPacketInit(&call);
512 	XDRInPacketInit(&reply);
513 
514 	XDROutPacketAddFixed(&call, dir->opaque, NFS_FHSIZE);
515 	XDROutPacketAddString(&call, filename);
516 
517 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
518 		NFSPROC_LOOKUP, &call);
519 
520 	if (!replyBuf) {
521 		XDRInPacketDestroy(&reply);
522 		XDROutPacketDestroy(&call);
523 		return EHOSTUNREACH;
524 	}
525 
526 	XDRInPacketSetTo(&reply, replyBuf, 0);
527 
528 	if (!is_successful_reply(&reply)) {
529 		XDRInPacketDestroy(&reply);
530 		XDROutPacketDestroy(&call);
531 		return B_ERROR;
532 	}
533 
534 	status = XDRInPacketGetInt32(&reply);
535 
536 	if (status != NFS_OK) {
537 		XDRInPacketDestroy(&reply);
538 		XDROutPacketDestroy(&call);
539 		return map_nfs_to_system_error(status);
540 	}
541 
542 	status = XDRInPacketGetFixed(&reply, fhandle->opaque, NFS_FHSIZE);
543 
544 	if (status != NFS_OK) {
545 		XDRInPacketDestroy(&reply);
546 		XDROutPacketDestroy(&call);
547 		return map_nfs_to_system_error(status);
548 	}
549 
550 	if (st)
551 		get_nfs_attr(&reply, st);
552 
553 	XDRInPacketDestroy(&reply);
554 	XDROutPacketDestroy(&call);
555 	return B_OK;
556 }
557 
558 
559 status_t
560 nfs_getattr(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
561 {
562 	struct XDROutPacket call;
563 	struct XDRInPacket reply;
564 	uint8 *replyBuf;
565 	int32 status;
566 
567 	XDROutPacketInit(&call);
568 	XDRInPacketInit(&reply);
569 
570 	XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE);
571 
572 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
573 		NFSPROC_GETATTR, &call);
574 	if (replyBuf == NULL) {
575 		XDRInPacketDestroy(&reply);
576 		XDROutPacketDestroy(&call);
577 		return EHOSTUNREACH;
578 	}
579 
580 	XDRInPacketSetTo(&reply, replyBuf, 0);
581 
582 	if (!is_successful_reply(&reply)) {
583 		XDRInPacketDestroy(&reply);
584 		XDROutPacketDestroy(&call);
585 		return B_ERROR;
586 	}
587 
588 	status = XDRInPacketGetInt32(&reply);
589 	if (status != NFS_OK) {
590 		XDRInPacketDestroy(&reply);
591 		XDROutPacketDestroy(&call);
592 		return map_nfs_to_system_error(status);
593 	}
594 
595 	get_nfs_attr(&reply, st);
596 
597 	XDRInPacketDestroy(&reply);
598 	XDROutPacketDestroy(&call);
599 	return B_OK;
600 }
601 
602 
603 status_t
604 nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st)
605 {
606 	struct XDROutPacket call;
607 	struct XDRInPacket reply;
608 	uint8 *replyBuf;
609 	int32 status;
610 
611 	XDROutPacketInit(&call);
612 	XDRInPacketInit(&reply);
613 
614 	XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE);
615 
616 	XDROutPacketAddInt32(&call, -1);
617 	XDROutPacketAddInt32(&call, -1);
618 	XDROutPacketAddInt32(&call, -1);
619 	XDROutPacketAddInt32(&call, 0);
620 	XDROutPacketAddInt32(&call, time(NULL));
621 	XDROutPacketAddInt32(&call, 0);
622 	XDROutPacketAddInt32(&call, time(NULL));
623 	XDROutPacketAddInt32(&call, 0);
624 
625 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
626 		NFSPROC_SETATTR, &call);
627 	if (replyBuf == NULL) {
628 		XDRInPacketDestroy(&reply);
629 		XDROutPacketDestroy(&call);
630 		return EHOSTUNREACH;
631 	}
632 
633 	XDRInPacketSetTo(&reply, replyBuf, 0);
634 
635 	if (!is_successful_reply(&reply)) {
636 		XDRInPacketDestroy(&reply);
637 		XDROutPacketDestroy(&call);
638 		return B_ERROR;
639 	}
640 
641 	status = XDRInPacketGetInt32(&reply);
642 	if (status != NFS_OK) {
643 		XDRInPacketDestroy(&reply);
644 		XDROutPacketDestroy(&call);
645 		return map_nfs_to_system_error(status);
646 	}
647 
648 	if (st)
649 		get_nfs_attr(&reply,st);
650 
651 	XDRInPacketDestroy(&reply);
652 	XDROutPacketDestroy(&call);
653 	return B_OK;
654 }
655 
656 
657 void
658 get_nfs_attr(struct XDRInPacket *reply, struct stat *st)
659 {
660 	nfs_ftype ftype=(nfs_ftype)XDRInPacketGetInt32(reply);
661 	(void) ftype;
662 	st->st_mode=XDRInPacketGetInt32(reply);
663 
664 	st->st_dev=0;	// just to be sure
665 	st->st_nlink=XDRInPacketGetInt32(reply);
666 	st->st_uid=XDRInPacketGetInt32(reply);
667 	st->st_gid=XDRInPacketGetInt32(reply);
668 	st->st_size=XDRInPacketGetInt32(reply);
669 	st->st_blksize=XDRInPacketGetInt32(reply);
670 	st->st_rdev=XDRInPacketGetInt32(reply);
671 	st->st_blocks=XDRInPacketGetInt32(reply);
672 	XDRInPacketGetInt32(reply);	// fsid
673 	st->st_ino=XDRInPacketGetInt32(reply);
674 	st->st_atime=XDRInPacketGetInt32(reply);
675 	XDRInPacketGetInt32(reply);	// usecs
676 	st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply);
677 	XDRInPacketGetInt32(reply);	// usecs
678 	st->st_ctime=XDRInPacketGetInt32(reply);
679 	XDRInPacketGetInt32(reply);	// usecs
680 }
681 
682 
683 status_t
684 map_nfs_to_system_error(status_t nfsstatus)
685 {
686 	switch (nfsstatus) {
687 		case NFS_OK:
688 			return B_OK;
689 
690 		case NFSERR_PERM:
691 			return EPERM;
692 
693 		case NFSERR_NOENT:
694 			return ENOENT;
695 
696 		case NFSERR_IO:
697 			return EIO;
698 
699 		case NFSERR_NXIO:
700 			return ENXIO;
701 
702 		case NFSERR_ACCES:
703 			return EACCES;
704 
705 		case NFSERR_EXIST:
706 			return EEXIST;
707 
708 		case NFSERR_NODEV:
709 			return ENODEV;
710 
711 		case NFSERR_NOTDIR:
712 			return ENOTDIR;
713 
714 		case NFSERR_ISDIR:
715 			return EISDIR;
716 
717 		case NFSERR_FBIG:
718 			return EFBIG;
719 
720 		case NFSERR_NOSPC:
721 			return ENOSPC;
722 
723 		case NFSERR_ROFS:
724 			return EROFS;
725 
726 		case NFSERR_NAMETOOLONG:
727 			return ENAMETOOLONG;
728 
729 		case NFSERR_NOTEMPTY:
730 			return ENOTEMPTY;
731 
732 		case NFSERR_STALE:
733 			return C_ERROR_STALE;
734 
735 		default:
736 			return B_ERROR;
737 	}
738 }
739 
740 
741 nfs_fhandle
742 handle_from_vnid(fs_nspace *ns, ino_t vnid)
743 {
744 	fs_node *current;
745 
746 	while (acquire_sem(ns->sem) == B_INTERRUPTED);
747 
748 	current = ns->first;
749 
750 	while (current != NULL && current->vnid != vnid)
751 		current = current->next;
752 
753 	while (release_sem(ns->sem) == B_INTERRUPTED);
754 
755 	return current->fhandle;
756 }
757 
758 
759 void
760 insert_node(fs_nspace *ns, fs_node *node)
761 {
762 	fs_node *current;
763 
764 	while (acquire_sem(ns->sem) == B_INTERRUPTED);
765 
766 	current = ns->first;
767 
768 	while (current != NULL && current->vnid != node->vnid)
769 		current = current->next;
770 
771 	if (current) {
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 	fs_nspace *ns;
821 	fs_node *current;
822 
823 	ns = _volume->private_volume;
824 
825 	if (!r) {
826 		while (acquire_sem(ns->sem) == B_INTERRUPTED);
827 	}
828 
829 	current = ns->first;
830 
831 	while (current != NULL && current->vnid != vnid)
832 		current = current->next;
833 
834 	if (!current)
835 		return EINVAL;
836 
837 	current->vnid = vnid;
838 	_node->private_node = current;
839 	_node->ops = &sNFSVnodeOps;
840 	*_type = current->mode;
841 	*_flags = 0;
842 
843 	if (!r) {
844 		while (release_sem(ns->sem) == B_INTERRUPTED);
845 	}
846 
847 	return B_OK;
848 }
849 
850 
851 static status_t
852 fs_release_vnode(fs_volume *_volume, fs_vnode *node, bool r)
853 {
854 	(void) _volume;
855 	(void) node;
856 	(void) r;
857 	return B_OK;
858 }
859 
860 
861 static status_t
862 fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid)
863 {
864 	fs_node *dummy;
865 	status_t result;
866 	fs_nspace *ns;
867 	fs_node *base;
868 	//dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug
869 
870 	ns = _volume->private_volume;
871 	base = _base->private_node;
872 
873 	if (!strcmp(".", file))
874 		*vnid = base->vnid;
875 	else {
876 		fs_node *newNode = (fs_node *)malloc(sizeof(fs_node));
877 		struct stat st;
878 
879 		if ((result = nfs_lookup(ns, &base->fhandle, file, &newNode->fhandle,
880 			&st)) < B_OK) {
881 			free(newNode);
882 			return result;
883 		}
884 
885 		newNode->vnid = st.st_ino;
886 		newNode->mode = st.st_mode;
887 		*vnid = newNode->vnid;
888 
889 		insert_node(ns, newNode);
890 	}
891 
892 	if ((result = get_vnode (_volume, *vnid, (void **)&dummy)) < B_OK)
893 		return result;
894 
895 	return B_OK;
896 }
897 
898 
899 static status_t
900 fs_opendir(fs_volume *_volume, fs_vnode *_node, void **_cookie)
901 {
902 	fs_nspace *ns;
903 	fs_node *node;
904 	nfs_cookie **cookie;
905 
906 	struct stat st;
907 	status_t result;
908 
909 	ns = _volume->private_volume;
910 	node = _node->private_node;
911 	cookie = (nfs_cookie **)_cookie;
912 
913 	if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK)
914 		return result;
915 
916 	if (!S_ISDIR(st.st_mode))
917 		return ENOTDIR;
918 
919 	*cookie = (nfs_cookie *)malloc(sizeof(nfs_cookie));
920 	memset((*cookie)->opaque,0,NFS_COOKIESIZE);
921 
922 	return B_OK;
923 }
924 
925 
926 static status_t
927 fs_closedir(fs_volume *_volume, fs_vnode *_node, void *cookie)
928 {
929 	(void) _volume;
930 	(void) _node;
931 	(void) cookie;
932 	return B_OK;
933 }
934 
935 
936 static status_t
937 fs_rewinddir(fs_volume *_volume, fs_vnode *_node, void *_cookie)
938 {
939 	nfs_cookie *cookie = (nfs_cookie *)_cookie;
940 	(void) _volume;
941 	(void) _node;
942 	memset (cookie->opaque, 0, NFS_COOKIESIZE);
943 
944 	return B_OK;
945 }
946 
947 
948 static status_t
949 fs_readdir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
950 		struct dirent *buf, size_t bufsize, uint32 *num)
951 {
952 	nfs_cookie *cookie = (nfs_cookie *)_cookie;
953 	uint32 max = *num;
954 	int32 eof;
955 
956 	fs_nspace *ns;
957 	fs_node *node;
958 
959 	size_t count = min_c(6000, max * 300);
960 
961 	*num = 0;
962 
963 	ns = _volume->private_volume;
964 	node = _node->private_node;
965 
966 	do {
967 		ino_t vnid;
968 		char *filename;
969 		uint8 *replyBuf;
970 		struct XDROutPacket call;
971 		struct XDRInPacket reply;
972 		int32 status;
973 
974 		XDROutPacketInit(&call);
975 		XDRInPacketInit(&reply);
976 
977 		XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE);
978 		XDROutPacketAddFixed(&call, cookie->opaque, NFS_COOKIESIZE);
979 		XDROutPacketAddInt32(&call, count);
980 
981 		replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
982 			NFSPROC_READDIR, &call);
983 
984 		if (!replyBuf) {
985 			XDRInPacketDestroy(&reply);
986 			XDROutPacketDestroy(&call);
987 			return B_ERROR;
988 		}
989 
990 		XDRInPacketSetTo(&reply, replyBuf, 0);
991 
992 		if (!is_successful_reply(&reply)) {
993 			XDRInPacketDestroy(&reply);
994 			XDROutPacketDestroy(&call);
995 			return B_ERROR;
996 		}
997 
998 		status = XDRInPacketGetInt32(&reply);
999 
1000 		if (status != NFS_OK) {
1001 			XDRInPacketDestroy(&reply);
1002 			XDROutPacketDestroy(&call);
1003 			return map_nfs_to_system_error(status);
1004 		}
1005 
1006 		while (XDRInPacketGetInt32(&reply) == 1) {
1007 			nfs_cookie newCookie;
1008 
1009 			vnid=XDRInPacketGetInt32(&reply);
1010 			filename=XDRInPacketGetString(&reply);
1011 
1012 			status = XDRInPacketGetFixed(&reply, newCookie.opaque,
1013 				NFS_COOKIESIZE);
1014 
1015 			if (status != NFS_OK)
1016 				return map_nfs_to_system_error(status);
1017 
1018 			//if (strcmp(".",filename)&&strcmp("..",filename))
1019 			//if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename)))
1020 			if (conf_ls_root_parent
1021 				|| ((ns->rootid != node->vnid) || strcmp("..", filename))) {
1022 				status_t result;
1023 				struct stat st;
1024 
1025 				fs_node *newNode = (fs_node *)malloc(sizeof(fs_node));
1026 				newNode->vnid = vnid;
1027 
1028 				if ((result = nfs_lookup(ns, &node->fhandle, filename,
1029 					&newNode->fhandle, &st)) < B_OK) {
1030 					free (filename);
1031 					free(newNode);
1032 					XDRInPacketDestroy (&reply);
1033 					XDROutPacketDestroy (&call);
1034 					return result;
1035 				}
1036 
1037 				newNode->mode = st.st_mode;
1038 				insert_node(ns,newNode);
1039 
1040 				if (bufsize < 2 * (sizeof(dev_t) + sizeof(ino_t))
1041 					+ sizeof(unsigned short) + strlen(filename) + 1) {
1042 					XDRInPacketDestroy(&reply);
1043 					XDROutPacketDestroy(&call);
1044 					return B_OK;
1045 				}
1046 
1047 				buf->d_dev = ns->nsid;
1048 				buf->d_pdev = ns->nsid;
1049 				buf->d_ino = vnid;
1050 				buf->d_pino = node->vnid;
1051 				buf->d_reclen = 2 * (sizeof(dev_t) + sizeof(ino_t))
1052 					+ sizeof(unsigned short) + 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
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
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
1118 fs_nspaceInit(struct fs_nspace *nspace)
1119 {
1120 	RPCPendingCallsInit(&nspace->pendingCalls);
1121 }
1122 
1123 
1124 void
1125 fs_nspaceDestroy(struct fs_nspace *nspace)
1126 {
1127 	RPCPendingCallsDestroy(&nspace->pendingCalls);
1128 }
1129 
1130 
1131 static status_t
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) : (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) : (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
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
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
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
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
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
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
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 		readbytes = XDRInPacketGetDynamic(&reply, buf);
1559 
1560 		buf = (char *)buf + readbytes;
1561 		(*len) += readbytes;
1562 		pos += readbytes;
1563 
1564 		XDRInPacketDestroy(&reply);
1565 		XDROutPacketDestroy(&call);
1566 
1567 		if (pos >= st.st_size)
1568 			break;
1569 	}
1570 
1571 	return B_OK;
1572 }
1573 
1574 
1575 static status_t
1576 fs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
1577 	const void *buf, size_t *len)
1578 {
1579 	fs_nspace *ns;
1580 	fs_node *node;
1581 	fs_file_cookie *cookie;
1582 	size_t bytesWritten = 0;
1583 
1584 	ns = _volume->private_volume;
1585 	node = _node->private_node;
1586 	cookie = (fs_file_cookie *)_cookie;
1587 
1588 	if (!cookie)
1589 		return EISDIR; /* do not permit reading of directories */
1590 	if (cookie->omode & O_APPEND)
1591 		pos += cookie->original_size;
1592 
1593 	while (bytesWritten < *len) {
1594 		size_t count = min_c(NFS_MAXDATA,(*len) - bytesWritten);
1595 
1596 		struct XDROutPacket call;
1597 		struct XDRInPacket reply;
1598 		int32 status;
1599 		uint8 *replyBuf;
1600 		struct stat st;
1601 
1602 		XDROutPacketInit(&call);
1603 		XDRInPacketInit(&reply);
1604 
1605 		XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE);
1606 		XDROutPacketAddInt32(&call, 0);
1607 		XDROutPacketAddInt32(&call, pos + bytesWritten);
1608 		XDROutPacketAddInt32(&call, 0);
1609 		XDROutPacketAddDynamic(&call, (const char *)buf + bytesWritten, count);
1610 
1611 		replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1612 			NFSPROC_WRITE, &call);
1613 
1614 		if (!replyBuf) {
1615 			XDRInPacketDestroy(&reply);
1616 			XDROutPacketDestroy(&call);
1617 			return B_ERROR;
1618 		}
1619 
1620 		XDRInPacketSetTo(&reply, replyBuf, 0);
1621 
1622 		if (!is_successful_reply(&reply)) {
1623 			XDRInPacketDestroy(&reply);
1624 			XDROutPacketDestroy(&call);
1625 			return B_ERROR;
1626 		}
1627 
1628 		status = XDRInPacketGetInt32(&reply);
1629 
1630 		if (status != NFS_OK) {
1631 			XDRInPacketDestroy(&reply);
1632 			XDROutPacketDestroy(&call);
1633 			return map_nfs_to_system_error(status);
1634 		}
1635 
1636 		get_nfs_attr(&reply, &st);
1637 
1638 		cookie->st = st;
1639 
1640 		bytesWritten += count;
1641 
1642 		XDRInPacketDestroy(&reply);
1643 		XDROutPacketDestroy(&call);
1644 	}
1645 
1646 	return B_OK;
1647 }
1648 
1649 
1650 static status_t
1651 fs_wstat(fs_volume *_volume, fs_vnode *_node, const struct stat *st, uint32 mask)
1652 {
1653 	fs_nspace *ns;
1654 	fs_node *node;
1655 	struct XDROutPacket call;
1656 	struct XDRInPacket reply;
1657 
1658 	uint8 *replyBuf;
1659 	int32 status;
1660 
1661 	ns = _volume->private_volume;
1662 	node = _node->private_node;
1663 
1664 	XDROutPacketInit(&call);
1665 	XDRInPacketInit(&reply);
1666 
1667 	XDROutPacketAddFixed(&call,node->fhandle.opaque,NFS_FHSIZE);
1668 
1669 	XDROutPacketAddInt32(&call, (mask & WSTAT_MODE) ? st->st_mode : -1);
1670 	XDROutPacketAddInt32(&call, (mask & WSTAT_UID) ? st->st_uid : -1);
1671 	XDROutPacketAddInt32(&call, (mask & WSTAT_GID) ? st->st_gid : -1);
1672 	XDROutPacketAddInt32(&call, (mask & WSTAT_SIZE) ? st->st_size : -1);
1673 	XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? st->st_atime : -1);
1674 	XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? 0 : -1);
1675 	XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? st->st_mtime : -1);
1676 	XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? 0 : -1);
1677 
1678 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1679 		NFSPROC_SETATTR, &call);
1680 
1681 	if (!replyBuf) {
1682 		XDRInPacketDestroy(&reply);
1683 		XDROutPacketDestroy(&call);
1684 		return EHOSTUNREACH;
1685 	}
1686 
1687 	XDRInPacketSetTo(&reply, replyBuf, 0);
1688 
1689 	if (!is_successful_reply(&reply)) {
1690 		XDRInPacketDestroy(&reply);
1691 		XDROutPacketDestroy(&call);
1692 		return B_ERROR;
1693 	}
1694 
1695 	status = XDRInPacketGetInt32(&reply);
1696 
1697 	if (status != NFS_OK)
1698 		return map_nfs_to_system_error(status);
1699 
1700 	XDRInPacketDestroy(&reply);
1701 	XDROutPacketDestroy(&call);
1702 
1703 	return notify_stat_changed(_volume->id, -1, node->vnid, mask);
1704 }
1705 
1706 static status_t
1707 fs_wfsstat(fs_volume *_volume, const struct fs_info *info, uint32 mask)
1708 {
1709 	(void) _volume;
1710 	(void) info;
1711 	(void) mask;
1712 	return B_OK;
1713 }
1714 
1715 static status_t
1716 fs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int omode,
1717 	int perms, void **_cookie, ino_t *vnid)
1718 {
1719 	nfs_fhandle fhandle;
1720 	struct stat st;
1721 	fs_file_cookie **cookie;
1722 
1723 	fs_nspace *ns;
1724 	fs_node *dir;
1725 
1726 	status_t result;
1727 
1728 	ns = _volume->private_volume;
1729 	dir = _dir->private_node;
1730 	cookie = (fs_file_cookie **)_cookie;
1731 
1732 	result = nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st);
1733 
1734 	if (result == B_OK) {
1735 		void *dummy;
1736 		fs_node *newNode = (fs_node *)malloc(sizeof(fs_node));
1737 		if (newNode == NULL)
1738 			return B_NO_MEMORY;
1739 
1740 		newNode->fhandle = fhandle;
1741 		newNode->vnid = st.st_ino;
1742 		newNode->mode = st.st_mode;
1743 		insert_node(ns, newNode);
1744 
1745 		*vnid = st.st_ino;
1746 
1747 		if ((result = get_vnode(_volume,*vnid,&dummy)) < B_OK)
1748 			return result;
1749 
1750 		if (S_ISDIR(st.st_mode))
1751 			return EISDIR;
1752 
1753 		if (omode & O_EXCL)
1754 			return EEXIST;
1755 
1756 		if (omode & O_TRUNC)
1757 		{
1758 			if ((result = nfs_truncate_file(ns, &fhandle, NULL)) < B_OK)
1759 				return result;
1760 		}
1761 
1762 		*cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1763 		if (*cookie == NULL)
1764 			return B_NO_MEMORY;
1765 
1766 		(*cookie)->omode=omode;
1767 		(*cookie)->original_size=st.st_size;
1768 		(*cookie)->st=st;
1769 
1770 		return B_OK;
1771 	} else if (result != ENOENT) {
1772 		return result;
1773 	} else {
1774 		struct XDROutPacket call;
1775 		struct XDRInPacket reply;
1776 
1777 		uint8 *replyBuf;
1778 		int32 status;
1779 
1780 		fs_node *newNode;
1781 
1782 		if (!(omode & O_CREAT))
1783 			return ENOENT;
1784 
1785 		XDROutPacketInit(&call);
1786 		XDRInPacketInit(&reply);
1787 
1788 		XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
1789 		XDROutPacketAddString(&call, name);
1790 		XDROutPacketAddInt32(&call, perms | S_IFREG);
1791 		XDROutPacketAddInt32(&call, -1);
1792 		XDROutPacketAddInt32(&call, -1);
1793 		XDROutPacketAddInt32(&call, 0);
1794 		XDROutPacketAddInt32(&call, time(NULL));
1795 		XDROutPacketAddInt32(&call, 0);
1796 		XDROutPacketAddInt32(&call, time(NULL));
1797 		XDROutPacketAddInt32(&call, 0);
1798 
1799 		replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
1800 			NFSPROC_CREATE, &call);
1801 
1802 		if (!replyBuf) {
1803 			XDRInPacketDestroy(&reply);
1804 			XDROutPacketDestroy(&call);
1805 			return B_ERROR;
1806 		}
1807 
1808 		XDRInPacketSetTo(&reply, replyBuf, 0);
1809 
1810 		if (!is_successful_reply(&reply)) {
1811 			XDRInPacketDestroy(&reply);
1812 			XDROutPacketDestroy(&call);
1813 			return B_ERROR;
1814 		}
1815 
1816 		status = XDRInPacketGetInt32(&reply);
1817 
1818 		if (status != NFS_OK) {
1819 			XDRInPacketDestroy(&reply);
1820 			XDROutPacketDestroy(&call);
1821 			return map_nfs_to_system_error(status);
1822 		}
1823 
1824 		status = XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE);
1825 
1826 		if (status != NFS_OK) {
1827 			XDRInPacketDestroy(&reply);
1828 			XDROutPacketDestroy(&call);
1829 			return map_nfs_to_system_error(status);
1830 		}
1831 
1832 		get_nfs_attr(&reply,&st);
1833 
1834 		newNode = (fs_node *)malloc(sizeof(fs_node));
1835 		if (newNode == NULL) {
1836 			XDRInPacketDestroy(&reply);
1837 			XDROutPacketDestroy(&call);
1838 			return B_NO_MEMORY;
1839 		}
1840 		newNode->fhandle = fhandle;
1841 		newNode->vnid = st.st_ino;
1842 		newNode->mode = st.st_mode;
1843 
1844 		insert_node (ns, newNode);
1845 
1846 		*vnid = st.st_ino;
1847 		*cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie));
1848 		if (*cookie == NULL) {
1849 			XDRInPacketDestroy(&reply);
1850 			XDROutPacketDestroy(&call);
1851 			return B_NO_MEMORY;
1852 		}
1853 		(*cookie)->omode = omode;
1854 		(*cookie)->original_size = st.st_size;
1855 		(*cookie)->st = st;
1856 
1857 		result = publish_vnode(_volume, *vnid, newNode, &sNFSVnodeOps,
1858 			S_IFREG, 0);
1859 		if (result < B_OK) {
1860 			XDRInPacketDestroy(&reply);
1861 			XDROutPacketDestroy(&call);
1862 			return result;
1863 		}
1864 
1865 		XDRInPacketDestroy(&reply);
1866 		XDROutPacketDestroy(&call);
1867 		return notify_entry_created(_volume->id, dir->vnid, name, *vnid);
1868 	}
1869 }
1870 
1871 
1872 static status_t
1873 fs_unlink(fs_volume *_volume, fs_vnode *_dir, const char *name)
1874 {
1875 	status_t result;
1876 	fs_nspace *ns;
1877 	fs_node *dir;
1878 	fs_node *newNode;
1879 	fs_node *dummy;
1880 
1881 	struct XDROutPacket call;
1882 	struct XDRInPacket reply;
1883 
1884 	struct stat st;
1885 	nfs_fhandle fhandle;
1886 	uint8 *replyBuf;
1887 
1888 	int32 status;
1889 
1890 	ns = _volume->private_volume;
1891 	dir = _dir->private_node;
1892 
1893 	XDROutPacketInit(&call);
1894 	XDRInPacketInit(&reply);
1895 
1896 	if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) {
1897 		XDRInPacketDestroy(&reply);
1898 		XDROutPacketDestroy(&call);
1899 		return result;
1900 	}
1901 
1902 	newNode = (fs_node *)malloc(sizeof(fs_node));
1903 	if (newNode == NULL) {
1904 		XDRInPacketDestroy(&reply);
1905 		XDROutPacketDestroy(&call);
1906 		return B_NO_MEMORY;
1907 	}
1908 	newNode->fhandle = fhandle;
1909 	newNode->vnid = st.st_ino;
1910 	newNode->mode = st.st_mode;
1911 
1912 	insert_node(ns, newNode);
1913 
1914 	if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) {
1915 		XDRInPacketDestroy(&reply);
1916 		XDROutPacketDestroy(&call);
1917 		return result;
1918 	}
1919 
1920 	if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1921 		XDRInPacketDestroy(&reply);
1922 		XDROutPacketDestroy(&call);
1923 		return EISDIR;
1924 	}
1925 
1926 	if ((result=remove_vnode(_volume,st.st_ino)) < B_OK) {
1927 		XDRInPacketDestroy(&reply);
1928 		XDROutPacketDestroy(&call);
1929 		return result;
1930 	}
1931 
1932 	if ((result=put_vnode(_volume, st.st_ino)) < B_OK) {
1933 		XDRInPacketDestroy(&reply);
1934 		XDROutPacketDestroy(&call);
1935 		return result;
1936 	}
1937 
1938 	XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
1939 	XDROutPacketAddString(&call, name);
1940 
1941 	replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call);
1942 
1943 	if (!replyBuf) {
1944 		XDRInPacketDestroy(&reply);
1945 		XDROutPacketDestroy(&call);
1946 		return EHOSTUNREACH;
1947 	}
1948 
1949 	XDRInPacketSetTo(&reply, replyBuf, 0);
1950 
1951 	if (!is_successful_reply(&reply)) {
1952 		XDRInPacketDestroy(&reply);
1953 		XDROutPacketDestroy(&call);
1954 		return B_ERROR;
1955 	}
1956 
1957 	status = XDRInPacketGetInt32(&reply);
1958 
1959 	if (status != NFS_OK) {
1960 		XDRInPacketDestroy(&reply);
1961 		XDROutPacketDestroy(&call);
1962 		return map_nfs_to_system_error(status);
1963 	}
1964 
1965 	XDRInPacketDestroy(&reply);
1966 	XDROutPacketDestroy(&call);
1967 
1968 	return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino);
1969 }
1970 
1971 
1972 static status_t
1973 fs_remove_vnode(fs_volume *_volume, fs_vnode *_node, bool r)
1974 {
1975 	fs_nspace *ns = _volume->private_volume;
1976 	fs_node *node = _node->private_node;
1977 
1978 	(void) r;
1979 
1980 	remove_node (ns, node->vnid);
1981 
1982 	return B_OK;
1983 }
1984 
1985 
1986 static status_t
1987 fs_mkdir(fs_volume *_volume, fs_vnode *_dir, const char *name, int perms)
1988 {
1989 	fs_nspace *ns;
1990 	fs_node *dir;
1991 
1992 	nfs_fhandle fhandle;
1993 	struct stat st;
1994 	fs_node *newNode;
1995 
1996 	status_t result;
1997 	uint8 *replyBuf;
1998 	int32 status;
1999 
2000 	struct XDROutPacket call;
2001 	struct XDRInPacket reply;
2002 
2003 	ns = _volume->private_volume;
2004 	dir = _dir->private_node;
2005 
2006 	XDROutPacketInit(&call);
2007 	XDRInPacketInit(&reply);
2008 
2009 	result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st);
2010 
2011 	if (result == B_OK) {
2012 		//void *dummy;
2013 
2014 		XDRInPacketDestroy(&reply);
2015 		XDROutPacketDestroy(&call);
2016 		// XXX: either OK or not get_vnode !!! ??
2017 		//if ((result=get_vnode(_volume,st.st_ino,&dummy))<B_OK)
2018 		//	return result;
2019 		return EEXIST;
2020 	} else if (result != ENOENT) {
2021 		XDRInPacketDestroy(&reply);
2022 		XDROutPacketDestroy(&call);
2023 		return result;
2024 	}
2025 
2026 	XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
2027 	XDROutPacketAddString(&call, name);
2028 	XDROutPacketAddInt32(&call, perms | S_IFDIR);
2029 	XDROutPacketAddInt32(&call, -1);
2030 	XDROutPacketAddInt32(&call, -1);
2031 	XDROutPacketAddInt32(&call, -1);
2032 	XDROutPacketAddInt32(&call, time(NULL));
2033 	XDROutPacketAddInt32(&call, 0);
2034 	XDROutPacketAddInt32(&call, time(NULL));
2035 	XDROutPacketAddInt32(&call, 0);
2036 
2037 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2038 		NFSPROC_MKDIR, &call);
2039 
2040 	if (!replyBuf) {
2041 		XDRInPacketDestroy(&reply);
2042 		XDROutPacketDestroy(&call);
2043 		return B_ERROR;
2044 	}
2045 
2046 	XDRInPacketSetTo(&reply, replyBuf, 0);
2047 
2048 	if (!is_successful_reply(&reply)) {
2049 		XDRInPacketDestroy(&reply);
2050 		XDROutPacketDestroy(&call);
2051 		return B_ERROR;
2052 	}
2053 
2054 	status = XDRInPacketGetInt32(&reply);
2055 
2056 	if (status != NFS_OK) {
2057 		XDROutPacketDestroy(&call);
2058 		return map_nfs_to_system_error(status);
2059 	}
2060 
2061 	status = XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE);
2062 
2063 	if (status != NFS_OK) {
2064 		XDROutPacketDestroy(&call);
2065 		return map_nfs_to_system_error(status);
2066 	}
2067 
2068 	get_nfs_attr(&reply, &st);
2069 
2070 	newNode=(fs_node *)malloc(sizeof(fs_node));
2071 	if (newNode == NULL) {
2072 		XDRInPacketDestroy(&reply);
2073 		XDROutPacketDestroy(&call);
2074 		return B_NO_MEMORY;
2075 	}
2076 	newNode->fhandle = fhandle;
2077 	newNode->vnid = st.st_ino;
2078 	newNode->mode = st.st_mode;
2079 
2080 	insert_node(ns, newNode);
2081 
2082 	XDRInPacketDestroy(&reply);
2083 	XDROutPacketDestroy(&call);
2084 
2085 	return notify_entry_created(_volume->id, dir->vnid, name, st.st_ino);
2086 }
2087 
2088 static status_t
2089 fs_rename(fs_volume *_volume, fs_vnode *_olddir, const char *oldname,
2090 		fs_vnode *_newdir, const char *newname)
2091 {
2092 	struct stat st;
2093 	nfs_fhandle fhandle;
2094 	status_t result;
2095 	struct XDROutPacket call;
2096 	struct XDRInPacket reply;
2097 	int32 status;
2098 	uint8 *replyBuf;
2099 	fs_nspace *ns;
2100 	fs_node *olddir;
2101 	fs_node *newdir;
2102 
2103 	ns = _volume->private_volume;
2104 	olddir = _olddir->private_node;
2105 	newdir = _newdir->private_node;
2106 
2107 	XDROutPacketInit(&call);
2108 	XDRInPacketInit(&reply);
2109 
2110 	if ((result = nfs_lookup(ns, &newdir->fhandle, newname, &fhandle, &st))
2111 		== B_OK) {
2112 		if (S_ISREG(st.st_mode))
2113 			result = fs_unlink (_volume,_newdir,newname);
2114 		else
2115 			result = fs_rmdir (_volume,_newdir,newname);
2116 
2117 		if (result < B_OK) {
2118 			XDRInPacketDestroy (&reply);
2119 			XDROutPacketDestroy (&call);
2120 			return result;
2121 		}
2122 	}
2123 
2124 	if ((result = nfs_lookup(ns, &olddir->fhandle, oldname, &fhandle, &st))
2125 		< B_OK) {
2126 		XDRInPacketDestroy(&reply);
2127 		XDROutPacketDestroy(&call);
2128 		return result;
2129 	}
2130 
2131 	XDROutPacketAddFixed(&call, olddir->fhandle.opaque, NFS_FHSIZE);
2132 	XDROutPacketAddString(&call, oldname);
2133 	XDROutPacketAddFixed(&call, newdir->fhandle.opaque, NFS_FHSIZE);
2134 	XDROutPacketAddString(&call, newname);
2135 
2136 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2137 		NFSPROC_RENAME, &call);
2138 
2139 	if (!replyBuf) {
2140 		XDRInPacketDestroy(&reply);
2141 		XDROutPacketDestroy(&call);
2142 		return EHOSTUNREACH;
2143 	}
2144 
2145 	XDRInPacketSetTo(&reply, replyBuf, 0);
2146 
2147 	if (!is_successful_reply(&reply)) {
2148 		XDRInPacketDestroy(&reply);
2149 		XDROutPacketDestroy(&call);
2150 		return B_ERROR;
2151 	}
2152 
2153 	status = XDRInPacketGetInt32(&reply);
2154 
2155 	if (status != NFS_OK) {
2156 		XDRInPacketDestroy(&reply);
2157 		XDROutPacketDestroy(&call);
2158 		return map_nfs_to_system_error(status);
2159 	}
2160 
2161 	XDRInPacketDestroy (&reply);
2162 	XDROutPacketDestroy (&call);
2163 
2164 	return notify_entry_moved(_volume->id, olddir->vnid, oldname, newdir->vnid,
2165 		newname, st.st_ino);
2166 }
2167 
2168 
2169 static status_t
2170 fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name)
2171 {
2172 	fs_nspace *ns;
2173 	fs_node *dir;
2174 
2175 	status_t result;
2176 	fs_node *newNode;
2177 	fs_node *dummy;
2178 	struct XDROutPacket call;
2179 	struct XDRInPacket reply;
2180 	int32 status;
2181 	uint8 *replyBuf;
2182 
2183 	struct stat st;
2184 	nfs_fhandle fhandle;
2185 
2186 	ns = _volume->private_volume;
2187 	dir = _dir->private_node;
2188 
2189 	XDROutPacketInit(&call);
2190 	XDRInPacketInit(&reply);
2191 
2192 	if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) {
2193 		XDRInPacketDestroy(&reply);
2194 		XDROutPacketDestroy(&call);
2195 		return result;
2196 	}
2197 
2198 	newNode = (fs_node *)malloc(sizeof(fs_node));
2199 	if (newNode == NULL) {
2200 		XDRInPacketDestroy(&reply);
2201 		XDROutPacketDestroy(&call);
2202 		return B_NO_MEMORY;
2203 	}
2204 	newNode->fhandle = fhandle;
2205 	newNode->vnid = st.st_ino;
2206 	newNode->mode = st.st_mode;
2207 
2208 	insert_node(ns, newNode);
2209 
2210 	if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) {
2211 		XDRInPacketDestroy(&reply);
2212 		XDROutPacketDestroy(&call);
2213 		return result;
2214 	}
2215 
2216 	if (!S_ISDIR(st.st_mode)) {
2217 		XDRInPacketDestroy(&reply);
2218 		XDROutPacketDestroy(&call);
2219 		return ENOTDIR;
2220 	}
2221 
2222 	if ((result = remove_vnode(_volume, st.st_ino)) < B_OK) {
2223 		XDRInPacketDestroy(&reply);
2224 		XDROutPacketDestroy(&call);
2225 		return result;
2226 	}
2227 
2228 	if ((result = put_vnode(_volume, st.st_ino)) < B_OK) {
2229 		XDRInPacketDestroy(&reply);
2230 		XDROutPacketDestroy(&call);
2231 		return result;
2232 	}
2233 
2234 	XDROutPacketAddFixed (&call, dir->fhandle.opaque, NFS_FHSIZE);
2235 	XDROutPacketAddString(&call, name);
2236 
2237 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2238 		NFSPROC_RMDIR, &call);
2239 
2240 	if (!replyBuf) {
2241 		XDRInPacketDestroy(&reply);
2242 		XDROutPacketDestroy(&call);
2243 		return EHOSTUNREACH;
2244 	}
2245 
2246 	XDRInPacketSetTo (&reply,replyBuf,0);
2247 
2248 	if (!is_successful_reply(&reply)) {
2249 		XDRInPacketDestroy(&reply);
2250 		XDROutPacketDestroy(&call);
2251 		return B_ERROR;
2252 	}
2253 
2254 	status = XDRInPacketGetInt32(&reply);
2255 
2256 	if (status != NFS_OK) {
2257 		XDRInPacketDestroy(&reply);
2258 		XDROutPacketDestroy(&call);
2259 		return map_nfs_to_system_error(status);
2260 	}
2261 
2262 	XDRInPacketDestroy(&reply);
2263 	XDROutPacketDestroy(&call);
2264 	return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino);
2265 }
2266 
2267 
2268 static status_t
2269 fs_readlink(fs_volume *_volume, fs_vnode *_node, char *buf, size_t *bufsize)
2270 {
2271 	struct XDROutPacket call;
2272 	uint8 *replyBuf;
2273 	int32 status;
2274 	size_t length;
2275 	char data[NFS_MAXPATHLEN];
2276 	struct XDRInPacket reply;
2277 	fs_nspace *ns;
2278 	fs_node *node;
2279 
2280 	ns = _volume->private_volume;
2281 	node = _node->private_node;
2282 
2283 	XDROutPacketInit(&call);
2284 	XDRInPacketInit(&reply);
2285 
2286 	XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE);
2287 
2288 	replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2289 		NFSPROC_READLINK, &call);
2290 
2291 	if (!replyBuf) {
2292 		XDRInPacketDestroy(&reply);
2293 		XDROutPacketDestroy(&call);
2294 		return EHOSTUNREACH;
2295 	}
2296 
2297 	XDRInPacketSetTo (&reply, replyBuf, 0);
2298 
2299 	if (!is_successful_reply(&reply)) {
2300 		XDRInPacketDestroy(&reply);
2301 		XDROutPacketDestroy(&call);
2302 		return B_ERROR;
2303 	}
2304 
2305 	status = XDRInPacketGetInt32(&reply);
2306 
2307 	if (status != NFS_OK) {
2308 		XDRInPacketDestroy(&reply);
2309 		XDROutPacketDestroy (&call);
2310 		return map_nfs_to_system_error(status);
2311 	}
2312 
2313 	length = XDRInPacketGetDynamic(&reply, data);
2314 
2315 	memcpy(buf, data, min_c(length, *bufsize));
2316 	*bufsize = length;
2317 
2318 	XDRInPacketDestroy(&reply);
2319 	XDROutPacketDestroy(&call);
2320 	return B_OK;
2321 }
2322 
2323 static status_t
2324 fs_symlink(fs_volume *_volume, fs_vnode *_dir, const char *name,
2325 	const char *path, int mode)
2326 {
2327 	fs_nspace *ns;
2328 	fs_node *dir;
2329 	nfs_fhandle fhandle;
2330 	struct stat st;
2331 	struct XDROutPacket call;
2332 	struct XDRInPacket reply;
2333 	status_t result;
2334 	uint8 *replyBuf;
2335 	int32 status;
2336 	fs_node *newNode;
2337 
2338 	ns = _volume->private_volume;
2339 	dir = _dir->private_node;
2340 
2341 	XDROutPacketInit(&call);
2342 	XDRInPacketInit(&reply);
2343 
2344 	result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st);
2345 
2346 	if (result == B_OK) {
2347 		void *dummy;
2348 		if ((result = get_vnode(_volume, st.st_ino, &dummy)) < B_OK)
2349 			return result;
2350 
2351 		XDRInPacketDestroy(&reply);
2352 		XDROutPacketDestroy(&call);
2353 		return EEXIST;
2354 	} else if (result != ENOENT) {
2355 		XDRInPacketDestroy(&reply);
2356 		XDROutPacketDestroy(&call);
2357 		return result;
2358 	}
2359 
2360 	XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE);
2361 	XDROutPacketAddString(&call, name);
2362 	XDROutPacketAddString(&call, path);
2363 	XDROutPacketAddInt32(&call, S_IFLNK);
2364 	XDROutPacketAddInt32(&call, -1);
2365 	XDROutPacketAddInt32(&call, -1);
2366 	XDROutPacketAddInt32(&call, -1);
2367 	XDROutPacketAddInt32(&call, time(NULL));
2368 	XDROutPacketAddInt32(&call, 0);
2369 	XDROutPacketAddInt32(&call, time(NULL));
2370 	XDROutPacketAddInt32(&call, 0);
2371 
2372 	replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION,
2373 		NFSPROC_SYMLINK, &call);
2374 
2375 	if (!replyBuf) {
2376 		XDRInPacketDestroy(&reply);
2377 		XDROutPacketDestroy(&call);
2378 		return B_ERROR;
2379 	}
2380 
2381 	XDRInPacketSetTo(&reply, replyBuf, 0);
2382 
2383 	if (!is_successful_reply(&reply)) {
2384 		XDRInPacketDestroy(&reply);
2385 		XDROutPacketDestroy(&call);
2386 		return B_ERROR;
2387 	}
2388 
2389 	status = XDRInPacketGetInt32(&reply);
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 	(void)status;
2396 
2397 	result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st);
2398 
2399 	if (result < B_OK) {
2400 		XDRInPacketDestroy(&reply);
2401 		XDROutPacketDestroy(&call);
2402 		return result;
2403 	}
2404 
2405 	newNode = (fs_node *)malloc(sizeof(fs_node));
2406 	if (newNode == NULL) {
2407 		XDRInPacketDestroy(&reply);
2408 		XDROutPacketDestroy(&call);
2409 		return B_NO_MEMORY;
2410 	}
2411 	newNode->fhandle = fhandle;
2412 	newNode->vnid = st.st_ino;
2413 
2414 	insert_node(ns, newNode);
2415 
2416 	result = notify_entry_created (_volume->id, dir->vnid, name, st.st_ino);
2417 
2418 	XDRInPacketDestroy(&reply);
2419 	XDROutPacketDestroy(&call);
2420 	return result;
2421 }
2422 
2423 
2424 static status_t
2425 fs_access(fs_volume *_volume, fs_vnode *node, int mode)
2426 {
2427 	(void) _volume;
2428 	(void) node;
2429 	(void) mode;
2430 	/* XXX */
2431 	return B_OK;
2432 }
2433 
2434 
2435 static status_t
2436 nfs_std_ops(int32 op, ...)
2437 {
2438 	switch (op) {
2439 		case B_MODULE_INIT:
2440 			return B_OK;
2441 		case B_MODULE_UNINIT:
2442 			return B_OK;
2443 
2444 		default:
2445 			return B_ERROR;
2446 	}
2447 }
2448 
2449 
2450 fs_volume_ops sNFSVolumeOps = {
2451 	&fs_unmount,
2452 	&fs_rfsstat,
2453 	&fs_wfsstat,
2454 	NULL,			// no sync!
2455 	&fs_read_vnode,
2456 
2457 	/* index directory & index operations */
2458 	NULL,	// &fs_open_index_dir
2459 	NULL,	// &fs_close_index_dir
2460 	NULL,	// &fs_free_index_dir_cookie
2461 	NULL,	// &fs_read_index_dir
2462 	NULL,	// &fs_rewind_index_dir
2463 
2464 	NULL,	// &fs_create_index
2465 	NULL,	// &fs_remove_index
2466 	NULL,	// &fs_stat_index
2467 
2468 	/* query operations */
2469 	NULL,	// &fs_open_query,
2470 	NULL,	// &fs_close_query,
2471 	NULL,	// &fs_free_query_cookie,
2472 	NULL,	// &fs_read_query,
2473 	NULL,	// &fs_rewind_query,
2474 };
2475 
2476 
2477 fs_vnode_ops sNFSVnodeOps = {
2478 	/* vnode operations */
2479 	&fs_walk,
2480 	NULL, // fs_get_vnode_name
2481 	&fs_release_vnode,
2482 	&fs_remove_vnode,
2483 
2484 	/* VM file access */
2485 	NULL, 	// &fs_can_page
2486 	NULL,	// &fs_read_pages
2487 	NULL, 	// &fs_write_pages
2488 
2489 	NULL,	// io()
2490 	NULL,	// cancel_io()
2491 
2492 	NULL,	// &fs_get_file_map,
2493 
2494 	NULL, 	// &fs_ioctl
2495 	NULL,	// &fs_setflags,
2496 	NULL,	// &fs_select
2497 	NULL,	// &fs_deselect
2498 	NULL, 	// &fs_fsync
2499 
2500 	&fs_readlink,
2501 	&fs_symlink,
2502 
2503 	NULL,	// &fs_link,
2504 	&fs_unlink,
2505 	&fs_rename,
2506 
2507 	&fs_access,
2508 	&fs_rstat,
2509 	&fs_wstat,
2510 	NULL,	// fs_preallocate()
2511 
2512 	/* file operations */
2513 	&fs_create,
2514 	&fs_open,
2515 	&fs_close,
2516 	&fs_free_cookie,
2517 	&fs_read,
2518 	&fs_write,
2519 
2520 	/* directory operations */
2521 	&fs_mkdir,
2522 	&fs_rmdir,
2523 	&fs_opendir,
2524 	&fs_closedir,
2525 	&fs_free_dircookie,
2526 	&fs_readdir,
2527 	&fs_rewinddir,
2528 
2529 	/* attribute directory operations */
2530 	NULL,	// &fs_open_attrdir,
2531 	NULL,	// &fs_close_attrdir,
2532 	NULL,	// &fs_free_attrdircookie,
2533 	NULL,	// &fs_read_attrdir,
2534 	NULL,	// &fs_rewind_attrdir,
2535 
2536 	/* attribute operations */
2537 	NULL,	// &fs_create_attr
2538 	NULL,	// &fs_open_attr_h,
2539 	NULL,	// &fs_close_attr_h,
2540 	NULL,	// &fs_free_attr_cookie_h,
2541 	NULL,	// &fs_read_attr_h,
2542 	NULL,	// &fs_write_attr_h,
2543 
2544 	NULL,	// &fs_read_attr_stat_h,
2545 	NULL,	// &fs_write_attr_stat
2546 	NULL,	// &fs_rename_attr
2547 	NULL,	// &fs_remove_attr
2548 };
2549 
2550 file_system_module_info sNFSFileSystem = {
2551 	{
2552 		"file_systems/nfs" B_CURRENT_FS_API_VERSION,
2553 		0,
2554 		nfs_std_ops,
2555 	},
2556 	"nfs",				// short name
2557 	"Network File System v2",	// pretty name
2558 	B_DISK_SYSTEM_SUPPORTS_WRITING, // DDM flags
2559 
2560 	// scanning
2561 	NULL,	// fs_identify_partition,
2562 	NULL,	// fs_scan_partition,
2563 	NULL,	// fs_free_identify_partition_cookie,
2564 	NULL,	// free_partition_content_cookie()
2565 
2566 	&fs_mount,
2567 };
2568 
2569 module_info *modules[] = {
2570 	(module_info *)&sNFSFileSystem,
2571 	NULL,
2572 };
2573