add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / fs.c
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