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