1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | #include <hurd/io.h> |
24 | #include <hurd/fs.h> |
25 | #include <fcntl.h> |
26 | #include <hurd/paths.h> |
27 | #include <hurd.h> |
28 | #include <dirent.h> |
29 | #include <string.h> |
30 | #include <sys/mman.h> |
31 | |
32 | #include "nfsd.h" |
33 | #include "../nfs/mount.h" /* XXX */ |
34 | #include <rpc/pmap_prot.h> |
35 | |
36 | static error_t |
37 | op_null (struct cache_handle *c, |
38 | int *p, |
39 | int **reply, |
40 | int version) |
41 | { |
42 | return 0; |
43 | } |
44 | |
45 | static error_t |
46 | op_getattr (struct cache_handle *c, |
47 | int *p, |
48 | int **reply, |
49 | int version) |
50 | { |
51 | struct stat st; |
52 | error_t err; |
53 | |
54 | err = io_stat (c->port, &st); |
55 | if (!err) |
56 | *reply = encode_fattr (*reply, &st, version); |
57 | return err; |
58 | } |
59 | |
60 | static error_t |
61 | complete_setattr (mach_port_t port, |
62 | int *p) |
63 | { |
64 | uid_t uid, gid; |
65 | off_t size; |
66 | time_value_t atime, mtime; |
67 | struct stat st; |
68 | error_t err; |
69 | |
70 | err = io_stat (port, &st); |
71 | if (err) |
72 | return err; |
73 | |
74 | uid = ntohl (*p); |
75 | p++; |
76 | gid = ntohl (*p); |
77 | p++; |
78 | if (uid == -1) |
79 | uid = st.st_uid; |
80 | if (gid == -1) |
81 | gid = st.st_gid; |
82 | if (uid != st.st_uid || gid != st.st_gid) |
83 | err = file_chown (port, uid, gid); |
84 | if (err) |
85 | return err; |
86 | |
87 | size = ntohl (*p); |
88 | p++; |
89 | if (size != -1 && size != st.st_size) |
90 | err = file_set_size (port, size); |
91 | if (err) |
92 | return err; |
93 | |
94 | atime.seconds = ntohl (*p); |
95 | p++; |
96 | atime.microseconds = ntohl (*p); |
97 | p++; |
98 | mtime.seconds = ntohl (*p); |
99 | p++; |
100 | mtime.microseconds = ntohl (*p); |
101 | p++; |
102 | |
103 | if (atime.seconds != -1 && atime.microseconds == -1) |
104 | atime.microseconds = 0; |
105 | if (mtime.seconds != -1 && mtime.microseconds == -1) |
106 | mtime.microseconds = 0; |
107 | |
108 | if (atime.seconds == -1) |
109 | atime.seconds = st.st_atim.tv_sec; |
110 | if (atime.microseconds == -1) |
111 | atime.microseconds = st.st_atim.tv_nsec / 1000; |
112 | if (mtime.seconds == -1) |
113 | mtime.seconds = st.st_mtim.tv_sec; |
114 | if (mtime.microseconds == -1) |
115 | mtime.microseconds = st.st_mtim.tv_nsec / 1000; |
116 | |
117 | if (atime.seconds != st.st_atim.tv_sec |
118 | || atime.microseconds != st.st_atim.tv_nsec / 1000 |
119 | || mtime.seconds != st.st_mtim.tv_sec |
120 | || mtime.microseconds != st.st_mtim.tv_nsec / 1000) |
121 | err = file_utimes (port, atime, mtime); |
122 | |
123 | return err; |
124 | } |
125 | |
126 | static error_t |
127 | op_setattr (struct cache_handle *c, |
128 | int *p, |
129 | int **reply, |
130 | int version) |
131 | { |
132 | error_t err = 0; |
133 | mode_t mode; |
134 | struct stat st; |
135 | |
136 | mode = ntohl (*p); |
137 | p++; |
138 | if (mode != -1) |
139 | err = file_chmod (c->port, mode); |
140 | |
141 | if (!err) |
142 | err = complete_setattr (c->port, p); |
143 | if (!err) |
144 | err = io_stat (c->port, &st); |
145 | if (err) |
146 | return err; |
147 | |
148 | *reply = encode_fattr (*reply, &st, version); |
149 | return 0; |
150 | } |
151 | |
152 | static error_t |
153 | op_lookup (struct cache_handle *c, |
154 | int *p, |
155 | int **reply, |
156 | int version) |
157 | { |
158 | error_t err; |
159 | char *name; |
160 | retry_type do_retry; |
161 | char retry_name [1024]; |
162 | mach_port_t newport; |
163 | struct cache_handle *newc; |
164 | struct stat st; |
165 | |
166 | decode_name (p, &name); |
167 | |
168 | err = dir_lookup (c->port, name, O_NOTRANS0x0080, 0, &do_retry, retry_name, |
169 | &newport); |
170 | free (name); |
171 | |
172 | |
173 | if (!err |
174 | && (do_retry != FS_RETRY_NORMAL |
175 | || retry_name[0] != '\0')) |
176 | err = EACCES((0x10 << 26) | ((13) & 0x3fff)); |
177 | |
178 | if (!err) |
179 | err = io_stat (newport, &st); |
180 | |
181 | if (err) |
182 | return err; |
183 | |
184 | newc = create_cached_handle (*(int *)c->handle, c, newport); |
185 | if (!newc) |
186 | return ESTALE((0x10 << 26) | ((70) & 0x3fff)); |
187 | *reply = encode_fhandle (*reply, newc->handle); |
188 | *reply = encode_fattr (*reply, &st, version); |
189 | return 0; |
190 | } |
191 | |
192 | static error_t |
193 | op_readlink (struct cache_handle *c, |
194 | int *p, |
195 | int **reply, |
196 | int version) |
197 | { |
198 | char buf[2048], *transp = buf; |
199 | mach_msg_type_number_t len = sizeof (buf); |
200 | error_t err; |
201 | |
202 | |
203 | err = file_get_translator (c->port, &transp, &len); |
204 | if (err) |
205 | { |
206 | if (transp != buf) |
207 | munmap (transp, len); |
208 | return err; |
209 | } |
210 | |
211 | if (len < sizeof (_HURD_SYMLINK"/hurd/" "symlink") |
212 | || memcmp (transp, _HURD_SYMLINK"/hurd/" "symlink", sizeof (_HURD_SYMLINK"/hurd/" "symlink"))) |
213 | return EINVAL((0x10 << 26) | ((22) & 0x3fff)); |
214 | |
215 | transp += sizeof (_HURD_SYMLINK"/hurd/" "symlink"); |
216 | |
217 | *reply = encode_string (*reply, transp); |
218 | |
219 | if (transp != buf) |
220 | munmap (transp, len); |
221 | |
222 | return 0; |
223 | } |
224 | |
225 | static size_t |
226 | count_read_buffersize (int *p, int version) |
227 | { |
228 | p++; |
229 | return ntohl (*p); |
230 | } |
231 | |
232 | static error_t |
233 | op_read (struct cache_handle *c, |
234 | int *p, |
235 | int **reply, |
236 | int version) |
237 | { |
238 | off_t offset; |
239 | size_t count; |
240 | char buf[2048], *bp = buf; |
241 | mach_msg_type_number_t buflen = sizeof (buf); |
242 | struct stat st; |
243 | error_t err; |
244 | |
245 | offset = ntohl (*p); |
246 | p++; |
247 | count = ntohl (*p); |
248 | p++; |
249 | |
250 | err = io_read (c->port, &bp, &buflen, offset, count); |
251 | if (err) |
252 | { |
253 | if (bp != buf) |
254 | munmap (bp, buflen); |
255 | return err; |
256 | } |
257 | |
258 | err = io_stat (c->port, &st); |
259 | if (err) |
260 | return err; |
261 | |
262 | *reply = encode_fattr (*reply, &st, version); |
263 | *reply = encode_data (*reply, bp, buflen); |
264 | |
265 | if (bp != buf) |
266 | munmap (bp, buflen); |
267 | |
268 | return 0; |
269 | } |
270 | |
271 | static error_t |
272 | op_write (struct cache_handle *c, |
273 | int *p, |
274 | int **reply, |
275 | int version) |
276 | { |
277 | off_t offset; |
278 | size_t count; |
279 | error_t err; |
280 | mach_msg_type_number_t amt; |
281 | char *bp; |
282 | struct stat st; |
283 | |
284 | p++; |
285 | offset = ntohl (*p); |
286 | p++; |
287 | p++; |
288 | count = ntohl (*p); |
289 | p++; |
290 | bp = (char *) *reply; |
291 | |
292 | while (count) |
293 | { |
294 | err = io_write (c->port, bp, count, offset, &amt); |
295 | if (err) |
296 | return err; |
297 | if (amt == 0) |
298 | return EIO((0x10 << 26) | ((5) & 0x3fff)); |
299 | count -= amt; |
300 | bp += amt; |
301 | offset += amt; |
302 | } |
303 | |
304 | file_sync (c->port, 1, 0); |
305 | |
306 | err = io_stat (c->port, &st); |
307 | if (err) |
308 | return err; |
309 | *reply = encode_fattr (*reply, &st, version); |
310 | return 0; |
311 | } |
312 | |
313 | static error_t |
314 | op_create (struct cache_handle *c, |
315 | int *p, |
316 | int **reply, |
317 | int version) |
318 | { |
319 | error_t err; |
320 | char *name; |
321 | retry_type do_retry; |
322 | char retry_name [1024]; |
323 | mach_port_t newport; |
324 | struct cache_handle *newc; |
325 | struct stat st; |
326 | mode_t mode; |
327 | int statchanged = 0; |
328 | off_t size; |
329 | |
330 | p = decode_name (p, &name); |
331 | mode = ntohl (*p); |
332 | p++; |
333 | |
334 | err = dir_lookup (c->port, name, O_NOTRANS0x0080 | O_CREAT0x0010 | O_TRUNC0x00010000, mode, |
335 | &do_retry, retry_name, &newport); |
336 | if (!err |
337 | && (do_retry != FS_RETRY_NORMAL |
338 | || retry_name[0] != '\0')) |
339 | err = EACCES((0x10 << 26) | ((13) & 0x3fff)); |
340 | |
341 | if (err) |
342 | return err; |
343 | |
344 | if (!err) |
345 | err = io_stat (newport, &st); |
346 | if (err) |
347 | goto errout; |
348 | |
349 | |
350 | |
351 | |
352 | p++, p++; |
353 | |
354 | size = ntohl (*p); |
355 | p++; |
356 | if (size != -1 && size != st.st_size) |
357 | { |
358 | err = file_set_size (newport, size); |
359 | statchanged = 1; |
360 | } |
361 | if (err) |
362 | goto errout; |
363 | |
364 | |
365 | |
366 | if (statchanged) |
367 | err = io_stat (newport, &st); |
368 | |
369 | if (err) |
370 | { |
371 | errout: |
372 | dir_unlink (c->port, name); |
373 | free (name); |
374 | return err; |
375 | } |
376 | free (name); |
377 | |
378 | newc = create_cached_handle (*(int *)c->handle, c, newport); |
379 | if (!newc) |
380 | return ESTALE((0x10 << 26) | ((70) & 0x3fff)); |
381 | |
382 | *reply = encode_fhandle (*reply, newc->handle); |
383 | *reply = encode_fattr (*reply, &st, version); |
384 | return 0; |
385 | } |
386 | |
387 | static error_t |
388 | op_remove (struct cache_handle *c, |
389 | int *p, |
390 | int **reply, |
391 | int version) |
392 | { |
393 | error_t err; |
394 | char *name; |
395 | |
396 | decode_name (p, &name); |
397 | |
398 | err = dir_unlink (c->port, name); |
| Value stored to 'err' is never read |
399 | free (name); |
400 | |
401 | return 0; |
402 | } |
403 | |
404 | static error_t |
405 | op_rename (struct cache_handle *fromc, |
406 | int *p, |
407 | int **reply, |
408 | int version) |
409 | { |
410 | struct cache_handle *toc; |
411 | char *fromname, *toname; |
412 | error_t err = 0; |
413 | |
414 | p = decode_name (p, &fromname); |
415 | p = lookup_cache_handle (p, &toc, fromc->ids); |
416 | decode_name (p, &toname); |
417 | |
418 | if (!toc) |
419 | err = ESTALE((0x10 << 26) | ((70) & 0x3fff)); |
420 | if (!err) |
421 | err = dir_rename (fromc->port, fromname, toc->port, toname, 0); |
422 | free (fromname); |
423 | free (toname); |
424 | return err; |
425 | } |
426 | |
427 | static error_t |
428 | op_link (struct cache_handle *filec, |
429 | int *p, |
430 | int **reply, |
431 | int version) |
432 | { |
433 | struct cache_handle *dirc; |
434 | char *name; |
435 | error_t err = 0; |
436 | |
437 | p = lookup_cache_handle (p, &dirc, filec->ids); |
438 | decode_name (p, &name); |
439 | |
440 | if (!dirc) |
441 | err = ESTALE((0x10 << 26) | ((70) & 0x3fff)); |
442 | if (!err) |
443 | err = dir_link (dirc->port, filec->port, name, 1); |
444 | |
445 | free (name); |
446 | return err; |
447 | } |
448 | |
449 | static error_t |
450 | op_symlink (struct cache_handle *c, |
451 | int *p, |
452 | int **reply, |
453 | int version) |
454 | { |
455 | char *name, *target; |
456 | error_t err; |
457 | mode_t mode; |
458 | file_t newport = MACH_PORT_NULL((mach_port_t) 0); |
459 | size_t len; |
460 | char *buf; |
461 | |
462 | p = decode_name (p, &name); |
463 | p = decode_name (p, &target); |
464 | mode = ntohl (*p); |
465 | p++; |
466 | if (mode == -1) |
467 | mode = 0777; |
468 | |
469 | len = strlen (target) + 1; |
470 | buf = alloca (sizeof (_HURD_SYMLINK) + len)__builtin_alloca (sizeof ("/hurd/" "symlink") + len); |
471 | memcpy (buf, _HURD_SYMLINK"/hurd/" "symlink", sizeof (_HURD_SYMLINK"/hurd/" "symlink")); |
472 | memcpy (buf + sizeof (_HURD_SYMLINK"/hurd/" "symlink"), target, len); |
473 | |
474 | err = dir_mkfile (c->port, O_WRITE0x0002, mode, &newport); |
475 | if (!err) |
476 | err = file_set_translator (newport, |
477 | FS_TRANS_EXCL0x00000002|FS_TRANS_SET0x00000004, |
478 | FS_TRANS_EXCL0x00000002|FS_TRANS_SET0x00000004, 0, |
479 | buf, sizeof (_HURD_SYMLINK"/hurd/" "symlink") + len, |
480 | MACH_PORT_NULL((mach_port_t) 0), MACH_MSG_TYPE_COPY_SEND19); |
481 | if (!err) |
482 | err = dir_link (c->port, newport, name, 1); |
483 | |
484 | free (name); |
485 | free (target); |
486 | |
487 | if (newport != MACH_PORT_NULL((mach_port_t) 0)) |
488 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), newport); |
489 | return err; |
490 | } |
491 | |
492 | static error_t |
493 | op_mkdir (struct cache_handle *c, |
494 | int *p, |
495 | int **reply, |
496 | int version) |
497 | { |
498 | char *name; |
499 | mode_t mode; |
500 | retry_type do_retry; |
501 | char retry_name [1024]; |
502 | mach_port_t newport; |
503 | struct stat st; |
504 | struct cache_handle *newc; |
505 | error_t err; |
506 | |
507 | p = decode_name (p, &name); |
508 | mode = ntohl (*p); |
509 | p++; |
510 | |
511 | err = dir_mkdir (c->port, name, mode); |
512 | |
513 | if (err) |
514 | { |
515 | free (name); |
516 | return err; |
517 | } |
518 | |
519 | err = dir_lookup (c->port, name, O_NOTRANS0x0080, 0, &do_retry, |
520 | retry_name, &newport); |
521 | free (name); |
522 | if (!err |
523 | && (do_retry != FS_RETRY_NORMAL |
524 | || retry_name[0] != '\0')) |
525 | err = EACCES((0x10 << 26) | ((13) & 0x3fff)); |
526 | if (err) |
527 | return err; |
528 | |
529 | |
530 | |
531 | if (!err) |
532 | err = io_stat (newport, &st); |
533 | if (err) |
534 | return err; |
535 | |
536 | newc = create_cached_handle (*(int *)c->handle, c, newport); |
537 | if (!newc) |
538 | return ESTALE((0x10 << 26) | ((70) & 0x3fff)); |
539 | *reply = encode_fhandle (*reply, newc->handle); |
540 | *reply = encode_fattr (*reply, &st, version); |
541 | return 0; |
542 | } |
543 | |
544 | static error_t |
545 | op_rmdir (struct cache_handle *c, |
546 | int *p, |
547 | int **reply, |
548 | int version) |
549 | { |
550 | char *name; |
551 | error_t err; |
552 | |
553 | decode_name (p, &name); |
554 | |
555 | err = dir_rmdir (c->port, name); |
556 | free (name); |
557 | return err; |
558 | } |
559 | |
560 | static error_t |
561 | op_readdir (struct cache_handle *c, |
562 | int *p, |
563 | int **reply, |
564 | int version) |
565 | { |
566 | int cookie; |
567 | unsigned count; |
568 | error_t err; |
569 | char *buf; |
570 | struct dirent *dp; |
571 | size_t bufsize; |
572 | int nentries; |
573 | int i; |
574 | int *replystart; |
575 | int *r; |
576 | |
577 | cookie = ntohl (*p); |
578 | p++; |
579 | count = ntohl (*p); |
580 | p++; |
581 | |
582 | buf = (char *) 0; |
583 | bufsize = 0; |
584 | err = dir_readdir (c->port, &buf, &bufsize, cookie, -1, count, &nentries); |
585 | if (err) |
586 | { |
587 | if (buf) |
588 | munmap (buf, bufsize); |
589 | return err; |
590 | } |
591 | |
592 | r = *reply; |
593 | |
594 | if (nentries == 0) |
595 | { |
596 | *(r++) = htonl (0); |
597 | *(r++) = htonl (1); |
598 | } |
599 | else |
600 | { |
601 | for (i = 0, dp = (struct dirent *) buf, replystart = *reply; |
602 | ((char *)dp < buf + bufsize |
603 | && i < nentries |
604 | && (char *)reply < (char *)replystart + count); |
605 | i++, dp = (struct dirent *) ((char *)dp + dp->d_reclen)) |
606 | { |
607 | *(r++) = htonl (1); |
608 | *(r++) = htonl (dp->d_ino); |
609 | r = encode_string (r, dp->d_name); |
610 | *(r++) = htonl (i + cookie + 1); |
611 | } |
612 | *(r++) = htonl (0); |
613 | *(r++) = htonl (0); |
614 | } |
615 | |
616 | *reply = r; |
617 | |
618 | if (buf) |
619 | munmap (buf, bufsize); |
620 | |
621 | return 0; |
622 | } |
623 | |
624 | static size_t |
625 | count_readdir_buffersize (int *p, int version) |
626 | { |
627 | p++; |
628 | return ntohl (*p); |
629 | } |
630 | |
631 | static error_t |
632 | op_statfs (struct cache_handle *c, |
633 | int *p, |
634 | int **reply, |
635 | int version) |
636 | { |
637 | struct statfs st; |
638 | error_t err; |
639 | |
640 | err = file_statfs (c->port, &st); |
641 | if (!err) |
642 | *reply = encode_statfs (*reply, &st); |
643 | return err; |
644 | } |
645 | |
646 | static error_t |
647 | op_mnt (struct cache_handle *c, |
648 | int *p, |
649 | int **reply, |
650 | int version) |
651 | { |
652 | file_t root; |
653 | struct cache_handle *newc; |
654 | char *name; |
655 | |
656 | decode_name (p, &name); |
657 | |
658 | root = file_name_lookup (name, 0, 0); |
659 | if (!root) |
660 | { |
661 | free (name); |
662 | return errno(*__errno_location ()); |
663 | } |
664 | |
665 | newc = create_cached_handle (enter_filesystem (name, root), c, root); |
666 | free (name); |
667 | if (!newc) |
668 | return ESTALE((0x10 << 26) | ((70) & 0x3fff)); |
669 | *reply = encode_fhandle (*reply, newc->handle); |
670 | return 0; |
671 | } |
672 | |
673 | static error_t |
674 | op_getport (struct cache_handle *c, |
675 | int *p, |
676 | int **reply, |
677 | int version) |
678 | { |
679 | int prog, vers, prot; |
680 | |
681 | prog = ntohl (*p); |
682 | p++; |
683 | vers = ntohl (*p); |
684 | p++; |
685 | prot = ntohl (*p); |
686 | p++; |
687 | |
688 | if (prot != IPPROTO_UDPIPPROTO_UDP) |
689 | *(*reply)++ = htonl (0); |
690 | else if ((prog == MOUNTPROG100005 && vers == MOUNTVERS1) |
691 | || (prog == NFS_PROGRAM((u_long)100003) && vers == NFS_VERSION((u_long)2))) |
692 | *(*reply)++ = htonl (NFS_PORT2049); |
693 | else if (prog == PMAPPROG((u_long)100000) && vers == PMAPVERS((u_long)2)) |
694 | *(*reply)++ = htonl (PMAPPORT((u_short)111)); |
695 | else |
696 | *(*reply)++ = 0; |
697 | |
698 | return 0; |
699 | } |
700 | |
701 |
|
702 | struct proctable nfs2table = |
703 | { |
704 | NFS2PROC_NULL0, |
705 | NFS2PROC_STATFS17, |
706 | { |
707 | { op_null, 0, 0, 0}, |
708 | { op_getattr, 0, 1, 1}, |
709 | { op_setattr, 0, 1, 1}, |
710 | { 0, 0, 0, 0 }, |
711 | { op_lookup, 0, 1, 1}, |
712 | { op_readlink, 0, 1, 1}, |
713 | { op_read, count_read_buffersize, 1, 1}, |
714 | { 0, 0, 0, 0 }, |
715 | { op_write, 0, 1, 1}, |
716 | { op_create, 0, 1, 1}, |
717 | { op_remove, 0, 1, 1}, |
718 | { op_rename, 0, 1, 1}, |
719 | { op_link, 0, 1, 1}, |
720 | { op_symlink, 0, 1, 1}, |
721 | { op_mkdir, 0, 1, 1}, |
722 | { op_rmdir, 0, 1, 1}, |
723 | { op_readdir, count_readdir_buffersize, 1, 1}, |
724 | { op_statfs, 0, 1, 1}, |
725 | } |
726 | }; |
727 | |
728 | |
729 | struct proctable mounttable = |
730 | { |
731 | MOUNTPROC_NULL0, |
732 | MOUNTPROC_EXPORT5, |
733 | { |
734 | { op_null, 0, 0, 0}, |
735 | { op_mnt, 0, 0, 1}, |
736 | { 0, 0, 0, 0}, |
737 | { op_null, 0, 0, 0}, |
738 | { op_null, 0, 0, 0}, |
739 | { 0, 0, 0, 0}, |
740 | } |
741 | }; |
742 | |
743 | struct proctable pmaptable = |
744 | { |
745 | PMAPPROC_NULL((u_long)0), |
746 | PMAPPROC_CALLIT((u_long)5), |
747 | { |
748 | { op_null, 0, 0, 0}, |
749 | { 0, 0, 0, 0}, |
750 | { 0, 0, 0, 0}, |
751 | { op_getport, 0, 0, 0}, |
752 | { 0, 0, 0, 0}, |
753 | { 0, 0, 0, 0}, |
754 | } |
755 | }; |