add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / fs.c
CommitLineData
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
8typedef struct Mount Mount;
9
10struct Mount
11{
12 Mount *next;
13 Udev *dev;
14 int npath;
15 char path[];
16};
17
18static Mount *mtab;
19
20void
21fsmount(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
53ulong
54hashpath(char *s)
55{
56 ulong h;
57 for(h=0; *s; s++)
58 h = (h * 13) + (*s - 'a');
59 return h;
60}
61
62char*
63basepath(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
85char*
86allocpath(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
107char*
108fullpath(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
124char*
125shortpath(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
140char*
141fsfullpath(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
154char*
155fsrootpath(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
170static Mount*
171path2mount(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
187static Udev*
188path2dev(char *path)
189{
190 Mount *m;
191
192 if(m = path2mount(path))
193 return m->dev;
194 return nil;
195}
196
197static int
198fsenter(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
210static void
211fsleave(void)
212{
213 current->linkloop--;
214}
215
216int 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
231int
232fsopen(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
249int
250fsaccess(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
270int 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
284int 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
302int 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
309int
310fsstat(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
328int
329sys_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
347int 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 }
375out:
376 putfile(f);
377 return err;
378}
379
380int
381fschown(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
397int 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
411int 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
425int
426fsreadlink(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
443int 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
457int
458fsrename(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
479int 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
498int
499fsmkdir(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
517int 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
531int
532fsutime(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
549struct linux_utimbuf
550{
551 long atime;
552 long mtime;
553};
554
555int 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
575int 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
595int
596fschmod(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
613int 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
627int
628fstruncate(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
645int 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
659int
660fsunlink(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
677int 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
691int 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
705int
706fslink(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
726int 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
745int 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