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