file.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052
  1. #include "stdinc.h"
  2. #include "vac.h"
  3. #include "dat.h"
  4. #include "fns.h"
  5. #include "error.h"
  6. #define debug 0
  7. /*
  8. * Vac file system. This is a simplified version of the same code in Fossil.
  9. *
  10. * The locking order in the tree is upward: a thread can hold the lock
  11. * for a VacFile and then acquire the lock of f->up (the parent),
  12. * but not vice-versa.
  13. *
  14. * A vac file is one or two venti files. Plain data files are one venti file,
  15. * while directores are two: a venti data file containing traditional
  16. * directory entries, and a venti directory file containing venti
  17. * directory entries. The traditional directory entries in the data file
  18. * contain integers indexing into the venti directory entry file.
  19. * It's a little complicated, but it makes the data usable by standard
  20. * tools like venti/copy.
  21. *
  22. */
  23. static int filemetaflush(VacFile*, char*);
  24. struct VacFile
  25. {
  26. VacFs *fs; /* immutable */
  27. /* meta data for file: protected by the lk in the parent */
  28. int ref; /* holds this data structure up */
  29. int partial; /* file was never really open */
  30. int removed; /* file has been removed */
  31. int dirty; /* dir is dirty with respect to meta data in block */
  32. u32int boff; /* block offset within msource for this file's metadata */
  33. VacDir dir; /* metadata for this file */
  34. VacFile *up; /* parent file */
  35. VacFile *next; /* sibling */
  36. RWLock lk; /* lock for the following */
  37. VtFile *source; /* actual data */
  38. VtFile *msource; /* metadata for children in a directory */
  39. VacFile *down; /* children */
  40. int mode;
  41. uvlong qidoffset; /* qid offset */
  42. };
  43. static VacFile*
  44. filealloc(VacFs *fs)
  45. {
  46. VacFile *f;
  47. f = vtmallocz(sizeof(VacFile));
  48. f->ref = 1;
  49. f->fs = fs;
  50. f->boff = NilBlock;
  51. f->mode = fs->mode;
  52. return f;
  53. }
  54. static void
  55. filefree(VacFile *f)
  56. {
  57. vtfileclose(f->source);
  58. vtfileclose(f->msource);
  59. vdcleanup(&f->dir);
  60. memset(f, ~0, sizeof *f); /* paranoia */
  61. vtfree(f);
  62. }
  63. static int
  64. chksource(VacFile *f)
  65. {
  66. if(f->partial)
  67. return 0;
  68. if(f->source == nil
  69. || ((f->dir.mode & ModeDir) && f->msource == nil)){
  70. werrstr(ERemoved);
  71. return -1;
  72. }
  73. return 0;
  74. }
  75. static int
  76. filelock(VacFile *f)
  77. {
  78. wlock(&f->lk);
  79. if(chksource(f) < 0){
  80. wunlock(&f->lk);
  81. return -1;
  82. }
  83. return 0;
  84. }
  85. static void
  86. fileunlock(VacFile *f)
  87. {
  88. wunlock(&f->lk);
  89. }
  90. static int
  91. filerlock(VacFile *f)
  92. {
  93. rlock(&f->lk);
  94. if(chksource(f) < 0){
  95. runlock(&f->lk);
  96. return -1;
  97. }
  98. return 0;
  99. }
  100. static void
  101. filerunlock(VacFile *f)
  102. {
  103. runlock(&f->lk);
  104. }
  105. /*
  106. * The file metadata, like f->dir and f->ref,
  107. * are synchronized via the parent's lock.
  108. * This is why locking order goes up.
  109. */
  110. static void
  111. filemetalock(VacFile *f)
  112. {
  113. assert(f->up != nil);
  114. wlock(&f->up->lk);
  115. }
  116. static void
  117. filemetaunlock(VacFile *f)
  118. {
  119. wunlock(&f->up->lk);
  120. }
  121. uvlong
  122. vacfilegetid(VacFile *f)
  123. {
  124. /* immutable */
  125. //fprint(2, "getid %s %lld+%lld = %lld\n", f->dir.elem, f->qidoffset, f->dir.qid, f->qidoffset+f->dir.qid);
  126. return f->qidoffset + f->dir.qid;
  127. }
  128. uvlong
  129. vacfilegetqidoffset(VacFile *f)
  130. {
  131. return f->qidoffset;
  132. }
  133. ulong
  134. vacfilegetmcount(VacFile *f)
  135. {
  136. ulong mcount;
  137. filemetalock(f);
  138. mcount = f->dir.mcount;
  139. filemetaunlock(f);
  140. return mcount;
  141. }
  142. ulong
  143. vacfilegetmode(VacFile *f)
  144. {
  145. ulong mode;
  146. filemetalock(f);
  147. mode = f->dir.mode;
  148. filemetaunlock(f);
  149. return mode;
  150. }
  151. int
  152. vacfileisdir(VacFile *f)
  153. {
  154. /* immutable */
  155. return (f->dir.mode & ModeDir) != 0;
  156. }
  157. int
  158. vacfileisroot(VacFile *f)
  159. {
  160. return f == f->fs->root;
  161. }
  162. /*
  163. * The files are reference counted, and while the reference
  164. * is bigger than zero, each file can be found in its parent's
  165. * f->down list (chains via f->next), so that multiple threads
  166. * end up sharing a VacFile* when referring to the same file.
  167. *
  168. * Each VacFile holds a reference to its parent.
  169. */
  170. VacFile*
  171. vacfileincref(VacFile *vf)
  172. {
  173. filemetalock(vf);
  174. assert(vf->ref > 0);
  175. vf->ref++;
  176. filemetaunlock(vf);
  177. return vf;
  178. }
  179. int
  180. vacfiledecref(VacFile *f)
  181. {
  182. VacFile *p, *q, **qq;
  183. if(f->up == nil){
  184. /* never linked in */
  185. assert(f->ref == 1);
  186. filefree(f);
  187. return 0;
  188. }
  189. filemetalock(f);
  190. f->ref--;
  191. if(f->ref > 0){
  192. filemetaunlock(f);
  193. return -1;
  194. }
  195. assert(f->ref == 0);
  196. assert(f->down == nil);
  197. if(f->source && vtfilelock(f->source, -1) >= 0){
  198. vtfileflush(f->source);
  199. vtfileunlock(f->source);
  200. }
  201. if(f->msource && vtfilelock(f->msource, -1) >= 0){
  202. vtfileflush(f->msource);
  203. vtfileunlock(f->msource);
  204. }
  205. /*
  206. * Flush f's directory information to the cache.
  207. */
  208. filemetaflush(f, nil);
  209. p = f->up;
  210. qq = &p->down;
  211. for(q = *qq; q; q = *qq){
  212. if(q == f)
  213. break;
  214. qq = &q->next;
  215. }
  216. assert(q != nil);
  217. *qq = f->next;
  218. filemetaunlock(f);
  219. filefree(f);
  220. vacfiledecref(p);
  221. return 0;
  222. }
  223. /*
  224. * Construct a vacfile for the root of a vac tree, given the
  225. * venti file for the root information. That venti file is a
  226. * directory file containing VtEntries for three more venti files:
  227. * the two venti files making up the root directory, and a
  228. * third venti file that would be the metadata half of the
  229. * "root's parent".
  230. *
  231. * Fossil generates slightly different vac files, due to a now
  232. * impossible-to-change bug, which contain a VtEntry
  233. * for just one venti file, that itself contains the expected
  234. * three directory entries. Sigh.
  235. */
  236. VacFile*
  237. _vacfileroot(VacFs *fs, VtFile *r)
  238. {
  239. int redirected;
  240. char err[ERRMAX];
  241. VtBlock *b;
  242. VtFile *r0, *r1, *r2;
  243. MetaBlock mb;
  244. MetaEntry me;
  245. VacFile *root, *mr;
  246. redirected = 0;
  247. Top:
  248. b = nil;
  249. root = nil;
  250. mr = nil;
  251. r1 = nil;
  252. r2 = nil;
  253. if(vtfilelock(r, -1) < 0)
  254. return nil;
  255. r0 = vtfileopen(r, 0, fs->mode);
  256. if(debug)
  257. fprint(2, "r0 %p\n", r0);
  258. if(r0 == nil)
  259. goto Err;
  260. r2 = vtfileopen(r, 2, fs->mode);
  261. if(debug)
  262. fprint(2, "r2 %p\n", r2);
  263. if(r2 == nil){
  264. /*
  265. * some vac files (e.g., from fossil)
  266. * have an extra layer of indirection.
  267. */
  268. rerrstr(err, sizeof err);
  269. if(!redirected && strstr(err, "not active")){
  270. redirected = 1;
  271. vtfileunlock(r);
  272. r = r0;
  273. goto Top;
  274. }
  275. goto Err;
  276. }
  277. r1 = vtfileopen(r, 1, fs->mode);
  278. if(debug)
  279. fprint(2, "r1 %p\n", r1);
  280. if(r1 == nil)
  281. goto Err;
  282. mr = filealloc(fs);
  283. mr->msource = r2;
  284. r2 = nil;
  285. root = filealloc(fs);
  286. root->boff = 0;
  287. root->up = mr;
  288. root->source = r0;
  289. r0 = nil;
  290. root->msource = r1;
  291. r1 = nil;
  292. mr->down = root;
  293. vtfileunlock(r);
  294. if(vtfilelock(mr->msource, VtOREAD) < 0)
  295. goto Err1;
  296. b = vtfileblock(mr->msource, 0, VtOREAD);
  297. vtfileunlock(mr->msource);
  298. if(b == nil)
  299. goto Err1;
  300. if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
  301. goto Err1;
  302. meunpack(&me, &mb, 0);
  303. if(vdunpack(&root->dir, &me) < 0)
  304. goto Err1;
  305. vtblockput(b);
  306. return root;
  307. Err:
  308. vtfileunlock(r);
  309. Err1:
  310. vtblockput(b);
  311. if(r0)
  312. vtfileclose(r0);
  313. if(r1)
  314. vtfileclose(r1);
  315. if(r2)
  316. vtfileclose(r2);
  317. if(mr)
  318. filefree(mr);
  319. if(root)
  320. filefree(root);
  321. return nil;
  322. }
  323. /*
  324. * Vac directories are a sequence of metablocks, each of which
  325. * contains a bunch of metaentries sorted by file name.
  326. * The whole sequence isn't sorted, though, so you still have
  327. * to look at every block to find a given name.
  328. * Dirlookup looks in f for an element name elem.
  329. * It returns a new VacFile with the dir, boff, and mode
  330. * filled in, but the sources (venti files) are not, and f is
  331. * not yet linked into the tree. These details must be taken
  332. * care of by the caller.
  333. *
  334. * f must be locked, f->msource must not.
  335. */
  336. static VacFile*
  337. dirlookup(VacFile *f, char *elem)
  338. {
  339. int i;
  340. MetaBlock mb;
  341. MetaEntry me;
  342. VtBlock *b;
  343. VtFile *meta;
  344. VacFile *ff;
  345. u32int bo, nb;
  346. meta = f->msource;
  347. b = nil;
  348. if(vtfilelock(meta, -1) < 0)
  349. return nil;
  350. nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
  351. for(bo=0; bo<nb; bo++){
  352. b = vtfileblock(meta, bo, VtOREAD);
  353. if(b == nil)
  354. goto Err;
  355. if(mbunpack(&mb, b->data, meta->dsize) < 0)
  356. goto Err;
  357. if(mbsearch(&mb, elem, &i, &me) >= 0){
  358. ff = filealloc(f->fs);
  359. if(vdunpack(&ff->dir, &me) < 0){
  360. filefree(ff);
  361. goto Err;
  362. }
  363. //fprint(2, "offset %s %lld\n", ff->dir.elem, ff->dir.qidoffset);
  364. ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
  365. vtfileunlock(meta);
  366. vtblockput(b);
  367. ff->boff = bo;
  368. ff->mode = f->mode;
  369. return ff;
  370. }
  371. vtblockput(b);
  372. b = nil;
  373. }
  374. werrstr(ENoFile);
  375. /* fall through */
  376. Err:
  377. vtfileunlock(meta);
  378. vtblockput(b);
  379. return nil;
  380. }
  381. /*
  382. * Open the venti file at offset in the directory f->source.
  383. * f is locked.
  384. */
  385. static VtFile *
  386. fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
  387. {
  388. VtFile *r;
  389. if((r = vtfileopen(f->source, offset, mode)) == nil)
  390. return nil;
  391. if(r == nil)
  392. return nil;
  393. if(r->gen != gen){
  394. werrstr(ERemoved);
  395. vtfileclose(r);
  396. return nil;
  397. }
  398. if(r->dir != dir && r->mode != -1){
  399. werrstr(EBadMeta);
  400. vtfileclose(r);
  401. return nil;
  402. }
  403. return r;
  404. }
  405. VacFile*
  406. vacfilegetparent(VacFile *f)
  407. {
  408. if(vacfileisroot(f))
  409. return vacfileincref(f);
  410. return vacfileincref(f->up);
  411. }
  412. /*
  413. * Given an unlocked vacfile (directory) f,
  414. * return the vacfile named elem in f.
  415. * Interprets . and .. as a convenience to callers.
  416. */
  417. VacFile*
  418. vacfilewalk(VacFile *f, char *elem)
  419. {
  420. VacFile *ff;
  421. if(elem[0] == 0){
  422. werrstr(EBadPath);
  423. return nil;
  424. }
  425. if(!vacfileisdir(f)){
  426. werrstr(ENotDir);
  427. return nil;
  428. }
  429. if(strcmp(elem, ".") == 0)
  430. return vacfileincref(f);
  431. if(strcmp(elem, "..") == 0)
  432. return vacfilegetparent(f);
  433. if(filelock(f) < 0)
  434. return nil;
  435. for(ff = f->down; ff; ff=ff->next){
  436. if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
  437. ff->ref++;
  438. goto Exit;
  439. }
  440. }
  441. ff = dirlookup(f, elem);
  442. if(ff == nil)
  443. goto Err;
  444. if(ff->dir.mode & ModeSnapshot)
  445. ff->mode = VtOREAD;
  446. if(vtfilelock(f->source, f->mode) < 0)
  447. goto Err;
  448. if(ff->dir.mode & ModeDir){
  449. ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
  450. ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
  451. if(ff->source == nil || ff->msource == nil)
  452. goto Err1;
  453. }else{
  454. ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
  455. if(ff->source == nil)
  456. goto Err1;
  457. }
  458. vtfileunlock(f->source);
  459. /* link in and up parent ref count */
  460. ff->next = f->down;
  461. f->down = ff;
  462. ff->up = f;
  463. vacfileincref(f);
  464. Exit:
  465. fileunlock(f);
  466. return ff;
  467. Err1:
  468. vtfileunlock(f->source);
  469. Err:
  470. fileunlock(f);
  471. if(ff != nil)
  472. vacfiledecref(ff);
  473. return nil;
  474. }
  475. /*
  476. * Open a path in the vac file system:
  477. * just walk each element one at a time.
  478. */
  479. VacFile*
  480. vacfileopen(VacFs *fs, char *path)
  481. {
  482. VacFile *f, *ff;
  483. char *p, elem[VtMaxStringSize], *opath;
  484. int n;
  485. f = fs->root;
  486. vacfileincref(f);
  487. opath = path;
  488. while(*path != 0){
  489. for(p = path; *p && *p != '/'; p++)
  490. ;
  491. n = p - path;
  492. if(n > 0){
  493. if(n > VtMaxStringSize){
  494. werrstr("%s: element too long", EBadPath);
  495. goto Err;
  496. }
  497. memmove(elem, path, n);
  498. elem[n] = 0;
  499. ff = vacfilewalk(f, elem);
  500. if(ff == nil){
  501. werrstr("%.*s: %r", utfnlen(opath, p-opath), opath);
  502. goto Err;
  503. }
  504. vacfiledecref(f);
  505. f = ff;
  506. }
  507. if(*p == '/')
  508. p++;
  509. path = p;
  510. }
  511. return f;
  512. Err:
  513. vacfiledecref(f);
  514. return nil;
  515. }
  516. /*
  517. * Extract the score for the bn'th block in f.
  518. */
  519. int
  520. vacfileblockscore(VacFile *f, u32int bn, u8int *score)
  521. {
  522. VtFile *s;
  523. uvlong size;
  524. int dsize, ret;
  525. ret = -1;
  526. if(filerlock(f) < 0)
  527. return -1;
  528. if(vtfilelock(f->source, VtOREAD) < 0)
  529. goto out;
  530. s = f->source;
  531. dsize = s->dsize;
  532. size = vtfilegetsize(s);
  533. if((uvlong)bn*dsize >= size)
  534. goto out;
  535. ret = vtfileblockscore(f->source, bn, score);
  536. out:
  537. vtfileunlock(f->source);
  538. filerunlock(f);
  539. return ret;
  540. }
  541. /*
  542. * Read data from f.
  543. */
  544. int
  545. vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
  546. {
  547. int n;
  548. if(offset < 0){
  549. werrstr(EBadOffset);
  550. return -1;
  551. }
  552. if(filerlock(f) < 0)
  553. return -1;
  554. if(vtfilelock(f->source, VtOREAD) < 0){
  555. filerunlock(f);
  556. return -1;
  557. }
  558. n = vtfileread(f->source, buf, cnt, offset);
  559. vtfileunlock(f->source);
  560. filerunlock(f);
  561. return n;
  562. }
  563. static int
  564. getentry(VtFile *f, VtEntry *e)
  565. {
  566. if(vtfilelock(f, VtOREAD) < 0)
  567. return -1;
  568. if(vtfilegetentry(f, e) < 0){
  569. vtfileunlock(f);
  570. return -1;
  571. }
  572. vtfileunlock(f);
  573. if(vtglobaltolocal(e->score) != NilBlock){
  574. werrstr("internal error - data not on venti");
  575. return -1;
  576. }
  577. return 0;
  578. }
  579. /*
  580. * Get the VtEntries for the data contained in f.
  581. */
  582. int
  583. vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me)
  584. {
  585. if(filerlock(f) < 0)
  586. return -1;
  587. if(e && getentry(f->source, e) < 0){
  588. filerunlock(f);
  589. return -1;
  590. }
  591. if(me){
  592. if(f->msource == nil)
  593. memset(me, 0, sizeof *me);
  594. if(getentry(f->msource, me) < 0){
  595. filerunlock(f);
  596. return -1;
  597. }
  598. }
  599. filerunlock(f);
  600. return 0;
  601. }
  602. /*
  603. * Get the file's size.
  604. */
  605. int
  606. vacfilegetsize(VacFile *f, uvlong *size)
  607. {
  608. if(filerlock(f) < 0)
  609. return -1;
  610. if(vtfilelock(f->source, VtOREAD) < 0){
  611. filerunlock(f);
  612. return -1;
  613. }
  614. *size = vtfilegetsize(f->source);
  615. vtfileunlock(f->source);
  616. filerunlock(f);
  617. return 0;
  618. }
  619. /*
  620. * Directory reading.
  621. *
  622. * A VacDirEnum is a buffer containing directory entries.
  623. * Directory entries contain malloced strings and need to
  624. * be cleaned up with vdcleanup. The invariant in the
  625. * VacDirEnum is that the directory entries between
  626. * vde->i and vde->n are owned by the vde and need to
  627. * be cleaned up if it is closed. Those from 0 up to vde->i
  628. * have been handed to the reader, and the reader must
  629. * take care of calling vdcleanup as appropriate.
  630. */
  631. VacDirEnum*
  632. vdeopen(VacFile *f)
  633. {
  634. VacDirEnum *vde;
  635. VacFile *p;
  636. if(!vacfileisdir(f)){
  637. werrstr(ENotDir);
  638. return nil;
  639. }
  640. /*
  641. * There might be changes to this directory's children
  642. * that have not been flushed out into the cache yet.
  643. * Those changes are only available if we look at the
  644. * VacFile structures directory. But the directory reader
  645. * is going to read the cache blocks directly, so update them.
  646. */
  647. if(filelock(f) < 0)
  648. return nil;
  649. for(p=f->down; p; p=p->next)
  650. filemetaflush(p, nil);
  651. fileunlock(f);
  652. vde = vtmallocz(sizeof(VacDirEnum));
  653. vde->file = vacfileincref(f);
  654. return vde;
  655. }
  656. /*
  657. * Figure out the size of the directory entry at offset.
  658. * The rest of the metadata is kept in the data half,
  659. * but since venti has to track the data size anyway,
  660. * we just use that one and avoid updating the directory
  661. * each time the file size changes.
  662. */
  663. static int
  664. direntrysize(VtFile *s, ulong offset, ulong gen, uvlong *size)
  665. {
  666. VtBlock *b;
  667. ulong bn;
  668. VtEntry e;
  669. int epb;
  670. epb = s->dsize/VtEntrySize;
  671. bn = offset/epb;
  672. offset -= bn*epb;
  673. b = vtfileblock(s, bn, VtOREAD);
  674. if(b == nil)
  675. goto Err;
  676. if(vtentryunpack(&e, b->data, offset) < 0)
  677. goto Err;
  678. /* dangling entries are returned as zero size */
  679. if(!(e.flags & VtEntryActive) || e.gen != gen)
  680. *size = 0;
  681. else
  682. *size = e.size;
  683. vtblockput(b);
  684. return 0;
  685. Err:
  686. vtblockput(b);
  687. return -1;
  688. }
  689. /*
  690. * Fill in vde with a new batch of directory entries.
  691. */
  692. static int
  693. vdefill(VacDirEnum *vde)
  694. {
  695. int i, n;
  696. VtFile *meta, *source;
  697. MetaBlock mb;
  698. MetaEntry me;
  699. VacFile *f;
  700. VtBlock *b;
  701. VacDir *de;
  702. /* clean up first */
  703. for(i=vde->i; i<vde->n; i++)
  704. vdcleanup(vde->buf+i);
  705. vtfree(vde->buf);
  706. vde->buf = nil;
  707. vde->i = 0;
  708. vde->n = 0;
  709. f = vde->file;
  710. source = f->source;
  711. meta = f->msource;
  712. b = vtfileblock(meta, vde->boff, VtOREAD);
  713. if(b == nil)
  714. goto Err;
  715. if(mbunpack(&mb, b->data, meta->dsize) < 0)
  716. goto Err;
  717. n = mb.nindex;
  718. vde->buf = vtmalloc(n * sizeof(VacDir));
  719. for(i=0; i<n; i++){
  720. de = vde->buf + i;
  721. meunpack(&me, &mb, i);
  722. if(vdunpack(de, &me) < 0)
  723. goto Err;
  724. vde->n++;
  725. if(!(de->mode & ModeDir))
  726. if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
  727. goto Err;
  728. }
  729. vde->boff++;
  730. vtblockput(b);
  731. return 0;
  732. Err:
  733. vtblockput(b);
  734. return -1;
  735. }
  736. /*
  737. * Read a single directory entry from vde into de.
  738. * Returns -1 on error, 0 on EOF, and 1 on success.
  739. * When it returns 1, it becomes the caller's responsibility
  740. * to call vdcleanup(de) to free the strings contained
  741. * inside, or else to call vdunread to give it back.
  742. */
  743. int
  744. vderead(VacDirEnum *vde, VacDir *de)
  745. {
  746. int ret;
  747. VacFile *f;
  748. u32int nb;
  749. f = vde->file;
  750. if(filerlock(f) < 0)
  751. return -1;
  752. if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
  753. filerunlock(f);
  754. return -1;
  755. }
  756. nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
  757. while(vde->i >= vde->n){
  758. if(vde->boff >= nb){
  759. ret = 0;
  760. goto Return;
  761. }
  762. if(vdefill(vde) < 0){
  763. ret = -1;
  764. goto Return;
  765. }
  766. }
  767. memmove(de, vde->buf + vde->i, sizeof(VacDir));
  768. vde->i++;
  769. ret = 1;
  770. Return:
  771. vtfileunlock(f->source);
  772. vtfileunlock(f->msource);
  773. filerunlock(f);
  774. return ret;
  775. }
  776. /*
  777. * "Unread" the last directory entry that was read,
  778. * so that the next vderead will return the same one.
  779. * If the caller calls vdeunread(vde) it should not call
  780. * vdcleanup on the entry being "unread".
  781. */
  782. int
  783. vdeunread(VacDirEnum *vde)
  784. {
  785. if(vde->i > 0){
  786. vde->i--;
  787. return 0;
  788. }
  789. return -1;
  790. }
  791. /*
  792. * Close the enumerator.
  793. */
  794. void
  795. vdeclose(VacDirEnum *vde)
  796. {
  797. int i;
  798. if(vde == nil)
  799. return;
  800. /* free the strings */
  801. for(i=vde->i; i<vde->n; i++)
  802. vdcleanup(vde->buf+i);
  803. vtfree(vde->buf);
  804. vacfiledecref(vde->file);
  805. vtfree(vde);
  806. }
  807. /*
  808. * On to mutation. If the vac file system has been opened
  809. * read-write, then the files and directories can all be edited.
  810. * Changes are kept in the in-memory cache until flushed out
  811. * to venti, so we must be careful to explicitly flush data
  812. * that we're not likely to modify again.
  813. *
  814. * Each VacFile has its own copy of its VacDir directory entry
  815. * in f->dir, but otherwise the cache is the authoratative source
  816. * for data. Thus, for the most part, it suffices if we just
  817. * call vtfileflushbefore and vtfileflush when we modify things.
  818. * There are a few places where we have to remember to write
  819. * changed VacDirs back into the cache. If f->dir *is* out of sync,
  820. * then f->dirty should be set.
  821. *
  822. * The metadata in a directory is, to venti, a plain data file,
  823. * but as mentioned above it is actually a sequence of
  824. * MetaBlocks that contain sorted lists of VacDir entries.
  825. * The filemetaxxx routines manipulate that stream.
  826. */
  827. /*
  828. * Find space in fp for the directory entry dir (not yet written to disk)
  829. * and write it to disk, returning NilBlock on failure,
  830. * or the block number on success.
  831. *
  832. * Start is a suggested block number to try.
  833. * The caller must have filemetalock'ed f and have
  834. * vtfilelock'ed f->up->msource.
  835. */
  836. static u32int
  837. filemetaalloc(VacFile *fp, VacDir *dir, u32int start)
  838. {
  839. u32int nb, bo;
  840. VtBlock *b;
  841. MetaBlock mb;
  842. int nn;
  843. uchar *p;
  844. int i, n;
  845. MetaEntry me;
  846. VtFile *ms;
  847. ms = fp->msource;
  848. n = vdsize(dir, VacDirVersion);
  849. /* Look for a block with room for a new entry of size n. */
  850. nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
  851. if(start == NilBlock){
  852. if(nb > 0)
  853. start = nb - 1;
  854. else
  855. start = 0;
  856. }
  857. if(start > nb)
  858. start = nb;
  859. for(bo=start; bo<nb; bo++){
  860. if((b = vtfileblock(ms, bo, VtOREAD)) == nil)
  861. goto Err;
  862. if(mbunpack(&mb, b->data, ms->dsize) < 0)
  863. goto Err;
  864. nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
  865. if(n <= nn && mb.nindex < mb.maxindex){
  866. /* reopen for writing */
  867. vtblockput(b);
  868. if((b = vtfileblock(ms, bo, VtORDWR)) == nil)
  869. goto Err;
  870. goto Found;
  871. }
  872. vtblockput(b);
  873. }
  874. /* No block found, extend the file by one metablock. */
  875. vtfileflushbefore(ms, nb*(uvlong)ms->dsize);
  876. if((b = vtfileblock(ms, nb, VtORDWR)) == nil)
  877. goto Err;
  878. vtfilesetsize(ms, (nb+1)*ms->dsize);
  879. mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
  880. Found:
  881. /* Now we have a block; allocate space to write the entry. */
  882. p = mballoc(&mb, n);
  883. if(p == nil){
  884. /* mballoc might have changed block */
  885. mbpack(&mb);
  886. werrstr(EBadMeta);
  887. goto Err;
  888. }
  889. /* Figure out where to put the index entry, and write it. */
  890. mbsearch(&mb, dir->elem, &i, &me);
  891. assert(me.p == nil); /* not already there */
  892. me.p = p;
  893. me.size = n;
  894. vdpack(dir, &me, VacDirVersion);
  895. vdunpack(dir, &me);
  896. mbinsert(&mb, i, &me);
  897. mbpack(&mb);
  898. vtblockput(b);
  899. return bo;
  900. Err:
  901. vtblockput(b);
  902. return NilBlock;
  903. }
  904. /*
  905. * Update f's directory entry in the block cache.
  906. * We look for the directory entry by name;
  907. * if we're trying to rename the file, oelem is the old name.
  908. *
  909. * Assumes caller has filemetalock'ed f.
  910. */
  911. static int
  912. filemetaflush(VacFile *f, char *oelem)
  913. {
  914. int i, n;
  915. MetaBlock mb;
  916. MetaEntry me, me2;
  917. VacFile *fp;
  918. VtBlock *b;
  919. u32int bo;
  920. if(!f->dirty)
  921. return 0;
  922. if(oelem == nil)
  923. oelem = f->dir.elem;
  924. /*
  925. * Locate f's old metadata in the parent's metadata file.
  926. * We know which block it was in, but not exactly where
  927. * in the block.
  928. */
  929. fp = f->up;
  930. if(vtfilelock(fp->msource, -1) < 0)
  931. return -1;
  932. /* can happen if source is clri'ed out from under us */
  933. if(f->boff == NilBlock)
  934. goto Err1;
  935. b = vtfileblock(fp->msource, f->boff, VtORDWR);
  936. if(b == nil)
  937. goto Err1;
  938. if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
  939. goto Err;
  940. if(mbsearch(&mb, oelem, &i, &me) < 0)
  941. goto Err;
  942. /*
  943. * Check whether we can resize the entry and keep it
  944. * in this block.
  945. */
  946. n = vdsize(&f->dir, VacDirVersion);
  947. if(mbresize(&mb, &me, n) >= 0){
  948. /* Okay, can be done without moving to another block. */
  949. /* Remove old data */
  950. mbdelete(&mb, i, &me);
  951. /* Find new location if renaming */
  952. if(strcmp(f->dir.elem, oelem) != 0)
  953. mbsearch(&mb, f->dir.elem, &i, &me2);
  954. /* Pack new data into new location. */
  955. vdpack(&f->dir, &me, VacDirVersion);
  956. vdunpack(&f->dir, &me);
  957. mbinsert(&mb, i, &me);
  958. mbpack(&mb);
  959. /* Done */
  960. vtblockput(b);
  961. vtfileunlock(fp->msource);
  962. f->dirty = 0;
  963. return 0;
  964. }
  965. /*
  966. * The entry must be moved to another block.
  967. * This can only really happen on renames that
  968. * make the name very long.
  969. */
  970. /* Allocate a spot in a new block. */
  971. if((bo = filemetaalloc(fp, &f->dir, f->boff+1)) == NilBlock){
  972. /* mbresize above might have modified block */
  973. mbpack(&mb);
  974. goto Err;
  975. }
  976. f->boff = bo;
  977. /* Now we're committed. Delete entry in old block. */
  978. mbdelete(&mb, i, &me);
  979. mbpack(&mb);
  980. vtblockput(b);
  981. vtfileunlock(fp->msource);
  982. f->dirty = 0;
  983. return 0;
  984. Err:
  985. vtblockput(b);
  986. Err1:
  987. vtfileunlock(fp->msource);
  988. return -1;
  989. }
  990. /*
  991. * Remove the directory entry for f.
  992. */
  993. static int
  994. filemetaremove(VacFile *f)
  995. {
  996. VtBlock *b;
  997. MetaBlock mb;
  998. MetaEntry me;
  999. int i;
  1000. VacFile *fp;
  1001. b = nil;
  1002. fp = f->up;
  1003. filemetalock(f);
  1004. if(vtfilelock(fp->msource, VtORDWR) < 0)
  1005. goto Err;
  1006. b = vtfileblock(fp->msource, f->boff, VtORDWR);
  1007. if(b == nil)
  1008. goto Err;
  1009. if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
  1010. goto Err;
  1011. if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
  1012. goto Err;
  1013. mbdelete(&mb, i, &me);
  1014. mbpack(&mb);
  1015. vtblockput(b);
  1016. vtfileunlock(fp->msource);
  1017. f->removed = 1;
  1018. f->boff = NilBlock;
  1019. f->dirty = 0;
  1020. filemetaunlock(f);
  1021. return 0;
  1022. Err:
  1023. vtfileunlock(fp->msource);
  1024. vtblockput(b);
  1025. filemetaunlock(f);
  1026. return -1;
  1027. }
  1028. /*
  1029. * That was far too much effort for directory entries.
  1030. * Now we can write code that *does* things.
  1031. */
  1032. /*
  1033. * Flush all data associated with f out of the cache and onto venti.
  1034. * If recursive is set, flush f's children too.
  1035. */
  1036. int
  1037. vacfileflush(VacFile *f, int recursive)
  1038. {
  1039. int ret;
  1040. VacFile **kids, *p;
  1041. int i, nkids;
  1042. if(f->mode == VtOREAD)
  1043. return 0;
  1044. ret = 0;
  1045. filemetalock(f);
  1046. if(filemetaflush(f, nil) < 0)
  1047. ret = -1;
  1048. filemetaunlock(f);
  1049. /*
  1050. * Vacfiledecref knows how to flush source and msource too.
  1051. */
  1052. if(filelock(f) < 0)
  1053. return -1;
  1054. vtfilelock(f->source, -1);
  1055. if(vtfileflush(f->source) < 0)
  1056. ret = -1;
  1057. vtfileunlock(f->source);
  1058. if(f->msource){
  1059. vtfilelock(f->msource, -1);
  1060. if(vtfileflush(f->msource) < 0)
  1061. ret = -1;
  1062. vtfileunlock(f->msource);
  1063. }
  1064. /*
  1065. * Lock order prevents us from flushing kids while holding
  1066. * lock, so make a list.
  1067. */
  1068. nkids = 0;
  1069. kids = nil;
  1070. if(recursive){
  1071. nkids = 0;
  1072. for(p=f->down; p; p=p->next)
  1073. nkids++;
  1074. kids = vtmalloc(nkids*sizeof(VacFile*));
  1075. i = 0;
  1076. for(p=f->down; p; p=p->next){
  1077. kids[i++] = p;
  1078. p->ref++;
  1079. }
  1080. }
  1081. fileunlock(f);
  1082. for(i=0; i<nkids; i++){
  1083. if(vacfileflush(kids[i], 1) < 0)
  1084. ret = -1;
  1085. vacfiledecref(kids[i]);
  1086. }
  1087. free(kids);
  1088. return ret;
  1089. }
  1090. /*
  1091. * Create a new file named elem in fp with the given mode.
  1092. * The mode can be changed later except for the ModeDir bit.
  1093. */
  1094. VacFile*
  1095. vacfilecreate(VacFile *fp, char *elem, ulong mode)
  1096. {
  1097. VacFile *ff;
  1098. VacDir *dir;
  1099. VtFile *pr, *r, *mr;
  1100. int type;
  1101. u32int bo;
  1102. if(filelock(fp) < 0)
  1103. return nil;
  1104. /*
  1105. * First, look to see that there's not a file in memory
  1106. * with the same name.
  1107. */
  1108. for(ff = fp->down; ff; ff=ff->next){
  1109. if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
  1110. ff = nil;
  1111. werrstr(EExists);
  1112. goto Err1;
  1113. }
  1114. }
  1115. /*
  1116. * Next check the venti blocks.
  1117. */
  1118. ff = dirlookup(fp, elem);
  1119. if(ff != nil){
  1120. werrstr(EExists);
  1121. goto Err1;
  1122. }
  1123. /*
  1124. * By the way, you can't create in a read-only file system.
  1125. */
  1126. pr = fp->source;
  1127. if(pr->mode != VtORDWR){
  1128. werrstr(EReadOnly);
  1129. goto Err1;
  1130. }
  1131. /*
  1132. * Okay, time to actually create something. Lock the two
  1133. * halves of the directory and create a file.
  1134. */
  1135. if(vtfilelock2(fp->source, fp->msource, -1) < 0)
  1136. goto Err1;
  1137. ff = filealloc(fp->fs);
  1138. ff->qidoffset = fp->qidoffset; /* hopefully fp->qidoffset == 0 */
  1139. type = VtDataType;
  1140. if(mode & ModeDir)
  1141. type = VtDirType;
  1142. mr = nil;
  1143. if((r = vtfilecreate(pr, pr->psize, pr->dsize, type)) == nil)
  1144. goto Err;
  1145. if(mode & ModeDir)
  1146. if((mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType)) == nil)
  1147. goto Err;
  1148. /*
  1149. * Fill in the directory entry and write it to disk.
  1150. */
  1151. dir = &ff->dir;
  1152. dir->elem = vtstrdup(elem);
  1153. dir->entry = r->offset;
  1154. dir->gen = r->gen;
  1155. if(mode & ModeDir){
  1156. dir->mentry = mr->offset;
  1157. dir->mgen = mr->gen;
  1158. }
  1159. dir->size = 0;
  1160. if(_vacfsnextqid(fp->fs, &dir->qid) < 0)
  1161. goto Err;
  1162. dir->uid = vtstrdup(fp->dir.uid);
  1163. dir->gid = vtstrdup(fp->dir.gid);
  1164. dir->mid = vtstrdup("");
  1165. dir->mtime = time(0L);
  1166. dir->mcount = 0;
  1167. dir->ctime = dir->mtime;
  1168. dir->atime = dir->mtime;
  1169. dir->mode = mode;
  1170. if((bo = filemetaalloc(fp, &ff->dir, NilBlock)) == NilBlock)
  1171. goto Err;
  1172. /*
  1173. * Now we're committed.
  1174. */
  1175. vtfileunlock(fp->source);
  1176. vtfileunlock(fp->msource);
  1177. ff->source = r;
  1178. ff->msource = mr;
  1179. ff->boff = bo;
  1180. /* Link into tree. */
  1181. ff->next = fp->down;
  1182. fp->down = ff;
  1183. ff->up = fp;
  1184. vacfileincref(fp);
  1185. fileunlock(fp);
  1186. return ff;
  1187. Err:
  1188. vtfileunlock(fp->source);
  1189. vtfileunlock(fp->msource);
  1190. if(r){
  1191. vtfilelock(r, -1);
  1192. vtfileremove(r);
  1193. }
  1194. if(mr){
  1195. vtfilelock(mr, -1);
  1196. vtfileremove(mr);
  1197. }
  1198. Err1:
  1199. if(ff)
  1200. vacfiledecref(ff);
  1201. fileunlock(fp);
  1202. return nil;
  1203. }
  1204. /*
  1205. * Change the size of the file f.
  1206. */
  1207. int
  1208. vacfilesetsize(VacFile *f, uvlong size)
  1209. {
  1210. if(vacfileisdir(f)){
  1211. werrstr(ENotFile);
  1212. return -1;
  1213. }
  1214. if(filelock(f) < 0)
  1215. return -1;
  1216. if(f->source->mode != VtORDWR){
  1217. werrstr(EReadOnly);
  1218. goto Err;
  1219. }
  1220. if(vtfilelock(f->source, -1) < 0)
  1221. goto Err;
  1222. if(vtfilesetsize(f->source, size) < 0){
  1223. vtfileunlock(f->source);
  1224. goto Err;
  1225. }
  1226. vtfileunlock(f->source);
  1227. fileunlock(f);
  1228. return 0;
  1229. Err:
  1230. fileunlock(f);
  1231. return -1;
  1232. }
  1233. /*
  1234. * Write data to f.
  1235. */
  1236. int
  1237. vacfilewrite(VacFile *f, void *buf, int cnt, vlong offset)
  1238. {
  1239. if(vacfileisdir(f)){
  1240. werrstr(ENotFile);
  1241. return -1;
  1242. }
  1243. if(filelock(f) < 0)
  1244. return -1;
  1245. if(f->source->mode != VtORDWR){
  1246. werrstr(EReadOnly);
  1247. goto Err;
  1248. }
  1249. if(offset < 0){
  1250. werrstr(EBadOffset);
  1251. goto Err;
  1252. }
  1253. if(vtfilelock(f->source, -1) < 0)
  1254. goto Err;
  1255. if(f->dir.mode & ModeAppend)
  1256. offset = vtfilegetsize(f->source);
  1257. if(vtfilewrite(f->source, buf, cnt, offset) != cnt
  1258. || vtfileflushbefore(f->source, offset) < 0){
  1259. vtfileunlock(f->source);
  1260. goto Err;
  1261. }
  1262. vtfileunlock(f->source);
  1263. fileunlock(f);
  1264. return cnt;
  1265. Err:
  1266. fileunlock(f);
  1267. return -1;
  1268. }
  1269. /*
  1270. * Set (!) the VtEntry for the data contained in f.
  1271. * This let's us efficiently copy data from one file to another.
  1272. */
  1273. int
  1274. vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me)
  1275. {
  1276. int ret;
  1277. vacfileflush(f, 0); /* flush blocks to venti, since we won't see them again */
  1278. if(!(e->flags&VtEntryActive)){
  1279. werrstr("missing entry for source");
  1280. return -1;
  1281. }
  1282. if(me && !(me->flags&VtEntryActive))
  1283. me = nil;
  1284. if(f->msource && !me){
  1285. werrstr("missing entry for msource");
  1286. return -1;
  1287. }
  1288. if(me && !f->msource){
  1289. werrstr("no msource to set");
  1290. return -1;
  1291. }
  1292. if(filelock(f) < 0)
  1293. return -1;
  1294. if(f->source->mode != VtORDWR
  1295. || (f->msource && f->msource->mode != VtORDWR)){
  1296. werrstr(EReadOnly);
  1297. fileunlock(f);
  1298. return -1;
  1299. }
  1300. if(vtfilelock2(f->source, f->msource, -1) < 0){
  1301. fileunlock(f);
  1302. return -1;
  1303. }
  1304. ret = 0;
  1305. if(vtfilesetentry(f->source, e) < 0)
  1306. ret = -1;
  1307. else if(me && vtfilesetentry(f->msource, me) < 0)
  1308. ret = -1;
  1309. vtfileunlock(f->source);
  1310. if(f->msource)
  1311. vtfileunlock(f->msource);
  1312. fileunlock(f);
  1313. return ret;
  1314. }
  1315. /*
  1316. * Get the directory entry for f.
  1317. */
  1318. int
  1319. vacfilegetdir(VacFile *f, VacDir *dir)
  1320. {
  1321. if(filerlock(f) < 0)
  1322. return -1;
  1323. filemetalock(f);
  1324. vdcopy(dir, &f->dir);
  1325. filemetaunlock(f);
  1326. if(!vacfileisdir(f)){
  1327. if(vtfilelock(f->source, VtOREAD) < 0){
  1328. filerunlock(f);
  1329. return -1;
  1330. }
  1331. dir->size = vtfilegetsize(f->source);
  1332. vtfileunlock(f->source);
  1333. }
  1334. filerunlock(f);
  1335. return 0;
  1336. }
  1337. /*
  1338. * Set the directory entry for f.
  1339. */
  1340. int
  1341. vacfilesetdir(VacFile *f, VacDir *dir)
  1342. {
  1343. VacFile *ff;
  1344. char *oelem;
  1345. u32int mask;
  1346. u64int size;
  1347. /* can not set permissions for the root */
  1348. if(vacfileisroot(f)){
  1349. werrstr(ERoot);
  1350. return -1;
  1351. }
  1352. if(filelock(f) < 0)
  1353. return -1;
  1354. filemetalock(f);
  1355. if(f->source->mode != VtORDWR){
  1356. werrstr(EReadOnly);
  1357. goto Err;
  1358. }
  1359. /* On rename, check new name does not already exist */
  1360. if(strcmp(f->dir.elem, dir->elem) != 0){
  1361. for(ff = f->up->down; ff; ff=ff->next){
  1362. if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
  1363. werrstr(EExists);
  1364. goto Err;
  1365. }
  1366. }
  1367. ff = dirlookup(f->up, dir->elem);
  1368. if(ff != nil){
  1369. vacfiledecref(ff);
  1370. werrstr(EExists);
  1371. goto Err;
  1372. }
  1373. werrstr(""); /* "failed" dirlookup poisoned it */
  1374. }
  1375. /* Get ready... */
  1376. if(vtfilelock2(f->source, f->msource, -1) < 0)
  1377. goto Err;
  1378. if(!vacfileisdir(f)){
  1379. size = vtfilegetsize(f->source);
  1380. if(size != dir->size){
  1381. if(vtfilesetsize(f->source, dir->size) < 0){
  1382. vtfileunlock(f->source);
  1383. if(f->msource)
  1384. vtfileunlock(f->msource);
  1385. goto Err;
  1386. }
  1387. }
  1388. }
  1389. /* ... now commited to changing it. */
  1390. vtfileunlock(f->source);
  1391. if(f->msource)
  1392. vtfileunlock(f->msource);
  1393. oelem = nil;
  1394. if(strcmp(f->dir.elem, dir->elem) != 0){
  1395. oelem = f->dir.elem;
  1396. f->dir.elem = vtstrdup(dir->elem);
  1397. }
  1398. if(strcmp(f->dir.uid, dir->uid) != 0){
  1399. vtfree(f->dir.uid);
  1400. f->dir.uid = vtstrdup(dir->uid);
  1401. }
  1402. if(strcmp(f->dir.gid, dir->gid) != 0){
  1403. vtfree(f->dir.gid);
  1404. f->dir.gid = vtstrdup(dir->gid);
  1405. }
  1406. f->dir.mtime = dir->mtime;
  1407. f->dir.atime = dir->atime;
  1408. mask = ~(ModeDir|ModeSnapshot);
  1409. f->dir.mode &= ~mask;
  1410. f->dir.mode |= mask & dir->mode;
  1411. f->dirty = 1;
  1412. if(filemetaflush(f, oelem) < 0){
  1413. vtfree(oelem);
  1414. goto Err; /* that sucks */
  1415. }
  1416. vtfree(oelem);
  1417. filemetaunlock(f);
  1418. fileunlock(f);
  1419. return 0;
  1420. Err:
  1421. filemetaunlock(f);
  1422. fileunlock(f);
  1423. return -1;
  1424. }
  1425. /*
  1426. * Set the qid space.
  1427. */
  1428. int
  1429. vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
  1430. {
  1431. int ret;
  1432. if(filelock(f) < 0)
  1433. return -1;
  1434. if(f->source->mode != VtORDWR){
  1435. fileunlock(f);
  1436. werrstr(EReadOnly);
  1437. return -1;
  1438. }
  1439. filemetalock(f);
  1440. f->dir.qidspace = 1;
  1441. f->dir.qidoffset = offset;
  1442. f->dir.qidmax = max;
  1443. f->dirty = 1;
  1444. ret = filemetaflush(f, nil);
  1445. filemetaunlock(f);
  1446. fileunlock(f);
  1447. return ret;
  1448. }
  1449. /*
  1450. * Check that the file is empty, returning 0 if it is.
  1451. * Returns -1 on error (and not being empty is an error).
  1452. */
  1453. static int
  1454. filecheckempty(VacFile *f)
  1455. {
  1456. u32int i, n;
  1457. VtBlock *b;
  1458. MetaBlock mb;
  1459. VtFile *r;
  1460. r = f->msource;
  1461. n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
  1462. for(i=0; i<n; i++){
  1463. b = vtfileblock(r, i, VtOREAD);
  1464. if(b == nil)
  1465. return -1;
  1466. if(mbunpack(&mb, b->data, r->dsize) < 0)
  1467. goto Err;
  1468. if(mb.nindex > 0){
  1469. werrstr(ENotEmpty);
  1470. goto Err;
  1471. }
  1472. vtblockput(b);
  1473. }
  1474. return 0;
  1475. Err:
  1476. vtblockput(b);
  1477. return -1;
  1478. }
  1479. /*
  1480. * Remove the vac file f.
  1481. */
  1482. int
  1483. vacfileremove(VacFile *f)
  1484. {
  1485. VacFile *ff;
  1486. /* Cannot remove the root */
  1487. if(vacfileisroot(f)){
  1488. werrstr(ERoot);
  1489. return -1;
  1490. }
  1491. if(filelock(f) < 0)
  1492. return -1;
  1493. if(f->source->mode != VtORDWR){
  1494. werrstr(EReadOnly);
  1495. goto Err1;
  1496. }
  1497. if(vtfilelock2(f->source, f->msource, -1) < 0)
  1498. goto Err1;
  1499. if(vacfileisdir(f) && filecheckempty(f)<0)
  1500. goto Err;
  1501. for(ff=f->down; ff; ff=ff->next)
  1502. assert(ff->removed);
  1503. vtfileremove(f->source);
  1504. f->source = nil;
  1505. if(f->msource){
  1506. vtfileremove(f->msource);
  1507. f->msource = nil;
  1508. }
  1509. fileunlock(f);
  1510. if(filemetaremove(f) < 0)
  1511. return -1;
  1512. return 0;
  1513. Err:
  1514. vtfileunlock(f->source);
  1515. if(f->msource)
  1516. vtfileunlock(f->msource);
  1517. Err1:
  1518. fileunlock(f);
  1519. return -1;
  1520. }
  1521. /*
  1522. * Vac file system format.
  1523. */
  1524. static char EBadVacFormat[] = "bad format for vac file";
  1525. static VacFs *
  1526. vacfsalloc(VtConn *z, int bsize, int ncache, int mode)
  1527. {
  1528. VacFs *fs;
  1529. fs = vtmallocz(sizeof(VacFs));
  1530. fs->z = z;
  1531. fs->bsize = bsize;
  1532. fs->mode = mode;
  1533. fs->cache = vtcachealloc(z, bsize, ncache);
  1534. return fs;
  1535. }
  1536. static int
  1537. readscore(int fd, uchar score[VtScoreSize])
  1538. {
  1539. char buf[45], *pref;
  1540. int n;
  1541. n = readn(fd, buf, sizeof(buf)-1);
  1542. if(n < sizeof(buf)-1) {
  1543. werrstr("short read");
  1544. return -1;
  1545. }
  1546. buf[n] = 0;
  1547. if(vtparsescore(buf, &pref, score) < 0){
  1548. werrstr(EBadVacFormat);
  1549. return -1;
  1550. }
  1551. if(pref==nil || strcmp(pref, "vac") != 0) {
  1552. werrstr("not a vac file");
  1553. return -1;
  1554. }
  1555. return 0;
  1556. }
  1557. VacFs*
  1558. vacfsopen(VtConn *z, char *file, int mode, int ncache)
  1559. {
  1560. int fd;
  1561. uchar score[VtScoreSize];
  1562. char *prefix;
  1563. if(vtparsescore(file, &prefix, score) >= 0){
  1564. if(prefix == nil || strcmp(prefix, "vac") != 0){
  1565. werrstr("not a vac file");
  1566. return nil;
  1567. }
  1568. }else{
  1569. fd = open(file, OREAD);
  1570. if(fd < 0)
  1571. return nil;
  1572. if(readscore(fd, score) < 0){
  1573. close(fd);
  1574. return nil;
  1575. }
  1576. close(fd);
  1577. }
  1578. return vacfsopenscore(z, score, mode, ncache);
  1579. }
  1580. VacFs*
  1581. vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache)
  1582. {
  1583. VacFs *fs;
  1584. int n;
  1585. VtRoot rt;
  1586. uchar buf[VtRootSize];
  1587. VacFile *root;
  1588. VtFile *r;
  1589. VtEntry e;
  1590. n = vtread(z, score, VtRootType, buf, VtRootSize);
  1591. if(n < 0)
  1592. return nil;
  1593. if(n != VtRootSize){
  1594. werrstr("vtread on root too short");
  1595. return nil;
  1596. }
  1597. if(vtrootunpack(&rt, buf) < 0)
  1598. return nil;
  1599. if(strcmp(rt.type, "vac") != 0) {
  1600. werrstr("not a vac root");
  1601. return nil;
  1602. }
  1603. fs = vacfsalloc(z, rt.blocksize, ncache, mode);
  1604. memmove(fs->score, score, VtScoreSize);
  1605. fs->mode = mode;
  1606. memmove(e.score, rt.score, VtScoreSize);
  1607. e.gen = 0;
  1608. e.psize = (rt.blocksize/VtEntrySize)*VtEntrySize;
  1609. e.dsize = rt.blocksize;
  1610. e.type = VtDirType;
  1611. e.flags = VtEntryActive;
  1612. e.size = 3*VtEntrySize;
  1613. root = nil;
  1614. if((r = vtfileopenroot(fs->cache, &e)) == nil)
  1615. goto Err;
  1616. if(debug)
  1617. fprint(2, "r %p\n", r);
  1618. root = _vacfileroot(fs, r);
  1619. if(debug)
  1620. fprint(2, "root %p\n", root);
  1621. vtfileclose(r);
  1622. if(root == nil)
  1623. goto Err;
  1624. fs->root = root;
  1625. return fs;
  1626. Err:
  1627. if(root)
  1628. vacfiledecref(root);
  1629. vacfsclose(fs);
  1630. return nil;
  1631. }
  1632. int
  1633. vacfsmode(VacFs *fs)
  1634. {
  1635. return fs->mode;
  1636. }
  1637. VacFile*
  1638. vacfsgetroot(VacFs *fs)
  1639. {
  1640. return vacfileincref(fs->root);
  1641. }
  1642. int
  1643. vacfsgetblocksize(VacFs *fs)
  1644. {
  1645. return fs->bsize;
  1646. }
  1647. int
  1648. vacfsgetscore(VacFs *fs, u8int *score)
  1649. {
  1650. memmove(score, fs->score, VtScoreSize);
  1651. return 0;
  1652. }
  1653. int
  1654. _vacfsnextqid(VacFs *fs, uvlong *qid)
  1655. {
  1656. ++fs->qid;
  1657. *qid = fs->qid;
  1658. return 0;
  1659. }
  1660. void
  1661. vacfsjumpqid(VacFs *fs, uvlong step)
  1662. {
  1663. fs->qid += step;
  1664. }
  1665. /*
  1666. * Set *maxqid to the maximum qid expected in this file system.
  1667. * In newer vac archives, the maximum qid is stored in the
  1668. * qidspace VacDir annotation. In older vac archives, the root
  1669. * got created last, so it had the maximum qid.
  1670. */
  1671. int
  1672. vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
  1673. {
  1674. VacDir vd;
  1675. if(vacfilegetdir(fs->root, &vd) < 0)
  1676. return -1;
  1677. if(vd.qidspace)
  1678. *maxqid = vd.qidmax;
  1679. else
  1680. *maxqid = vd.qid;
  1681. vdcleanup(&vd);
  1682. return 0;
  1683. }
  1684. void
  1685. vacfsclose(VacFs *fs)
  1686. {
  1687. if(fs->root)
  1688. vacfiledecref(fs->root);
  1689. fs->root = nil;
  1690. vtcachefree(fs->cache);
  1691. vtfree(fs);
  1692. }
  1693. /*
  1694. * Create a fresh vac fs.
  1695. */
  1696. VacFs *
  1697. vacfscreate(VtConn *z, int bsize, int ncache)
  1698. {
  1699. VacFs *fs;
  1700. VtFile *f;
  1701. uchar buf[VtEntrySize], metascore[VtScoreSize];
  1702. VtEntry e;
  1703. VtBlock *b;
  1704. MetaBlock mb;
  1705. VacDir vd;
  1706. MetaEntry me;
  1707. int psize;
  1708. if((fs = vacfsalloc(z, bsize, ncache, VtORDWR)) == nil)
  1709. return nil;
  1710. /*
  1711. * Fake up an empty vac fs.
  1712. */
  1713. psize = bsize/VtEntrySize*VtEntrySize;
  1714. f = vtfilecreateroot(fs->cache, psize, bsize, VtDirType);
  1715. vtfilelock(f, VtORDWR);
  1716. /* Write metablock containing root directory VacDir. */
  1717. b = vtcacheallocblock(fs->cache, VtDataType);
  1718. mbinit(&mb, b->data, bsize, bsize/BytesPerEntry);
  1719. memset(&vd, 0, sizeof vd);
  1720. vd.elem = "/";
  1721. vd.mode = 0777|ModeDir;
  1722. vd.uid = "vac";
  1723. vd.gid = "vac";
  1724. vd.mid = "";
  1725. me.size = vdsize(&vd, VacDirVersion);
  1726. me.p = mballoc(&mb, me.size);
  1727. vdpack(&vd, &me, VacDirVersion);
  1728. mbinsert(&mb, 0, &me);
  1729. mbpack(&mb);
  1730. vtblockwrite(b);
  1731. memmove(metascore, b->score, VtScoreSize);
  1732. vtblockput(b);
  1733. /* First entry: empty venti directory stream. */
  1734. memset(&e, 0, sizeof e);
  1735. e.flags = VtEntryActive;
  1736. e.psize = psize;
  1737. e.dsize = bsize;
  1738. e.type = VtDirType;
  1739. memmove(e.score, vtzeroscore, VtScoreSize);
  1740. vtentrypack(&e, buf, 0);
  1741. vtfilewrite(f, buf, VtEntrySize, 0);
  1742. /* Second entry: empty metadata stream. */
  1743. e.type = VtDataType;
  1744. vtentrypack(&e, buf, 0);
  1745. vtfilewrite(f, buf, VtEntrySize, VtEntrySize);
  1746. /* Third entry: metadata stream with root directory. */
  1747. memmove(e.score, metascore, VtScoreSize);
  1748. e.size = bsize;
  1749. vtentrypack(&e, buf, 0);
  1750. vtfilewrite(f, buf, VtEntrySize, VtEntrySize*2);
  1751. vtfileflush(f);
  1752. vtfileunlock(f);
  1753. /* Now open it as a vac fs. */
  1754. fs->root = _vacfileroot(fs, f);
  1755. if(fs->root == nil){
  1756. werrstr("vacfileroot: %r");
  1757. vacfsclose(fs);
  1758. return nil;
  1759. }
  1760. return fs;
  1761. }
  1762. int
  1763. vacfssync(VacFs *fs)
  1764. {
  1765. uchar buf[1024];
  1766. VtEntry e;
  1767. VtFile *f;
  1768. VtRoot root;
  1769. /* Sync the entire vacfs to disk. */
  1770. if(vacfileflush(fs->root, 1) < 0)
  1771. return -1;
  1772. if(vtfilelock(fs->root->up->msource, -1) < 0)
  1773. return -1;
  1774. if(vtfileflush(fs->root->up->msource) < 0){
  1775. vtfileunlock(fs->root->up->msource);
  1776. return -1;
  1777. }
  1778. vtfileunlock(fs->root->up->msource);
  1779. /* Prepare the dir stream for the root block. */
  1780. if(getentry(fs->root->source, &e) < 0)
  1781. return -1;
  1782. vtentrypack(&e, buf, 0);
  1783. if(getentry(fs->root->msource, &e) < 0)
  1784. return -1;
  1785. vtentrypack(&e, buf, 1);
  1786. if(getentry(fs->root->up->msource, &e) < 0)
  1787. return -1;
  1788. vtentrypack(&e, buf, 2);
  1789. f = vtfilecreateroot(fs->cache, fs->bsize, fs->bsize, VtDirType);
  1790. vtfilelock(f, VtORDWR);
  1791. if(vtfilewrite(f, buf, 3*VtEntrySize, 0) < 0
  1792. || vtfileflush(f) < 0){
  1793. vtfileunlock(f);
  1794. vtfileclose(f);
  1795. return -1;
  1796. }
  1797. vtfileunlock(f);
  1798. if(getentry(f, &e) < 0){
  1799. vtfileclose(f);
  1800. return -1;
  1801. }
  1802. vtfileclose(f);
  1803. /* Build a root block. */
  1804. memset(&root, 0, sizeof root);
  1805. strcpy(root.type, "vac");
  1806. strcpy(root.name, fs->name);
  1807. memmove(root.score, e.score, VtScoreSize);
  1808. root.blocksize = fs->bsize;
  1809. memmove(root.prev, fs->score, VtScoreSize);
  1810. vtrootpack(&root, buf);
  1811. if(vtwrite(fs->z, fs->score, VtRootType, buf, VtRootSize) < 0){
  1812. werrstr("writing root: %r");
  1813. return -1;
  1814. }
  1815. if(vtsync(fs->z) < 0)
  1816. return -1;
  1817. return 0;
  1818. }