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