URI:
       tfile.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tfile.c (31246B)
       ---
            1 #include "stdinc.h"
            2 #include "9.h"                        /* for consPrint */
            3 #include "dat.h"
            4 #include "fns.h"
            5 #include "error.h"
            6 
            7 /*
            8  * locking order is upwards.  A thread can hold the lock for a File
            9  * and then acquire the lock of its parent
           10  */
           11 
           12 struct File {
           13         Fs        *fs;                /* immutable */
           14 
           15         /* meta data for file: protected by the lk in the parent */
           16         int        ref;                /* holds this data structure up */
           17 
           18         int        partial;        /* file was never really open */
           19         int        removed;        /* file has been removed */
           20         int        dirty;        /* dir is dirty with respect to meta data in block */
           21         u32int        boff;        /* block offset within msource for this file's meta data */
           22 
           23         DirEntry dir;        /* meta data for this file, including component name */
           24 
           25         File        *up;                /* parent file (directory) */
           26         File        *next;                /* sibling */
           27 
           28         /* data for file */
           29         RWLock        lk;                /* lock for the following */
           30         Source        *source;
           31         Source        *msource;        /* for directories: meta data for children */
           32         File        *down;                /* children */
           33 
           34         int        mode;
           35         int        issnapshot;
           36 };
           37 
           38 static int fileMetaFlush2(File*, char*);
           39 static u32int fileMetaAlloc(File*, DirEntry*, u32int);
           40 static int fileRLock(File*);
           41 static void fileRUnlock(File*);
           42 static int fileLock(File*);
           43 static void fileUnlock(File*);
           44 static void fileMetaLock(File*);
           45 static void fileMetaUnlock(File*);
           46 static void fileRAccess(File*);
           47 static void fileWAccess(File*, char*);
           48 
           49 static File *
           50 fileAlloc(Fs *fs)
           51 {
           52         File *f;
           53 
           54         f = vtmallocz(sizeof(File));
           55         f->ref = 1;
           56         f->fs = fs;
           57         f->boff = NilBlock;
           58         f->mode = fs->mode;
           59         return f;
           60 }
           61 
           62 static void
           63 fileFree(File *f)
           64 {
           65         sourceClose(f->source);
           66         sourceClose(f->msource);
           67         deCleanup(&f->dir);
           68 
           69         memset(f, ~0, sizeof(File));
           70         vtfree(f);
           71 }
           72 
           73 /*
           74  * the file is locked already
           75  * f->msource is unlocked
           76  */
           77 static File *
           78 dirLookup(File *f, char *elem)
           79 {
           80         int i;
           81         MetaBlock mb;
           82         MetaEntry me;
           83         Block *b;
           84         Source *meta;
           85         File *ff;
           86         u32int bo, nb;
           87 
           88         meta = f->msource;
           89         b = nil;
           90         if(!sourceLock(meta, -1))
           91                 return nil;
           92         nb = (sourceGetSize(meta)+meta->dsize-1)/meta->dsize;
           93         for(bo=0; bo<nb; bo++){
           94                 b = sourceBlock(meta, bo, OReadOnly);
           95                 if(b == nil)
           96                         goto Err;
           97                 if(!mbUnpack(&mb, b->data, meta->dsize))
           98                         goto Err;
           99                 if(mbSearch(&mb, elem, &i, &me)){
          100                         ff = fileAlloc(f->fs);
          101                         if(!deUnpack(&ff->dir, &me)){
          102                                 fileFree(ff);
          103                                 goto Err;
          104                         }
          105                         sourceUnlock(meta);
          106                         blockPut(b);
          107                         ff->boff = bo;
          108                         ff->mode = f->mode;
          109                         ff->issnapshot = f->issnapshot;
          110                         return ff;
          111                 }
          112 
          113                 blockPut(b);
          114                 b = nil;
          115         }
          116         werrstr(ENoFile);
          117         /* fall through */
          118 Err:
          119         sourceUnlock(meta);
          120         blockPut(b);
          121         return nil;
          122 }
          123 
          124 File *
          125 fileRoot(Source *r)
          126 {
          127         Block *b;
          128         Source *r0, *r1, *r2;
          129         MetaBlock mb;
          130         MetaEntry me;
          131         File *root, *mr;
          132         Fs *fs;
          133 
          134         b = nil;
          135         root = nil;
          136         mr = nil;
          137         r1 = nil;
          138         r2 = nil;
          139 
          140         fs = r->fs;
          141         if(!sourceLock(r, -1))
          142                 return nil;
          143         r0 = sourceOpen(r, 0, fs->mode, 0);
          144         if(r0 == nil)
          145                 goto Err;
          146         r1 = sourceOpen(r, 1, fs->mode, 0);
          147         if(r1 == nil)
          148                 goto Err;
          149         r2 = sourceOpen(r, 2, fs->mode, 0);
          150         if(r2 == nil)
          151                 goto Err;
          152 
          153         mr = fileAlloc(fs);
          154         mr->msource = r2;
          155         r2 = nil;
          156 
          157         root = fileAlloc(fs);
          158         root->boff = 0;
          159         root->up = mr;
          160         root->source = r0;
          161         r0->file = root;                        /* point back to source */
          162         r0 = nil;
          163         root->msource = r1;
          164         r1 = nil;
          165 
          166         mr->down = root;
          167 
          168         if(!sourceLock(mr->msource, -1))
          169                 goto Err;
          170         b = sourceBlock(mr->msource, 0, OReadOnly);
          171         sourceUnlock(mr->msource);
          172         if(b == nil)
          173                 goto Err;
          174 
          175         if(!mbUnpack(&mb, b->data, mr->msource->dsize))
          176                 goto Err;
          177 
          178         meUnpack(&me, &mb, 0);
          179         if(!deUnpack(&root->dir, &me))
          180                 goto Err;
          181         blockPut(b);
          182         sourceUnlock(r);
          183         fileRAccess(root);
          184 
          185         return root;
          186 Err:
          187         blockPut(b);
          188         if(r0)
          189                 sourceClose(r0);
          190         if(r1)
          191                 sourceClose(r1);
          192         if(r2)
          193                 sourceClose(r2);
          194         if(mr)
          195                 fileFree(mr);
          196         if(root)
          197                 fileFree(root);
          198         sourceUnlock(r);
          199 
          200         return nil;
          201 }
          202 
          203 static Source *
          204 fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode,
          205         int issnapshot)
          206 {
          207         char *rname, *fname;
          208         Source *r;
          209 
          210         if(!sourceLock(f->source, mode))
          211                 return nil;
          212         r = sourceOpen(f->source, offset, mode, issnapshot);
          213         sourceUnlock(f->source);
          214         if(r == nil)
          215                 return nil;
          216         if(r->gen != gen){
          217                 werrstr(ERemoved);
          218                 goto Err;
          219         }
          220         if(r->dir != dir && r->mode != -1){
          221                 /* this hasn't been as useful as we hoped it would be. */
          222                 rname = sourceName(r);
          223                 fname = fileName(f);
          224                 consPrint("%s: source %s for file %s: fileOpenSource: "
          225                         "dir mismatch %d %d\n",
          226                         f->source->fs->name, rname, fname, r->dir, dir);
          227                 free(rname);
          228                 free(fname);
          229 
          230                 werrstr(EBadMeta);
          231                 goto Err;
          232         }
          233         return r;
          234 Err:
          235         sourceClose(r);
          236         return nil;
          237 }
          238 
          239 File *
          240 _fileWalk(File *f, char *elem, int partial)
          241 {
          242         File *ff;
          243 
          244         fileRAccess(f);
          245 
          246         if(elem[0] == 0){
          247                 werrstr(EBadPath);
          248                 return nil;
          249         }
          250 
          251         if(!fileIsDir(f)){
          252                 werrstr(ENotDir);
          253                 return nil;
          254         }
          255 
          256         if(strcmp(elem, ".") == 0){
          257                 return fileIncRef(f);
          258         }
          259 
          260         if(strcmp(elem, "..") == 0){
          261                 if(fileIsRoot(f))
          262                         return fileIncRef(f);
          263                 return fileIncRef(f->up);
          264         }
          265 
          266         if(!fileLock(f))
          267                 return nil;
          268 
          269         for(ff = f->down; ff; ff=ff->next){
          270                 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
          271                         ff->ref++;
          272                         goto Exit;
          273                 }
          274         }
          275 
          276         ff = dirLookup(f, elem);
          277         if(ff == nil)
          278                 goto Err;
          279 
          280         if(ff->dir.mode & ModeSnapshot){
          281                 ff->mode = OReadOnly;
          282                 ff->issnapshot = 1;
          283         }
          284 
          285         if(partial){
          286                 /*
          287                  * Do nothing.  We're opening this file only so we can clri it.
          288                  * Usually the sources can't be opened, hence we won't even bother.
          289                  * Be VERY careful with the returned file.  If you hand it to a routine
          290                  * expecting ff->source and/or ff->msource to be non-nil, we're
          291                  * likely to dereference nil.  FileClri should be the only routine
          292                  * setting partial.
          293                  */
          294                 ff->partial = 1;
          295         }else if(ff->dir.mode & ModeDir){
          296                 ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen,
          297                         1, ff->mode, ff->issnapshot);
          298                 ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen,
          299                         0, ff->mode, ff->issnapshot);
          300                 if(ff->source == nil || ff->msource == nil)
          301                         goto Err;
          302         }else{
          303                 ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen,
          304                         0, ff->mode, ff->issnapshot);
          305                 if(ff->source == nil)
          306                         goto Err;
          307         }
          308 
          309         /* link in and up parent ref count */
          310         if (ff->source)
          311                 ff->source->file = ff;                /* point back */
          312         ff->next = f->down;
          313         f->down = ff;
          314         ff->up = f;
          315         fileIncRef(f);
          316 Exit:
          317         fileUnlock(f);
          318         return ff;
          319 Err:
          320         fileUnlock(f);
          321         if(ff != nil)
          322                 fileDecRef(ff);
          323         return nil;
          324 }
          325 
          326 File *
          327 fileWalk(File *f, char *elem)
          328 {
          329         return _fileWalk(f, elem, 0);
          330 }
          331 
          332 File *
          333 _fileOpen(Fs *fs, char *path, int partial)
          334 {
          335         File *f, *ff;
          336         char *p, elem[VtMaxStringSize], *opath;
          337         int n;
          338 
          339         f = fs->file;
          340         fileIncRef(f);
          341         opath = path;
          342         while(*path != 0){
          343                 for(p = path; *p && *p != '/'; p++)
          344                         ;
          345                 n = p - path;
          346                 if(n > 0){
          347                         if(n > VtMaxStringSize){
          348                                 werrstr("%s: element too long", EBadPath);
          349                                 goto Err;
          350                         }
          351                         memmove(elem, path, n);
          352                         elem[n] = 0;
          353                         ff = _fileWalk(f, elem, partial && *p=='\0');
          354                         if(ff == nil){
          355                                 werrstr("%.*s: %r", utfnlen(opath, p-opath),
          356                                         opath);
          357                                 goto Err;
          358                         }
          359                         fileDecRef(f);
          360                         f = ff;
          361                 }
          362                 if(*p == '/')
          363                         p++;
          364                 path = p;
          365         }
          366         return f;
          367 Err:
          368         fileDecRef(f);
          369         return nil;
          370 }
          371 
          372 File*
          373 fileOpen(Fs *fs, char *path)
          374 {
          375         return _fileOpen(fs, path, 0);
          376 }
          377 
          378 static void
          379 fileSetTmp(File *f, int istmp)
          380 {
          381         int i;
          382         Entry e;
          383         Source *r;
          384 
          385         for(i=0; i<2; i++){
          386                 if(i==0)
          387                         r = f->source;
          388                 else
          389                         r = f->msource;
          390                 if(r == nil)
          391                         continue;
          392                 if(!sourceGetEntry(r, &e)){
          393                         fprint(2, "sourceGetEntry failed (cannot happen): %r\n");
          394                         continue;
          395                 }
          396                 if(istmp)
          397                         e.flags |= VtEntryNoArchive;
          398                 else
          399                         e.flags &= ~VtEntryNoArchive;
          400                 if(!sourceSetEntry(r, &e)){
          401                         fprint(2, "sourceSetEntry failed (cannot happen): %r\n");
          402                         continue;
          403                 }
          404         }
          405 }
          406 
          407 File *
          408 fileCreate(File *f, char *elem, ulong mode, char *uid)
          409 {
          410         File *ff;
          411         DirEntry *dir;
          412         Source *pr, *r, *mr;
          413         int isdir;
          414 
          415         if(!fileLock(f))
          416                 return nil;
          417 
          418         r = nil;
          419         mr = nil;
          420         for(ff = f->down; ff; ff=ff->next){
          421                 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
          422                         ff = nil;
          423                         werrstr(EExists);
          424                         goto Err1;
          425                 }
          426         }
          427 
          428         ff = dirLookup(f, elem);
          429         if(ff != nil){
          430                 werrstr(EExists);
          431                 goto Err1;
          432         }
          433 
          434         pr = f->source;
          435         if(pr->mode != OReadWrite){
          436                 werrstr(EReadOnly);
          437                 goto Err1;
          438         }
          439 
          440         if(!sourceLock2(f->source, f->msource, -1))
          441                 goto Err1;
          442 
          443         ff = fileAlloc(f->fs);
          444         isdir = mode & ModeDir;
          445 
          446         r = sourceCreate(pr, pr->dsize, isdir, 0);
          447         if(r == nil)
          448                 goto Err;
          449         if(isdir){
          450                 mr = sourceCreate(pr, pr->dsize, 0, r->offset);
          451                 if(mr == nil)
          452                         goto Err;
          453         }
          454 
          455         dir = &ff->dir;
          456         dir->elem = vtstrdup(elem);
          457         dir->entry = r->offset;
          458         dir->gen = r->gen;
          459         if(isdir){
          460                 dir->mentry = mr->offset;
          461                 dir->mgen = mr->gen;
          462         }
          463         dir->size = 0;
          464         if(!fsNextQid(f->fs, &dir->qid))
          465                 goto Err;
          466         dir->uid = vtstrdup(uid);
          467         dir->gid = vtstrdup(f->dir.gid);
          468         dir->mid = vtstrdup(uid);
          469         dir->mtime = time(0L);
          470         dir->mcount = 0;
          471         dir->ctime = dir->mtime;
          472         dir->atime = dir->mtime;
          473         dir->mode = mode;
          474 
          475         ff->boff = fileMetaAlloc(f, dir, 0);
          476         if(ff->boff == NilBlock)
          477                 goto Err;
          478 
          479         sourceUnlock(f->source);
          480         sourceUnlock(f->msource);
          481 
          482         ff->source = r;
          483         r->file = ff;                        /* point back */
          484         ff->msource = mr;
          485 
          486         if(mode&ModeTemporary){
          487                 if(!sourceLock2(r, mr, -1))
          488                         goto Err1;
          489                 fileSetTmp(ff, 1);
          490                 sourceUnlock(r);
          491                 if(mr)
          492                         sourceUnlock(mr);
          493         }
          494 
          495         /* committed */
          496 
          497         /* link in and up parent ref count */
          498         ff->next = f->down;
          499         f->down = ff;
          500         ff->up = f;
          501         fileIncRef(f);
          502 
          503         fileWAccess(f, uid);
          504 
          505         fileUnlock(f);
          506         return ff;
          507 
          508 Err:
          509         sourceUnlock(f->source);
          510         sourceUnlock(f->msource);
          511 Err1:
          512         if(r){
          513                 sourceLock(r, -1);
          514                 sourceRemove(r);
          515         }
          516         if(mr){
          517                 sourceLock(mr, -1);
          518                 sourceRemove(mr);
          519         }
          520         if(ff)
          521                 fileDecRef(ff);
          522         fileUnlock(f);
          523         return 0;
          524 }
          525 
          526 int
          527 fileRead(File *f, void *buf, int cnt, vlong offset)
          528 {
          529         Source *s;
          530         uvlong size;
          531         u32int bn;
          532         int off, dsize, n, nn;
          533         Block *b;
          534         uchar *p;
          535 
          536 if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);
          537 
          538         if(!fileRLock(f))
          539                 return -1;
          540 
          541         if(offset < 0){
          542                 werrstr(EBadOffset);
          543                 goto Err1;
          544         }
          545 
          546         fileRAccess(f);
          547 
          548         if(!sourceLock(f->source, OReadOnly))
          549                 goto Err1;
          550 
          551         s = f->source;
          552         dsize = s->dsize;
          553         size = sourceGetSize(s);
          554 
          555         if(offset >= size)
          556                 offset = size;
          557 
          558         if(cnt > size-offset)
          559                 cnt = size-offset;
          560         bn = offset/dsize;
          561         off = offset%dsize;
          562         p = buf;
          563         while(cnt > 0){
          564                 b = sourceBlock(s, bn, OReadOnly);
          565                 if(b == nil)
          566                         goto Err;
          567                 n = cnt;
          568                 if(n > dsize-off)
          569                         n = dsize-off;
          570                 nn = dsize-off;
          571                 if(nn > n)
          572                         nn = n;
          573                 memmove(p, b->data+off, nn);
          574                 memset(p+nn, 0, nn-n);
          575                 off = 0;
          576                 bn++;
          577                 cnt -= n;
          578                 p += n;
          579                 blockPut(b);
          580         }
          581         sourceUnlock(s);
          582         fileRUnlock(f);
          583         return p-(uchar*)buf;
          584 
          585 Err:
          586         sourceUnlock(s);
          587 Err1:
          588         fileRUnlock(f);
          589         return -1;
          590 }
          591 
          592 /*
          593  * Changes the file block bn to be the given block score.
          594  * Very sneaky.  Only used by flfmt.
          595  */
          596 int
          597 fileMapBlock(File *f, ulong bn, uchar score[VtScoreSize], ulong tag)
          598 {
          599         Block *b;
          600         Entry e;
          601         Source *s;
          602 
          603         if(!fileLock(f))
          604                 return 0;
          605 
          606         s = nil;
          607         if(f->dir.mode & ModeDir){
          608                 werrstr(ENotFile);
          609                 goto Err;
          610         }
          611 
          612         if(f->source->mode != OReadWrite){
          613                 werrstr(EReadOnly);
          614                 goto Err;
          615         }
          616 
          617         if(!sourceLock(f->source, -1))
          618                 goto Err;
          619 
          620         s = f->source;
          621         b = _sourceBlock(s, bn, OReadWrite, 1, tag);
          622         if(b == nil)
          623                 goto Err;
          624 
          625         if(!sourceGetEntry(s, &e))
          626                 goto Err;
          627         if(b->l.type == BtDir){
          628                 memmove(e.score, score, VtScoreSize);
          629                 assert(e.tag == tag || e.tag == 0);
          630                 e.tag = tag;
          631                 e.flags |= VtEntryLocal;
          632                 entryPack(&e, b->data, f->source->offset % f->source->epb);
          633         }else
          634                 memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize);
          635         blockDirty(b);
          636         blockPut(b);
          637         sourceUnlock(s);
          638         fileUnlock(f);
          639         return 1;
          640 
          641 Err:
          642         if(s)
          643                 sourceUnlock(s);
          644         fileUnlock(f);
          645         return 0;
          646 }
          647 
          648 int
          649 fileSetSize(File *f, uvlong size)
          650 {
          651         int r;
          652 
          653         if(!fileLock(f))
          654                 return 0;
          655         r = 0;
          656         if(f->dir.mode & ModeDir){
          657                 werrstr(ENotFile);
          658                 goto Err;
          659         }
          660         if(f->source->mode != OReadWrite){
          661                 werrstr(EReadOnly);
          662                 goto Err;
          663         }
          664         if(!sourceLock(f->source, -1))
          665                 goto Err;
          666         r = sourceSetSize(f->source, size);
          667         sourceUnlock(f->source);
          668 Err:
          669         fileUnlock(f);
          670         return r;
          671 }
          672 
          673 int
          674 fileWrite(File *f, void *buf, int cnt, vlong offset, char *uid)
          675 {
          676         Source *s;
          677         ulong bn;
          678         int off, dsize, n;
          679         Block *b;
          680         uchar *p;
          681         vlong eof;
          682 
          683 if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);
          684 
          685         if(!fileLock(f))
          686                 return -1;
          687 
          688         s = nil;
          689         if(f->dir.mode & ModeDir){
          690                 werrstr(ENotFile);
          691                 goto Err;
          692         }
          693 
          694         if(f->source->mode != OReadWrite){
          695                 werrstr(EReadOnly);
          696                 goto Err;
          697         }
          698         if(offset < 0){
          699                 werrstr(EBadOffset);
          700                 goto Err;
          701         }
          702 
          703         fileWAccess(f, uid);
          704 
          705         if(!sourceLock(f->source, -1))
          706                 goto Err;
          707         s = f->source;
          708         dsize = s->dsize;
          709 
          710         eof = sourceGetSize(s);
          711         if(f->dir.mode & ModeAppend)
          712                 offset = eof;
          713         bn = offset/dsize;
          714         off = offset%dsize;
          715         p = buf;
          716         while(cnt > 0){
          717                 n = cnt;
          718                 if(n > dsize-off)
          719                         n = dsize-off;
          720                 b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite);
          721                 if(b == nil){
          722                         if(offset > eof)
          723                                 sourceSetSize(s, offset);
          724                         goto Err;
          725                 }
          726                 memmove(b->data+off, p, n);
          727                 off = 0;
          728                 cnt -= n;
          729                 p += n;
          730                 offset += n;
          731                 bn++;
          732                 blockDirty(b);
          733                 blockPut(b);
          734         }
          735         if(offset > eof && !sourceSetSize(s, offset))
          736                 goto Err;
          737         sourceUnlock(s);
          738         fileUnlock(f);
          739         return p-(uchar*)buf;
          740 Err:
          741         if(s)
          742                 sourceUnlock(s);
          743         fileUnlock(f);
          744         return -1;
          745 }
          746 
          747 int
          748 fileGetDir(File *f, DirEntry *dir)
          749 {
          750         if(!fileRLock(f))
          751                 return 0;
          752 
          753         fileMetaLock(f);
          754         deCopy(dir, &f->dir);
          755         fileMetaUnlock(f);
          756 
          757         if(!fileIsDir(f)){
          758                 if(!sourceLock(f->source, OReadOnly)){
          759                         fileRUnlock(f);
          760                         return 0;
          761                 }
          762                 dir->size = sourceGetSize(f->source);
          763                 sourceUnlock(f->source);
          764         }
          765         fileRUnlock(f);
          766 
          767         return 1;
          768 }
          769 
          770 int
          771 fileTruncate(File *f, char *uid)
          772 {
          773         if(fileIsDir(f)){
          774                 werrstr(ENotFile);
          775                 return 0;
          776         }
          777 
          778         if(!fileLock(f))
          779                 return 0;
          780 
          781         if(f->source->mode != OReadWrite){
          782                 werrstr(EReadOnly);
          783                 fileUnlock(f);
          784                 return 0;
          785         }
          786         if(!sourceLock(f->source, -1)){
          787                 fileUnlock(f);
          788                 return 0;
          789         }
          790         if(!sourceTruncate(f->source)){
          791                 sourceUnlock(f->source);
          792                 fileUnlock(f);
          793                 return 0;
          794         }
          795         sourceUnlock(f->source);
          796         fileUnlock(f);
          797 
          798         fileWAccess(f, uid);
          799 
          800         return 1;
          801 }
          802 
          803 int
          804 fileSetDir(File *f, DirEntry *dir, char *uid)
          805 {
          806         File *ff;
          807         char *oelem;
          808         u32int mask;
          809         u64int size;
          810 
          811         /* can not set permissions for the root */
          812         if(fileIsRoot(f)){
          813                 werrstr(ERoot);
          814                 return 0;
          815         }
          816 
          817         if(!fileLock(f))
          818                 return 0;
          819 
          820         if(f->source->mode != OReadWrite){
          821                 werrstr(EReadOnly);
          822                 fileUnlock(f);
          823                 return 0;
          824         }
          825 
          826         fileMetaLock(f);
          827 
          828         /* check new name does not already exist */
          829         if(strcmp(f->dir.elem, dir->elem) != 0){
          830                 for(ff = f->up->down; ff; ff=ff->next){
          831                         if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
          832                                 werrstr(EExists);
          833                                 goto Err;
          834                         }
          835                 }
          836 
          837                 ff = dirLookup(f->up, dir->elem);
          838                 if(ff != nil){
          839                         fileDecRef(ff);
          840                         werrstr(EExists);
          841                         goto Err;
          842                 }
          843         }
          844 
          845         if(!sourceLock2(f->source, f->msource, -1))
          846                 goto Err;
          847         if(!fileIsDir(f)){
          848                 size = sourceGetSize(f->source);
          849                 if(size != dir->size){
          850                         if(!sourceSetSize(f->source, dir->size)){
          851                                 sourceUnlock(f->source);
          852                                 if(f->msource)
          853                                         sourceUnlock(f->msource);
          854                                 goto Err;
          855                         }
          856                         /* commited to changing it now */
          857                 }
          858         }
          859         /* commited to changing it now */
          860         if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary))
          861                 fileSetTmp(f, dir->mode&ModeTemporary);
          862         sourceUnlock(f->source);
          863         if(f->msource)
          864                 sourceUnlock(f->msource);
          865 
          866         oelem = nil;
          867         if(strcmp(f->dir.elem, dir->elem) != 0){
          868                 oelem = f->dir.elem;
          869                 f->dir.elem = vtstrdup(dir->elem);
          870         }
          871 
          872         if(strcmp(f->dir.uid, dir->uid) != 0){
          873                 vtfree(f->dir.uid);
          874                 f->dir.uid = vtstrdup(dir->uid);
          875         }
          876 
          877         if(strcmp(f->dir.gid, dir->gid) != 0){
          878                 vtfree(f->dir.gid);
          879                 f->dir.gid = vtstrdup(dir->gid);
          880         }
          881 
          882         f->dir.mtime = dir->mtime;
          883         f->dir.atime = dir->atime;
          884 
          885 //fprint(2, "mode %x %x ", f->dir.mode, dir->mode);
          886         mask = ~(ModeDir|ModeSnapshot);
          887         f->dir.mode &= ~mask;
          888         f->dir.mode |= mask & dir->mode;
          889         f->dirty = 1;
          890 //fprint(2, "->%x\n", f->dir.mode);
          891 
          892         fileMetaFlush2(f, oelem);
          893         vtfree(oelem);
          894 
          895         fileMetaUnlock(f);
          896         fileUnlock(f);
          897 
          898         fileWAccess(f->up, uid);
          899 
          900         return 1;
          901 Err:
          902         fileMetaUnlock(f);
          903         fileUnlock(f);
          904         return 0;
          905 }
          906 
          907 int
          908 fileSetQidSpace(File *f, u64int offset, u64int max)
          909 {
          910         int ret;
          911 
          912         if(!fileLock(f))
          913                 return 0;
          914         fileMetaLock(f);
          915         f->dir.qidSpace = 1;
          916         f->dir.qidOffset = offset;
          917         f->dir.qidMax = max;
          918         ret = fileMetaFlush2(f, nil)>=0;
          919         fileMetaUnlock(f);
          920         fileUnlock(f);
          921         return ret;
          922 }
          923 
          924 
          925 uvlong
          926 fileGetId(File *f)
          927 {
          928         /* immutable */
          929         return f->dir.qid;
          930 }
          931 
          932 ulong
          933 fileGetMcount(File *f)
          934 {
          935         ulong mcount;
          936 
          937         fileMetaLock(f);
          938         mcount = f->dir.mcount;
          939         fileMetaUnlock(f);
          940         return mcount;
          941 }
          942 
          943 ulong
          944 fileGetMode(File *f)
          945 {
          946         ulong mode;
          947 
          948         fileMetaLock(f);
          949         mode = f->dir.mode;
          950         fileMetaUnlock(f);
          951         return mode;
          952 }
          953 
          954 int
          955 fileIsDir(File *f)
          956 {
          957         /* immutable */
          958         return (f->dir.mode & ModeDir) != 0;
          959 }
          960 
          961 int
          962 fileIsAppend(File *f)
          963 {
          964         return (f->dir.mode & ModeAppend) != 0;
          965 }
          966 
          967 int
          968 fileIsExclusive(File *f)
          969 {
          970         return (f->dir.mode & ModeExclusive) != 0;
          971 }
          972 
          973 int
          974 fileIsTemporary(File *f)
          975 {
          976         return (f->dir.mode & ModeTemporary) != 0;
          977 }
          978 
          979 int
          980 fileIsRoot(File *f)
          981 {
          982         return f == f->fs->file;
          983 }
          984 
          985 int
          986 fileIsRoFs(File *f)
          987 {
          988         return f->fs->mode == OReadOnly;
          989 }
          990 
          991 int
          992 fileGetSize(File *f, uvlong *size)
          993 {
          994         if(!fileRLock(f))
          995                 return 0;
          996         if(!sourceLock(f->source, OReadOnly)){
          997                 fileRUnlock(f);
          998                 return 0;
          999         }
         1000         *size = sourceGetSize(f->source);
         1001         sourceUnlock(f->source);
         1002         fileRUnlock(f);
         1003 
         1004         return 1;
         1005 }
         1006 
         1007 int
         1008 fileMetaFlush(File *f, int rec)
         1009 {
         1010         File **kids, *p;
         1011         int nkids;
         1012         int i, rv;
         1013 
         1014         fileMetaLock(f);
         1015         rv = fileMetaFlush2(f, nil);
         1016         fileMetaUnlock(f);
         1017 
         1018         if(!rec || !fileIsDir(f))
         1019                 return rv;
         1020 
         1021         if(!fileLock(f))
         1022                 return rv;
         1023         nkids = 0;
         1024         for(p=f->down; p; p=p->next)
         1025                 nkids++;
         1026         kids = vtmalloc(nkids*sizeof(File*));
         1027         i = 0;
         1028         for(p=f->down; p; p=p->next){
         1029                 kids[i++] = p;
         1030                 p->ref++;
         1031         }
         1032         fileUnlock(f);
         1033 
         1034         for(i=0; i<nkids; i++){
         1035                 rv |= fileMetaFlush(kids[i], 1);
         1036                 fileDecRef(kids[i]);
         1037         }
         1038         vtfree(kids);
         1039         return rv;
         1040 }
         1041 
         1042 /* assumes metaLock is held */
         1043 static int
         1044 fileMetaFlush2(File *f, char *oelem)
         1045 {
         1046         File *fp;
         1047         Block *b, *bb;
         1048         MetaBlock mb;
         1049         MetaEntry me, me2;
         1050         int i, n;
         1051         u32int boff;
         1052 
         1053         if(!f->dirty)
         1054                 return 0;
         1055 
         1056         if(oelem == nil)
         1057                 oelem = f->dir.elem;
         1058 
         1059 //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem);
         1060 
         1061         fp = f->up;
         1062 
         1063         if(!sourceLock(fp->msource, -1))
         1064                 return -1;
         1065         /* can happen if source is clri'ed out from under us */
         1066         if(f->boff == NilBlock)
         1067                 goto Err1;
         1068         b = sourceBlock(fp->msource, f->boff, OReadWrite);
         1069         if(b == nil)
         1070                 goto Err1;
         1071 
         1072         if(!mbUnpack(&mb, b->data, fp->msource->dsize))
         1073                 goto Err;
         1074         if(!mbSearch(&mb, oelem, &i, &me))
         1075                 goto Err;
         1076 
         1077         n = deSize(&f->dir);
         1078 if(0)fprint(2, "old size %d new size %d\n", me.size, n);
         1079 
         1080         if(mbResize(&mb, &me, n)){
         1081                 /* fits in the block */
         1082                 mbDelete(&mb, i);
         1083                 if(strcmp(f->dir.elem, oelem) != 0)
         1084                         mbSearch(&mb, f->dir.elem, &i, &me2);
         1085                 dePack(&f->dir, &me);
         1086                 mbInsert(&mb, i, &me);
         1087                 mbPack(&mb);
         1088                 blockDirty(b);
         1089                 blockPut(b);
         1090                 sourceUnlock(fp->msource);
         1091                 f->dirty = 0;
         1092 
         1093                 return 1;
         1094         }
         1095 
         1096         /*
         1097          * moving entry to another block
         1098          * it is feasible for the fs to crash leaving two copies
         1099          * of the directory entry.  This is just too much work to
         1100          * fix.  Given that entries are only allocated in a block that
         1101          * is less than PercentageFull, most modifications of meta data
         1102          * will fit within the block.  i.e. this code should almost
         1103          * never be executed.
         1104          */
         1105         boff = fileMetaAlloc(fp, &f->dir, f->boff+1);
         1106         if(boff == NilBlock){
         1107                 /* mbResize might have modified block */
         1108                 mbPack(&mb);
         1109                 blockDirty(b);
         1110                 goto Err;
         1111         }
         1112 fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
         1113         f->boff = boff;
         1114 
         1115         /* make sure deletion goes to disk after new entry */
         1116         bb = sourceBlock(fp->msource, f->boff, OReadWrite);
         1117         mbDelete(&mb, i);
         1118         mbPack(&mb);
         1119         blockDependency(b, bb, -1, nil, nil);
         1120         blockPut(bb);
         1121         blockDirty(b);
         1122         blockPut(b);
         1123         sourceUnlock(fp->msource);
         1124 
         1125         f->dirty = 0;
         1126 
         1127         return 1;
         1128 
         1129 Err:
         1130         blockPut(b);
         1131 Err1:
         1132         sourceUnlock(fp->msource);
         1133         return -1;
         1134 }
         1135 
         1136 static int
         1137 fileMetaRemove(File *f, char *uid)
         1138 {
         1139         Block *b;
         1140         MetaBlock mb;
         1141         MetaEntry me;
         1142         int i;
         1143         File *up;
         1144 
         1145         up = f->up;
         1146 
         1147         fileWAccess(up, uid);
         1148 
         1149         fileMetaLock(f);
         1150 
         1151         sourceLock(up->msource, OReadWrite);
         1152         b = sourceBlock(up->msource, f->boff, OReadWrite);
         1153         if(b == nil)
         1154                 goto Err;
         1155 
         1156         if(!mbUnpack(&mb, b->data, up->msource->dsize))
         1157 {
         1158 fprint(2, "U\n");
         1159                 goto Err;
         1160 }
         1161         if(!mbSearch(&mb, f->dir.elem, &i, &me))
         1162 {
         1163 fprint(2, "S\n");
         1164                 goto Err;
         1165 }
         1166         mbDelete(&mb, i);
         1167         mbPack(&mb);
         1168         sourceUnlock(up->msource);
         1169 
         1170         blockDirty(b);
         1171         blockPut(b);
         1172 
         1173         f->removed = 1;
         1174         f->boff = NilBlock;
         1175         f->dirty = 0;
         1176 
         1177         fileMetaUnlock(f);
         1178         return 1;
         1179 
         1180 Err:
         1181         sourceUnlock(up->msource);
         1182         blockPut(b);
         1183         fileMetaUnlock(f);
         1184         return 0;
         1185 }
         1186 
         1187 /* assume file is locked, assume f->msource is locked */
         1188 static int
         1189 fileCheckEmpty(File *f)
         1190 {
         1191         u32int i, n;
         1192         Block *b;
         1193         MetaBlock mb;
         1194         Source *r;
         1195 
         1196         r = f->msource;
         1197         n = (sourceGetSize(r)+r->dsize-1)/r->dsize;
         1198         for(i=0; i<n; i++){
         1199                 b = sourceBlock(r, i, OReadOnly);
         1200                 if(b == nil)
         1201                         goto Err;
         1202                 if(!mbUnpack(&mb, b->data, r->dsize))
         1203                         goto Err;
         1204                 if(mb.nindex > 0){
         1205                         werrstr(ENotEmpty);
         1206                         goto Err;
         1207                 }
         1208                 blockPut(b);
         1209         }
         1210         return 1;
         1211 Err:
         1212         blockPut(b);
         1213         return 0;
         1214 }
         1215 
         1216 int
         1217 fileRemove(File *f, char *uid)
         1218 {
         1219         File *ff;
         1220 
         1221         /* can not remove the root */
         1222         if(fileIsRoot(f)){
         1223                 werrstr(ERoot);
         1224                 return 0;
         1225         }
         1226 
         1227         if(!fileLock(f))
         1228                 return 0;
         1229 
         1230         if(f->source->mode != OReadWrite){
         1231                 werrstr(EReadOnly);
         1232                 goto Err1;
         1233         }
         1234         if(!sourceLock2(f->source, f->msource, -1))
         1235                 goto Err1;
         1236         if(fileIsDir(f) && !fileCheckEmpty(f))
         1237                 goto Err;
         1238 
         1239         for(ff=f->down; ff; ff=ff->next)
         1240                 assert(ff->removed);
         1241 
         1242         sourceRemove(f->source);
         1243         f->source->file = nil;                /* erase back pointer */
         1244         f->source = nil;
         1245         if(f->msource){
         1246                 sourceRemove(f->msource);
         1247                 f->msource = nil;
         1248         }
         1249 
         1250         fileUnlock(f);
         1251 
         1252         if(!fileMetaRemove(f, uid))
         1253                 return 0;
         1254 
         1255         return 1;
         1256 
         1257 Err:
         1258         sourceUnlock(f->source);
         1259         if(f->msource)
         1260                 sourceUnlock(f->msource);
         1261 Err1:
         1262         fileUnlock(f);
         1263         return 0;
         1264 }
         1265 
         1266 static int
         1267 clri(File *f, char *uid)
         1268 {
         1269         int r;
         1270 
         1271         if(f == nil)
         1272                 return 0;
         1273         if(f->up->source->mode != OReadWrite){
         1274                 werrstr(EReadOnly);
         1275                 fileDecRef(f);
         1276                 return 0;
         1277         }
         1278         r = fileMetaRemove(f, uid);
         1279         fileDecRef(f);
         1280         return r;
         1281 }
         1282 
         1283 int
         1284 fileClriPath(Fs *fs, char *path, char *uid)
         1285 {
         1286         return clri(_fileOpen(fs, path, 1), uid);
         1287 }
         1288 
         1289 int
         1290 fileClri(File *dir, char *elem, char *uid)
         1291 {
         1292         return clri(_fileWalk(dir, elem, 1), uid);
         1293 }
         1294 
         1295 File *
         1296 fileIncRef(File *vf)
         1297 {
         1298         fileMetaLock(vf);
         1299         assert(vf->ref > 0);
         1300         vf->ref++;
         1301         fileMetaUnlock(vf);
         1302         return vf;
         1303 }
         1304 
         1305 int
         1306 fileDecRef(File *f)
         1307 {
         1308         File *p, *q, **qq;
         1309 
         1310         if(f->up == nil){
         1311                 /* never linked in */
         1312                 assert(f->ref == 1);
         1313                 fileFree(f);
         1314                 return 1;
         1315         }
         1316 
         1317         fileMetaLock(f);
         1318         f->ref--;
         1319         if(f->ref > 0){
         1320                 fileMetaUnlock(f);
         1321                 return 0;
         1322         }
         1323         assert(f->ref == 0);
         1324         assert(f->down == nil);
         1325 
         1326         fileMetaFlush2(f, nil);
         1327 
         1328         p = f->up;
         1329         qq = &p->down;
         1330         for(q = *qq; q; q = *qq){
         1331                 if(q == f)
         1332                         break;
         1333                 qq = &q->next;
         1334         }
         1335         assert(q != nil);
         1336         *qq = f->next;
         1337 
         1338         fileMetaUnlock(f);
         1339         fileFree(f);
         1340 
         1341         fileDecRef(p);
         1342         return 1;
         1343 }
         1344 
         1345 File *
         1346 fileGetParent(File *f)
         1347 {
         1348         if(fileIsRoot(f))
         1349                 return fileIncRef(f);
         1350         return fileIncRef(f->up);
         1351 }
         1352 
         1353 DirEntryEnum *
         1354 deeOpen(File *f)
         1355 {
         1356         DirEntryEnum *dee;
         1357         File *p;
         1358 
         1359         if(!fileIsDir(f)){
         1360                 werrstr(ENotDir);
         1361                 fileDecRef(f);
         1362                 return nil;
         1363         }
         1364 
         1365         /* flush out meta data */
         1366         if(!fileLock(f))
         1367                 return nil;
         1368         for(p=f->down; p; p=p->next)
         1369                 fileMetaFlush2(p, nil);
         1370         fileUnlock(f);
         1371 
         1372         dee = vtmallocz(sizeof(DirEntryEnum));
         1373         dee->file = fileIncRef(f);
         1374 
         1375         return dee;
         1376 }
         1377 
         1378 static int
         1379 dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)
         1380 {
         1381         Block *b;
         1382         ulong bn;
         1383         Entry e;
         1384         int epb;
         1385 
         1386         epb = s->dsize/VtEntrySize;
         1387         bn = elem/epb;
         1388         elem -= bn*epb;
         1389 
         1390         b = sourceBlock(s, bn, OReadOnly);
         1391         if(b == nil)
         1392                 goto Err;
         1393         if(!entryUnpack(&e, b->data, elem))
         1394                 goto Err;
         1395 
         1396         /* hanging entries are returned as zero size */
         1397         if(!(e.flags & VtEntryActive) || e.gen != gen)
         1398                 *size = 0;
         1399         else
         1400                 *size = e.size;
         1401         blockPut(b);
         1402         return 1;
         1403 
         1404 Err:
         1405         blockPut(b);
         1406         return 0;
         1407 }
         1408 
         1409 static int
         1410 deeFill(DirEntryEnum *dee)
         1411 {
         1412         int i, n;
         1413         Source *meta, *source;
         1414         MetaBlock mb;
         1415         MetaEntry me;
         1416         File *f;
         1417         Block *b;
         1418         DirEntry *de;
         1419 
         1420         /* clean up first */
         1421         for(i=dee->i; i<dee->n; i++)
         1422                 deCleanup(dee->buf+i);
         1423         vtfree(dee->buf);
         1424         dee->buf = nil;
         1425         dee->i = 0;
         1426         dee->n = 0;
         1427 
         1428         f = dee->file;
         1429 
         1430         source = f->source;
         1431         meta = f->msource;
         1432 
         1433         b = sourceBlock(meta, dee->boff, OReadOnly);
         1434         if(b == nil)
         1435                 goto Err;
         1436         if(!mbUnpack(&mb, b->data, meta->dsize))
         1437                 goto Err;
         1438 
         1439         n = mb.nindex;
         1440         dee->buf = vtmalloc(n * sizeof(DirEntry));
         1441 
         1442         for(i=0; i<n; i++){
         1443                 de = dee->buf + i;
         1444                 meUnpack(&me, &mb, i);
         1445                 if(!deUnpack(de, &me))
         1446                         goto Err;
         1447                 dee->n++;
         1448                 if(!(de->mode & ModeDir))
         1449                 if(!dirEntrySize(source, de->entry, de->gen, &de->size))
         1450                         goto Err;
         1451         }
         1452         dee->boff++;
         1453         blockPut(b);
         1454         return 1;
         1455 Err:
         1456         blockPut(b);
         1457         return 0;
         1458 }
         1459 
         1460 int
         1461 deeRead(DirEntryEnum *dee, DirEntry *de)
         1462 {
         1463         int ret, didread;
         1464         File *f;
         1465         u32int nb;
         1466 
         1467         if(dee == nil){
         1468                 werrstr("cannot happen in deeRead");
         1469                 return -1;
         1470         }
         1471 
         1472         f = dee->file;
         1473         if(!fileRLock(f))
         1474                 return -1;
         1475 
         1476         if(!sourceLock2(f->source, f->msource, OReadOnly)){
         1477                 fileRUnlock(f);
         1478                 return -1;
         1479         }
         1480 
         1481         nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
         1482 
         1483         didread = 0;
         1484         while(dee->i >= dee->n){
         1485                 if(dee->boff >= nb){
         1486                         ret = 0;
         1487                         goto Return;
         1488                 }
         1489                 didread = 1;
         1490                 if(!deeFill(dee)){
         1491                         ret = -1;
         1492                         goto Return;
         1493                 }
         1494         }
         1495 
         1496         memmove(de, dee->buf + dee->i, sizeof(DirEntry));
         1497         dee->i++;
         1498         ret = 1;
         1499 
         1500 Return:
         1501         sourceUnlock(f->source);
         1502         sourceUnlock(f->msource);
         1503         fileRUnlock(f);
         1504 
         1505         if(didread)
         1506                 fileRAccess(f);
         1507         return ret;
         1508 }
         1509 
         1510 void
         1511 deeClose(DirEntryEnum *dee)
         1512 {
         1513         int i;
         1514         if(dee == nil)
         1515                 return;
         1516         for(i=dee->i; i<dee->n; i++)
         1517                 deCleanup(dee->buf+i);
         1518         vtfree(dee->buf);
         1519         fileDecRef(dee->file);
         1520         vtfree(dee);
         1521 }
         1522 
         1523 /*
         1524  * caller must lock f->source and f->msource
         1525  * caller must NOT lock the source and msource
         1526  * referenced by dir.
         1527  */
         1528 static u32int
         1529 fileMetaAlloc(File *f, DirEntry *dir, u32int start)
         1530 {
         1531         u32int nb, bo;
         1532         Block *b, *bb;
         1533         MetaBlock mb;
         1534         int nn;
         1535         uchar *p;
         1536         int i, n, epb;
         1537         MetaEntry me;
         1538         Source *s, *ms;
         1539 
         1540         s = f->source;
         1541         ms = f->msource;
         1542 
         1543         n = deSize(dir);
         1544         nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize;
         1545         b = nil;
         1546         if(start > nb)
         1547                 start = nb;
         1548         for(bo=start; bo<nb; bo++){
         1549                 b = sourceBlock(ms, bo, OReadWrite);
         1550                 if(b == nil)
         1551                         goto Err;
         1552                 if(!mbUnpack(&mb, b->data, ms->dsize))
         1553                         goto Err;
         1554                 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
         1555                 if(n <= nn && mb.nindex < mb.maxindex)
         1556                         break;
         1557                 blockPut(b);
         1558                 b = nil;
         1559         }
         1560 
         1561         /* add block to meta file */
         1562         if(b == nil){
         1563                 b = sourceBlock(ms, bo, OReadWrite);
         1564                 if(b == nil)
         1565                         goto Err;
         1566                 sourceSetSize(ms, (nb+1)*ms->dsize);
         1567                 mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
         1568         }
         1569 
         1570         p = mbAlloc(&mb, n);
         1571         if(p == nil){
         1572                 /* mbAlloc might have changed block */
         1573                 mbPack(&mb);
         1574                 blockDirty(b);
         1575                 werrstr(EBadMeta);
         1576                 goto Err;
         1577         }
         1578 
         1579         mbSearch(&mb, dir->elem, &i, &me);
         1580         assert(me.p == nil);
         1581         me.p = p;
         1582         me.size = n;
         1583         dePack(dir, &me);
         1584         mbInsert(&mb, i, &me);
         1585         mbPack(&mb);
         1586 
         1587         /* meta block depends on super block for qid ... */
         1588         bb = cacheLocal(b->c, PartSuper, 0, OReadOnly);
         1589         blockDependency(b, bb, -1, nil, nil);
         1590         blockPut(bb);
         1591 
         1592         /* ... and one or two dir entries */
         1593         epb = s->dsize/VtEntrySize;
         1594         bb = sourceBlock(s, dir->entry/epb, OReadOnly);
         1595         blockDependency(b, bb, -1, nil, nil);
         1596         blockPut(bb);
         1597         if(dir->mode & ModeDir){
         1598                 bb = sourceBlock(s, dir->mentry/epb, OReadOnly);
         1599                 blockDependency(b, bb, -1, nil, nil);
         1600                 blockPut(bb);
         1601         }
         1602 
         1603         blockDirty(b);
         1604         blockPut(b);
         1605         return bo;
         1606 Err:
         1607         blockPut(b);
         1608         return NilBlock;
         1609 }
         1610 
         1611 static int
         1612 chkSource(File *f)
         1613 {
         1614         if(f->partial)
         1615                 return 1;
         1616 
         1617         if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){
         1618                 werrstr(ERemoved);
         1619                 return 0;
         1620         }
         1621         return 1;
         1622 }
         1623 
         1624 static int
         1625 fileRLock(File *f)
         1626 {
         1627         assert(!canwlock(&f->fs->elk));
         1628         rlock(&f->lk);
         1629         if(!chkSource(f)){
         1630                 fileRUnlock(f);
         1631                 return 0;
         1632         }
         1633         return 1;
         1634 }
         1635 
         1636 static void
         1637 fileRUnlock(File *f)
         1638 {
         1639         runlock(&f->lk);
         1640 }
         1641 
         1642 static int
         1643 fileLock(File *f)
         1644 {
         1645         assert(!canwlock(&f->fs->elk));
         1646         wlock(&f->lk);
         1647         if(!chkSource(f)){
         1648                 fileUnlock(f);
         1649                 return 0;
         1650         }
         1651         return 1;
         1652 }
         1653 
         1654 static void
         1655 fileUnlock(File *f)
         1656 {
         1657         wunlock(&f->lk);
         1658 }
         1659 
         1660 /*
         1661  * f->source and f->msource must NOT be locked.
         1662  * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
         1663  * We have to respect that ordering.
         1664  */
         1665 static void
         1666 fileMetaLock(File *f)
         1667 {
         1668 if(f->up == nil)
         1669 fprint(2, "f->elem = %s\n", f->dir.elem);
         1670         assert(f->up != nil);
         1671         assert(!canwlock(&f->fs->elk));
         1672         wlock(&f->up->lk);
         1673 }
         1674 
         1675 static void
         1676 fileMetaUnlock(File *f)
         1677 {
         1678         wunlock(&f->up->lk);
         1679 }
         1680 
         1681 /*
         1682  * f->source and f->msource must NOT be locked.
         1683  * see fileMetaLock.
         1684  */
         1685 static void
         1686 fileRAccess(File* f)
         1687 {
         1688         if(f->mode == OReadOnly || f->fs->noatimeupd)
         1689                 return;
         1690 
         1691         fileMetaLock(f);
         1692         f->dir.atime = time(0L);
         1693         f->dirty = 1;
         1694         fileMetaUnlock(f);
         1695 }
         1696 
         1697 /*
         1698  * f->source and f->msource must NOT be locked.
         1699  * see fileMetaLock.
         1700  */
         1701 static void
         1702 fileWAccess(File* f, char *mid)
         1703 {
         1704         if(f->mode == OReadOnly)
         1705                 return;
         1706 
         1707         fileMetaLock(f);
         1708         f->dir.atime = f->dir.mtime = time(0L);
         1709         if(strcmp(f->dir.mid, mid) != 0){
         1710                 vtfree(f->dir.mid);
         1711                 f->dir.mid = vtstrdup(mid);
         1712         }
         1713         f->dir.mcount++;
         1714         f->dirty = 1;
         1715         fileMetaUnlock(f);
         1716 
         1717 /*RSC: let's try this */
         1718 /*presotto - lets not
         1719         if(f->up)
         1720                 fileWAccess(f->up, mid);
         1721 */
         1722 }
         1723 
         1724 static int
         1725 getEntry(Source *r, Entry *e, int checkepoch)
         1726 {
         1727         u32int epoch;
         1728         Block *b;
         1729 
         1730         if(r == nil){
         1731                 memset(&e, 0, sizeof e);
         1732                 return 1;
         1733         }
         1734 
         1735         b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly);
         1736         if(b == nil)
         1737                 return 0;
         1738         if(!entryUnpack(e, b->data, r->offset % r->epb)){
         1739                 blockPut(b);
         1740                 return 0;
         1741         }
         1742         epoch = b->l.epoch;
         1743         blockPut(b);
         1744 
         1745         if(checkepoch){
         1746                 b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly);
         1747                 if(b){
         1748                         if(b->l.epoch >= epoch)
         1749                                 fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n",
         1750                                         r, b->addr, b->l.epoch, r->score, epoch);
         1751                         blockPut(b);
         1752                 }
         1753         }
         1754 
         1755         return 1;
         1756 }
         1757 
         1758 static int
         1759 setEntry(Source *r, Entry *e)
         1760 {
         1761         Block *b;
         1762         Entry oe;
         1763 
         1764         b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite);
         1765         if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
         1766         if(b == nil)
         1767                 return 0;
         1768         if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
         1769                 blockPut(b);
         1770                 return 0;
         1771         }
         1772         e->gen = oe.gen;
         1773         entryPack(e, b->data, r->offset % r->epb);
         1774 
         1775         /* BUG b should depend on the entry pointer */
         1776 
         1777         blockDirty(b);
         1778         blockPut(b);
         1779         return 1;
         1780 }
         1781 
         1782 /* assumes hold elk */
         1783 int
         1784 fileSnapshot(File *dst, File *src, u32int epoch, int doarchive)
         1785 {
         1786         Entry e, ee;
         1787 
         1788         /* add link to snapshot */
         1789         if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
         1790                 return 0;
         1791 
         1792         e.snap = epoch;
         1793         e.archive = doarchive;
         1794         ee.snap = epoch;
         1795         ee.archive = doarchive;
         1796 
         1797         if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
         1798                 return 0;
         1799         return 1;
         1800 }
         1801 
         1802 int
         1803 fileGetSources(File *f, Entry *e, Entry *ee)
         1804 {
         1805         if(!getEntry(f->source, e, 0)
         1806         || !getEntry(f->msource, ee, 0))
         1807                 return 0;
         1808         return 1;
         1809 }
         1810 
         1811 /*
         1812  * Walk down to the block(s) containing the Entries
         1813  * for f->source and f->msource, copying as we go.
         1814  */
         1815 int
         1816 fileWalkSources(File *f)
         1817 {
         1818         if(f->mode == OReadOnly){
         1819                 fprint(2, "readonly in fileWalkSources\n");
         1820                 return 1;
         1821         }
         1822         if(!sourceLock2(f->source, f->msource, OReadWrite)){
         1823                 fprint(2, "sourceLock2 failed in fileWalkSources\n");
         1824                 return 0;
         1825         }
         1826         sourceUnlock(f->source);
         1827         sourceUnlock(f->msource);
         1828         return 1;
         1829 }
         1830 
         1831 /*
         1832  * convert File* to full path name in malloced string.
         1833  * this hasn't been as useful as we hoped it would be.
         1834  */
         1835 char *
         1836 fileName(File *f)
         1837 {
         1838         char *name, *pname;
         1839         File *p;
         1840         static char root[] = "/";
         1841 
         1842         if (f == nil)
         1843                 return vtstrdup("/**GOK**");
         1844 
         1845         p = fileGetParent(f);
         1846         if (p == f)
         1847                 name = vtstrdup(root);
         1848         else {
         1849                 pname = fileName(p);
         1850                 if (strcmp(pname, root) == 0)
         1851                         name = smprint("/%s", f->dir.elem);
         1852                 else
         1853                         name = smprint("%s/%s", pname, f->dir.elem);
         1854                 free(pname);
         1855         }
         1856         fileDecRef(p);
         1857         return name;
         1858 }