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