devfs-posix.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devfs-posix.c (15130B)
       ---
            1 #include        "u.h"
            2 #include        <stdio.h> /* for remove, rename */
            3 #include        <pwd.h>
            4 #include        <grp.h>        /* going to regret this - getgrgid is a stack smasher */
            5 #include        <sys/socket.h>
            6 #include        <sys/un.h>
            7 
            8 #if defined(__FreeBSD__)
            9 #include        <sys/disk.h>
           10 #include        <sys/disklabel.h>
           11 #include        <sys/ioctl.h>
           12 #endif
           13 
           14 #if defined(__APPLE__)
           15 #include        <sys/disk.h>
           16 #endif
           17 
           18 #if defined(__linux__)
           19 #include        <linux/hdreg.h>
           20 #include        <linux/fs.h>
           21 #include        <sys/ioctl.h>
           22 #endif
           23 
           24 #include        "lib.h"
           25 #include        "mem.h"
           26 #include        "dat.h"
           27 #include        "fns.h"
           28 #include        "error.h"
           29 
           30 enum
           31 {
           32         Trace = 0,
           33         FsChar = 'Z',
           34 };
           35 
           36 extern char *canopen;
           37 extern Path *addelem(Path*, char*, Chan*);
           38 static char *uidtoname(int);
           39 static char *gidtoname(int);
           40 static int nametouid(char*);
           41 static int nametogid(char*);
           42 
           43 static vlong disksize(int, struct stat*);
           44 
           45 typedef struct UnixFd UnixFd;
           46 struct UnixFd
           47 {
           48         int        fd;
           49         int        issocket;
           50         DIR*        dir;
           51         vlong        diroffset;
           52         QLock        dirlock;
           53         struct dirent *nextde;
           54         Path        *path;
           55 };
           56 
           57 void
           58 oserrstr(void)
           59 {
           60         if (errno == EINTR)
           61                 kstrcpy(up->errstr, Eintr, ERRMAX);
           62         else
           63                 kstrcpy(up->errstr, strerror(errno), ERRMAX);
           64 }
           65 
           66 void
           67 oserror(void)
           68 {
           69         if (errno == EINTR)
           70                 error(Eintr);
           71         else
           72                 error(strerror(errno));
           73 }
           74 
           75 static Qid
           76 fsqid(struct stat *st)
           77 {
           78         Qid q;
           79         int dev;
           80         static int nqdev;
           81         static uchar *qdev;
           82 
           83         if(qdev == 0)
           84                 qdev = smalloc(65536U);
           85 
           86         q.type = 0;
           87         if((st->st_mode&S_IFMT) ==  S_IFDIR)
           88                 q.type = QTDIR;
           89 
           90         dev = st->st_dev & 0xFFFFUL;
           91         if(qdev[dev] == 0)
           92                 qdev[dev] = ++nqdev;
           93         
           94         q.path = (vlong)qdev[dev]<<48;
           95         q.path ^= st->st_ino;
           96         q.vers = st->st_mtime;
           97         
           98         return q;
           99 }
          100 
          101 static Chan*
          102 fsattach(char *spec)
          103 {
          104         struct stat st;
          105         Chan *c;
          106         UnixFd *ufd;
          107         int dev;
          108         
          109         dev = 1;
          110         if(spec && spec[0]){
          111                 snprint(up->genbuf, sizeof up->genbuf, "no file system #%C%s", FsChar, spec);
          112                 error(up->genbuf);
          113         }
          114 
          115         if(stat("/", &st) < 0)
          116                 oserror();
          117 
          118         c = devattach(FsChar, 0);
          119         ufd = mallocz(sizeof(UnixFd), 1);
          120         ufd->path = newpath("/");
          121         ufd->fd = -1;
          122 
          123         c->aux = ufd;
          124         c->dev = dev;
          125         c->qid = fsqid(&st);
          126         
          127         if(Trace)
          128                 print("fsattach /\n");
          129 
          130         return c;
          131 }
          132 
          133 static Chan*
          134 fsclone(Chan *c, Chan *nc)
          135 {
          136         UnixFd *ufd;
          137         
          138         ufd = mallocz(sizeof(UnixFd), 1);
          139         *ufd = *(UnixFd*)c->aux;
          140         if(ufd->path)
          141                 incref(&ufd->path->ref);
          142         ufd->fd = -1;
          143         nc->aux = ufd;
          144         return nc;
          145 }
          146 
          147 static char*
          148 lastelem(char *s)
          149 {
          150         char *t;
          151 
          152         if(s[0] == '/' && s[1] == 0)
          153                 return s;
          154         t = strrchr(s, '/');
          155         if(t == nil)
          156                 return s;
          157         return t+1;
          158 }
          159 
          160 static char*
          161 fspath(Chan *c, char *suffix)
          162 {
          163         char *s, *t;
          164         int len;
          165         UnixFd *ufd;
          166         
          167         ufd = c->aux;
          168         s = ufd->path->s;
          169         len = strlen(s)+1;
          170         if(suffix)
          171                 len += 1+strlen(suffix);
          172         t = smalloc(len);
          173         strcpy(t, s);
          174         if(suffix){
          175                 if(s[strlen(s)-1] != '/')
          176                         strcat(t, "/");
          177                 strcat(t, suffix);
          178         }
          179         return t;
          180 }
          181 
          182 static int
          183 fswalk1(Chan *c, char *name)
          184 {
          185         struct stat st;
          186         char *path;
          187         UnixFd *ufd;
          188         
          189         ufd = c->aux;
          190         if(strcmp(name, "..") == 0 && strcmp(ufd->path->s, "/") == 0)
          191                 return 0;
          192         
          193         path = fspath(c, name);
          194         if(stat(path, &st) < 0){
          195                 if(Trace)
          196                         print("fswalk1 %s (%s)\n", path, strerror(errno));        
          197                 free(path);
          198                 return -1;
          199         }
          200         if(Trace)
          201                 print("fswalk1 %s\n", path);        
          202         free(path);
          203         
          204         c->qid = fsqid(&st);
          205         return 0;
          206 }
          207 
          208 static void
          209 replacepath(Chan *c, Path *p)
          210 {
          211         UnixFd *ufd;
          212         
          213         ufd = c->aux;
          214         incref(&p->ref);
          215         pathclose(ufd->path);
          216         ufd->path = p;
          217 }
          218 
          219 static Walkqid*
          220 fswalk(Chan *c, Chan *nc, char **name, int nname)
          221 {
          222         int i;
          223         Path *path;
          224         Walkqid *wq;
          225         UnixFd *ufd;
          226 
          227         if(nc != nil)
          228                 panic("fswalk: nc != nil");
          229         wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
          230         nc = devclone(c);
          231         fsclone(c, nc);
          232         ufd = c->aux;
          233         path = ufd->path;
          234         incref(&path->ref);
          235 
          236         wq->clone = nc;
          237         for(i=0; i<nname; i++){
          238                 ufd = nc->aux;
          239                 replacepath(nc, path);
          240                 if(fswalk1(nc, name[i]) < 0){
          241                         if(i == 0){
          242                                 pathclose(path);
          243                                 cclose(nc);
          244                                 free(wq);
          245                                 error(Enonexist);
          246                         }
          247                         break;
          248                 }
          249                 path = addelem(path, name[i], nil);
          250                 wq->qid[i] = nc->qid;
          251         }
          252         replacepath(nc, path);
          253         pathclose(path);
          254         if(i != nname){
          255                 cclose(nc);
          256                 wq->clone = nil;
          257         }
          258         wq->nqid = i;
          259         return wq;
          260 }
          261 
          262 static int
          263 fsdirstat(char *path, int dev, Dir *d)
          264 {
          265         int fd;
          266         struct stat st;
          267         
          268         if(stat(path, &st) < 0 && lstat(path, &st) < 0)
          269                 return -1;
          270 
          271         d->name = lastelem(path);
          272         d->uid = uidtoname(st.st_uid);
          273         d->gid = gidtoname(st.st_gid);
          274         d->muid = "";
          275         d->qid = fsqid(&st);
          276         d->mode = (d->qid.type<<24) | (st.st_mode&0777);
          277         d->atime = st.st_atime;
          278         d->mtime = st.st_mtime;
          279         d->length = st.st_size;
          280         if(S_ISBLK(st.st_mode) && (fd = open(path, O_RDONLY)) >= 0){
          281                 d->length = disksize(fd, &st);
          282                 close(fd);
          283         }
          284         
          285         // devmnt leaves 1-9 unused so that we can steal them.
          286         // it is easier for all involved if #Z shows M as the file type instead of Z.
          287         // dev is c->dev, either 1 (#Z) or 2 (#Zplan9).
          288         d->type = 'M';
          289         d->dev = dev;
          290         return 0;
          291 }
          292 
          293 static int
          294 fsstat(Chan *c, uchar *buf, int n)
          295 {
          296         Dir d;
          297         char *path;
          298         UnixFd *ufd;
          299 
          300         ufd = c->aux;
          301         if(Trace)
          302                 print("fsstat %s\n", ufd->path->s);
          303 
          304         if(n < BIT16SZ)
          305                 error(Eshortstat);
          306 
          307         path = fspath(c, nil);
          308         if(fsdirstat(path, c->dev, &d) < 0){
          309                 free(path);
          310                 oserror();
          311         }
          312         if(strcmp(ufd->path->s, "/") == 0)
          313                 d.name = "/";
          314         n = convD2M(&d, buf, n);
          315         free(path);
          316         return n;
          317 }
          318 
          319 static int
          320 opensocket(UnixFd *ufd, char *path)
          321 {
          322         int fd;
          323         struct stat st;
          324         struct sockaddr_un su;
          325         
          326         if(stat(path, &st) < 0)
          327                 return -1;
          328         if(!S_ISSOCK(st.st_mode))
          329                 return -1;
          330         memset(&su, 0, sizeof su);
          331         su.sun_family = AF_UNIX;
          332         if(strlen(path)+1 > sizeof su.sun_path){
          333                 errno = ENAMETOOLONG;
          334                 return -1;
          335         }
          336         strcpy(su.sun_path, path);
          337         if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
          338                 return -1;
          339         if(connect(fd, (struct sockaddr*)&su, sizeof su) < 0){
          340                 close(fd);
          341                 return -1;
          342         }
          343         ufd->fd = fd;
          344         ufd->issocket = 1;
          345         return 0;
          346 }                
          347 
          348 static Chan*
          349 fsopen(Chan *c, int mode)
          350 {
          351         char *path;
          352         int m;
          353         UnixFd *ufd;
          354         
          355         ufd = c->aux;
          356         if(Trace)
          357                 print("fsopen %s %#x\n", ufd->path->s, mode);
          358 
          359         /* protect files whose path does not begin with allowed */
          360         if(strncmp(ufd->path->s, canopen, strlen(canopen)) != 0)
          361                 error(Eperm);
          362 
          363         if(mode & ~(OTRUNC|ORCLOSE|3))
          364                 error(Ebadarg);
          365 
          366         if((c->qid.type & QTDIR) && mode != OREAD)
          367                 error(Eperm);
          368         
          369         if((c->qid.type&QTDIR) && mode != OREAD)
          370                 error(Eperm);
          371 
          372         c->mode = openmode(mode);
          373         path = fspath(c, nil);
          374         if(c->qid.type & QTDIR){
          375                 ufd->dir = opendir(path);
          376                 if(ufd->dir == nil){
          377                         free(path);
          378                         oserror();
          379                 }
          380                 ufd->diroffset = 0;
          381                 ufd->nextde = nil;
          382         }else{
          383                 m = mode & 3;
          384                 if(m == OEXEC)
          385                         m = OREAD;
          386                 if(mode & OTRUNC)
          387                         m |= O_TRUNC;
          388                 if((ufd->fd = open(path, m)) < 0 && opensocket(ufd, path) < 0){
          389                         free(path);
          390                         oserror();
          391                 }
          392         }
          393         free(path);
          394         c->flag |= COPEN;
          395         return c;
          396 }
          397 
          398 static void
          399 fscreate(Chan *c, char *name, int mode, ulong perm)
          400 {
          401         char *path, *path0;
          402         int fd, mm;
          403         UnixFd *ufd;
          404         struct stat st;
          405 
          406         ufd = c->aux;
          407         if(Trace)
          408                 print("fscreate %s %#x %#o\n", ufd->path->s, mode, perm);
          409 
          410         if(!(c->qid.type & QTDIR))
          411                 error(Enotdir);
          412 
          413         if(mode & ~(OTRUNC|ORCLOSE|3))
          414                 error(Ebadarg);
          415 
          416         if(perm & ~(DMDIR|0777))
          417                 error(Ebadarg);
          418 
          419         path0 = fspath(c, nil);
          420         path = fspath(c, name);
          421         if(waserror()){
          422                 free(path);
          423                 free(path0);
          424                 nexterror();
          425         }
          426         
          427         if(stat(path0, &st) < 0)
          428                 oserror();
          429 
          430         if(perm & DMDIR){
          431                 if(mode != OREAD)
          432                         error(Eperm);
          433                 /* have to do the minimum 0400 so we can open it */
          434                 if(mkdir(path, (0400 | perm) & 0777) < 0)
          435                         oserror();
          436                 if((fd = open(path, 0)) < 0)
          437                         oserror();
          438                 fchown(fd, -1, st.st_gid);
          439                 if(fstat(fd, &st) < 0){
          440                         close(fd);
          441                         oserror();
          442                 }
          443                 if((ufd->dir = opendir(path)) == nil) {
          444                         /* arguably we should set the mode here too 
          445                           * but it's hard to see that this case 
          446                           * will ever happen 
          447                           */
          448                         close(fd);
          449                         oserror();
          450                 }
          451                 // Be like Plan 9 file servers: inherit mode bits 
          452                 // and group from parent.
          453                 fchmod(fd, perm & st.st_mode & 0777);
          454                 close(fd);
          455                 ufd->diroffset = 0;
          456                 ufd->nextde = nil;
          457         }else{
          458                 mm = mode & 3;
          459                 if(mode & OTRUNC)
          460                         mm |= O_TRUNC;
          461                 if((fd = open(path, mm|O_CREAT|O_EXCL, 0666)) < 0)
          462                         oserror();
          463                 // Be like Plan 9 file servers: inherit mode bits 
          464                 // and group from parent.
          465                 fchmod(fd, perm & st.st_mode & 0777);
          466                 fchown(fd, -1, st.st_gid);
          467                 if(fstat(fd, &st) < 0){
          468                         close(fd);
          469                         oserror();
          470                 }
          471                 ufd->fd = fd;
          472         }
          473         free(path);
          474         free(path0);
          475         poperror();
          476         
          477         ufd->path = addelem(ufd->path, name, nil);
          478         c->qid = fsqid(&st);
          479         c->offset = 0;
          480         c->flag |= COPEN;
          481         c->mode = openmode(mode);
          482 }
          483 
          484 static void
          485 fsclose(Chan *c)
          486 {
          487         UnixFd *ufd;
          488         char *path;
          489         
          490         ufd = c->aux;
          491         if(Trace)
          492                 print("fsclose %s\n", ufd->path->s);
          493 
          494         if(c->flag & COPEN) {
          495                 if(c->flag & CRCLOSE) {
          496                         path = fspath(c, nil);
          497                         unlink(path);
          498                         free(path);
          499                 }
          500                 if(c->qid.type & QTDIR)
          501                         closedir(ufd->dir);
          502                 else
          503                         close(ufd->fd);
          504         }
          505         if(ufd->path)
          506                 pathclose(ufd->path);
          507         free(ufd);
          508 }
          509 
          510 static long fsdirread(Chan*, uchar*, long, vlong);
          511 
          512 static long
          513 fsread(Chan *c, void *va, long n, vlong offset)
          514 {
          515         int r;
          516         UnixFd *ufd;
          517 
          518         if(c->qid.type & QTDIR)
          519                 return fsdirread(c, va, n, offset);
          520 
          521         ufd = c->aux;
          522         if(ufd->issocket)
          523                 r = read(ufd->fd, va, n);
          524         else
          525                 r = pread(ufd->fd, va, n, offset);
          526         if(r < 0)
          527                 oserror();
          528         return r;
          529 }
          530 
          531 static long
          532 fswrite(Chan *c, void *va, long n, vlong offset)
          533 {
          534         int r;
          535         UnixFd *ufd;
          536 
          537         ufd = c->aux;
          538         if(ufd->issocket)
          539                 r = write(ufd->fd, va, n);
          540         else
          541                 r = pwrite(ufd->fd, va, n, offset);
          542         if(r < 0)
          543                 oserror();
          544         return r;
          545 }
          546 
          547 static int
          548 fswstat(Chan *c, uchar *buf, int n)
          549 {
          550         char *elem, *path, *npath, *strs, *t;
          551         int nn;
          552         Dir d;
          553         UnixFd *ufd;
          554 
          555         if(n < 2)
          556                 error(Ebadstat);
          557 
          558         nn = GBIT16((uchar*)buf);
          559         strs = smalloc(nn);
          560         if(convM2D(buf, n, &d, strs) != n){
          561                 free(strs);
          562                 error(Ebadstat);
          563         }
          564         
          565         path = fspath(c, nil);
          566         if(waserror()){
          567                 free(path);
          568                 free(strs);
          569                 nexterror();
          570         }
          571         
          572         if(d.muid[0])
          573                 error("cannot change muid");
          574 
          575         if(d.uid[0] || d.gid[0]){
          576                 int uid, gid;
          577                 
          578                 uid = -1;
          579                 gid = -1;
          580                 if(d.uid[0] && (uid = nametouid(d.uid)) < 0)
          581                         error("unknown uid");
          582                 if(d.gid[0] && (gid = nametogid(d.gid)) < 0)
          583                         error("unknown gid");
          584                 if(chown(path, uid, gid) < 0)
          585                         oserror();
          586         }
          587         
          588         ufd = c->aux;
          589         elem = lastelem(path);
          590         if(d.name[0] && strcmp(d.name, elem) != 0){
          591                 if(strchr(d.name, '/'))
          592                         error(Ebadarg);
          593                 npath = smalloc(strlen(path)+strlen(d.name)+1);
          594                 strcpy(npath, path);
          595                 t = strrchr(npath, '/');
          596                 strcpy(t+1, d.name);
          597                 if(rename(path, npath) < 0){
          598                         free(npath);
          599                         oserror();
          600                 }
          601                 free(npath);
          602         }
          603         
          604         if(~d.mode != 0 && chmod(path, d.mode&0777) < 0)
          605                 oserror();
          606 
          607         // TODO: Code to change uid, gid.
          608         
          609         poperror();
          610         return n;
          611 }
          612 
          613 static int
          614 isdots(char *name)
          615 {
          616         if(name[0] != '.')
          617                 return 0;
          618         if(name[1] == '\0')
          619                 return 1;
          620         if(name[1] != '.')
          621                 return 0;
          622         if(name[2] == '\0')
          623                 return 1;
          624         return 0;
          625 }
          626 
          627 static long
          628 fsdirread(Chan *c, uchar *va, long count, vlong offset)
          629 {
          630         char *path;
          631         int n, total;
          632         struct dirent *de;
          633         UnixFd *ufd;
          634         Dir d;
          635 
          636         ufd = c->aux;
          637         qlock(&ufd->dirlock);
          638         if(waserror()){
          639                 qunlock(&ufd->dirlock);
          640                 nexterror();
          641         }
          642 
          643         if(ufd->diroffset != offset){
          644                 if(offset != 0)
          645                         error(Ebadarg);
          646                 ufd->diroffset = 0;
          647                 ufd->nextde = nil;
          648                 rewinddir(ufd->dir);
          649         }
          650 
          651         total = 0;
          652         while(total+BIT16SZ < count) {
          653                 if(ufd->nextde){
          654                         de = ufd->nextde;
          655                         ufd->nextde = nil;
          656                 }
          657                 else if((de = readdir(ufd->dir)) == nil)
          658                         break;
          659                 if(isdots(de->d_name))
          660                         continue;
          661                 path = fspath(c, de->d_name);
          662                 if(fsdirstat(path, c->dev, &d) < 0){
          663                         free(path);
          664                         continue;
          665                 }
          666                 n = convD2M(&d, (uchar*)va+total, count-total);
          667                 free(path);
          668                 if(n == BIT16SZ){
          669                         ufd->nextde = de;
          670                         break;
          671                 }
          672                 total += n;
          673         }
          674         ufd->diroffset += total;
          675         qunlock(&ufd->dirlock);
          676         poperror();
          677         return total;
          678 }
          679 
          680 static void
          681 fsremove(Chan *c)
          682 {
          683         char *path;
          684         UnixFd *ufd;
          685 
          686         ufd = c->aux;
          687         if(Trace)
          688                 print("fsremove %s\n", ufd->path->s);
          689 
          690         path = fspath(c, nil);
          691         if(waserror()){
          692                 free(path);
          693                 nexterror();
          694         }
          695         if(c->qid.type & QTDIR){
          696                 if(rmdir(path) < 0)
          697                         oserror();
          698         }else{
          699                 if(remove(path) < 0)
          700                         oserror();
          701         }
          702         free(path);
          703         poperror();
          704 }
          705 
          706 Dev fsdevtab = {
          707         FsChar,
          708         "fs",
          709 
          710         devreset,
          711         devinit,
          712         devshutdown,
          713         fsattach,
          714         fswalk,
          715         fsstat,
          716         fsopen,
          717         fscreate,
          718         fsclose,
          719         fsread,
          720         devbread,
          721         fswrite,
          722         devbwrite,
          723         fsremove,
          724         fswstat,
          725 };
          726 
          727 
          728 /* Uid management code adapted from u9fs */
          729 
          730 /*
          731  * we keep a table by numeric id.  by name lookups happen infrequently
          732  * while by-number lookups happen once for every directory entry read
          733  * and every stat request.
          734  */
          735 typedef struct User User;
          736 struct User {
          737         int id;
          738         gid_t defaultgid;
          739         char *name;
          740         User *next;
          741 };
          742 
          743 
          744 static User *utab[64];
          745 static User *gtab[64];
          746 
          747 static User*
          748 adduser(struct passwd *p)
          749 {
          750         User *u;
          751 
          752         u = smalloc(sizeof(*u));
          753         u->id = p->pw_uid;
          754         kstrdup(&u->name, p->pw_name);
          755         u->next = utab[p->pw_uid%nelem(utab)];
          756         u->defaultgid = p->pw_gid;
          757         utab[p->pw_uid%nelem(utab)] = u;
          758         return u;
          759 }
          760 
          761 static User*
          762 addgroup(struct group *g)
          763 {
          764         User *u;
          765 
          766         u = smalloc(sizeof(*u));
          767         u->id = g->gr_gid;
          768         kstrdup(&u->name, g->gr_name);
          769         u->next = gtab[g->gr_gid%nelem(gtab)];
          770         gtab[g->gr_gid%nelem(gtab)] = u;
          771         return u;
          772 }
          773 
          774 static User*
          775 uname2user(char *name)
          776 {
          777         int i;
          778         User *u;
          779         struct passwd *p;
          780 
          781         for(i=0; i<nelem(utab); i++)
          782                 for(u=utab[i]; u; u=u->next)
          783                         if(strcmp(u->name, name) == 0)
          784                                 return u;
          785 
          786         if((p = getpwnam(name)) == nil)
          787                 return nil;
          788         return adduser(p);
          789 }
          790 
          791 static User*
          792 uid2user(int id)
          793 {
          794         User *u;
          795         struct passwd *p;
          796 
          797         for(u=utab[id%nelem(utab)]; u; u=u->next)
          798                 if(u->id == id)
          799                         return u;
          800 
          801         if((p = getpwuid(id)) == nil)
          802                 return nil;
          803         return adduser(p);
          804 }
          805 
          806 static User*
          807 gname2user(char *name)
          808 {
          809         int i;
          810         User *u;
          811         struct group *g;
          812 
          813         for(i=0; i<nelem(gtab); i++)
          814                 for(u=gtab[i]; u; u=u->next)
          815                         if(strcmp(u->name, name) == 0)
          816                                 return u;
          817 
          818         if((g = getgrnam(name)) == nil)
          819                 return nil;
          820         return addgroup(g);
          821 }
          822 
          823 static User*
          824 gid2user(int id)
          825 {
          826         User *u;
          827         struct group *g;
          828 
          829         for(u=gtab[id%nelem(gtab)]; u; u=u->next)
          830                 if(u->id == id)
          831                         return u;
          832 
          833         if((g = getgrgid(id)) == nil)
          834                 return nil;
          835         return addgroup(g);
          836 }
          837 
          838 static char*
          839 uidtoname(int uid)
          840 {
          841         User *u;
          842         
          843         u = uid2user(uid);
          844         if(u == nil)
          845                 return "?";
          846         return u->name;
          847 }
          848 
          849 static char*
          850 gidtoname(int gid)
          851 {
          852         User *u;
          853         
          854         u = gid2user(gid);
          855         if(u == nil)
          856                 return "?";
          857         return u->name;
          858 }
          859 
          860 static int
          861 nametouid(char *name)
          862 {
          863         User *u;
          864         
          865         u = uname2user(name);
          866         if(u == nil)
          867                 return -1;
          868         return u->id;
          869 }
          870 
          871 static int
          872 nametogid(char *name)
          873 {
          874         User *u;
          875         
          876         u = gname2user(name);
          877         if(u == nil)
          878                 return -1;
          879         return u->id;
          880 }
          881 
          882 #if defined(__linux__)
          883 
          884 static vlong
          885 disksize(int fd, struct stat *st)
          886 {
          887         uvlong u64;
          888         long l;
          889         struct hd_geometry geo;
          890         
          891         memset(&geo, 0, sizeof geo);
          892         l = 0;
          893         u64 = 0;
          894 #ifdef BLKGETSIZE64
          895         if(ioctl(fd, BLKGETSIZE64, &u64) >= 0)
          896                 return u64;
          897 #endif
          898         if(ioctl(fd, BLKGETSIZE, &l) >= 0)
          899                 return l*512;
          900         if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
          901                 return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
          902         return 0;
          903 }
          904 
          905 #elif defined(__FreeBSD__) && defined(DIOCGMEDIASIZE)
          906 
          907 static vlong
          908 disksize(int fd, struct stat *st)
          909 {
          910         off_t mediasize;
          911         
          912         if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
          913                 return mediasize;
          914         return 0;
          915 }
          916 
          917 #elif defined(__APPLE__)
          918 
          919 static vlong
          920 disksize(int fd, struct stat *st)
          921 {
          922         uvlong bc;
          923         unsigned int bs;
          924 
          925         bs = 0;
          926         bc = 0;
          927         ioctl(fd, DKIOCGETBLOCKSIZE, &bs);
          928         ioctl(fd, DKIOCGETBLOCKCOUNT, &bc);
          929         if(bs >0 && bc > 0)
          930                 return bc*bs;
          931         return 0;
          932 }
          933 
          934 #else
          935 
          936 static vlong
          937 disksize(int fd, struct stat *st)
          938 {
          939         return 0;
          940 }
          941 
          942 #endif