15e96a66cSDavid du Colombier #include "stdinc.h" 23b86f2f8SDavid du Colombier #include "9.h" /* for consPrint */ 35e96a66cSDavid du Colombier #include "dat.h" 45e96a66cSDavid du Colombier #include "fns.h" 55e96a66cSDavid du Colombier #include "error.h" 65e96a66cSDavid du Colombier 75e96a66cSDavid du Colombier /* 85e96a66cSDavid du Colombier * locking order is upwards. A thread can hold the lock for a File 95e96a66cSDavid du Colombier * and then acquire the lock of its parent 105e96a66cSDavid du Colombier */ 115e96a66cSDavid du Colombier 125e96a66cSDavid du Colombier struct File { 135e96a66cSDavid du Colombier Fs *fs; /* immutable */ 145e96a66cSDavid du Colombier 155e96a66cSDavid du Colombier /* meta data for file: protected by the lk in the parent */ 165e96a66cSDavid du Colombier int ref; /* holds this data structure up */ 175e96a66cSDavid du Colombier 185e96a66cSDavid du Colombier int partial; /* file was never really open */ 195e96a66cSDavid du Colombier int removed; /* file has been removed */ 205e96a66cSDavid du Colombier int dirty; /* dir is dirty with respect to meta data in block */ 215e96a66cSDavid du Colombier u32int boff; /* block offset within msource for this file's meta data */ 225e96a66cSDavid du Colombier 233b86f2f8SDavid du Colombier DirEntry dir; /* meta data for this file, including component name */ 245e96a66cSDavid du Colombier 253b86f2f8SDavid du Colombier File *up; /* parent file (directory) */ 265e96a66cSDavid du Colombier File *next; /* sibling */ 275e96a66cSDavid du Colombier 285e96a66cSDavid du Colombier /* data for file */ 29*d7aba6c3SDavid du Colombier RWLock lk; /* lock for the following */ 305e96a66cSDavid du Colombier Source *source; 315e96a66cSDavid du Colombier Source *msource; /* for directories: meta data for children */ 325e96a66cSDavid du Colombier File *down; /* children */ 335e96a66cSDavid du Colombier 345e96a66cSDavid du Colombier int mode; 3557195852SDavid du Colombier int issnapshot; 365e96a66cSDavid du Colombier }; 375e96a66cSDavid du Colombier 385e96a66cSDavid du Colombier static int fileMetaFlush2(File*, char*); 395e96a66cSDavid du Colombier static u32int fileMetaAlloc(File*, DirEntry*, u32int); 405e96a66cSDavid du Colombier static int fileRLock(File*); 415e96a66cSDavid du Colombier static void fileRUnlock(File*); 425e96a66cSDavid du Colombier static int fileLock(File*); 435e96a66cSDavid du Colombier static void fileUnlock(File*); 445e96a66cSDavid du Colombier static void fileMetaLock(File*); 455e96a66cSDavid du Colombier static void fileMetaUnlock(File*); 465e96a66cSDavid du Colombier static void fileRAccess(File*); 475e96a66cSDavid du Colombier static void fileWAccess(File*, char*); 485e96a66cSDavid du Colombier 495e96a66cSDavid du Colombier static File * 505e96a66cSDavid du Colombier fileAlloc(Fs *fs) 515e96a66cSDavid du Colombier { 525e96a66cSDavid du Colombier File *f; 535e96a66cSDavid du Colombier 54*d7aba6c3SDavid du Colombier f = vtmallocz(sizeof(File)); 555e96a66cSDavid du Colombier f->ref = 1; 565e96a66cSDavid du Colombier f->fs = fs; 575e96a66cSDavid du Colombier f->boff = NilBlock; 585e96a66cSDavid du Colombier f->mode = fs->mode; 595e96a66cSDavid du Colombier return f; 605e96a66cSDavid du Colombier } 615e96a66cSDavid du Colombier 625e96a66cSDavid du Colombier static void 635e96a66cSDavid du Colombier fileFree(File *f) 645e96a66cSDavid du Colombier { 655e96a66cSDavid du Colombier sourceClose(f->source); 665e96a66cSDavid du Colombier sourceClose(f->msource); 675e96a66cSDavid du Colombier deCleanup(&f->dir); 685e96a66cSDavid du Colombier 695e96a66cSDavid du Colombier memset(f, ~0, sizeof(File)); 70*d7aba6c3SDavid du Colombier vtfree(f); 715e96a66cSDavid du Colombier } 725e96a66cSDavid du Colombier 735e96a66cSDavid du Colombier /* 745e96a66cSDavid du Colombier * the file is locked already 755e96a66cSDavid du Colombier * f->msource is unlocked 765e96a66cSDavid du Colombier */ 775e96a66cSDavid du Colombier static File * 785e96a66cSDavid du Colombier dirLookup(File *f, char *elem) 795e96a66cSDavid du Colombier { 805e96a66cSDavid du Colombier int i; 815e96a66cSDavid du Colombier MetaBlock mb; 825e96a66cSDavid du Colombier MetaEntry me; 835e96a66cSDavid du Colombier Block *b; 845e96a66cSDavid du Colombier Source *meta; 855e96a66cSDavid du Colombier File *ff; 865e96a66cSDavid du Colombier u32int bo, nb; 875e96a66cSDavid du Colombier 885e96a66cSDavid du Colombier meta = f->msource; 895e96a66cSDavid du Colombier b = nil; 905e96a66cSDavid du Colombier if(!sourceLock(meta, -1)) 915e96a66cSDavid du Colombier return nil; 925e96a66cSDavid du Colombier nb = (sourceGetSize(meta)+meta->dsize-1)/meta->dsize; 935e96a66cSDavid du Colombier for(bo=0; bo<nb; bo++){ 945e96a66cSDavid du Colombier b = sourceBlock(meta, bo, OReadOnly); 955e96a66cSDavid du Colombier if(b == nil) 965e96a66cSDavid du Colombier goto Err; 975e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, meta->dsize)) 985e96a66cSDavid du Colombier goto Err; 995e96a66cSDavid du Colombier if(mbSearch(&mb, elem, &i, &me)){ 1005e96a66cSDavid du Colombier ff = fileAlloc(f->fs); 1015e96a66cSDavid du Colombier if(!deUnpack(&ff->dir, &me)){ 1025e96a66cSDavid du Colombier fileFree(ff); 1035e96a66cSDavid du Colombier goto Err; 1045e96a66cSDavid du Colombier } 1055e96a66cSDavid du Colombier sourceUnlock(meta); 1065e96a66cSDavid du Colombier blockPut(b); 1075e96a66cSDavid du Colombier ff->boff = bo; 1085e96a66cSDavid du Colombier ff->mode = f->mode; 10957195852SDavid du Colombier ff->issnapshot = f->issnapshot; 1105e96a66cSDavid du Colombier return ff; 1115e96a66cSDavid du Colombier } 1125e96a66cSDavid du Colombier 1135e96a66cSDavid du Colombier blockPut(b); 1145e96a66cSDavid du Colombier b = nil; 1155e96a66cSDavid du Colombier } 116*d7aba6c3SDavid du Colombier werrstr(ENoFile); 1175e96a66cSDavid du Colombier /* fall through */ 1185e96a66cSDavid du Colombier Err: 1195e96a66cSDavid du Colombier sourceUnlock(meta); 1205e96a66cSDavid du Colombier blockPut(b); 1215e96a66cSDavid du Colombier return nil; 1225e96a66cSDavid du Colombier } 1235e96a66cSDavid du Colombier 1245e96a66cSDavid du Colombier File * 1255e96a66cSDavid du Colombier fileRoot(Source *r) 1265e96a66cSDavid du Colombier { 1275e96a66cSDavid du Colombier Block *b; 1285e96a66cSDavid du Colombier Source *r0, *r1, *r2; 1295e96a66cSDavid du Colombier MetaBlock mb; 1305e96a66cSDavid du Colombier MetaEntry me; 1315e96a66cSDavid du Colombier File *root, *mr; 1325e96a66cSDavid du Colombier Fs *fs; 1335e96a66cSDavid du Colombier 1345e96a66cSDavid du Colombier b = nil; 1355e96a66cSDavid du Colombier root = nil; 1365e96a66cSDavid du Colombier mr = nil; 1375e96a66cSDavid du Colombier r1 = nil; 1385e96a66cSDavid du Colombier r2 = nil; 1395e96a66cSDavid du Colombier 1405e96a66cSDavid du Colombier fs = r->fs; 1415e96a66cSDavid du Colombier if(!sourceLock(r, -1)) 1425e96a66cSDavid du Colombier return nil; 14357195852SDavid du Colombier r0 = sourceOpen(r, 0, fs->mode, 0); 1445e96a66cSDavid du Colombier if(r0 == nil) 1455e96a66cSDavid du Colombier goto Err; 14657195852SDavid du Colombier r1 = sourceOpen(r, 1, fs->mode, 0); 1475e96a66cSDavid du Colombier if(r1 == nil) 1485e96a66cSDavid du Colombier goto Err; 14957195852SDavid du Colombier r2 = sourceOpen(r, 2, fs->mode, 0); 1505e96a66cSDavid du Colombier if(r2 == nil) 1515e96a66cSDavid du Colombier goto Err; 1525e96a66cSDavid du Colombier 1535e96a66cSDavid du Colombier mr = fileAlloc(fs); 1545e96a66cSDavid du Colombier mr->msource = r2; 1555e96a66cSDavid du Colombier r2 = nil; 1565e96a66cSDavid du Colombier 1575e96a66cSDavid du Colombier root = fileAlloc(fs); 1585e96a66cSDavid du Colombier root->boff = 0; 1595e96a66cSDavid du Colombier root->up = mr; 1605e96a66cSDavid du Colombier root->source = r0; 1613b86f2f8SDavid du Colombier r0->file = root; /* point back to source */ 1625e96a66cSDavid du Colombier r0 = nil; 1635e96a66cSDavid du Colombier root->msource = r1; 1645e96a66cSDavid du Colombier r1 = nil; 1655e96a66cSDavid du Colombier 1665e96a66cSDavid du Colombier mr->down = root; 1675e96a66cSDavid du Colombier 1685e96a66cSDavid du Colombier if(!sourceLock(mr->msource, -1)) 1695e96a66cSDavid du Colombier goto Err; 1705e96a66cSDavid du Colombier b = sourceBlock(mr->msource, 0, OReadOnly); 1715e96a66cSDavid du Colombier sourceUnlock(mr->msource); 1725e96a66cSDavid du Colombier if(b == nil) 1735e96a66cSDavid du Colombier goto Err; 1745e96a66cSDavid du Colombier 1755e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, mr->msource->dsize)) 1765e96a66cSDavid du Colombier goto Err; 1775e96a66cSDavid du Colombier 1785e96a66cSDavid du Colombier meUnpack(&me, &mb, 0); 1795e96a66cSDavid du Colombier if(!deUnpack(&root->dir, &me)) 1805e96a66cSDavid du Colombier goto Err; 1815e96a66cSDavid du Colombier blockPut(b); 1825e96a66cSDavid du Colombier sourceUnlock(r); 1835e96a66cSDavid du Colombier fileRAccess(root); 1845e96a66cSDavid du Colombier 1855e96a66cSDavid du Colombier return root; 1865e96a66cSDavid du Colombier Err: 1875e96a66cSDavid du Colombier blockPut(b); 1885e96a66cSDavid du Colombier if(r0) 1895e96a66cSDavid du Colombier sourceClose(r0); 1905e96a66cSDavid du Colombier if(r1) 1915e96a66cSDavid du Colombier sourceClose(r1); 1925e96a66cSDavid du Colombier if(r2) 1935e96a66cSDavid du Colombier sourceClose(r2); 1945e96a66cSDavid du Colombier if(mr) 1955e96a66cSDavid du Colombier fileFree(mr); 1965e96a66cSDavid du Colombier if(root) 1975e96a66cSDavid du Colombier fileFree(root); 1985e96a66cSDavid du Colombier sourceUnlock(r); 1995e96a66cSDavid du Colombier 2005e96a66cSDavid du Colombier return nil; 2015e96a66cSDavid du Colombier } 2025e96a66cSDavid du Colombier 2035e96a66cSDavid du Colombier static Source * 2043b86f2f8SDavid du Colombier fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode, 2053b86f2f8SDavid du Colombier int issnapshot) 2065e96a66cSDavid du Colombier { 2073b86f2f8SDavid du Colombier char *rname, *fname; 2085e96a66cSDavid du Colombier Source *r; 2095e96a66cSDavid du Colombier 2105e96a66cSDavid du Colombier if(!sourceLock(f->source, mode)) 2115e96a66cSDavid du Colombier return nil; 21257195852SDavid du Colombier r = sourceOpen(f->source, offset, mode, issnapshot); 2135e96a66cSDavid du Colombier sourceUnlock(f->source); 2145e96a66cSDavid du Colombier if(r == nil) 2155e96a66cSDavid du Colombier return nil; 2165e96a66cSDavid du Colombier if(r->gen != gen){ 217*d7aba6c3SDavid du Colombier werrstr(ERemoved); 2185e96a66cSDavid du Colombier goto Err; 2195e96a66cSDavid du Colombier } 2205e96a66cSDavid du Colombier if(r->dir != dir && r->mode != -1){ 2213b86f2f8SDavid du Colombier /* this hasn't been as useful as we hoped it would be. */ 2223b86f2f8SDavid du Colombier rname = sourceName(r); 2233b86f2f8SDavid du Colombier fname = fileName(f); 2243b86f2f8SDavid du Colombier consPrint("%s: source %s for file %s: fileOpenSource: " 2253b86f2f8SDavid du Colombier "dir mismatch %d %d\n", 2263b86f2f8SDavid du Colombier f->source->fs->name, rname, fname, r->dir, dir); 2273b86f2f8SDavid du Colombier free(rname); 2283b86f2f8SDavid du Colombier free(fname); 2293b86f2f8SDavid du Colombier 230*d7aba6c3SDavid du Colombier werrstr(EBadMeta); 2315e96a66cSDavid du Colombier goto Err; 2325e96a66cSDavid du Colombier } 2335e96a66cSDavid du Colombier return r; 2345e96a66cSDavid du Colombier Err: 2355e96a66cSDavid du Colombier sourceClose(r); 2365e96a66cSDavid du Colombier return nil; 2375e96a66cSDavid du Colombier } 2385e96a66cSDavid du Colombier 2395e96a66cSDavid du Colombier File * 2405e96a66cSDavid du Colombier _fileWalk(File *f, char *elem, int partial) 2415e96a66cSDavid du Colombier { 2425e96a66cSDavid du Colombier File *ff; 2435e96a66cSDavid du Colombier 2445e96a66cSDavid du Colombier fileRAccess(f); 2455e96a66cSDavid du Colombier 2465e96a66cSDavid du Colombier if(elem[0] == 0){ 247*d7aba6c3SDavid du Colombier werrstr(EBadPath); 2485e96a66cSDavid du Colombier return nil; 2495e96a66cSDavid du Colombier } 2505e96a66cSDavid du Colombier 2515e96a66cSDavid du Colombier if(!fileIsDir(f)){ 252*d7aba6c3SDavid du Colombier werrstr(ENotDir); 2535e96a66cSDavid du Colombier return nil; 2545e96a66cSDavid du Colombier } 2555e96a66cSDavid du Colombier 2565e96a66cSDavid du Colombier if(strcmp(elem, ".") == 0){ 2575e96a66cSDavid du Colombier return fileIncRef(f); 2585e96a66cSDavid du Colombier } 2595e96a66cSDavid du Colombier 2605e96a66cSDavid du Colombier if(strcmp(elem, "..") == 0){ 2615e96a66cSDavid du Colombier if(fileIsRoot(f)) 2625e96a66cSDavid du Colombier return fileIncRef(f); 2635e96a66cSDavid du Colombier return fileIncRef(f->up); 2645e96a66cSDavid du Colombier } 2655e96a66cSDavid du Colombier 2665e96a66cSDavid du Colombier if(!fileLock(f)) 2675e96a66cSDavid du Colombier return nil; 2685e96a66cSDavid du Colombier 2695e96a66cSDavid du Colombier for(ff = f->down; ff; ff=ff->next){ 2705e96a66cSDavid du Colombier if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ 2715e96a66cSDavid du Colombier ff->ref++; 2725e96a66cSDavid du Colombier goto Exit; 2735e96a66cSDavid du Colombier } 2745e96a66cSDavid du Colombier } 2755e96a66cSDavid du Colombier 2765e96a66cSDavid du Colombier ff = dirLookup(f, elem); 2775e96a66cSDavid du Colombier if(ff == nil) 2785e96a66cSDavid du Colombier goto Err; 2795e96a66cSDavid du Colombier 28057195852SDavid du Colombier if(ff->dir.mode & ModeSnapshot){ 2815e96a66cSDavid du Colombier ff->mode = OReadOnly; 28257195852SDavid du Colombier ff->issnapshot = 1; 28357195852SDavid du Colombier } 2845e96a66cSDavid du Colombier 2855e96a66cSDavid du Colombier if(partial){ 2865e96a66cSDavid du Colombier /* 2875e96a66cSDavid du Colombier * Do nothing. We're opening this file only so we can clri it. 2885e96a66cSDavid du Colombier * Usually the sources can't be opened, hence we won't even bother. 2895e96a66cSDavid du Colombier * Be VERY careful with the returned file. If you hand it to a routine 2905e96a66cSDavid du Colombier * expecting ff->source and/or ff->msource to be non-nil, we're 2915e96a66cSDavid du Colombier * likely to dereference nil. FileClri should be the only routine 2925e96a66cSDavid du Colombier * setting partial. 2935e96a66cSDavid du Colombier */ 2945e96a66cSDavid du Colombier ff->partial = 1; 2955e96a66cSDavid du Colombier }else if(ff->dir.mode & ModeDir){ 2963b86f2f8SDavid du Colombier ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, 2973b86f2f8SDavid du Colombier 1, ff->mode, ff->issnapshot); 2983b86f2f8SDavid du Colombier ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen, 2993b86f2f8SDavid du Colombier 0, ff->mode, ff->issnapshot); 3005e96a66cSDavid du Colombier if(ff->source == nil || ff->msource == nil) 3015e96a66cSDavid du Colombier goto Err; 3025e96a66cSDavid du Colombier }else{ 3033b86f2f8SDavid du Colombier ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, 3043b86f2f8SDavid du Colombier 0, ff->mode, ff->issnapshot); 3055e96a66cSDavid du Colombier if(ff->source == nil) 3065e96a66cSDavid du Colombier goto Err; 3075e96a66cSDavid du Colombier } 3085e96a66cSDavid du Colombier 3095e96a66cSDavid du Colombier /* link in and up parent ref count */ 3103b86f2f8SDavid du Colombier if (ff->source) 3113b86f2f8SDavid du Colombier ff->source->file = ff; /* point back */ 3125e96a66cSDavid du Colombier ff->next = f->down; 3135e96a66cSDavid du Colombier f->down = ff; 3145e96a66cSDavid du Colombier ff->up = f; 3155e96a66cSDavid du Colombier fileIncRef(f); 3165e96a66cSDavid du Colombier Exit: 3175e96a66cSDavid du Colombier fileUnlock(f); 3185e96a66cSDavid du Colombier return ff; 3195e96a66cSDavid du Colombier Err: 3205e96a66cSDavid du Colombier fileUnlock(f); 3215e96a66cSDavid du Colombier if(ff != nil) 3225e96a66cSDavid du Colombier fileDecRef(ff); 3235e96a66cSDavid du Colombier return nil; 3245e96a66cSDavid du Colombier } 3255e96a66cSDavid du Colombier 3265e96a66cSDavid du Colombier File * 3275e96a66cSDavid du Colombier fileWalk(File *f, char *elem) 3285e96a66cSDavid du Colombier { 3295e96a66cSDavid du Colombier return _fileWalk(f, elem, 0); 3305e96a66cSDavid du Colombier } 3315e96a66cSDavid du Colombier 3325e96a66cSDavid du Colombier File * 3335e96a66cSDavid du Colombier _fileOpen(Fs *fs, char *path, int partial) 3345e96a66cSDavid du Colombier { 3355e96a66cSDavid du Colombier File *f, *ff; 336f8e525acSDavid du Colombier char *p, elem[VtMaxStringSize], *opath; 3375e96a66cSDavid du Colombier int n; 3385e96a66cSDavid du Colombier 3395e96a66cSDavid du Colombier f = fs->file; 3405e96a66cSDavid du Colombier fileIncRef(f); 341f8e525acSDavid du Colombier opath = path; 3425e96a66cSDavid du Colombier while(*path != 0){ 3435e96a66cSDavid du Colombier for(p = path; *p && *p != '/'; p++) 3445e96a66cSDavid du Colombier ; 3455e96a66cSDavid du Colombier n = p - path; 3465e96a66cSDavid du Colombier if(n > 0){ 3475e96a66cSDavid du Colombier if(n > VtMaxStringSize){ 348*d7aba6c3SDavid du Colombier werrstr("%s: element too long", EBadPath); 3495e96a66cSDavid du Colombier goto Err; 3505e96a66cSDavid du Colombier } 3515e96a66cSDavid du Colombier memmove(elem, path, n); 3525e96a66cSDavid du Colombier elem[n] = 0; 3535e96a66cSDavid du Colombier ff = _fileWalk(f, elem, partial && *p=='\0'); 354f8e525acSDavid du Colombier if(ff == nil){ 355*d7aba6c3SDavid du Colombier werrstr("%.*s: %r", utfnlen(opath, p-opath), 3563b86f2f8SDavid du Colombier opath); 3575e96a66cSDavid du Colombier goto Err; 358f8e525acSDavid du Colombier } 3595e96a66cSDavid du Colombier fileDecRef(f); 3605e96a66cSDavid du Colombier f = ff; 3615e96a66cSDavid du Colombier } 3625e96a66cSDavid du Colombier if(*p == '/') 3635e96a66cSDavid du Colombier p++; 3645e96a66cSDavid du Colombier path = p; 3655e96a66cSDavid du Colombier } 3665e96a66cSDavid du Colombier return f; 3675e96a66cSDavid du Colombier Err: 3685e96a66cSDavid du Colombier fileDecRef(f); 3695e96a66cSDavid du Colombier return nil; 3705e96a66cSDavid du Colombier } 3715e96a66cSDavid du Colombier 3725e96a66cSDavid du Colombier File* 3735e96a66cSDavid du Colombier fileOpen(Fs *fs, char *path) 3745e96a66cSDavid du Colombier { 3755e96a66cSDavid du Colombier return _fileOpen(fs, path, 0); 3765e96a66cSDavid du Colombier } 3775e96a66cSDavid du Colombier 378fe853e23SDavid du Colombier static void 379fe853e23SDavid du Colombier fileSetTmp(File *f, int istmp) 380fe853e23SDavid du Colombier { 381fe853e23SDavid du Colombier int i; 382fe853e23SDavid du Colombier Entry e; 383fe853e23SDavid du Colombier Source *r; 384fe853e23SDavid du Colombier 385fe853e23SDavid du Colombier for(i=0; i<2; i++){ 386fe853e23SDavid du Colombier if(i==0) 387fe853e23SDavid du Colombier r = f->source; 388fe853e23SDavid du Colombier else 389fe853e23SDavid du Colombier r = f->msource; 390fe853e23SDavid du Colombier if(r == nil) 391fe853e23SDavid du Colombier continue; 392f352e144SDavid du Colombier if(!sourceGetEntry(r, &e)){ 393fe853e23SDavid du Colombier fprint(2, "sourceGetEntry failed (cannot happen): %r\n"); 394fe853e23SDavid du Colombier continue; 395fe853e23SDavid du Colombier } 396fe853e23SDavid du Colombier if(istmp) 397fe853e23SDavid du Colombier e.flags |= VtEntryNoArchive; 398fe853e23SDavid du Colombier else 399fe853e23SDavid du Colombier e.flags &= ~VtEntryNoArchive; 400f352e144SDavid du Colombier if(!sourceSetEntry(r, &e)){ 401fe853e23SDavid du Colombier fprint(2, "sourceSetEntry failed (cannot happen): %r\n"); 402fe853e23SDavid du Colombier continue; 403fe853e23SDavid du Colombier } 404fe853e23SDavid du Colombier } 405fe853e23SDavid du Colombier } 406fe853e23SDavid du Colombier 4075e96a66cSDavid du Colombier File * 4085e96a66cSDavid du Colombier fileCreate(File *f, char *elem, ulong mode, char *uid) 4095e96a66cSDavid du Colombier { 4105e96a66cSDavid du Colombier File *ff; 4115e96a66cSDavid du Colombier DirEntry *dir; 4125e96a66cSDavid du Colombier Source *pr, *r, *mr; 4135e96a66cSDavid du Colombier int isdir; 4145e96a66cSDavid du Colombier 4155e96a66cSDavid du Colombier if(!fileLock(f)) 4165e96a66cSDavid du Colombier return nil; 4175e96a66cSDavid du Colombier 4185e96a66cSDavid du Colombier r = nil; 4195e96a66cSDavid du Colombier mr = nil; 4205e96a66cSDavid du Colombier for(ff = f->down; ff; ff=ff->next){ 4215e96a66cSDavid du Colombier if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ 4225e96a66cSDavid du Colombier ff = nil; 423*d7aba6c3SDavid du Colombier werrstr(EExists); 4245e96a66cSDavid du Colombier goto Err1; 4255e96a66cSDavid du Colombier } 4265e96a66cSDavid du Colombier } 4275e96a66cSDavid du Colombier 4285e96a66cSDavid du Colombier ff = dirLookup(f, elem); 4295e96a66cSDavid du Colombier if(ff != nil){ 430*d7aba6c3SDavid du Colombier werrstr(EExists); 4315e96a66cSDavid du Colombier goto Err1; 4325e96a66cSDavid du Colombier } 4335e96a66cSDavid du Colombier 4345e96a66cSDavid du Colombier pr = f->source; 4355e96a66cSDavid du Colombier if(pr->mode != OReadWrite){ 436*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 4375e96a66cSDavid du Colombier goto Err1; 4385e96a66cSDavid du Colombier } 4395e96a66cSDavid du Colombier 4405e96a66cSDavid du Colombier if(!sourceLock2(f->source, f->msource, -1)) 4415e96a66cSDavid du Colombier goto Err1; 4425e96a66cSDavid du Colombier 4435e96a66cSDavid du Colombier ff = fileAlloc(f->fs); 4445e96a66cSDavid du Colombier isdir = mode & ModeDir; 4455e96a66cSDavid du Colombier 4465e96a66cSDavid du Colombier r = sourceCreate(pr, pr->dsize, isdir, 0); 4475e96a66cSDavid du Colombier if(r == nil) 4485e96a66cSDavid du Colombier goto Err; 4495e96a66cSDavid du Colombier if(isdir){ 4505e96a66cSDavid du Colombier mr = sourceCreate(pr, pr->dsize, 0, r->offset); 4515e96a66cSDavid du Colombier if(mr == nil) 4525e96a66cSDavid du Colombier goto Err; 4535e96a66cSDavid du Colombier } 4545e96a66cSDavid du Colombier 4555e96a66cSDavid du Colombier dir = &ff->dir; 456*d7aba6c3SDavid du Colombier dir->elem = vtstrdup(elem); 4575e96a66cSDavid du Colombier dir->entry = r->offset; 4585e96a66cSDavid du Colombier dir->gen = r->gen; 4595e96a66cSDavid du Colombier if(isdir){ 4605e96a66cSDavid du Colombier dir->mentry = mr->offset; 4615e96a66cSDavid du Colombier dir->mgen = mr->gen; 4625e96a66cSDavid du Colombier } 4635e96a66cSDavid du Colombier dir->size = 0; 4645e96a66cSDavid du Colombier if(!fsNextQid(f->fs, &dir->qid)) 4655e96a66cSDavid du Colombier goto Err; 466*d7aba6c3SDavid du Colombier dir->uid = vtstrdup(uid); 467*d7aba6c3SDavid du Colombier dir->gid = vtstrdup(f->dir.gid); 468*d7aba6c3SDavid du Colombier dir->mid = vtstrdup(uid); 4695e96a66cSDavid du Colombier dir->mtime = time(0L); 4705e96a66cSDavid du Colombier dir->mcount = 0; 4715e96a66cSDavid du Colombier dir->ctime = dir->mtime; 4725e96a66cSDavid du Colombier dir->atime = dir->mtime; 4735e96a66cSDavid du Colombier dir->mode = mode; 4745e96a66cSDavid du Colombier 4755e96a66cSDavid du Colombier ff->boff = fileMetaAlloc(f, dir, 0); 4765e96a66cSDavid du Colombier if(ff->boff == NilBlock) 4775e96a66cSDavid du Colombier goto Err; 4785e96a66cSDavid du Colombier 4795e96a66cSDavid du Colombier sourceUnlock(f->source); 4805e96a66cSDavid du Colombier sourceUnlock(f->msource); 4815e96a66cSDavid du Colombier 4825e96a66cSDavid du Colombier ff->source = r; 4833b86f2f8SDavid du Colombier r->file = ff; /* point back */ 4845e96a66cSDavid du Colombier ff->msource = mr; 4855e96a66cSDavid du Colombier 486fe853e23SDavid du Colombier if(mode&ModeTemporary){ 487fe853e23SDavid du Colombier if(!sourceLock2(r, mr, -1)) 488fe853e23SDavid du Colombier goto Err1; 489fe853e23SDavid du Colombier fileSetTmp(ff, 1); 490fe853e23SDavid du Colombier sourceUnlock(r); 491fe853e23SDavid du Colombier if(mr) 492fe853e23SDavid du Colombier sourceUnlock(mr); 493fe853e23SDavid du Colombier } 494fe853e23SDavid du Colombier 495fe853e23SDavid du Colombier /* committed */ 496fe853e23SDavid du Colombier 4975e96a66cSDavid du Colombier /* link in and up parent ref count */ 4985e96a66cSDavid du Colombier ff->next = f->down; 4995e96a66cSDavid du Colombier f->down = ff; 5005e96a66cSDavid du Colombier ff->up = f; 5015e96a66cSDavid du Colombier fileIncRef(f); 5025e96a66cSDavid du Colombier 5035e96a66cSDavid du Colombier fileWAccess(f, uid); 5045e96a66cSDavid du Colombier 5055e96a66cSDavid du Colombier fileUnlock(f); 5065e96a66cSDavid du Colombier return ff; 5075e96a66cSDavid du Colombier 5085e96a66cSDavid du Colombier Err: 5095e96a66cSDavid du Colombier sourceUnlock(f->source); 5105e96a66cSDavid du Colombier sourceUnlock(f->msource); 5115e96a66cSDavid du Colombier Err1: 512dc5a79c1SDavid du Colombier if(r){ 513dc5a79c1SDavid du Colombier sourceLock(r, -1); 5145e96a66cSDavid du Colombier sourceRemove(r); 515dc5a79c1SDavid du Colombier } 516dc5a79c1SDavid du Colombier if(mr){ 517dc5a79c1SDavid du Colombier sourceLock(mr, -1); 5185e96a66cSDavid du Colombier sourceRemove(mr); 519dc5a79c1SDavid du Colombier } 5205e96a66cSDavid du Colombier if(ff) 5215e96a66cSDavid du Colombier fileDecRef(ff); 5225e96a66cSDavid du Colombier fileUnlock(f); 5235e96a66cSDavid du Colombier return 0; 5245e96a66cSDavid du Colombier } 5255e96a66cSDavid du Colombier 5265e96a66cSDavid du Colombier int 5275e96a66cSDavid du Colombier fileRead(File *f, void *buf, int cnt, vlong offset) 5285e96a66cSDavid du Colombier { 5295e96a66cSDavid du Colombier Source *s; 5305e96a66cSDavid du Colombier uvlong size; 5315e96a66cSDavid du Colombier u32int bn; 5325e96a66cSDavid du Colombier int off, dsize, n, nn; 5335e96a66cSDavid du Colombier Block *b; 5345e96a66cSDavid du Colombier uchar *p; 5355e96a66cSDavid du Colombier 5365e96a66cSDavid du Colombier if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset); 5375e96a66cSDavid du Colombier 5385e96a66cSDavid du Colombier if(!fileRLock(f)) 5395e96a66cSDavid du Colombier return -1; 5405e96a66cSDavid du Colombier 5415e96a66cSDavid du Colombier if(offset < 0){ 542*d7aba6c3SDavid du Colombier werrstr(EBadOffset); 5435e96a66cSDavid du Colombier goto Err1; 5445e96a66cSDavid du Colombier } 5455e96a66cSDavid du Colombier 5465e96a66cSDavid du Colombier fileRAccess(f); 5475e96a66cSDavid du Colombier 5485e96a66cSDavid du Colombier if(!sourceLock(f->source, OReadOnly)) 5495e96a66cSDavid du Colombier goto Err1; 5505e96a66cSDavid du Colombier 5515e96a66cSDavid du Colombier s = f->source; 5525e96a66cSDavid du Colombier dsize = s->dsize; 5535e96a66cSDavid du Colombier size = sourceGetSize(s); 5545e96a66cSDavid du Colombier 5555e96a66cSDavid du Colombier if(offset >= size) 5565e96a66cSDavid du Colombier offset = size; 5575e96a66cSDavid du Colombier 5585e96a66cSDavid du Colombier if(cnt > size-offset) 5595e96a66cSDavid du Colombier cnt = size-offset; 5605e96a66cSDavid du Colombier bn = offset/dsize; 5615e96a66cSDavid du Colombier off = offset%dsize; 5625e96a66cSDavid du Colombier p = buf; 5635e96a66cSDavid du Colombier while(cnt > 0){ 5645e96a66cSDavid du Colombier b = sourceBlock(s, bn, OReadOnly); 5655e96a66cSDavid du Colombier if(b == nil) 5665e96a66cSDavid du Colombier goto Err; 5675e96a66cSDavid du Colombier n = cnt; 5685e96a66cSDavid du Colombier if(n > dsize-off) 5695e96a66cSDavid du Colombier n = dsize-off; 5705e96a66cSDavid du Colombier nn = dsize-off; 5715e96a66cSDavid du Colombier if(nn > n) 5725e96a66cSDavid du Colombier nn = n; 5735e96a66cSDavid du Colombier memmove(p, b->data+off, nn); 5745e96a66cSDavid du Colombier memset(p+nn, 0, nn-n); 5755e96a66cSDavid du Colombier off = 0; 5765e96a66cSDavid du Colombier bn++; 5775e96a66cSDavid du Colombier cnt -= n; 5785e96a66cSDavid du Colombier p += n; 5795e96a66cSDavid du Colombier blockPut(b); 5805e96a66cSDavid du Colombier } 5815e96a66cSDavid du Colombier sourceUnlock(s); 5825e96a66cSDavid du Colombier fileRUnlock(f); 5835e96a66cSDavid du Colombier return p-(uchar*)buf; 5845e96a66cSDavid du Colombier 5855e96a66cSDavid du Colombier Err: 5865e96a66cSDavid du Colombier sourceUnlock(s); 5875e96a66cSDavid du Colombier Err1: 5885e96a66cSDavid du Colombier fileRUnlock(f); 5895e96a66cSDavid du Colombier return -1; 5905e96a66cSDavid du Colombier } 5915e96a66cSDavid du Colombier 592fe853e23SDavid du Colombier /* 593fe853e23SDavid du Colombier * Changes the file block bn to be the given block score. 594fe853e23SDavid du Colombier * Very sneaky. Only used by flfmt. 595fe853e23SDavid du Colombier */ 596fe853e23SDavid du Colombier int 597fe853e23SDavid du Colombier fileMapBlock(File *f, ulong bn, uchar score[VtScoreSize], ulong tag) 598fe853e23SDavid du Colombier { 599fe853e23SDavid du Colombier Block *b; 600fe853e23SDavid du Colombier Entry e; 601fe853e23SDavid du Colombier Source *s; 602fe853e23SDavid du Colombier 603fe853e23SDavid du Colombier if(!fileLock(f)) 604fe853e23SDavid du Colombier return 0; 605fe853e23SDavid du Colombier 606fe853e23SDavid du Colombier s = nil; 607fe853e23SDavid du Colombier if(f->dir.mode & ModeDir){ 608*d7aba6c3SDavid du Colombier werrstr(ENotFile); 609fe853e23SDavid du Colombier goto Err; 610fe853e23SDavid du Colombier } 611fe853e23SDavid du Colombier 612fe853e23SDavid du Colombier if(f->source->mode != OReadWrite){ 613*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 614fe853e23SDavid du Colombier goto Err; 615fe853e23SDavid du Colombier } 616fe853e23SDavid du Colombier 617fe853e23SDavid du Colombier if(!sourceLock(f->source, -1)) 618fe853e23SDavid du Colombier goto Err; 619fe853e23SDavid du Colombier 620fe853e23SDavid du Colombier s = f->source; 621fe853e23SDavid du Colombier b = _sourceBlock(s, bn, OReadWrite, 1, tag); 622fe853e23SDavid du Colombier if(b == nil) 623fe853e23SDavid du Colombier goto Err; 624fe853e23SDavid du Colombier 625fe853e23SDavid du Colombier if(!sourceGetEntry(s, &e)) 626fe853e23SDavid du Colombier goto Err; 627fe853e23SDavid du Colombier if(b->l.type == BtDir){ 628fe853e23SDavid du Colombier memmove(e.score, score, VtScoreSize); 629fe853e23SDavid du Colombier assert(e.tag == tag || e.tag == 0); 630fe853e23SDavid du Colombier e.tag = tag; 631fe853e23SDavid du Colombier e.flags |= VtEntryLocal; 632fe853e23SDavid du Colombier entryPack(&e, b->data, f->source->offset % f->source->epb); 633fe853e23SDavid du Colombier }else 634fe853e23SDavid du Colombier memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize); 635fe853e23SDavid du Colombier blockDirty(b); 636fe853e23SDavid du Colombier blockPut(b); 637fe853e23SDavid du Colombier sourceUnlock(s); 638fe853e23SDavid du Colombier fileUnlock(f); 639fe853e23SDavid du Colombier return 1; 640fe853e23SDavid du Colombier 641fe853e23SDavid du Colombier Err: 642fe853e23SDavid du Colombier if(s) 643fe853e23SDavid du Colombier sourceUnlock(s); 644fe853e23SDavid du Colombier fileUnlock(f); 645fe853e23SDavid du Colombier return 0; 646fe853e23SDavid du Colombier } 647fe853e23SDavid du Colombier 648fe853e23SDavid du Colombier int 649fe853e23SDavid du Colombier fileSetSize(File *f, uvlong size) 650fe853e23SDavid du Colombier { 651fe853e23SDavid du Colombier int r; 652fe853e23SDavid du Colombier 653fe853e23SDavid du Colombier if(!fileLock(f)) 654fe853e23SDavid du Colombier return 0; 655fe853e23SDavid du Colombier r = 0; 656fe853e23SDavid du Colombier if(f->dir.mode & ModeDir){ 657*d7aba6c3SDavid du Colombier werrstr(ENotFile); 658fe853e23SDavid du Colombier goto Err; 659fe853e23SDavid du Colombier } 660fe853e23SDavid du Colombier if(f->source->mode != OReadWrite){ 661*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 662fe853e23SDavid du Colombier goto Err; 663fe853e23SDavid du Colombier } 664fe853e23SDavid du Colombier if(!sourceLock(f->source, -1)) 665fe853e23SDavid du Colombier goto Err; 666fe853e23SDavid du Colombier r = sourceSetSize(f->source, size); 667fe853e23SDavid du Colombier sourceUnlock(f->source); 668fe853e23SDavid du Colombier Err: 669fe853e23SDavid du Colombier fileUnlock(f); 670fe853e23SDavid du Colombier return r; 671fe853e23SDavid du Colombier } 672fe853e23SDavid du Colombier 6735e96a66cSDavid du Colombier int 6745e96a66cSDavid du Colombier fileWrite(File *f, void *buf, int cnt, vlong offset, char *uid) 6755e96a66cSDavid du Colombier { 6765e96a66cSDavid du Colombier Source *s; 6775e96a66cSDavid du Colombier ulong bn; 6785e96a66cSDavid du Colombier int off, dsize, n; 6795e96a66cSDavid du Colombier Block *b; 6805e96a66cSDavid du Colombier uchar *p; 6815e96a66cSDavid du Colombier vlong eof; 6825e96a66cSDavid du Colombier 6835e96a66cSDavid du Colombier if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset); 6845e96a66cSDavid du Colombier 6855e96a66cSDavid du Colombier if(!fileLock(f)) 6865e96a66cSDavid du Colombier return -1; 6875e96a66cSDavid du Colombier 6885e96a66cSDavid du Colombier s = nil; 6895e96a66cSDavid du Colombier if(f->dir.mode & ModeDir){ 690*d7aba6c3SDavid du Colombier werrstr(ENotFile); 6915e96a66cSDavid du Colombier goto Err; 6925e96a66cSDavid du Colombier } 6935e96a66cSDavid du Colombier 6945e96a66cSDavid du Colombier if(f->source->mode != OReadWrite){ 695*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 6965e96a66cSDavid du Colombier goto Err; 6975e96a66cSDavid du Colombier } 6985e96a66cSDavid du Colombier if(offset < 0){ 699*d7aba6c3SDavid du Colombier werrstr(EBadOffset); 7005e96a66cSDavid du Colombier goto Err; 7015e96a66cSDavid du Colombier } 7025e96a66cSDavid du Colombier 7035e96a66cSDavid du Colombier fileWAccess(f, uid); 7045e96a66cSDavid du Colombier 7055e96a66cSDavid du Colombier if(!sourceLock(f->source, -1)) 7065e96a66cSDavid du Colombier goto Err; 7075e96a66cSDavid du Colombier s = f->source; 7085e96a66cSDavid du Colombier dsize = s->dsize; 7095e96a66cSDavid du Colombier 7105e96a66cSDavid du Colombier eof = sourceGetSize(s); 7115e96a66cSDavid du Colombier if(f->dir.mode & ModeAppend) 7125e96a66cSDavid du Colombier offset = eof; 7135e96a66cSDavid du Colombier bn = offset/dsize; 7145e96a66cSDavid du Colombier off = offset%dsize; 7155e96a66cSDavid du Colombier p = buf; 7165e96a66cSDavid du Colombier while(cnt > 0){ 7175e96a66cSDavid du Colombier n = cnt; 7185e96a66cSDavid du Colombier if(n > dsize-off) 7195e96a66cSDavid du Colombier n = dsize-off; 7205e96a66cSDavid du Colombier b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite); 7215e96a66cSDavid du Colombier if(b == nil){ 7225e96a66cSDavid du Colombier if(offset > eof) 7235e96a66cSDavid du Colombier sourceSetSize(s, offset); 7245e96a66cSDavid du Colombier goto Err; 7255e96a66cSDavid du Colombier } 7265e96a66cSDavid du Colombier memmove(b->data+off, p, n); 7275e96a66cSDavid du Colombier off = 0; 7285e96a66cSDavid du Colombier cnt -= n; 7295e96a66cSDavid du Colombier p += n; 7305e96a66cSDavid du Colombier offset += n; 7315e96a66cSDavid du Colombier bn++; 7325e96a66cSDavid du Colombier blockDirty(b); 7335e96a66cSDavid du Colombier blockPut(b); 7345e96a66cSDavid du Colombier } 7355e96a66cSDavid du Colombier if(offset > eof && !sourceSetSize(s, offset)) 7365e96a66cSDavid du Colombier goto Err; 7375e96a66cSDavid du Colombier sourceUnlock(s); 7385e96a66cSDavid du Colombier fileUnlock(f); 7395e96a66cSDavid du Colombier return p-(uchar*)buf; 7405e96a66cSDavid du Colombier Err: 7415e96a66cSDavid du Colombier if(s) 7425e96a66cSDavid du Colombier sourceUnlock(s); 7435e96a66cSDavid du Colombier fileUnlock(f); 7445e96a66cSDavid du Colombier return -1; 7455e96a66cSDavid du Colombier } 7465e96a66cSDavid du Colombier 7475e96a66cSDavid du Colombier int 7485e96a66cSDavid du Colombier fileGetDir(File *f, DirEntry *dir) 7495e96a66cSDavid du Colombier { 7505e96a66cSDavid du Colombier if(!fileRLock(f)) 7515e96a66cSDavid du Colombier return 0; 7525e96a66cSDavid du Colombier 7535e96a66cSDavid du Colombier fileMetaLock(f); 7545e96a66cSDavid du Colombier deCopy(dir, &f->dir); 7555e96a66cSDavid du Colombier fileMetaUnlock(f); 7565e96a66cSDavid du Colombier 7575e96a66cSDavid du Colombier if(!fileIsDir(f)){ 7585e96a66cSDavid du Colombier if(!sourceLock(f->source, OReadOnly)){ 7595e96a66cSDavid du Colombier fileRUnlock(f); 7605e96a66cSDavid du Colombier return 0; 7615e96a66cSDavid du Colombier } 7625e96a66cSDavid du Colombier dir->size = sourceGetSize(f->source); 7635e96a66cSDavid du Colombier sourceUnlock(f->source); 7645e96a66cSDavid du Colombier } 7655e96a66cSDavid du Colombier fileRUnlock(f); 7665e96a66cSDavid du Colombier 7675e96a66cSDavid du Colombier return 1; 7685e96a66cSDavid du Colombier } 7695e96a66cSDavid du Colombier 7705e96a66cSDavid du Colombier int 7715e96a66cSDavid du Colombier fileTruncate(File *f, char *uid) 7725e96a66cSDavid du Colombier { 7735e96a66cSDavid du Colombier if(fileIsDir(f)){ 774*d7aba6c3SDavid du Colombier werrstr(ENotFile); 7755e96a66cSDavid du Colombier return 0; 7765e96a66cSDavid du Colombier } 7775e96a66cSDavid du Colombier 7785e96a66cSDavid du Colombier if(!fileLock(f)) 7795e96a66cSDavid du Colombier return 0; 7805e96a66cSDavid du Colombier 7815e96a66cSDavid du Colombier if(f->source->mode != OReadWrite){ 782*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 7835e96a66cSDavid du Colombier fileUnlock(f); 7845e96a66cSDavid du Colombier return 0; 7855e96a66cSDavid du Colombier } 7865e96a66cSDavid du Colombier if(!sourceLock(f->source, -1)){ 7875e96a66cSDavid du Colombier fileUnlock(f); 7885e96a66cSDavid du Colombier return 0; 7895e96a66cSDavid du Colombier } 7905e96a66cSDavid du Colombier if(!sourceTruncate(f->source)){ 7915e96a66cSDavid du Colombier sourceUnlock(f->source); 7925e96a66cSDavid du Colombier fileUnlock(f); 7935e96a66cSDavid du Colombier return 0; 7945e96a66cSDavid du Colombier } 7955e96a66cSDavid du Colombier sourceUnlock(f->source); 7965e96a66cSDavid du Colombier fileUnlock(f); 7975e96a66cSDavid du Colombier 798a960ed1cSDavid du Colombier fileWAccess(f, uid); 7995e96a66cSDavid du Colombier 8005e96a66cSDavid du Colombier return 1; 8015e96a66cSDavid du Colombier } 8025e96a66cSDavid du Colombier 8035e96a66cSDavid du Colombier int 8045e96a66cSDavid du Colombier fileSetDir(File *f, DirEntry *dir, char *uid) 8055e96a66cSDavid du Colombier { 8065e96a66cSDavid du Colombier File *ff; 8075e96a66cSDavid du Colombier char *oelem; 8085e96a66cSDavid du Colombier u32int mask; 8095e96a66cSDavid du Colombier u64int size; 8105e96a66cSDavid du Colombier 8115e96a66cSDavid du Colombier /* can not set permissions for the root */ 8125e96a66cSDavid du Colombier if(fileIsRoot(f)){ 813*d7aba6c3SDavid du Colombier werrstr(ERoot); 8145e96a66cSDavid du Colombier return 0; 8155e96a66cSDavid du Colombier } 8165e96a66cSDavid du Colombier 8175e96a66cSDavid du Colombier if(!fileLock(f)) 8185e96a66cSDavid du Colombier return 0; 8195e96a66cSDavid du Colombier 8205e96a66cSDavid du Colombier if(f->source->mode != OReadWrite){ 821*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 8225e96a66cSDavid du Colombier fileUnlock(f); 8235e96a66cSDavid du Colombier return 0; 8245e96a66cSDavid du Colombier } 8255e96a66cSDavid du Colombier 8265e96a66cSDavid du Colombier fileMetaLock(f); 8275e96a66cSDavid du Colombier 8285e96a66cSDavid du Colombier /* check new name does not already exist */ 8295e96a66cSDavid du Colombier if(strcmp(f->dir.elem, dir->elem) != 0){ 8305e96a66cSDavid du Colombier for(ff = f->up->down; ff; ff=ff->next){ 8315e96a66cSDavid du Colombier if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){ 832*d7aba6c3SDavid du Colombier werrstr(EExists); 8335e96a66cSDavid du Colombier goto Err; 8345e96a66cSDavid du Colombier } 8355e96a66cSDavid du Colombier } 8365e96a66cSDavid du Colombier 8375e96a66cSDavid du Colombier ff = dirLookup(f->up, dir->elem); 8385e96a66cSDavid du Colombier if(ff != nil){ 8395e96a66cSDavid du Colombier fileDecRef(ff); 840*d7aba6c3SDavid du Colombier werrstr(EExists); 8415e96a66cSDavid du Colombier goto Err; 8425e96a66cSDavid du Colombier } 8435e96a66cSDavid du Colombier } 8445e96a66cSDavid du Colombier 845fe853e23SDavid du Colombier if(!sourceLock2(f->source, f->msource, -1)) 8465e96a66cSDavid du Colombier goto Err; 847fe853e23SDavid du Colombier if(!fileIsDir(f)){ 8485e96a66cSDavid du Colombier size = sourceGetSize(f->source); 8495e96a66cSDavid du Colombier if(size != dir->size){ 8505e96a66cSDavid du Colombier if(!sourceSetSize(f->source, dir->size)){ 8515e96a66cSDavid du Colombier sourceUnlock(f->source); 852fe853e23SDavid du Colombier if(f->msource) 853fe853e23SDavid du Colombier sourceUnlock(f->msource); 8545e96a66cSDavid du Colombier goto Err; 8555e96a66cSDavid du Colombier } 8565e96a66cSDavid du Colombier /* commited to changing it now */ 8575e96a66cSDavid du Colombier } 8585e96a66cSDavid du Colombier } 8595e96a66cSDavid du Colombier /* commited to changing it now */ 860fe853e23SDavid du Colombier if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary)) 861fe853e23SDavid du Colombier fileSetTmp(f, dir->mode&ModeTemporary); 862fe853e23SDavid du Colombier sourceUnlock(f->source); 863fe853e23SDavid du Colombier if(f->msource) 864fe853e23SDavid du Colombier sourceUnlock(f->msource); 865fe853e23SDavid du Colombier 8665e96a66cSDavid du Colombier oelem = nil; 8675e96a66cSDavid du Colombier if(strcmp(f->dir.elem, dir->elem) != 0){ 8685e96a66cSDavid du Colombier oelem = f->dir.elem; 869*d7aba6c3SDavid du Colombier f->dir.elem = vtstrdup(dir->elem); 8705e96a66cSDavid du Colombier } 8715e96a66cSDavid du Colombier 8725e96a66cSDavid du Colombier if(strcmp(f->dir.uid, dir->uid) != 0){ 873*d7aba6c3SDavid du Colombier vtfree(f->dir.uid); 874*d7aba6c3SDavid du Colombier f->dir.uid = vtstrdup(dir->uid); 8755e96a66cSDavid du Colombier } 8765e96a66cSDavid du Colombier 8775e96a66cSDavid du Colombier if(strcmp(f->dir.gid, dir->gid) != 0){ 878*d7aba6c3SDavid du Colombier vtfree(f->dir.gid); 879*d7aba6c3SDavid du Colombier f->dir.gid = vtstrdup(dir->gid); 8805e96a66cSDavid du Colombier } 8815e96a66cSDavid du Colombier 8825e96a66cSDavid du Colombier f->dir.mtime = dir->mtime; 8835e96a66cSDavid du Colombier f->dir.atime = dir->atime; 8845e96a66cSDavid du Colombier 8855e96a66cSDavid du Colombier //fprint(2, "mode %x %x ", f->dir.mode, dir->mode); 8865e96a66cSDavid du Colombier mask = ~(ModeDir|ModeSnapshot); 8875e96a66cSDavid du Colombier f->dir.mode &= ~mask; 8885e96a66cSDavid du Colombier f->dir.mode |= mask & dir->mode; 8895e96a66cSDavid du Colombier f->dirty = 1; 8905e96a66cSDavid du Colombier //fprint(2, "->%x\n", f->dir.mode); 8915e96a66cSDavid du Colombier 8925e96a66cSDavid du Colombier fileMetaFlush2(f, oelem); 893*d7aba6c3SDavid du Colombier vtfree(oelem); 8945e96a66cSDavid du Colombier 8955e96a66cSDavid du Colombier fileMetaUnlock(f); 8965e96a66cSDavid du Colombier fileUnlock(f); 8975e96a66cSDavid du Colombier 8985e96a66cSDavid du Colombier fileWAccess(f->up, uid); 8995e96a66cSDavid du Colombier 9005e96a66cSDavid du Colombier return 1; 9015e96a66cSDavid du Colombier Err: 9025e96a66cSDavid du Colombier fileMetaUnlock(f); 9035e96a66cSDavid du Colombier fileUnlock(f); 9045e96a66cSDavid du Colombier return 0; 9055e96a66cSDavid du Colombier } 9065e96a66cSDavid du Colombier 9075e96a66cSDavid du Colombier int 9085e96a66cSDavid du Colombier fileSetQidSpace(File *f, u64int offset, u64int max) 9095e96a66cSDavid du Colombier { 9105e96a66cSDavid du Colombier int ret; 9115e96a66cSDavid du Colombier 9125e96a66cSDavid du Colombier if(!fileLock(f)) 9135e96a66cSDavid du Colombier return 0; 9145e96a66cSDavid du Colombier fileMetaLock(f); 9155e96a66cSDavid du Colombier f->dir.qidSpace = 1; 9165e96a66cSDavid du Colombier f->dir.qidOffset = offset; 9175e96a66cSDavid du Colombier f->dir.qidMax = max; 9180b9a5132SDavid du Colombier ret = fileMetaFlush2(f, nil)>=0; 9195e96a66cSDavid du Colombier fileMetaUnlock(f); 9205e96a66cSDavid du Colombier fileUnlock(f); 9215e96a66cSDavid du Colombier return ret; 9225e96a66cSDavid du Colombier } 9235e96a66cSDavid du Colombier 9245e96a66cSDavid du Colombier 9255e96a66cSDavid du Colombier uvlong 9265e96a66cSDavid du Colombier fileGetId(File *f) 9275e96a66cSDavid du Colombier { 9285e96a66cSDavid du Colombier /* immutable */ 9295e96a66cSDavid du Colombier return f->dir.qid; 9305e96a66cSDavid du Colombier } 9315e96a66cSDavid du Colombier 9325e96a66cSDavid du Colombier ulong 9335e96a66cSDavid du Colombier fileGetMcount(File *f) 9345e96a66cSDavid du Colombier { 9355e96a66cSDavid du Colombier ulong mcount; 9365e96a66cSDavid du Colombier 9375e96a66cSDavid du Colombier fileMetaLock(f); 9385e96a66cSDavid du Colombier mcount = f->dir.mcount; 9395e96a66cSDavid du Colombier fileMetaUnlock(f); 9405e96a66cSDavid du Colombier return mcount; 9415e96a66cSDavid du Colombier } 9425e96a66cSDavid du Colombier 9435e96a66cSDavid du Colombier ulong 9445e96a66cSDavid du Colombier fileGetMode(File *f) 9455e96a66cSDavid du Colombier { 9465e96a66cSDavid du Colombier ulong mode; 9475e96a66cSDavid du Colombier 9485e96a66cSDavid du Colombier fileMetaLock(f); 9495e96a66cSDavid du Colombier mode = f->dir.mode; 9505e96a66cSDavid du Colombier fileMetaUnlock(f); 9515e96a66cSDavid du Colombier return mode; 9525e96a66cSDavid du Colombier } 9535e96a66cSDavid du Colombier 9545e96a66cSDavid du Colombier int 9555e96a66cSDavid du Colombier fileIsDir(File *f) 9565e96a66cSDavid du Colombier { 9575e96a66cSDavid du Colombier /* immutable */ 9585e96a66cSDavid du Colombier return (f->dir.mode & ModeDir) != 0; 9595e96a66cSDavid du Colombier } 9605e96a66cSDavid du Colombier 9615e96a66cSDavid du Colombier int 9626bbfed0dSDavid du Colombier fileIsAppend(File *f) 9636bbfed0dSDavid du Colombier { 9646bbfed0dSDavid du Colombier return (f->dir.mode & ModeAppend) != 0; 9656bbfed0dSDavid du Colombier } 9666bbfed0dSDavid du Colombier 9676bbfed0dSDavid du Colombier int 9686bbfed0dSDavid du Colombier fileIsExclusive(File *f) 9696bbfed0dSDavid du Colombier { 9706bbfed0dSDavid du Colombier return (f->dir.mode & ModeExclusive) != 0; 9716bbfed0dSDavid du Colombier } 9726bbfed0dSDavid du Colombier 9736bbfed0dSDavid du Colombier int 9746bbfed0dSDavid du Colombier fileIsTemporary(File *f) 9756bbfed0dSDavid du Colombier { 9766bbfed0dSDavid du Colombier return (f->dir.mode & ModeTemporary) != 0; 9776bbfed0dSDavid du Colombier } 9786bbfed0dSDavid du Colombier 9796bbfed0dSDavid du Colombier int 9805e96a66cSDavid du Colombier fileIsRoot(File *f) 9815e96a66cSDavid du Colombier { 9825e96a66cSDavid du Colombier return f == f->fs->file; 9835e96a66cSDavid du Colombier } 9845e96a66cSDavid du Colombier 9855e96a66cSDavid du Colombier int 9865e96a66cSDavid du Colombier fileIsRoFs(File *f) 9875e96a66cSDavid du Colombier { 9885e96a66cSDavid du Colombier return f->fs->mode == OReadOnly; 9895e96a66cSDavid du Colombier } 9905e96a66cSDavid du Colombier 9915e96a66cSDavid du Colombier int 9925e96a66cSDavid du Colombier fileGetSize(File *f, uvlong *size) 9935e96a66cSDavid du Colombier { 9945e96a66cSDavid du Colombier if(!fileRLock(f)) 9955e96a66cSDavid du Colombier return 0; 9965e96a66cSDavid du Colombier if(!sourceLock(f->source, OReadOnly)){ 9975e96a66cSDavid du Colombier fileRUnlock(f); 9985e96a66cSDavid du Colombier return 0; 9995e96a66cSDavid du Colombier } 10005e96a66cSDavid du Colombier *size = sourceGetSize(f->source); 10015e96a66cSDavid du Colombier sourceUnlock(f->source); 10025e96a66cSDavid du Colombier fileRUnlock(f); 10035e96a66cSDavid du Colombier 10045e96a66cSDavid du Colombier return 1; 10055e96a66cSDavid du Colombier } 10065e96a66cSDavid du Colombier 10070b9a5132SDavid du Colombier int 10085e96a66cSDavid du Colombier fileMetaFlush(File *f, int rec) 10095e96a66cSDavid du Colombier { 10105e96a66cSDavid du Colombier File **kids, *p; 10115e96a66cSDavid du Colombier int nkids; 10120b9a5132SDavid du Colombier int i, rv; 10135e96a66cSDavid du Colombier 10145e96a66cSDavid du Colombier fileMetaLock(f); 10150b9a5132SDavid du Colombier rv = fileMetaFlush2(f, nil); 10165e96a66cSDavid du Colombier fileMetaUnlock(f); 10175e96a66cSDavid du Colombier 10185e96a66cSDavid du Colombier if(!rec || !fileIsDir(f)) 10190b9a5132SDavid du Colombier return rv; 10205e96a66cSDavid du Colombier 10215e96a66cSDavid du Colombier if(!fileLock(f)) 10220b9a5132SDavid du Colombier return rv; 10235e96a66cSDavid du Colombier nkids = 0; 10245e96a66cSDavid du Colombier for(p=f->down; p; p=p->next) 10255e96a66cSDavid du Colombier nkids++; 1026*d7aba6c3SDavid du Colombier kids = vtmalloc(nkids*sizeof(File*)); 10275e96a66cSDavid du Colombier i = 0; 10285e96a66cSDavid du Colombier for(p=f->down; p; p=p->next){ 10295e96a66cSDavid du Colombier kids[i++] = p; 10305e96a66cSDavid du Colombier p->ref++; 10315e96a66cSDavid du Colombier } 10325e96a66cSDavid du Colombier fileUnlock(f); 10335e96a66cSDavid du Colombier 10345e96a66cSDavid du Colombier for(i=0; i<nkids; i++){ 10350b9a5132SDavid du Colombier rv |= fileMetaFlush(kids[i], 1); 10365e96a66cSDavid du Colombier fileDecRef(kids[i]); 10375e96a66cSDavid du Colombier } 1038*d7aba6c3SDavid du Colombier vtfree(kids); 10390b9a5132SDavid du Colombier return rv; 10405e96a66cSDavid du Colombier } 10415e96a66cSDavid du Colombier 10425e96a66cSDavid du Colombier /* assumes metaLock is held */ 10435e96a66cSDavid du Colombier static int 10445e96a66cSDavid du Colombier fileMetaFlush2(File *f, char *oelem) 10455e96a66cSDavid du Colombier { 10465e96a66cSDavid du Colombier File *fp; 10475e96a66cSDavid du Colombier Block *b, *bb; 10485e96a66cSDavid du Colombier MetaBlock mb; 10495e96a66cSDavid du Colombier MetaEntry me, me2; 10505e96a66cSDavid du Colombier int i, n; 10515e96a66cSDavid du Colombier u32int boff; 10525e96a66cSDavid du Colombier 10535e96a66cSDavid du Colombier if(!f->dirty) 10540b9a5132SDavid du Colombier return 0; 10555e96a66cSDavid du Colombier 10565e96a66cSDavid du Colombier if(oelem == nil) 10575e96a66cSDavid du Colombier oelem = f->dir.elem; 10585e96a66cSDavid du Colombier 10595e96a66cSDavid du Colombier //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem); 10605e96a66cSDavid du Colombier 10615e96a66cSDavid du Colombier fp = f->up; 10625e96a66cSDavid du Colombier 10635e96a66cSDavid du Colombier if(!sourceLock(fp->msource, -1)) 10640b9a5132SDavid du Colombier return -1; 10656042bf6dSDavid du Colombier /* can happen if source is clri'ed out from under us */ 10666042bf6dSDavid du Colombier if(f->boff == NilBlock) 10676042bf6dSDavid du Colombier goto Err1; 10685e96a66cSDavid du Colombier b = sourceBlock(fp->msource, f->boff, OReadWrite); 10695e96a66cSDavid du Colombier if(b == nil) 10705e96a66cSDavid du Colombier goto Err1; 10715e96a66cSDavid du Colombier 10725e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, fp->msource->dsize)) 10735e96a66cSDavid du Colombier goto Err; 10745e96a66cSDavid du Colombier if(!mbSearch(&mb, oelem, &i, &me)) 10755e96a66cSDavid du Colombier goto Err; 10765e96a66cSDavid du Colombier 10775e96a66cSDavid du Colombier n = deSize(&f->dir); 10785e96a66cSDavid du Colombier if(0)fprint(2, "old size %d new size %d\n", me.size, n); 10795e96a66cSDavid du Colombier 10805e96a66cSDavid du Colombier if(mbResize(&mb, &me, n)){ 10815e96a66cSDavid du Colombier /* fits in the block */ 10825e96a66cSDavid du Colombier mbDelete(&mb, i); 10835e96a66cSDavid du Colombier if(strcmp(f->dir.elem, oelem) != 0) 10845e96a66cSDavid du Colombier mbSearch(&mb, f->dir.elem, &i, &me2); 10855e96a66cSDavid du Colombier dePack(&f->dir, &me); 10865e96a66cSDavid du Colombier mbInsert(&mb, i, &me); 10875e96a66cSDavid du Colombier mbPack(&mb); 10885e96a66cSDavid du Colombier blockDirty(b); 10895e96a66cSDavid du Colombier blockPut(b); 10905e96a66cSDavid du Colombier sourceUnlock(fp->msource); 10915e96a66cSDavid du Colombier f->dirty = 0; 10925e96a66cSDavid du Colombier 10935e96a66cSDavid du Colombier return 1; 10945e96a66cSDavid du Colombier } 10955e96a66cSDavid du Colombier 10965e96a66cSDavid du Colombier /* 10975e96a66cSDavid du Colombier * moving entry to another block 10985e96a66cSDavid du Colombier * it is feasible for the fs to crash leaving two copies 10995e96a66cSDavid du Colombier * of the directory entry. This is just too much work to 11005e96a66cSDavid du Colombier * fix. Given that entries are only allocated in a block that 11015e96a66cSDavid du Colombier * is less than PercentageFull, most modifications of meta data 11025e96a66cSDavid du Colombier * will fit within the block. i.e. this code should almost 11035e96a66cSDavid du Colombier * never be executed. 11045e96a66cSDavid du Colombier */ 11055e96a66cSDavid du Colombier boff = fileMetaAlloc(fp, &f->dir, f->boff+1); 11065e96a66cSDavid du Colombier if(boff == NilBlock){ 11075e96a66cSDavid du Colombier /* mbResize might have modified block */ 11085e96a66cSDavid du Colombier mbPack(&mb); 11095e96a66cSDavid du Colombier blockDirty(b); 11105e96a66cSDavid du Colombier goto Err; 11115e96a66cSDavid du Colombier } 11125e96a66cSDavid du Colombier fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); 11135e96a66cSDavid du Colombier f->boff = boff; 11145e96a66cSDavid du Colombier 11155e96a66cSDavid du Colombier /* make sure deletion goes to disk after new entry */ 11165e96a66cSDavid du Colombier bb = sourceBlock(fp->msource, f->boff, OReadWrite); 11175e96a66cSDavid du Colombier mbDelete(&mb, i); 11185e96a66cSDavid du Colombier mbPack(&mb); 111961201b97SDavid du Colombier blockDependency(b, bb, -1, nil, nil); 11205e96a66cSDavid du Colombier blockPut(bb); 11215e96a66cSDavid du Colombier blockDirty(b); 11225e96a66cSDavid du Colombier blockPut(b); 11235e96a66cSDavid du Colombier sourceUnlock(fp->msource); 11245e96a66cSDavid du Colombier 11255e96a66cSDavid du Colombier f->dirty = 0; 11265e96a66cSDavid du Colombier 11275e96a66cSDavid du Colombier return 1; 11285e96a66cSDavid du Colombier 11295e96a66cSDavid du Colombier Err: 11305e96a66cSDavid du Colombier blockPut(b); 11315e96a66cSDavid du Colombier Err1: 11325e96a66cSDavid du Colombier sourceUnlock(fp->msource); 11330b9a5132SDavid du Colombier return -1; 11345e96a66cSDavid du Colombier } 11355e96a66cSDavid du Colombier 11365e96a66cSDavid du Colombier static int 11375e96a66cSDavid du Colombier fileMetaRemove(File *f, char *uid) 11385e96a66cSDavid du Colombier { 11395e96a66cSDavid du Colombier Block *b; 11405e96a66cSDavid du Colombier MetaBlock mb; 11415e96a66cSDavid du Colombier MetaEntry me; 11425e96a66cSDavid du Colombier int i; 11435e96a66cSDavid du Colombier File *up; 11445e96a66cSDavid du Colombier 11455e96a66cSDavid du Colombier up = f->up; 11465e96a66cSDavid du Colombier 11475e96a66cSDavid du Colombier fileWAccess(up, uid); 11485e96a66cSDavid du Colombier 11495e96a66cSDavid du Colombier fileMetaLock(f); 11505e96a66cSDavid du Colombier 11515e96a66cSDavid du Colombier sourceLock(up->msource, OReadWrite); 11525e96a66cSDavid du Colombier b = sourceBlock(up->msource, f->boff, OReadWrite); 11535e96a66cSDavid du Colombier if(b == nil) 11545e96a66cSDavid du Colombier goto Err; 11555e96a66cSDavid du Colombier 11565e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, up->msource->dsize)) 11575e96a66cSDavid du Colombier { 11585e96a66cSDavid du Colombier fprint(2, "U\n"); 11595e96a66cSDavid du Colombier goto Err; 11605e96a66cSDavid du Colombier } 11615e96a66cSDavid du Colombier if(!mbSearch(&mb, f->dir.elem, &i, &me)) 11625e96a66cSDavid du Colombier { 11635e96a66cSDavid du Colombier fprint(2, "S\n"); 11645e96a66cSDavid du Colombier goto Err; 11655e96a66cSDavid du Colombier } 11665e96a66cSDavid du Colombier mbDelete(&mb, i); 11675e96a66cSDavid du Colombier mbPack(&mb); 11685e96a66cSDavid du Colombier sourceUnlock(up->msource); 11695e96a66cSDavid du Colombier 11705e96a66cSDavid du Colombier blockDirty(b); 11715e96a66cSDavid du Colombier blockPut(b); 11725e96a66cSDavid du Colombier 11735e96a66cSDavid du Colombier f->removed = 1; 11745e96a66cSDavid du Colombier f->boff = NilBlock; 11755e96a66cSDavid du Colombier f->dirty = 0; 11765e96a66cSDavid du Colombier 11775e96a66cSDavid du Colombier fileMetaUnlock(f); 11785e96a66cSDavid du Colombier return 1; 11795e96a66cSDavid du Colombier 11805e96a66cSDavid du Colombier Err: 11815e96a66cSDavid du Colombier sourceUnlock(up->msource); 11825e96a66cSDavid du Colombier blockPut(b); 11835e96a66cSDavid du Colombier fileMetaUnlock(f); 11845e96a66cSDavid du Colombier return 0; 11855e96a66cSDavid du Colombier } 11865e96a66cSDavid du Colombier 11875e96a66cSDavid du Colombier /* assume file is locked, assume f->msource is locked */ 11885e96a66cSDavid du Colombier static int 11895e96a66cSDavid du Colombier fileCheckEmpty(File *f) 11905e96a66cSDavid du Colombier { 11915e96a66cSDavid du Colombier u32int i, n; 11925e96a66cSDavid du Colombier Block *b; 11935e96a66cSDavid du Colombier MetaBlock mb; 11945e96a66cSDavid du Colombier Source *r; 11955e96a66cSDavid du Colombier 11965e96a66cSDavid du Colombier r = f->msource; 11975e96a66cSDavid du Colombier n = (sourceGetSize(r)+r->dsize-1)/r->dsize; 11985e96a66cSDavid du Colombier for(i=0; i<n; i++){ 11995e96a66cSDavid du Colombier b = sourceBlock(r, i, OReadOnly); 12005e96a66cSDavid du Colombier if(b == nil) 12015e96a66cSDavid du Colombier goto Err; 12025e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, r->dsize)) 12035e96a66cSDavid du Colombier goto Err; 12045e96a66cSDavid du Colombier if(mb.nindex > 0){ 1205*d7aba6c3SDavid du Colombier werrstr(ENotEmpty); 12065e96a66cSDavid du Colombier goto Err; 12075e96a66cSDavid du Colombier } 12085e96a66cSDavid du Colombier blockPut(b); 12095e96a66cSDavid du Colombier } 12105e96a66cSDavid du Colombier return 1; 12115e96a66cSDavid du Colombier Err: 12125e96a66cSDavid du Colombier blockPut(b); 12135e96a66cSDavid du Colombier return 0; 12145e96a66cSDavid du Colombier } 12155e96a66cSDavid du Colombier 12165e96a66cSDavid du Colombier int 12175e96a66cSDavid du Colombier fileRemove(File *f, char *uid) 12185e96a66cSDavid du Colombier { 12195e96a66cSDavid du Colombier File *ff; 12205e96a66cSDavid du Colombier 12215e96a66cSDavid du Colombier /* can not remove the root */ 12225e96a66cSDavid du Colombier if(fileIsRoot(f)){ 1223*d7aba6c3SDavid du Colombier werrstr(ERoot); 12245e96a66cSDavid du Colombier return 0; 12255e96a66cSDavid du Colombier } 12265e96a66cSDavid du Colombier 12275e96a66cSDavid du Colombier if(!fileLock(f)) 12285e96a66cSDavid du Colombier return 0; 12295e96a66cSDavid du Colombier 12305e96a66cSDavid du Colombier if(f->source->mode != OReadWrite){ 1231*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 12325e96a66cSDavid du Colombier goto Err1; 12335e96a66cSDavid du Colombier } 12345e96a66cSDavid du Colombier if(!sourceLock2(f->source, f->msource, -1)) 12355e96a66cSDavid du Colombier goto Err1; 12365e96a66cSDavid du Colombier if(fileIsDir(f) && !fileCheckEmpty(f)) 12375e96a66cSDavid du Colombier goto Err; 12385e96a66cSDavid du Colombier 12395e96a66cSDavid du Colombier for(ff=f->down; ff; ff=ff->next) 12405e96a66cSDavid du Colombier assert(ff->removed); 12415e96a66cSDavid du Colombier 12425e96a66cSDavid du Colombier sourceRemove(f->source); 12433b86f2f8SDavid du Colombier f->source->file = nil; /* erase back pointer */ 12445e96a66cSDavid du Colombier f->source = nil; 12455e96a66cSDavid du Colombier if(f->msource){ 12465e96a66cSDavid du Colombier sourceRemove(f->msource); 12475e96a66cSDavid du Colombier f->msource = nil; 12485e96a66cSDavid du Colombier } 12495e96a66cSDavid du Colombier 12505e96a66cSDavid du Colombier fileUnlock(f); 12515e96a66cSDavid du Colombier 12525e96a66cSDavid du Colombier if(!fileMetaRemove(f, uid)) 12535e96a66cSDavid du Colombier return 0; 12545e96a66cSDavid du Colombier 12555e96a66cSDavid du Colombier return 1; 12565e96a66cSDavid du Colombier 12575e96a66cSDavid du Colombier Err: 12585e96a66cSDavid du Colombier sourceUnlock(f->source); 12595e96a66cSDavid du Colombier if(f->msource) 12605e96a66cSDavid du Colombier sourceUnlock(f->msource); 12615e96a66cSDavid du Colombier Err1: 12625e96a66cSDavid du Colombier fileUnlock(f); 12635e96a66cSDavid du Colombier return 0; 12645e96a66cSDavid du Colombier } 12655e96a66cSDavid du Colombier 1266dc5a79c1SDavid du Colombier static int 1267dc5a79c1SDavid du Colombier clri(File *f, char *uid) 12685e96a66cSDavid du Colombier { 12695e96a66cSDavid du Colombier int r; 12705e96a66cSDavid du Colombier 12715e96a66cSDavid du Colombier if(f == nil) 12725e96a66cSDavid du Colombier return 0; 12735e96a66cSDavid du Colombier if(f->up->source->mode != OReadWrite){ 1274*d7aba6c3SDavid du Colombier werrstr(EReadOnly); 12755e96a66cSDavid du Colombier fileDecRef(f); 12765e96a66cSDavid du Colombier return 0; 12775e96a66cSDavid du Colombier } 12785e96a66cSDavid du Colombier r = fileMetaRemove(f, uid); 12795e96a66cSDavid du Colombier fileDecRef(f); 12805e96a66cSDavid du Colombier return r; 12815e96a66cSDavid du Colombier } 12825e96a66cSDavid du Colombier 1283dc5a79c1SDavid du Colombier int 1284dc5a79c1SDavid du Colombier fileClriPath(Fs *fs, char *path, char *uid) 1285dc5a79c1SDavid du Colombier { 1286dc5a79c1SDavid du Colombier return clri(_fileOpen(fs, path, 1), uid); 1287dc5a79c1SDavid du Colombier } 1288dc5a79c1SDavid du Colombier 1289dc5a79c1SDavid du Colombier int 1290dc5a79c1SDavid du Colombier fileClri(File *dir, char *elem, char *uid) 1291dc5a79c1SDavid du Colombier { 1292dc5a79c1SDavid du Colombier return clri(_fileWalk(dir, elem, 1), uid); 1293dc5a79c1SDavid du Colombier } 1294dc5a79c1SDavid du Colombier 12955e96a66cSDavid du Colombier File * 12965e96a66cSDavid du Colombier fileIncRef(File *vf) 12975e96a66cSDavid du Colombier { 12985e96a66cSDavid du Colombier fileMetaLock(vf); 12995e96a66cSDavid du Colombier assert(vf->ref > 0); 13005e96a66cSDavid du Colombier vf->ref++; 13015e96a66cSDavid du Colombier fileMetaUnlock(vf); 13025e96a66cSDavid du Colombier return vf; 13035e96a66cSDavid du Colombier } 13045e96a66cSDavid du Colombier 13055e96a66cSDavid du Colombier int 13065e96a66cSDavid du Colombier fileDecRef(File *f) 13075e96a66cSDavid du Colombier { 13085e96a66cSDavid du Colombier File *p, *q, **qq; 13095e96a66cSDavid du Colombier 13105e96a66cSDavid du Colombier if(f->up == nil){ 13115e96a66cSDavid du Colombier /* never linked in */ 13125e96a66cSDavid du Colombier assert(f->ref == 1); 13135e96a66cSDavid du Colombier fileFree(f); 13145e96a66cSDavid du Colombier return 1; 13155e96a66cSDavid du Colombier } 13165e96a66cSDavid du Colombier 13175e96a66cSDavid du Colombier fileMetaLock(f); 13185e96a66cSDavid du Colombier f->ref--; 13195e96a66cSDavid du Colombier if(f->ref > 0){ 13205e96a66cSDavid du Colombier fileMetaUnlock(f); 13215e96a66cSDavid du Colombier return 0; 13225e96a66cSDavid du Colombier } 13235e96a66cSDavid du Colombier assert(f->ref == 0); 13245e96a66cSDavid du Colombier assert(f->down == nil); 13255e96a66cSDavid du Colombier 13265e96a66cSDavid du Colombier fileMetaFlush2(f, nil); 13275e96a66cSDavid du Colombier 13285e96a66cSDavid du Colombier p = f->up; 13295e96a66cSDavid du Colombier qq = &p->down; 13305e96a66cSDavid du Colombier for(q = *qq; q; q = *qq){ 13315e96a66cSDavid du Colombier if(q == f) 13325e96a66cSDavid du Colombier break; 13335e96a66cSDavid du Colombier qq = &q->next; 13345e96a66cSDavid du Colombier } 13355e96a66cSDavid du Colombier assert(q != nil); 13365e96a66cSDavid du Colombier *qq = f->next; 13375e96a66cSDavid du Colombier 13385e96a66cSDavid du Colombier fileMetaUnlock(f); 13395e96a66cSDavid du Colombier fileFree(f); 13405e96a66cSDavid du Colombier 13415e96a66cSDavid du Colombier fileDecRef(p); 13425e96a66cSDavid du Colombier return 1; 13435e96a66cSDavid du Colombier } 13445e96a66cSDavid du Colombier 13455e96a66cSDavid du Colombier File * 13465e96a66cSDavid du Colombier fileGetParent(File *f) 13475e96a66cSDavid du Colombier { 13485e96a66cSDavid du Colombier if(fileIsRoot(f)) 13495e96a66cSDavid du Colombier return fileIncRef(f); 13505e96a66cSDavid du Colombier return fileIncRef(f->up); 13515e96a66cSDavid du Colombier } 13525e96a66cSDavid du Colombier 13535e96a66cSDavid du Colombier DirEntryEnum * 13545e96a66cSDavid du Colombier deeOpen(File *f) 13555e96a66cSDavid du Colombier { 13565e96a66cSDavid du Colombier DirEntryEnum *dee; 13575e96a66cSDavid du Colombier File *p; 13585e96a66cSDavid du Colombier 13595e96a66cSDavid du Colombier if(!fileIsDir(f)){ 1360*d7aba6c3SDavid du Colombier werrstr(ENotDir); 13615e96a66cSDavid du Colombier fileDecRef(f); 13625e96a66cSDavid du Colombier return nil; 13635e96a66cSDavid du Colombier } 13645e96a66cSDavid du Colombier 13655e96a66cSDavid du Colombier /* flush out meta data */ 13665e96a66cSDavid du Colombier if(!fileLock(f)) 13675e96a66cSDavid du Colombier return nil; 13685e96a66cSDavid du Colombier for(p=f->down; p; p=p->next) 13695e96a66cSDavid du Colombier fileMetaFlush2(p, nil); 13705e96a66cSDavid du Colombier fileUnlock(f); 13715e96a66cSDavid du Colombier 1372*d7aba6c3SDavid du Colombier dee = vtmallocz(sizeof(DirEntryEnum)); 13735e96a66cSDavid du Colombier dee->file = fileIncRef(f); 13745e96a66cSDavid du Colombier 13755e96a66cSDavid du Colombier return dee; 13765e96a66cSDavid du Colombier } 13775e96a66cSDavid du Colombier 13785e96a66cSDavid du Colombier static int 13795e96a66cSDavid du Colombier dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) 13805e96a66cSDavid du Colombier { 13815e96a66cSDavid du Colombier Block *b; 13825e96a66cSDavid du Colombier ulong bn; 13835e96a66cSDavid du Colombier Entry e; 13845e96a66cSDavid du Colombier int epb; 13855e96a66cSDavid du Colombier 13865e96a66cSDavid du Colombier epb = s->dsize/VtEntrySize; 13875e96a66cSDavid du Colombier bn = elem/epb; 13885e96a66cSDavid du Colombier elem -= bn*epb; 13895e96a66cSDavid du Colombier 13905e96a66cSDavid du Colombier b = sourceBlock(s, bn, OReadOnly); 13915e96a66cSDavid du Colombier if(b == nil) 13925e96a66cSDavid du Colombier goto Err; 13935e96a66cSDavid du Colombier if(!entryUnpack(&e, b->data, elem)) 13945e96a66cSDavid du Colombier goto Err; 13955e96a66cSDavid du Colombier 13965e96a66cSDavid du Colombier /* hanging entries are returned as zero size */ 13975e96a66cSDavid du Colombier if(!(e.flags & VtEntryActive) || e.gen != gen) 13985e96a66cSDavid du Colombier *size = 0; 13995e96a66cSDavid du Colombier else 14005e96a66cSDavid du Colombier *size = e.size; 14015e96a66cSDavid du Colombier blockPut(b); 14025e96a66cSDavid du Colombier return 1; 14035e96a66cSDavid du Colombier 14045e96a66cSDavid du Colombier Err: 14055e96a66cSDavid du Colombier blockPut(b); 14065e96a66cSDavid du Colombier return 0; 14075e96a66cSDavid du Colombier } 14085e96a66cSDavid du Colombier 14095e96a66cSDavid du Colombier static int 14105e96a66cSDavid du Colombier deeFill(DirEntryEnum *dee) 14115e96a66cSDavid du Colombier { 14125e96a66cSDavid du Colombier int i, n; 14135e96a66cSDavid du Colombier Source *meta, *source; 14145e96a66cSDavid du Colombier MetaBlock mb; 14155e96a66cSDavid du Colombier MetaEntry me; 14165e96a66cSDavid du Colombier File *f; 14175e96a66cSDavid du Colombier Block *b; 14185e96a66cSDavid du Colombier DirEntry *de; 14195e96a66cSDavid du Colombier 14205e96a66cSDavid du Colombier /* clean up first */ 14215e96a66cSDavid du Colombier for(i=dee->i; i<dee->n; i++) 14225e96a66cSDavid du Colombier deCleanup(dee->buf+i); 1423*d7aba6c3SDavid du Colombier vtfree(dee->buf); 14245e96a66cSDavid du Colombier dee->buf = nil; 14255e96a66cSDavid du Colombier dee->i = 0; 14265e96a66cSDavid du Colombier dee->n = 0; 14275e96a66cSDavid du Colombier 14285e96a66cSDavid du Colombier f = dee->file; 14295e96a66cSDavid du Colombier 14305e96a66cSDavid du Colombier source = f->source; 14315e96a66cSDavid du Colombier meta = f->msource; 14325e96a66cSDavid du Colombier 14335e96a66cSDavid du Colombier b = sourceBlock(meta, dee->boff, OReadOnly); 14345e96a66cSDavid du Colombier if(b == nil) 14355e96a66cSDavid du Colombier goto Err; 14365e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, meta->dsize)) 14375e96a66cSDavid du Colombier goto Err; 14385e96a66cSDavid du Colombier 14395e96a66cSDavid du Colombier n = mb.nindex; 1440*d7aba6c3SDavid du Colombier dee->buf = vtmalloc(n * sizeof(DirEntry)); 14415e96a66cSDavid du Colombier 14425e96a66cSDavid du Colombier for(i=0; i<n; i++){ 14435e96a66cSDavid du Colombier de = dee->buf + i; 14445e96a66cSDavid du Colombier meUnpack(&me, &mb, i); 14455e96a66cSDavid du Colombier if(!deUnpack(de, &me)) 14465e96a66cSDavid du Colombier goto Err; 14475e96a66cSDavid du Colombier dee->n++; 14485e96a66cSDavid du Colombier if(!(de->mode & ModeDir)) 14495e96a66cSDavid du Colombier if(!dirEntrySize(source, de->entry, de->gen, &de->size)) 14505e96a66cSDavid du Colombier goto Err; 14515e96a66cSDavid du Colombier } 14525e96a66cSDavid du Colombier dee->boff++; 14535e96a66cSDavid du Colombier blockPut(b); 14545e96a66cSDavid du Colombier return 1; 14555e96a66cSDavid du Colombier Err: 14565e96a66cSDavid du Colombier blockPut(b); 14575e96a66cSDavid du Colombier return 0; 14585e96a66cSDavid du Colombier } 14595e96a66cSDavid du Colombier 14605e96a66cSDavid du Colombier int 14615e96a66cSDavid du Colombier deeRead(DirEntryEnum *dee, DirEntry *de) 14625e96a66cSDavid du Colombier { 14635e96a66cSDavid du Colombier int ret, didread; 14645e96a66cSDavid du Colombier File *f; 14655e96a66cSDavid du Colombier u32int nb; 14665e96a66cSDavid du Colombier 1467418f3c22SDavid du Colombier if(dee == nil){ 1468*d7aba6c3SDavid du Colombier werrstr("cannot happen in deeRead"); 1469418f3c22SDavid du Colombier return -1; 1470418f3c22SDavid du Colombier } 1471418f3c22SDavid du Colombier 14725e96a66cSDavid du Colombier f = dee->file; 14735e96a66cSDavid du Colombier if(!fileRLock(f)) 14745e96a66cSDavid du Colombier return -1; 14755e96a66cSDavid du Colombier 14765e96a66cSDavid du Colombier if(!sourceLock2(f->source, f->msource, OReadOnly)){ 14775e96a66cSDavid du Colombier fileRUnlock(f); 14785e96a66cSDavid du Colombier return -1; 14795e96a66cSDavid du Colombier } 14805e96a66cSDavid du Colombier 14815e96a66cSDavid du Colombier nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize; 14825e96a66cSDavid du Colombier 14835e96a66cSDavid du Colombier didread = 0; 14845e96a66cSDavid du Colombier while(dee->i >= dee->n){ 14855e96a66cSDavid du Colombier if(dee->boff >= nb){ 14865e96a66cSDavid du Colombier ret = 0; 14875e96a66cSDavid du Colombier goto Return; 14885e96a66cSDavid du Colombier } 14895e96a66cSDavid du Colombier didread = 1; 14905e96a66cSDavid du Colombier if(!deeFill(dee)){ 14915e96a66cSDavid du Colombier ret = -1; 14925e96a66cSDavid du Colombier goto Return; 14935e96a66cSDavid du Colombier } 14945e96a66cSDavid du Colombier } 14955e96a66cSDavid du Colombier 14965e96a66cSDavid du Colombier memmove(de, dee->buf + dee->i, sizeof(DirEntry)); 14975e96a66cSDavid du Colombier dee->i++; 14985e96a66cSDavid du Colombier ret = 1; 14995e96a66cSDavid du Colombier 15005e96a66cSDavid du Colombier Return: 15015e96a66cSDavid du Colombier sourceUnlock(f->source); 15025e96a66cSDavid du Colombier sourceUnlock(f->msource); 15035e96a66cSDavid du Colombier fileRUnlock(f); 15045e96a66cSDavid du Colombier 15055e96a66cSDavid du Colombier if(didread) 15065e96a66cSDavid du Colombier fileRAccess(f); 15075e96a66cSDavid du Colombier return ret; 15085e96a66cSDavid du Colombier } 15095e96a66cSDavid du Colombier 15105e96a66cSDavid du Colombier void 15115e96a66cSDavid du Colombier deeClose(DirEntryEnum *dee) 15125e96a66cSDavid du Colombier { 15135e96a66cSDavid du Colombier int i; 15145e96a66cSDavid du Colombier if(dee == nil) 15155e96a66cSDavid du Colombier return; 15165e96a66cSDavid du Colombier for(i=dee->i; i<dee->n; i++) 15175e96a66cSDavid du Colombier deCleanup(dee->buf+i); 1518*d7aba6c3SDavid du Colombier vtfree(dee->buf); 15195e96a66cSDavid du Colombier fileDecRef(dee->file); 1520*d7aba6c3SDavid du Colombier vtfree(dee); 15215e96a66cSDavid du Colombier } 15225e96a66cSDavid du Colombier 15235e96a66cSDavid du Colombier /* 15245e96a66cSDavid du Colombier * caller must lock f->source and f->msource 15255e96a66cSDavid du Colombier * caller must NOT lock the source and msource 15265e96a66cSDavid du Colombier * referenced by dir. 15275e96a66cSDavid du Colombier */ 15285e96a66cSDavid du Colombier static u32int 15295e96a66cSDavid du Colombier fileMetaAlloc(File *f, DirEntry *dir, u32int start) 15305e96a66cSDavid du Colombier { 15315e96a66cSDavid du Colombier u32int nb, bo; 15325e96a66cSDavid du Colombier Block *b, *bb; 15335e96a66cSDavid du Colombier MetaBlock mb; 15345e96a66cSDavid du Colombier int nn; 15355e96a66cSDavid du Colombier uchar *p; 15365e96a66cSDavid du Colombier int i, n, epb; 15375e96a66cSDavid du Colombier MetaEntry me; 15385e96a66cSDavid du Colombier Source *s, *ms; 15395e96a66cSDavid du Colombier 15405e96a66cSDavid du Colombier s = f->source; 15415e96a66cSDavid du Colombier ms = f->msource; 15425e96a66cSDavid du Colombier 15435e96a66cSDavid du Colombier n = deSize(dir); 15445e96a66cSDavid du Colombier nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize; 15455e96a66cSDavid du Colombier b = nil; 15465e96a66cSDavid du Colombier if(start > nb) 15475e96a66cSDavid du Colombier start = nb; 15485e96a66cSDavid du Colombier for(bo=start; bo<nb; bo++){ 15495e96a66cSDavid du Colombier b = sourceBlock(ms, bo, OReadWrite); 15505e96a66cSDavid du Colombier if(b == nil) 15515e96a66cSDavid du Colombier goto Err; 15525e96a66cSDavid du Colombier if(!mbUnpack(&mb, b->data, ms->dsize)) 15535e96a66cSDavid du Colombier goto Err; 15545e96a66cSDavid du Colombier nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; 15555e96a66cSDavid du Colombier if(n <= nn && mb.nindex < mb.maxindex) 15565e96a66cSDavid du Colombier break; 15575e96a66cSDavid du Colombier blockPut(b); 15585e96a66cSDavid du Colombier b = nil; 15595e96a66cSDavid du Colombier } 15605e96a66cSDavid du Colombier 15615e96a66cSDavid du Colombier /* add block to meta file */ 15625e96a66cSDavid du Colombier if(b == nil){ 15635e96a66cSDavid du Colombier b = sourceBlock(ms, bo, OReadWrite); 15645e96a66cSDavid du Colombier if(b == nil) 15655e96a66cSDavid du Colombier goto Err; 15665e96a66cSDavid du Colombier sourceSetSize(ms, (nb+1)*ms->dsize); 15675e96a66cSDavid du Colombier mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); 15685e96a66cSDavid du Colombier } 15695e96a66cSDavid du Colombier 15705e96a66cSDavid du Colombier p = mbAlloc(&mb, n); 15715e96a66cSDavid du Colombier if(p == nil){ 15725e96a66cSDavid du Colombier /* mbAlloc might have changed block */ 15735e96a66cSDavid du Colombier mbPack(&mb); 15745e96a66cSDavid du Colombier blockDirty(b); 1575*d7aba6c3SDavid du Colombier werrstr(EBadMeta); 15765e96a66cSDavid du Colombier goto Err; 15775e96a66cSDavid du Colombier } 15785e96a66cSDavid du Colombier 15795e96a66cSDavid du Colombier mbSearch(&mb, dir->elem, &i, &me); 15805e96a66cSDavid du Colombier assert(me.p == nil); 15815e96a66cSDavid du Colombier me.p = p; 15825e96a66cSDavid du Colombier me.size = n; 15835e96a66cSDavid du Colombier dePack(dir, &me); 15845e96a66cSDavid du Colombier mbInsert(&mb, i, &me); 15855e96a66cSDavid du Colombier mbPack(&mb); 15865e96a66cSDavid du Colombier 15875e96a66cSDavid du Colombier /* meta block depends on super block for qid ... */ 15885e96a66cSDavid du Colombier bb = cacheLocal(b->c, PartSuper, 0, OReadOnly); 158961201b97SDavid du Colombier blockDependency(b, bb, -1, nil, nil); 15905e96a66cSDavid du Colombier blockPut(bb); 15915e96a66cSDavid du Colombier 15925e96a66cSDavid du Colombier /* ... and one or two dir entries */ 15935e96a66cSDavid du Colombier epb = s->dsize/VtEntrySize; 15945e96a66cSDavid du Colombier bb = sourceBlock(s, dir->entry/epb, OReadOnly); 159561201b97SDavid du Colombier blockDependency(b, bb, -1, nil, nil); 15965e96a66cSDavid du Colombier blockPut(bb); 15975e96a66cSDavid du Colombier if(dir->mode & ModeDir){ 15985e96a66cSDavid du Colombier bb = sourceBlock(s, dir->mentry/epb, OReadOnly); 159961201b97SDavid du Colombier blockDependency(b, bb, -1, nil, nil); 16005e96a66cSDavid du Colombier blockPut(bb); 16015e96a66cSDavid du Colombier } 16025e96a66cSDavid du Colombier 16035e96a66cSDavid du Colombier blockDirty(b); 16045e96a66cSDavid du Colombier blockPut(b); 16055e96a66cSDavid du Colombier return bo; 16065e96a66cSDavid du Colombier Err: 16075e96a66cSDavid du Colombier blockPut(b); 16085e96a66cSDavid du Colombier return NilBlock; 16095e96a66cSDavid du Colombier } 16105e96a66cSDavid du Colombier 16115e96a66cSDavid du Colombier static int 16125e96a66cSDavid du Colombier chkSource(File *f) 16135e96a66cSDavid du Colombier { 16145e96a66cSDavid du Colombier if(f->partial) 16155e96a66cSDavid du Colombier return 1; 16165e96a66cSDavid du Colombier 16175e96a66cSDavid du Colombier if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ 1618*d7aba6c3SDavid du Colombier werrstr(ERemoved); 16195e96a66cSDavid du Colombier return 0; 16205e96a66cSDavid du Colombier } 16215e96a66cSDavid du Colombier return 1; 16225e96a66cSDavid du Colombier } 16235e96a66cSDavid du Colombier 16245e96a66cSDavid du Colombier static int 16255e96a66cSDavid du Colombier fileRLock(File *f) 16265e96a66cSDavid du Colombier { 1627*d7aba6c3SDavid du Colombier assert(!canwlock(&f->fs->elk)); 1628*d7aba6c3SDavid du Colombier rlock(&f->lk); 16295e96a66cSDavid du Colombier if(!chkSource(f)){ 16305e96a66cSDavid du Colombier fileRUnlock(f); 16315e96a66cSDavid du Colombier return 0; 16325e96a66cSDavid du Colombier } 16335e96a66cSDavid du Colombier return 1; 16345e96a66cSDavid du Colombier } 16355e96a66cSDavid du Colombier 16365e96a66cSDavid du Colombier static void 16375e96a66cSDavid du Colombier fileRUnlock(File *f) 16385e96a66cSDavid du Colombier { 1639*d7aba6c3SDavid du Colombier runlock(&f->lk); 16405e96a66cSDavid du Colombier } 16415e96a66cSDavid du Colombier 16425e96a66cSDavid du Colombier static int 16435e96a66cSDavid du Colombier fileLock(File *f) 16445e96a66cSDavid du Colombier { 1645*d7aba6c3SDavid du Colombier assert(!canwlock(&f->fs->elk)); 1646*d7aba6c3SDavid du Colombier wlock(&f->lk); 16475e96a66cSDavid du Colombier if(!chkSource(f)){ 16485e96a66cSDavid du Colombier fileUnlock(f); 16495e96a66cSDavid du Colombier return 0; 16505e96a66cSDavid du Colombier } 16515e96a66cSDavid du Colombier return 1; 16525e96a66cSDavid du Colombier } 16535e96a66cSDavid du Colombier 16545e96a66cSDavid du Colombier static void 16555e96a66cSDavid du Colombier fileUnlock(File *f) 16565e96a66cSDavid du Colombier { 1657*d7aba6c3SDavid du Colombier wunlock(&f->lk); 16585e96a66cSDavid du Colombier } 16595e96a66cSDavid du Colombier 16605e96a66cSDavid du Colombier /* 16615e96a66cSDavid du Colombier * f->source and f->msource must NOT be locked. 16625e96a66cSDavid du Colombier * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). 16635e96a66cSDavid du Colombier * We have to respect that ordering. 16645e96a66cSDavid du Colombier */ 16655e96a66cSDavid du Colombier static void 16665e96a66cSDavid du Colombier fileMetaLock(File *f) 16675e96a66cSDavid du Colombier { 16685e96a66cSDavid du Colombier if(f->up == nil) 16695e96a66cSDavid du Colombier fprint(2, "f->elem = %s\n", f->dir.elem); 16705e96a66cSDavid du Colombier assert(f->up != nil); 1671*d7aba6c3SDavid du Colombier assert(!canwlock(&f->fs->elk)); 1672*d7aba6c3SDavid du Colombier wlock(&f->up->lk); 16735e96a66cSDavid du Colombier } 16745e96a66cSDavid du Colombier 16755e96a66cSDavid du Colombier static void 16765e96a66cSDavid du Colombier fileMetaUnlock(File *f) 16775e96a66cSDavid du Colombier { 1678*d7aba6c3SDavid du Colombier wunlock(&f->up->lk); 16795e96a66cSDavid du Colombier } 16805e96a66cSDavid du Colombier 16815e96a66cSDavid du Colombier /* 16825e96a66cSDavid du Colombier * f->source and f->msource must NOT be locked. 16835e96a66cSDavid du Colombier * see fileMetaLock. 16845e96a66cSDavid du Colombier */ 16855e96a66cSDavid du Colombier static void 16865e96a66cSDavid du Colombier fileRAccess(File* f) 16875e96a66cSDavid du Colombier { 1688f4051287SDavid du Colombier if(f->mode == OReadOnly || f->fs->noatimeupd) 16895e96a66cSDavid du Colombier return; 16905e96a66cSDavid du Colombier 16915e96a66cSDavid du Colombier fileMetaLock(f); 16925e96a66cSDavid du Colombier f->dir.atime = time(0L); 16935e96a66cSDavid du Colombier f->dirty = 1; 16945e96a66cSDavid du Colombier fileMetaUnlock(f); 16955e96a66cSDavid du Colombier } 16965e96a66cSDavid du Colombier 16975e96a66cSDavid du Colombier /* 16985e96a66cSDavid du Colombier * f->source and f->msource must NOT be locked. 16995e96a66cSDavid du Colombier * see fileMetaLock. 17005e96a66cSDavid du Colombier */ 17015e96a66cSDavid du Colombier static void 17025e96a66cSDavid du Colombier fileWAccess(File* f, char *mid) 17035e96a66cSDavid du Colombier { 17045e96a66cSDavid du Colombier if(f->mode == OReadOnly) 17055e96a66cSDavid du Colombier return; 17065e96a66cSDavid du Colombier 17075e96a66cSDavid du Colombier fileMetaLock(f); 17085e96a66cSDavid du Colombier f->dir.atime = f->dir.mtime = time(0L); 17095e96a66cSDavid du Colombier if(strcmp(f->dir.mid, mid) != 0){ 1710*d7aba6c3SDavid du Colombier vtfree(f->dir.mid); 1711*d7aba6c3SDavid du Colombier f->dir.mid = vtstrdup(mid); 17125e96a66cSDavid du Colombier } 17135e96a66cSDavid du Colombier f->dir.mcount++; 17145e96a66cSDavid du Colombier f->dirty = 1; 17155e96a66cSDavid du Colombier fileMetaUnlock(f); 1716d58da526SDavid du Colombier 1717d58da526SDavid du Colombier /*RSC: let's try this */ 1718d58da526SDavid du Colombier /*presotto - lets not 1719d58da526SDavid du Colombier if(f->up) 1720d58da526SDavid du Colombier fileWAccess(f->up, mid); 1721d58da526SDavid du Colombier */ 17225e96a66cSDavid du Colombier } 17235e96a66cSDavid du Colombier 17245e96a66cSDavid du Colombier static int 1725e569ccb5SDavid du Colombier getEntry(Source *r, Entry *e, int checkepoch) 17265e96a66cSDavid du Colombier { 1727e569ccb5SDavid du Colombier u32int epoch; 17285e96a66cSDavid du Colombier Block *b; 17295e96a66cSDavid du Colombier 17305e96a66cSDavid du Colombier if(r == nil){ 17315e96a66cSDavid du Colombier memset(&e, 0, sizeof e); 17325e96a66cSDavid du Colombier return 1; 17335e96a66cSDavid du Colombier } 17345e96a66cSDavid du Colombier 17355e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly); 17365e96a66cSDavid du Colombier if(b == nil) 17375e96a66cSDavid du Colombier return 0; 17385e96a66cSDavid du Colombier if(!entryUnpack(e, b->data, r->offset % r->epb)){ 17395e96a66cSDavid du Colombier blockPut(b); 17405e96a66cSDavid du Colombier return 0; 17415e96a66cSDavid du Colombier } 1742e569ccb5SDavid du Colombier epoch = b->l.epoch; 17435e96a66cSDavid du Colombier blockPut(b); 1744e569ccb5SDavid du Colombier 1745e569ccb5SDavid du Colombier if(checkepoch){ 1746e569ccb5SDavid du Colombier b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly); 1747e569ccb5SDavid du Colombier if(b){ 1748e569ccb5SDavid du Colombier if(b->l.epoch >= epoch) 1749e569ccb5SDavid du Colombier fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n", 1750e569ccb5SDavid du Colombier r, b->addr, b->l.epoch, r->score, epoch); 1751e569ccb5SDavid du Colombier blockPut(b); 1752e569ccb5SDavid du Colombier } 1753e569ccb5SDavid du Colombier } 1754e569ccb5SDavid du Colombier 17555e96a66cSDavid du Colombier return 1; 17565e96a66cSDavid du Colombier } 17575e96a66cSDavid du Colombier 17585e96a66cSDavid du Colombier static int 17595e96a66cSDavid du Colombier setEntry(Source *r, Entry *e) 17605e96a66cSDavid du Colombier { 17615e96a66cSDavid du Colombier Block *b; 17625e96a66cSDavid du Colombier Entry oe; 17635e96a66cSDavid du Colombier 17645e96a66cSDavid du Colombier b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); 17655e96a66cSDavid du Colombier if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); 17665e96a66cSDavid du Colombier if(b == nil) 17675e96a66cSDavid du Colombier return 0; 17685e96a66cSDavid du Colombier if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ 17695e96a66cSDavid du Colombier blockPut(b); 17705e96a66cSDavid du Colombier return 0; 17715e96a66cSDavid du Colombier } 17725e96a66cSDavid du Colombier e->gen = oe.gen; 17735e96a66cSDavid du Colombier entryPack(e, b->data, r->offset % r->epb); 17745e96a66cSDavid du Colombier 17755e96a66cSDavid du Colombier /* BUG b should depend on the entry pointer */ 17765e96a66cSDavid du Colombier 17775e96a66cSDavid du Colombier blockDirty(b); 17785e96a66cSDavid du Colombier blockPut(b); 17795e96a66cSDavid du Colombier return 1; 17805e96a66cSDavid du Colombier } 17815e96a66cSDavid du Colombier 17825e96a66cSDavid du Colombier /* assumes hold elk */ 17835e96a66cSDavid du Colombier int 17845e96a66cSDavid du Colombier fileSnapshot(File *dst, File *src, u32int epoch, int doarchive) 17855e96a66cSDavid du Colombier { 17865e96a66cSDavid du Colombier Entry e, ee; 17875e96a66cSDavid du Colombier 17885e96a66cSDavid du Colombier /* add link to snapshot */ 17895e96a66cSDavid du Colombier if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) 17905e96a66cSDavid du Colombier return 0; 17915e96a66cSDavid du Colombier 17925e96a66cSDavid du Colombier e.snap = epoch; 17935e96a66cSDavid du Colombier e.archive = doarchive; 17945e96a66cSDavid du Colombier ee.snap = epoch; 17955e96a66cSDavid du Colombier ee.archive = doarchive; 17965e96a66cSDavid du Colombier 17975e96a66cSDavid du Colombier if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) 17985e96a66cSDavid du Colombier return 0; 17995e96a66cSDavid du Colombier return 1; 18005e96a66cSDavid du Colombier } 18015e96a66cSDavid du Colombier 18025e96a66cSDavid du Colombier int 1803e569ccb5SDavid du Colombier fileGetSources(File *f, Entry *e, Entry *ee) 18045e96a66cSDavid du Colombier { 1805e569ccb5SDavid du Colombier if(!getEntry(f->source, e, 0) 1806e569ccb5SDavid du Colombier || !getEntry(f->msource, ee, 0)) 18075e96a66cSDavid du Colombier return 0; 18085e96a66cSDavid du Colombier return 1; 18095e96a66cSDavid du Colombier } 18105e96a66cSDavid du Colombier 1811e569ccb5SDavid du Colombier /* 1812e569ccb5SDavid du Colombier * Walk down to the block(s) containing the Entries 1813e569ccb5SDavid du Colombier * for f->source and f->msource, copying as we go. 1814e569ccb5SDavid du Colombier */ 18155e96a66cSDavid du Colombier int 18165e96a66cSDavid du Colombier fileWalkSources(File *f) 18175e96a66cSDavid du Colombier { 1818e569ccb5SDavid du Colombier if(f->mode == OReadOnly){ 1819e569ccb5SDavid du Colombier fprint(2, "readonly in fileWalkSources\n"); 18205e96a66cSDavid du Colombier return 1; 1821e569ccb5SDavid du Colombier } 1822e569ccb5SDavid du Colombier if(!sourceLock2(f->source, f->msource, OReadWrite)){ 1823e569ccb5SDavid du Colombier fprint(2, "sourceLock2 failed in fileWalkSources\n"); 18245e96a66cSDavid du Colombier return 0; 1825e569ccb5SDavid du Colombier } 18265e96a66cSDavid du Colombier sourceUnlock(f->source); 18275e96a66cSDavid du Colombier sourceUnlock(f->msource); 18285e96a66cSDavid du Colombier return 1; 18295e96a66cSDavid du Colombier } 18303b86f2f8SDavid du Colombier 18313b86f2f8SDavid du Colombier /* 18323b86f2f8SDavid du Colombier * convert File* to full path name in malloced string. 18333b86f2f8SDavid du Colombier * this hasn't been as useful as we hoped it would be. 18343b86f2f8SDavid du Colombier */ 18353b86f2f8SDavid du Colombier char * 18363b86f2f8SDavid du Colombier fileName(File *f) 18373b86f2f8SDavid du Colombier { 18383b86f2f8SDavid du Colombier char *name, *pname; 18393b86f2f8SDavid du Colombier File *p; 18403b86f2f8SDavid du Colombier static char root[] = "/"; 18413b86f2f8SDavid du Colombier 18423b86f2f8SDavid du Colombier if (f == nil) 1843*d7aba6c3SDavid du Colombier return vtstrdup("/**GOK**"); 18443b86f2f8SDavid du Colombier 18453b86f2f8SDavid du Colombier p = fileGetParent(f); 18463b86f2f8SDavid du Colombier if (p == f) 1847*d7aba6c3SDavid du Colombier name = vtstrdup(root); 18483b86f2f8SDavid du Colombier else { 18493b86f2f8SDavid du Colombier pname = fileName(p); 18503b86f2f8SDavid du Colombier if (strcmp(pname, root) == 0) 18513b86f2f8SDavid du Colombier name = smprint("/%s", f->dir.elem); 18523b86f2f8SDavid du Colombier else 18533b86f2f8SDavid du Colombier name = smprint("%s/%s", pname, f->dir.elem); 18543b86f2f8SDavid du Colombier free(pname); 18553b86f2f8SDavid du Colombier } 18563b86f2f8SDavid du Colombier fileDecRef(p); 18573b86f2f8SDavid du Colombier return name; 18583b86f2f8SDavid du Colombier } 1859