add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / rootdev.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 Rfile Rfile;
9 typedef struct Rpath Rpath;
10
11 struct Rfile
12 {
13 Ufile;
14 struct
15 {
16 Dir *d;
17 int i;
18 int n;
19 } diraux;
20 };
21
22 struct Rpath
23 {
24 Ref;
25
26 Rpath *hash;
27
28 int deleted;
29 char str[];
30 };
31
32 static Rpath *rpathtab[64];
33 static QLock rpathtablk;
34
35 static Rpath **
36 rpathent(char *path)
37 {
38 Rpath **prp;
39
40 prp = &rpathtab[hashpath(path) % nelem(rpathtab)];
41 while(*prp){
42 if(strcmp(path, (*prp)->str) == 0)
43 break;
44 prp = &((*prp)->hash);
45 }
46 return prp;
47 }
48
49 static char*
50 linkname(char *name)
51 {
52 if(strncmp(name, ".udir.L.", 8) == 0)
53 name += 8;
54 return name;
55 }
56
57 static char*
58 udirpath(char *base, char *name, char type)
59 {
60 char buf[9];
61
62 strcpy(buf, ".udir.T.");
63 buf[6] = type;
64 return allocpath(base, buf, name);
65 }
66
67 static int
68 udirget(char *base, char *name, char type, char **val)
69 {
70 char *f, *b;
71 int n, r, s;
72 int fd;
73
74 r = -1;
75 f = udirpath(base, name, type);
76 if((fd = open(shortpath(current->kcwd, f), OREAD)) < 0)
77 goto out;
78 if(val == nil){
79 r = 0;
80 goto out;
81 }
82 if((s = seek(fd, 0, 2)) < 0)
83 goto out;
84 b = kmalloc(s+1);
85 n = 0;
86 if(s > 0){
87 seek(fd, 0, 0);
88 if((n = read(fd, b, s)) < 0){
89 free(b);
90 goto out;
91 }
92 }
93 b[n] = 0;
94
95 r = 0;
96 *val = b;
97 out:
98 free(f);
99 close(fd);
100 return r;
101 }
102
103 static char*
104 resolvepath1(char *path, int link)
105 {
106 char *r, *b, *p, *o, *e;
107 char **a;
108
109 int n;
110 int i;
111
112 r = nil;
113 a = nil;
114 n = 0;
115
116 b = kstrdup(path);
117 for(p=b; *p; p++){
118 if(*p == '/'){
119 if((n % 16) == 0)
120 a = krealloc(a, sizeof(a[0]) * (n+16));
121 a[n++] = p;
122 }
123 }
124
125 e = nil;
126 for(i=n-1; i>=0; i--){
127 char *t;
128 char *f;
129
130 o = e;
131 e = a[i];
132 *e++ = 0;
133
134 f = linkname(e);
135 t = nil;
136
137 if(!udirget(b, f, 'L', &t)){
138 if(t == nil)
139 break;
140 if(link && o==nil){
141 free(t);
142 if(f != e)
143 break;
144 t = udirpath(b, e, 'L');
145 }
146 r = fullpath(b, t);
147 free(t);
148 if(o && o[1]){
149 t = r;
150 r = fullpath(t, &o[1]);
151 free(t);
152 }
153 break;
154 }
155
156 --e;
157 if(o) *o = '/';
158 }
159 free(b);
160 free(a);
161
162 return r;
163 }
164
165 static char *
166 resolvepath(char *path, int link)
167 {
168 char *t;
169 int x;
170
171 x = 0;
172 path = kstrdup(path);
173 while(t = resolvepath1(path, link)){
174 if(++x > 8){
175 free(t);
176 free(path);
177 return nil;
178 }
179 free(path); path = t;
180 }
181 return path;
182 }
183
184 static int
185 ropen(char *path, int mode, int perm, Ufile **pf)
186 {
187 Ufile *f;
188 int err;
189 char *s, *t;
190 int mode9, perm9;
191 int fd;
192 char *base;
193 char *name;
194 Rpath **prp;
195
196 trace("ropen(%s, %#o, %#o, ...)", path, mode, perm);
197
198 base = nil;
199 name = nil;
200 mode9 = mode & 3;
201 perm9 = (perm & ~current->umask) & 0777;
202
203 s = shortpath(current->kcwd, path);
204
205 if(mode & O_CREAT) {
206 Dir *d;
207
208 err = -EINVAL;
209 if((base = basepath(path, &name)) == nil)
210 goto out;
211
212 /* resolve base directory */
213 if((d = dirstat(shortpath(current->kcwd, base))) == nil){
214 err = mkerror();
215 if(t = resolvepath1(base, 0)){
216 free(base); base = t;
217 t = allocpath(t, nil, name);
218 err = fsopen(t, mode, perm, pf);
219 free(t);
220 }
221 goto out;
222 }
223 err = -ENOTDIR;
224 if((d->mode & DMDIR) == 0){
225 free(d);
226 goto out;
227 }
228 free(d);
229
230 /* check if here is a symlink in the way */
231 t = udirpath(base, name, 'L');
232 if((fd = open(shortpath(current->kcwd, t), OREAD)) >= 0){
233 free(t);
234 close(fd);
235
236 if(mode & O_EXCL){
237 err = -EEXIST;
238 goto out;
239 }
240
241 if((t = resolvepath1(path, 0)) == nil)
242 goto out;
243 err = fsopen(t, mode, perm, pf);
244 free(t);
245 goto out;
246 }
247 free(t);
248
249 if(mode & (O_EXCL | O_TRUNC)){
250 if(mode & O_EXCL)
251 mode9 |= OEXCL;
252 fd = create(s, mode9, perm9);
253 } else {
254 /* try open first to avoid truncating existing the file */
255 if((fd = open(s, mode9)) < 0)
256 fd = create(s, mode9, perm9);
257 }
258 if(fd < 0){
259 err = mkerror();
260 goto out;
261 }
262 } else {
263 if(((mode & 3) == O_RDWR) || ((mode & 3) == O_WRONLY))
264 if(mode & O_TRUNC)
265 mode9 |= OTRUNC;
266
267 if((fd = open(s, mode9)) < 0){
268 err = mkerror();
269 if(t = resolvepath1(path, 0)){
270 err = fsopen(t, mode, perm, pf);
271 free(t);
272 }
273 goto out;
274 }
275 }
276
277 qlock(&rpathtablk);
278 prp = rpathent(path);
279 if(*prp != nil){
280 incref(*prp);
281 } else {
282 Rpath *rp;
283
284 rp = kmalloc(sizeof(*rp) + strlen(path) + 1);
285 rp->ref = 1;
286 rp->hash = nil;
287 rp->deleted = 0;
288 strcpy(rp->str, path);
289 *prp = rp;
290 }
291 qunlock(&rpathtablk);
292
293 f = kmallocz(sizeof(Rfile), 1);
294 f->ref = 1;
295 f->path = kstrdup(path);
296 f->dev = ROOTDEV;
297 f->mode = mode;
298 f->fd = fd;
299 f->off = 0;
300 *pf = f;
301
302 err = 0;
303
304 out:
305 free(base);
306 free(name);
307
308 return err;
309 }
310
311 static int
312 rclose(Ufile *f)
313 {
314 Rpath **prp;
315 Rfile *file = (Rfile*)f;
316 static char path[1024]; /* protected by rpathtablk */
317
318 qlock(&rpathtablk);
319 prp = rpathent(file->path);
320 if(!decref(*prp)){
321 Rpath *rp = *prp;
322 *prp = rp->hash;
323 if(rp->deleted){
324 if(fd2path(file->fd, path, sizeof(path)) == 0)
325 remove(shortpath(current->kcwd, path));
326 }
327 free(rp);
328 }
329 qunlock(&rpathtablk);
330
331 close(file->fd);
332 return 0;
333 }
334
335 static int
336 rread(Ufile *f, void *buf, int len, vlong off)
337 {
338 Rfile *file = (Rfile*)f;
339 int ret, n;
340
341 n = ret = 0;
342 if(notifyme(1))
343 return -ERESTART;
344 while((n < len) && ((ret = pread(file->fd, (uchar*)buf + n, len - n, off + n)) > 0))
345 n += ret;
346 notifyme(0);
347 if(ret < 0)
348 return mkerror();
349 return n;
350 }
351
352 static int
353 rwrite(Ufile *f, void *buf, int len, vlong off)
354 {
355 Rfile *file = (Rfile*)f;
356 int ret;
357
358 if(notifyme(1))
359 return -ERESTART;
360 ret = pwrite(file->fd, buf, len, off);
361 notifyme(0);
362 if(ret < 0)
363 ret = mkerror();
364 return ret;
365 }
366
367 static vlong
368 rsize(Ufile *f)
369 {
370 Rfile *file = (Rfile*)f;
371
372 return seek(file->fd, 0, 2);
373 }
374
375 static int
376 raccess(char *path, int mode)
377 {
378 static char omode[] = {
379 0, // ---
380 OEXEC, // --x
381 OWRITE, // -w-
382 ORDWR, // -wx
383 OREAD, // r--
384 OEXEC, // r-x
385 ORDWR, // rw-
386 ORDWR // rwx
387 };
388
389 int err;
390 int fd;
391 Dir *d;
392 char *s;
393
394 err = -EINVAL;
395 if(mode & ~07)
396 return err;
397
398 s = shortpath(current->kcwd, path);
399 if((d = dirstat(s)) == nil){
400 err = mkerror();
401 if(path = resolvepath1(path, 0)){
402 err = fsaccess(path, mode);
403 free(path);
404 }
405 goto out;
406 }
407
408 /* ignore the exec bit... firefox gets confused */
409 mode &= ~01;
410 if((mode == 0) || (d->mode & DMDIR)){
411 err = 0;
412 } else {
413 err = -EACCES;
414 if((mode & 01) && ((d->mode & 0111) == 0))
415 goto out;
416 if((mode & 02) && ((d->mode & 0222) == 0))
417 goto out;
418 if((mode & 04) && ((d->mode & 0444) == 0))
419 goto out;
420 if((fd = open(s, omode[mode])) >= 0){
421 close(fd);
422 err = 0;
423 }
424 }
425 out:
426 free(d);
427 return err;
428 }
429
430 static ulong
431 dir2statmode(Dir *d)
432 {
433 ulong mode;
434
435 mode = d->mode & 0777;
436 if(d->mode & DMDIR)
437 mode |= S_IFDIR;
438 else if(strcmp(d->name, "cons") == 0)
439 mode |= S_IFCHR;
440 else if(strncmp(d->name, "PTS.", 4) == 0)
441 mode |= S_IFCHR;
442 else if(strcmp(d->name, "zero") == 0)
443 mode |= S_IFCHR | 0222;
444 else if(strcmp(d->name, "null") == 0)
445 mode |= S_IFCHR | 0222;
446 else if(strncmp(d->name, ".udir.", 6) == 0){
447 switch(d->name[6]){
448 case 'L':
449 mode |= S_IFLNK;
450 break;
451 case 'S':
452 mode |= S_IFSOCK;
453 break;
454 case 'F':
455 mode |= S_IFIFO;
456 break;
457 case 'C':
458 mode |= S_IFCHR;
459 break;
460 case 'B':
461 mode |= S_IFBLK;
462 break;
463 }
464 } else if(d->type == '|')
465 mode |= S_IFIFO;
466 else if(d->type == 'H')
467 mode |= S_IFBLK;
468 else
469 mode |= S_IFREG;
470
471 return mode;
472 }
473
474 static void
475 dir2ustat(Dir *d, Ustat *s)
476 {
477 s->mode = dir2statmode(d);
478 s->uid = current->uid;
479 s->gid = current->gid;
480 s->size = d->length;
481 s->atime = d->atime;
482 s->mtime = d->mtime;
483 s->ctime = d->mtime;
484 s->ino = 0; // use d->qid?
485 s->dev = 0;
486 s->rdev = 0;
487 }
488
489 static int
490 rstat(char *path, int link, Ustat *s)
491 {
492 Dir *d;
493 int err;
494 char *t;
495
496 if((d = dirstat(shortpath(current->kcwd, path))) == nil){
497 if(link){
498 char *base;
499 char *name;
500 if(base = basepath(path, &name)){
501 t = udirpath(base, name, 'L');
502 free(name);
503 free(base);
504 d = dirstat(shortpath(current->kcwd, t));
505 free(t);
506 }
507
508 }
509 }
510 if(d == nil){
511 err = mkerror();
512 if(t = resolvepath1(path, 0)){
513 err = fsstat(t, link, s);
514 free(t);
515 }
516 return err;
517 }
518
519 dir2ustat(d, s);
520 s->ino = hashpath(path);
521
522 free(d);
523 return 0;
524 }
525
526 static int
527 rfstat(Ufile *f, Ustat *s)
528 {
529 Dir *d;
530
531 if((d = dirfstat(f->fd)) == nil)
532 return mkerror();
533
534 dir2ustat(d, s);
535 s->ino = hashpath(f->path);
536
537 free(d);
538 return 0;
539 }
540
541 static char*
542 fixname(char *name)
543 {
544 if(name == nil)
545 return nil;
546 if(strncmp(name, ".udir.", 6) == 0){
547 if(name[6] && name[7]=='.')
548 name += 8;
549 }
550 return name;
551 }
552
553 static int
554 rreaddir(Ufile *f, Udirent **pd)
555 {
556 Dir *d;
557 int i, n;
558
559 seek(f->fd, 0, 0);
560 n = dirreadall(f->fd, &d);
561 if(n < 0)
562 return mkerror();
563 for(i=0; i<n; i++){
564 if((*pd = newdirent(f->path, fixname(d[i].name), dir2statmode(&d[i]))) == nil)
565 break;
566 pd = &((*pd)->next);
567 }
568 free(d);
569 return i;
570 }
571
572 static int
573 rreadlink(char *path, char *buf, int len)
574 {
575 int err;
576 int fd;
577
578 char *t;
579 char *name;
580 char *base;
581
582 trace("rreadlink(%s)", path);
583
584 if((base = basepath(path, &name)) == nil)
585 return -EINVAL;
586
587 /* resolve base path */
588 if((fd = open(shortpath(current->kcwd, base), OREAD)) < 0){
589 err = mkerror();
590 if(t = resolvepath1(base, 0)){
591 free(base); base = t;
592 t = allocpath(base, nil, name);
593 err = fsreadlink(t, buf, len);
594 free(t);
595 }
596 goto out;
597 }
598 close(fd);
599
600 /* check if path is regular file */
601 if((fd = open(shortpath(current->kcwd, path), OREAD)) >= 0){
602 close(fd);
603 err = -EINVAL;
604 goto out;
605 }
606
607 t = udirpath(base, name, 'L');
608 if((fd = open(shortpath(current->kcwd, t), OREAD)) < 0){
609 err = mkerror();
610 free(t);
611 goto out;
612 }
613 free(t);
614 if((err = read(fd, buf, len)) < 0)
615 err = mkerror();
616 close(fd);
617 out:
618 free(base);
619 free(name);
620 return err;
621 }
622
623 enum {
624 COPYSIZE = 8*1024,
625 };
626
627 static int
628 copyfile(char *from, char *to)
629 {
630 int err, fromfd, tofd;
631 char *buf, *s;
632 Dir *ent;
633 Dir *dir;
634
635 dir = nil;
636 buf = nil;
637 ent = nil;
638
639 tofd = -1;
640
641 trace("copyfile(%s, %s)", from, to);
642
643 if((fromfd = open(shortpath(current->kcwd, from), OREAD)) < 0){
644 err = mkerror();
645 goto out;
646 }
647 if((dir = dirfstat(fromfd)) == nil){
648 err = mkerror();
649 goto out;
650 }
651 s = shortpath(current->kcwd, to);
652 if((err = open(s, OREAD)) >= 0){
653 close(err);
654 err = -EEXIST;
655 goto out;
656 }
657 if(dir->mode & DMDIR){
658 int n;
659 if((tofd = create(s, OREAD, dir->mode)) < 0){
660 err = mkerror();
661 goto out;
662 }
663 close(tofd);
664 tofd = -1;
665 while((n = dirread(fromfd, &ent)) > 0){
666 int i;
667
668 for(i=0; i<n; i++){
669 char *froment, *toent;
670
671 froment = allocpath(from, nil, ent[i].name);
672 toent = allocpath(to, nil, ent[i].name);
673 err = copyfile(froment, toent);
674 free(froment);
675 free(toent);
676
677 if(err < 0)
678 goto out;
679 }
680 free(ent); ent = nil;
681 }
682 } else {
683 if((tofd = create(s, OWRITE, dir->mode)) < 0){
684 err = mkerror();
685 goto out;
686 }
687 buf = kmalloc(COPYSIZE);
688 for(;;){
689 err = read(fromfd, buf, COPYSIZE);
690 if(err == 0)
691 break;
692 if(err < 0){
693 err = mkerror();
694 goto out;
695 }
696 if(write(tofd, buf, err) != err){
697 err = mkerror();
698 goto out;
699 }
700 }
701 }
702
703 err = 0;
704 out:
705 free(ent);
706 free(dir);
707 free(buf);
708 close(fromfd);
709 close(tofd);
710 return err;
711 }
712
713 static int
714 removefile(char *path)
715 {
716 int err;
717 int n;
718 Dir *d;
719 int fd;
720 char *s;
721
722 trace("removefile(%s)", path);
723
724 s = shortpath(current->kcwd, path);
725
726 if((d = dirstat(s)) == nil)
727 return mkerror();
728 if(remove(s) == 0){
729 free(d);
730 return 0;
731 }
732 if((d->mode & DMDIR) == 0){
733 free(d);
734 return mkerror();
735 }
736 free(d);
737 if((fd = open(s, OREAD)) < 0)
738 return mkerror();
739 err = 0;
740 d = nil;
741 while((n = dirread(fd, &d)) > 0){
742 char *t;
743 int i;
744
745 for(i=0; i<n; i++){
746 t = allocpath(path, nil, d[i].name);
747 err = removefile(t);
748 free(t);
749
750 if(err < 0)
751 break;
752 }
753 free(d); d = nil;
754
755 if(err < 0)
756 break;
757 }
758 close(fd);
759 if(err < 0)
760 return err;
761 if(n < 0)
762 return mkerror();
763 if(remove(s) < 0)
764 return mkerror();
765 return 0;
766 }
767
768 static int
769 resolvefromtopath(char **from, char **to)
770 {
771 char *t;
772
773 trace("resolvefromtopath(%s, %s)", *from, *to);
774
775 if((*from = resolvepath(*from, 1)) == nil){
776 *to = nil;
777 return -ELOOP;
778 }
779 if((*to = resolvepath(*to, 1)) == nil){
780 free(*from);
781 *from = nil;
782 return -ELOOP;
783 }
784 if(strstr(*from, ".udir.L")){
785 char *x;
786
787 x = nil;
788 for(t=*to; *t; t++){
789 if(*t == '/')
790 x = t;
791 }
792
793 if(strncmp(x+1, ".udir.", 6)){
794 *x = 0;
795 t = udirpath(*to, x+1, 'L');
796 free(*to); *to = t;
797 }
798 }
799
800 return 0;
801 }
802
803 static int
804 rrename(char *from, char *to)
805 {
806 int err;
807 char *x, *y, *t;
808
809 trace("rrename(%s, %s)", from, to);
810
811 if((err = resolvefromtopath(&from, &to)) < 0)
812 goto out;
813 if(strcmp(from, to) == 0)
814 goto out;
815 x = nil;
816 for(t=from; *t; t++){
817 if(*t == '/')
818 x = t;
819 }
820 y = nil;
821 for(t=to; *t; t++){
822 if(*t == '/')
823 y = t;
824 }
825 if(x && y){
826 char *e;
827
828 e = nil;
829 *x = 0; *y = 0;
830 if(strcmp(from, to) == 0)
831 e = &y[1];
832 *x = '/'; *y = '/';
833
834 if(e != nil){
835 Dir d;
836
837 nulldir(&d);
838 d.name = e;
839
840 remove(to);
841 if(dirwstat(shortpath(current->kcwd, from), &d) < 0)
842 err = mkerror();
843 goto out;
844 }
845 }
846 t = ksmprint("%s%d%d.tmp", to, current->pid, current->tid);
847 if((err = copyfile(from, t)) == 0){
848 Dir d;
849
850 nulldir(&d);
851 d.name = &y[1];
852
853 remove(shortpath(current->kcwd, to));
854 if(dirwstat(shortpath(current->kcwd, t), &d) < 0) {
855 err = mkerror();
856 } else {
857 removefile(from);
858 }
859 }
860 if(err != 0)
861 removefile(t);
862 free(t);
863 out:
864 free(from);
865 free(to);
866
867 return err;
868 }
869
870 static int
871 rmkdir(char *path, int mode)
872 {
873 int err;
874 Dir *d;
875 int fd;
876 int mode9;
877
878 char *base;
879 char *name;
880 char *t;
881
882 trace("rmkdir(%s, %#o)", path, mode);
883
884 if((base = basepath(path, &name)) == nil)
885 return -EINVAL;
886
887 if((d = dirstat(shortpath(current->kcwd, base))) == nil){
888 err = mkerror();
889 if(t = resolvepath1(base, 0)){
890 free(base); base = t;
891 t = allocpath(base, nil, name);
892 err = fsmkdir(t, mode);
893 free(t);
894 }
895 goto out;
896 }
897 err = -ENOTDIR;
898 if((d->mode & DMDIR) == 0){
899 free(d);
900 goto out;
901 }
902 free(d);
903
904 err = -EEXIST;
905 t = udirpath(base, name, 'L');
906 if(d = dirstat(shortpath(current->kcwd, t))){
907 free(d);
908 free(t);
909 goto out;
910 }
911 free(t);
912
913 mode9 = DMDIR | ((mode & ~current->umask) & 0777);
914 if((fd = create(shortpath(current->kcwd, path), OREAD|OEXCL, mode9)) < 0){
915 err = mkerror();
916 goto out;
917 }
918 close(fd);
919 err = 0;
920
921 out:
922 free(name);
923 free(base);
924 return err;
925 }
926
927 static void
928 combinedir(Dir *ndir, Dir *odir)
929 {
930 if(ndir->mode != ~0)
931 ndir->mode = (odir->mode & ~0777) | (ndir->mode & 0777);
932 }
933
934 static int
935 uwstat(char *path, Dir *ndir, int link)
936 {
937 int err;
938 Dir *dir;
939 char *s;
940
941 trace("uwstat(%s, ..., %d)", path, link);
942
943 s = shortpath(current->kcwd, path);
944 if((dir = dirstat(s)) == nil){
945 err = mkerror();
946 if(link){
947 char *base;
948 char *name;
949
950 if(base = basepath(path, &name)){
951 char *t;
952
953 t = udirpath(base, name, 'L');
954 free(base);
955 free(name);
956
957 err = uwstat(t, ndir, 0);
958 free(t);
959 }
960 }
961 return err;
962 }
963 combinedir(ndir, dir);
964 err = 0;
965 if(dirwstat(s, ndir) < 0)
966 err = mkerror();
967 free(dir);
968 return err;
969 }
970
971 static int
972 uwfstat(Ufile *f, Dir *ndir)
973 {
974 int err;
975 Dir *dir;
976
977 if((dir = dirfstat(f->fd)) == nil){
978 err = mkerror();
979 goto out;
980 }
981 combinedir(ndir, dir);
982 err = 0;
983 if(dirfwstat(f->fd, ndir) < 0)
984 err = mkerror();
985 out:
986 free(dir);
987 return err;
988 }
989
990 static int
991 rutime(char *path, long atime, long mtime)
992 {
993 Dir ndir;
994 int err;
995
996 trace("rutime(%s, %ld, %ld)", path, atime, mtime);
997
998 nulldir(&ndir);
999 ndir.atime = atime;
1000 ndir.mtime = mtime;
1001
1002 if((err = uwstat(path, &ndir, 1)) < 0){
1003 char *t;
1004
1005 if(t = resolvepath1(path, 0)){
1006 err = fsutime(t, atime, mtime);
1007 free(t);
1008 }
1009 }
1010 return err;
1011 }
1012
1013 static int
1014 rchmod(char *path, int mode)
1015 {
1016 Dir ndir;
1017 int err;
1018
1019 trace("rchmod(%s, %#o)", path, mode);
1020
1021 nulldir(&ndir);
1022 ndir.mode = mode;
1023
1024 if((err = uwstat(path, &ndir, 1)) < 0){
1025 char *t;
1026
1027 if(t = resolvepath1(path, 0)){
1028 err = fschmod(t, mode);
1029 free(t);
1030 }
1031 }
1032 return err;
1033 }
1034
1035 static int
1036 rchown(char *path, int uid, int gid, int link)
1037 {
1038 Ustat s;
1039
1040 USED(uid);
1041 USED(gid);
1042
1043 /* FIXME, just return the right errorcode for now */
1044 return fsstat(path, link, &s);
1045 }
1046
1047 static int
1048 rtruncate(char *path, vlong size)
1049 {
1050 Dir ndir;
1051 int err;
1052
1053 trace("rtruncate(%s, %lld)", path, size);
1054
1055 nulldir(&ndir);
1056 ndir.length = size;
1057
1058 if((err = uwstat(path, &ndir, 0)) < 0){
1059 char *t;
1060
1061 if(t = resolvepath1(path, 0)){
1062 err = fstruncate(t, size);
1063 free(t);
1064 }
1065 }
1066 return err;
1067 }
1068
1069 static int
1070 rfchmod(Ufile *f, int mode)
1071 {
1072 Dir ndir;
1073
1074 nulldir(&ndir);
1075 ndir.mode = mode;
1076 return uwfstat(f, &ndir);
1077 }
1078
1079 static int
1080 rfchown(Ufile *f, int uid, int gid)
1081 {
1082 USED(f);
1083 USED(uid);
1084 USED(gid);
1085
1086 return 0;
1087 }
1088
1089 static int
1090 rftruncate(Ufile *f, vlong size)
1091 {
1092 Dir ndir;
1093
1094 nulldir(&ndir);
1095 ndir.length = size;
1096 return uwfstat(f, &ndir);
1097 }
1098
1099 static int
1100 runlink(char *path, int rmdir)
1101 {
1102 int err;
1103 Dir *dir;
1104 char *t, *s;
1105 char *base;
1106 char *name;
1107 char *rpath;
1108 Rpath **prp;
1109
1110 trace("runlink(%s, %d)", path, rmdir);
1111
1112 rpath = nil;
1113 dir = nil;
1114 err = -EINVAL;
1115 if((base = basepath(path, &name)) == nil)
1116 goto out;
1117 if(dir = dirstat(shortpath(current->kcwd, path))){
1118 rpath = kstrdup(path);
1119 } else {
1120 rpath = udirpath(base, name, 'L');
1121 dir = dirstat(shortpath(current->kcwd, rpath));
1122 }
1123 if(dir == nil){
1124 err = mkerror();
1125 if(t = resolvepath1(path, 0)){
1126 err = fsunlink(t, rmdir);
1127 free(t);
1128 }
1129 goto out;
1130 }
1131 if(rmdir){
1132 if((dir->mode & DMDIR) == 0){
1133 err = -ENOTDIR;
1134 goto out;
1135 }
1136 } else {
1137 if(dir->mode & DMDIR){
1138 err = -EISDIR;
1139 goto out;
1140 }
1141 }
1142
1143 s = shortpath(current->kcwd, rpath);
1144
1145 qlock(&rpathtablk);
1146 prp = rpathent(path);
1147 if(*prp){
1148 Dir ndir;
1149
1150 t = ksmprint(".%s.%d.deleted", name, current->kpid);
1151 nulldir(&ndir);
1152 ndir.name = t;
1153 trace("runlink: file %s still in use renaming to -> %s", path, t);
1154 if(dirwstat(s, &ndir) < 0){
1155 qunlock(&rpathtablk);
1156 err = mkerror();
1157 free(t);
1158 goto out;
1159 }
1160 free(t);
1161 (*prp)->deleted = 1;
1162 qunlock(&rpathtablk);
1163
1164 } else {
1165 int x;
1166 qunlock(&rpathtablk);
1167
1168 x = 0;
1169 while(remove(s) < 0){
1170 err = mkerror();
1171 if(++x > 8){
1172 /* old debian bug clashes with mntgen */
1173 if(strcmp(base, "/")==0 && strstr(path, ".dpkg-"))
1174 err = -ENOENT;
1175 goto out;
1176 }
1177 }
1178 }
1179 err = 0;
1180 out:
1181 free(dir);
1182 free(name);
1183 free(base);
1184 free(rpath);
1185
1186 return err;
1187 }
1188
1189 static int
1190 rlink(char *old, char *new, int sym)
1191 {
1192 int err;
1193 int fd;
1194 char *base;
1195 char *name;
1196 char *t;
1197
1198 trace("rlink(%s, %s, %d)", old, new, sym);
1199
1200 if((base = basepath(new, &name)) == nil)
1201 return -EINVAL;
1202
1203 /* resolve base directory */
1204 if((fd = open(shortpath(current->kcwd, base), OREAD)) < 0){
1205 err = mkerror();
1206 if(t = resolvepath1(base, 0)){
1207 free(base); base = t;
1208 t = allocpath(base, nil, name);
1209 err = fslink(old, t, sym);
1210 free(t);
1211 }
1212 goto out;
1213 }
1214 close(fd);
1215
1216 if(sym == 0){
1217 if((err = resolvefromtopath(&old, &new)) == 0)
1218 err = copyfile(old, new);
1219 free(old);
1220 free(new);
1221 goto out;
1222 }
1223
1224 /* check if regular file is in the way */
1225 err = -EEXIST;
1226 if((fd = open(shortpath(current->kcwd, new), OREAD)) >= 0){
1227 close(fd);
1228 goto out;
1229 }
1230
1231 /* try to create the link, will fail if alreadt exists */
1232 t = udirpath(base, name, 'L');
1233 if((fd = create(shortpath(current->kcwd, t), OWRITE|OEXCL, 0777)) < 0){
1234 err = mkerror();
1235 free(t);
1236 goto out;
1237 }
1238 free(t);
1239
1240 if(write(fd, old, strlen(old)) < 0){
1241 err = mkerror();
1242 close(fd);
1243 goto out;
1244 }
1245 close(fd);
1246 err = 0;
1247 out:
1248 free(base);
1249 free(name);
1250 return err;
1251 }
1252
1253 static Udev rootdev =
1254 {
1255 .open = ropen,
1256 .access = raccess,
1257 .stat = rstat,
1258 .link = rlink,
1259 .unlink = runlink,
1260 .rename = rrename,
1261 .mkdir = rmkdir,
1262 .utime = rutime,
1263 .chmod = rchmod,
1264 .chown = rchown,
1265 .truncate = rtruncate,
1266
1267 .read = rread,
1268 .write = rwrite,
1269 .size = rsize,
1270 .close = rclose,
1271
1272 .fstat = rfstat,
1273 .readdir = rreaddir,
1274 .readlink = rreadlink,
1275
1276 .fchmod = rfchmod,
1277 .fchown = rfchown,
1278 .ftruncate = rftruncate,
1279 };
1280
1281 void rootdevinit(void)
1282 {
1283 devtab[ROOTDEV] = &rootdev;
1284
1285 fsmount(&rootdev, "");
1286 }