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