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