file.c 39 KB

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