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