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