cae36a52 |
1 | #include <u.h> |
2 | #include <libc.h> |
3 | #include <ureg.h> |
4 | #include "dat.h" |
5 | #include "fns.h" |
6 | #include "linux.h" |
7 | |
8 | typedef struct Mount Mount; |
9 | |
10 | struct Mount |
11 | { |
12 | Mount *next; |
13 | Udev *dev; |
14 | int npath; |
15 | char path[]; |
16 | }; |
17 | |
18 | static Mount *mtab; |
19 | |
20 | void |
21 | fsmount(Udev *dev, char *path) |
22 | { |
23 | Mount *m, **p; |
24 | int n; |
25 | |
26 | if(dev == nil) |
27 | return; |
28 | |
29 | n = strlen(path); |
30 | m = kmalloc(sizeof(*m) + n + 1); |
31 | m->dev = dev; |
32 | m->next = nil; |
33 | m->npath = n; |
34 | strcpy(m->path, path); |
35 | |
36 | for(p=&mtab;;p=&((*p)->next)){ |
37 | Mount *x; |
38 | |
39 | if(x = *p){ |
40 | if(m->npath < x->npath) |
41 | continue; |
42 | if(m->npath == x->npath){ |
43 | if(strcmp(m->path, x->path) < 0) |
44 | continue; |
45 | } |
46 | } |
47 | m->next = *p; |
48 | *p = m; |
49 | break; |
50 | } |
51 | } |
52 | |
53 | ulong |
54 | hashpath(char *s) |
55 | { |
56 | ulong h; |
57 | for(h=0; *s; s++) |
58 | h = (h * 13) + (*s - 'a'); |
59 | return h; |
60 | } |
61 | |
62 | char* |
63 | basepath(char *p, char **ps) |
64 | { |
65 | char *x, *s; |
66 | int n; |
67 | |
68 | if(s = strrchr(p, '/')){ |
69 | if(s[1] != 0){ |
70 | if(ps) |
71 | *ps = kstrdup(s+1); |
72 | if((n = s - p) == 0) |
73 | n = 1; |
74 | x = kmalloc(n+1); |
75 | memmove(x, p, n); |
76 | x[n] = 0; |
77 | return x; |
78 | } |
79 | } |
80 | if(ps) |
81 | *ps = nil; |
82 | return nil; |
83 | } |
84 | |
85 | char* |
86 | allocpath(char *base, char *prefix, char *name) |
87 | { |
88 | char *p, *s; |
89 | int n, m, k; |
90 | |
91 | n = strlen(base); |
92 | m = strlen(name); |
93 | k = prefix ? strlen(prefix) : 0; |
94 | p = s = kmalloc(n+m+k+2); |
95 | memmove(p, base, n); |
96 | p += n; |
97 | if(m || k) |
98 | *p++ = '/'; |
99 | if(k){ |
100 | memmove(p, prefix, k); |
101 | p += k; |
102 | } |
103 | memmove(p, name, m+1); |
104 | return s; |
105 | } |
106 | |
107 | char* |
108 | fullpath(char *base, char *name) |
109 | { |
110 | char *s; |
111 | |
112 | if(*name == '/' || *name == '#'){ |
113 | s = kstrdup(name); |
114 | } else if(base) { |
115 | s = allocpath(base, nil, name); |
116 | } else { |
117 | s = nil; |
118 | } |
119 | if(s != nil) |
120 | cleanname(s); |
121 | return s; |
122 | } |
123 | |
124 | char* |
125 | shortpath(char *base, char *path) |
126 | { |
127 | int n; |
128 | |
129 | n = strlen(base); |
130 | if((n <= strlen(path)) && (strncmp(path, base, n)==0)){ |
131 | path += n; |
132 | if(*path == '/') |
133 | path++; |
134 | if(*path == 0) |
135 | path = "."; |
136 | } |
137 | return path; |
138 | } |
139 | |
140 | char* |
141 | fsfullpath(char *path) |
142 | { |
143 | char *root; |
144 | |
145 | path = fullpath(current->cwd, path); |
146 | if(path && (root = current->root)){ |
147 | root = allocpath(root, nil, path+1); |
148 | free(path); |
149 | path = root; |
150 | } |
151 | return path; |
152 | } |
153 | |
154 | char* |
155 | fsrootpath(char *path) |
156 | { |
157 | char *root; |
158 | |
159 | if(root = current->root){ |
160 | root = shortpath(root, path); |
161 | if(*root == '.'){ |
162 | path = "/"; |
163 | } else if(root > path){ |
164 | path = root-1; |
165 | } |
166 | } |
167 | return path; |
168 | } |
169 | |
170 | static Mount* |
171 | path2mount(char *path) |
172 | { |
173 | Mount *m; |
174 | |
175 | for(m=mtab; m; m=m->next){ |
176 | if(strncmp(path, m->path, m->npath) == 0){ |
177 | switch(path[m->npath]){ |
178 | case '\0': |
179 | case '/': |
180 | return m; |
181 | } |
182 | } |
183 | } |
184 | return nil; |
185 | } |
186 | |
187 | static Udev* |
188 | path2dev(char *path) |
189 | { |
190 | Mount *m; |
191 | |
192 | if(m = path2mount(path)) |
193 | return m->dev; |
194 | return nil; |
195 | } |
196 | |
197 | static int |
198 | fsenter(int *perr) |
199 | { |
200 | int err; |
201 | |
202 | if(perr == nil) |
203 | perr = &err; |
204 | if(current->linkloop > 8) |
205 | return *perr = -ELOOP; |
206 | current->linkloop++; |
207 | return 0; |
208 | } |
209 | |
210 | static void |
211 | fsleave(void) |
212 | { |
213 | current->linkloop--; |
214 | } |
215 | |
216 | int sys_getcwd(char *buf, int len) |
217 | { |
218 | int n; |
219 | char *cwd; |
220 | |
221 | trace("sys_getcwd(%p, %x)", buf, len); |
222 | |
223 | cwd = current->cwd; |
224 | n = strlen(cwd)+1; |
225 | if(n > len) |
226 | return -ERANGE; |
227 | memmove(buf, cwd, n); |
228 | return n; |
229 | } |
230 | |
231 | int |
232 | fsopen(char *path, int mode, int perm, Ufile **pf) |
233 | { |
234 | int err; |
235 | Udev *dev; |
236 | |
237 | trace("fsopen(%s, %#o, %#o)", path, mode, perm); |
238 | |
239 | *pf = nil; |
240 | if(fsenter(&err) < 0) |
241 | return err; |
242 | err = -ENOENT; |
243 | if((dev = path2dev(path)) && dev->open) |
244 | err = dev->open(path, mode, perm, pf); |
245 | fsleave(); |
246 | return err; |
247 | } |
248 | |
249 | int |
250 | fsaccess(char *path, int mode) |
251 | { |
252 | int err; |
253 | Udev *dev; |
254 | |
255 | trace("fsaccess(%s, %#o)", path, mode); |
256 | |
257 | if(fsenter(&err) < 0) |
258 | return err; |
259 | err = -ENOENT; |
260 | if(dev = path2dev(path)){ |
261 | err = 0; |
262 | if(dev->access) |
263 | err = dev->access(path, mode); |
264 | } |
265 | fsleave(); |
266 | |
267 | return err; |
268 | } |
269 | |
270 | int sys_access(char *name, int mode) |
271 | { |
272 | int err; |
273 | |
274 | trace("sys_access(%s, %#o)", name, mode); |
275 | |
276 | if((name = fsfullpath(name)) == nil) |
277 | return -EFAULT; |
278 | err = fsaccess(name, mode); |
279 | free(name); |
280 | |
281 | return err; |
282 | } |
283 | |
284 | int sys_open(char *name, int mode, int perm) |
285 | { |
286 | int err; |
287 | Ufile *file; |
288 | |
289 | trace("sys_open(%s, %#o, %#o)", name, mode, perm); |
290 | |
291 | if((name = fsfullpath(name)) == nil) |
292 | return -EFAULT; |
293 | err = fsopen(name, mode, perm, &file); |
294 | free(name); |
295 | |
296 | if(err == 0) |
297 | err = newfd(file, FD_CLOEXEC); |
298 | |
299 | return err; |
300 | } |
301 | |
302 | int sys_creat(char *name, int perm) |
303 | { |
304 | trace("sys_create(%s, %#o)", name, perm); |
305 | |
306 | return sys_open(name, O_CREAT|O_TRUNC, perm); |
307 | } |
308 | |
309 | int |
310 | fsstat(char *path, int link, Ustat *ps) |
311 | { |
312 | int err; |
313 | Udev *dev; |
314 | |
315 | trace("fsstat(%s, %d)", path, link); |
316 | |
317 | if(fsenter(&err) < 0) |
318 | return err; |
319 | err = -EPERM; |
320 | if((dev = path2dev(path)) && dev->stat){ |
321 | memset(ps, 0, sizeof(Ustat)); |
322 | err = dev->stat(path, link, ps); |
323 | } |
324 | fsleave(); |
325 | return err; |
326 | } |
327 | |
328 | int |
329 | sys_chdir(char *name) |
330 | { |
331 | int err; |
332 | Ufile *f; |
333 | |
334 | trace("sys_chdir(%s)", name); |
335 | |
336 | if((name = fsfullpath(name)) == nil) |
337 | return -EFAULT; |
338 | err = fsopen(name, O_RDONLY, 0, &f); |
339 | free(name); |
340 | if(err == 0){ |
341 | err = chdirfile(f); |
342 | putfile(f); |
343 | } |
344 | return err; |
345 | } |
346 | |
347 | int sys_chroot(char *name) |
348 | { |
349 | Ufile *f; |
350 | Ustat s; |
351 | int err; |
352 | |
353 | trace("sys_chroot(%s)", name); |
354 | |
355 | f = nil; |
356 | if((err = fsopen(name, O_RDONLY, 0, &f)) < 0) |
357 | goto out; |
358 | err = -ENOTDIR; |
359 | if(f->path == nil) |
360 | goto out; |
361 | if(devtab[f->dev]->fstat == nil) |
362 | goto out; |
363 | if((err = devtab[f->dev]->fstat(f, &s)) < 0) |
364 | goto out; |
365 | err = -ENOTDIR; |
366 | if((s.mode & ~0777) != S_IFDIR) |
367 | goto out; |
368 | err = 0; |
369 | free(current->root); |
370 | if(strcmp(f->path, "/") == 0){ |
371 | current->root = nil; |
372 | } else { |
373 | current->root = kstrdup(f->path); |
374 | } |
375 | out: |
376 | putfile(f); |
377 | return err; |
378 | } |
379 | |
380 | int |
381 | fschown(char *path, int uid, int gid, int link) |
382 | { |
383 | int err; |
384 | Udev *dev; |
385 | |
386 | trace("fschown(%s, %d, %d, %d)", path, uid, gid, link); |
387 | |
388 | if(fsenter(&err) < 0) |
389 | return err; |
390 | err = -EPERM; |
391 | if((dev = path2dev(path)) && dev->chown) |
392 | err = dev->chown(path, uid, gid, link); |
393 | fsleave(); |
394 | return err; |
395 | } |
396 | |
397 | int sys_chown(char *name, int uid, int gid) |
398 | { |
399 | int err; |
400 | |
401 | trace("sys_chown(%s, %d, %d)", name, uid, gid); |
402 | |
403 | if((name = fsfullpath(name)) == nil) |
404 | return -EFAULT; |
405 | err = fschown(name, uid, gid, 0); |
406 | free(name); |
407 | |
408 | return err; |
409 | } |
410 | |
411 | int sys_lchown(char *name, int uid, int gid) |
412 | { |
413 | int err; |
414 | |
415 | trace("sys_lchown(%s, %d, %d)", name, uid, gid); |
416 | |
417 | if((name = fsfullpath(name)) == nil) |
418 | return -EFAULT; |
419 | err = fschown(name, uid, gid, 1); |
420 | free(name); |
421 | |
422 | return err; |
423 | } |
424 | |
425 | int |
426 | fsreadlink(char *path, char *buf, int len) |
427 | { |
428 | int err; |
429 | Udev *dev; |
430 | |
431 | trace("fsreadlink(%s)", path); |
432 | |
433 | if(fsenter(&err) < 0) |
434 | return err; |
435 | err = -EPERM; |
436 | if((dev = path2dev(path)) && dev->readlink) |
437 | err = dev->readlink(path, buf, len); |
438 | fsleave(); |
439 | |
440 | return err; |
441 | } |
442 | |
443 | int sys_readlink(char *name, char *buf, int len) |
444 | { |
445 | int err; |
446 | |
447 | trace("sys_readlink(%s, %p, %x)", name, buf, len); |
448 | |
449 | if((name = fsfullpath(name)) == nil) |
450 | return -EFAULT; |
451 | err = fsreadlink(name, buf, len); |
452 | free(name); |
453 | |
454 | return err; |
455 | } |
456 | |
457 | int |
458 | fsrename(char *old, char *new) |
459 | { |
460 | int err; |
461 | Udev *dev; |
462 | |
463 | trace("fsrename(%s, %s)", old, new); |
464 | |
465 | if(fsenter(&err) < 0) |
466 | return err; |
467 | err = -EPERM; |
468 | if((dev = path2dev(old)) && dev->rename){ |
469 | err = -EXDEV; |
470 | if(dev == path2dev(new)) |
471 | err = dev->rename(old, new); |
472 | } |
473 | fsleave(); |
474 | |
475 | return err; |
476 | } |
477 | |
478 | |
479 | int sys_rename(char *from, char *to) |
480 | { |
481 | int err; |
482 | |
483 | trace("sys_rename(%s, %s)", from, to); |
484 | |
485 | if((from = fsfullpath(from)) == nil) |
486 | return -EFAULT; |
487 | if((to = fsfullpath(to)) == nil){ |
488 | free(from); |
489 | return -EFAULT; |
490 | } |
491 | err = fsrename(from, to); |
492 | free(from); |
493 | free(to); |
494 | |
495 | return err; |
496 | } |
497 | |
498 | int |
499 | fsmkdir(char *path, int mode) |
500 | { |
501 | int err; |
502 | Udev *dev; |
503 | |
504 | trace("fsmkdir(%s, %#o)", path, mode); |
505 | |
506 | if(fsenter(&err) < 0) |
507 | return err; |
508 | |
509 | err = -EPERM; |
510 | if((dev = path2dev(path)) && dev->mkdir) |
511 | err = dev->mkdir(path, mode); |
512 | fsleave(); |
513 | |
514 | return err; |
515 | } |
516 | |
517 | int sys_mkdir(char *name, int mode) |
518 | { |
519 | int err; |
520 | |
521 | trace("sys_mkdir(%s, %#o)", name, mode); |
522 | |
523 | if((name = fsfullpath(name)) == nil) |
524 | return -EFAULT; |
525 | err = fsmkdir(name, mode); |
526 | free(name); |
527 | |
528 | return err; |
529 | } |
530 | |
531 | int |
532 | fsutime(char *path, int atime, int mtime) |
533 | { |
534 | int err; |
535 | Udev *dev; |
536 | |
537 | trace("fsutime(%s, %d, %d)", path, atime, mtime); |
538 | |
539 | if(fsenter(&err) < 0) |
540 | return err; |
541 | err = -EPERM; |
542 | if((dev = path2dev(path)) && dev->utime) |
543 | err = dev->utime(path, atime, mtime); |
544 | fsleave(); |
545 | |
546 | return err; |
547 | } |
548 | |
549 | struct linux_utimbuf |
550 | { |
551 | long atime; |
552 | long mtime; |
553 | }; |
554 | |
555 | int sys_utime(char *name, void *times) |
556 | { |
557 | int err; |
558 | struct linux_utimbuf *t = times; |
559 | |
560 | trace("sys_utime(%s, %p)", name, times); |
561 | |
562 | if((name = fsfullpath(name)) == nil) |
563 | return -EFAULT; |
564 | if(t != nil){ |
565 | err = fsutime(name, t->atime, t->mtime); |
566 | }else{ |
567 | long x = time(0); |
568 | err = fsutime(name, x, x); |
569 | } |
570 | free(name); |
571 | |
572 | return err; |
573 | } |
574 | |
575 | int sys_utimes(char *name, void *tvp) |
576 | { |
577 | int err; |
578 | struct linux_timeval *t = tvp; |
579 | |
580 | trace("sys_utimes(%s, %p)", name, tvp); |
581 | |
582 | if((name = fsfullpath(name)) == nil) |
583 | return -EFAULT; |
584 | if(t != nil){ |
585 | err = fsutime(name, t[0].tv_sec, t[1].tv_sec); |
586 | }else{ |
587 | long x = time(0); |
588 | err = fsutime(name, x, x); |
589 | } |
590 | free(name); |
591 | |
592 | return err; |
593 | } |
594 | |
595 | int |
596 | fschmod(char *path, int mode) |
597 | { |
598 | int err; |
599 | Udev *dev; |
600 | |
601 | trace("fschmod(%s, %#o)", path, mode); |
602 | |
603 | if(fsenter(&err) < 0) |
604 | return err; |
605 | err = -EPERM; |
606 | if((dev = path2dev(path)) && dev->chmod) |
607 | err = dev->chmod(path, mode); |
608 | fsleave(); |
609 | |
610 | return err; |
611 | } |
612 | |
613 | int sys_chmod(char *name, int mode) |
614 | { |
615 | int err; |
616 | |
617 | trace("sys_chmod(%s, %#o)", name, mode); |
618 | |
619 | if((name = fsfullpath(name)) == nil) |
620 | return -EFAULT; |
621 | err = fschmod(name, mode); |
622 | free(name); |
623 | |
624 | return err; |
625 | } |
626 | |
627 | int |
628 | fstruncate(char *path, vlong size) |
629 | { |
630 | int err; |
631 | Udev *dev; |
632 | |
633 | trace("fstruncate(%s, %llx)", path, size); |
634 | |
635 | if(fsenter(&err) < 0) |
636 | return err; |
637 | err = -EPERM; |
638 | if((dev = path2dev(path)) && dev->truncate) |
639 | err = dev->truncate(path, size); |
640 | fsleave(); |
641 | |
642 | return err; |
643 | } |
644 | |
645 | int sys_truncate(char *name, ulong size) |
646 | { |
647 | int err; |
648 | |
649 | trace("sys_truncate(%s, %lux)", name, size); |
650 | |
651 | if((name = fsfullpath(name)) == nil) |
652 | return -EFAULT; |
653 | err = fstruncate(name, size); |
654 | free(name); |
655 | |
656 | return err; |
657 | } |
658 | |
659 | int |
660 | fsunlink(char *path, int rmdir) |
661 | { |
662 | int err; |
663 | Udev *dev; |
664 | |
665 | trace("fsunlink(%s, %d)", path, rmdir); |
666 | |
667 | if(fsenter(&err) < 0) |
668 | return err; |
669 | err = -EPERM; |
670 | if((dev = path2dev(path)) && dev->unlink) |
671 | err = dev->unlink(path, rmdir); |
672 | fsleave(); |
673 | |
674 | return err; |
675 | } |
676 | |
677 | int sys_unlink(char *name) |
678 | { |
679 | int err; |
680 | |
681 | trace("sys_unlink(%s)", name); |
682 | |
683 | if((name = fsfullpath(name)) == nil) |
684 | return -EFAULT; |
685 | err = fsunlink(name, 0); |
686 | free(name); |
687 | |
688 | return err; |
689 | } |
690 | |
691 | int sys_rmdir(char *name) |
692 | { |
693 | int err; |
694 | |
695 | trace("sys_rmdir(%s)", name); |
696 | |
697 | if((name = fsfullpath(name)) == nil) |
698 | return -EFAULT; |
699 | err = fsunlink(name, 1); |
700 | free(name); |
701 | |
702 | return err; |
703 | } |
704 | |
705 | int |
706 | fslink(char *old, char *new, int sym) |
707 | { |
708 | int err; |
709 | Udev *dev; |
710 | |
711 | trace("fslink(%s, %s, %d)", old, new, sym); |
712 | |
713 | if(fsenter(&err) < 0) |
714 | return err; |
715 | err = -EPERM; |
716 | if((dev = path2dev(new)) && dev->link){ |
717 | err = -EXDEV; |
718 | if(sym || dev == path2dev(old)) |
719 | err = dev->link(old, new, sym); |
720 | } |
721 | fsleave(); |
722 | |
723 | return err; |
724 | } |
725 | |
726 | int sys_link(char *old, char *new) |
727 | { |
728 | int err; |
729 | |
730 | trace("sys_link(%s, %s)", old, new); |
731 | |
732 | if((old = fsfullpath(old)) == nil) |
733 | return -EFAULT; |
734 | if((new = fsfullpath(new)) == nil){ |
735 | free(old); |
736 | return -EFAULT; |
737 | } |
738 | err = fslink(old, new, 0); |
739 | free(old); |
740 | free(new); |
741 | |
742 | return err; |
743 | } |
744 | |
745 | int sys_symlink(char *old, char *new) |
746 | { |
747 | int err; |
748 | |
749 | trace("sys_symlink(%s, %s)", old, new); |
750 | |
751 | if((new = fsfullpath(new)) == nil) |
752 | return -EFAULT; |
753 | err = fslink(old, new, 1); |
754 | free(new); |
755 | |
756 | return err; |
757 | } |
758 | |