file.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <thread.h>
  6. #include <9p.h>
  7. /*
  8. * To avoid deadlock, the following rules must be followed.
  9. * Always lock child then parent, never parent then child.
  10. * If holding the free file lock, do not lock any Files.
  11. */
  12. struct Filelist
  13. {
  14. File *f;
  15. Filelist *link;
  16. };
  17. struct Readdir
  18. {
  19. File *dir;
  20. Filelist *fl;
  21. };
  22. static QLock filelk;
  23. static File *freefilelist;
  24. static File*
  25. allocfile(void)
  26. {
  27. int i, a;
  28. File *f;
  29. enum { N = 16 };
  30. qlock(&filelk);
  31. if(freefilelist == nil){
  32. f = emalloc9p(N*sizeof(*f));
  33. for(i=0; i<N-1; i++)
  34. f[i].aux = &f[i+1];
  35. f[N-1].aux = nil;
  36. f[0].allocd = 1;
  37. freefilelist = f;
  38. }
  39. f = freefilelist;
  40. freefilelist = f->aux;
  41. qunlock(&filelk);
  42. a = f->allocd;
  43. memset(f, 0, sizeof *f);
  44. f->allocd = a;
  45. return f;
  46. }
  47. static void
  48. freefile(File *f)
  49. {
  50. Filelist *fl, *flnext;
  51. for(fl=f->filelist; fl; fl=flnext){
  52. flnext = fl->link;
  53. assert(fl->f == nil);
  54. free(fl);
  55. }
  56. free(f->name);
  57. free(f->uid);
  58. free(f->gid);
  59. free(f->muid);
  60. qlock(&filelk);
  61. assert(f->ref == 0);
  62. f->aux = freefilelist;
  63. freefilelist = f;
  64. qunlock(&filelk);
  65. }
  66. static void
  67. cleanfilelist(File *f)
  68. {
  69. Filelist **l;
  70. Filelist *fl;
  71. /*
  72. * can't delete filelist structures while there
  73. * are open readers of this directory, because
  74. * they might have references to the structures.
  75. * instead, just leave the empty refs in the list
  76. * until there is no activity and then clean up.
  77. */
  78. if(f->readers.ref != 0)
  79. return;
  80. if(f->nxchild == 0)
  81. return;
  82. /*
  83. * no dir readers, file is locked, and
  84. * there are empty entries in the file list.
  85. * clean them out.
  86. */
  87. for(l=&f->filelist; fl=*l; ){
  88. if(fl->f == nil){
  89. *l = (*l)->link;
  90. free(fl);
  91. }else
  92. l = &(*l)->link;
  93. }
  94. f->nxchild = 0;
  95. }
  96. void
  97. closefile(File *f)
  98. {
  99. if(decref(f) == 0){
  100. f->tree->destroy(f);
  101. freefile(f);
  102. }
  103. }
  104. static void
  105. nop(File*)
  106. {
  107. }
  108. int
  109. removefile(File *f)
  110. {
  111. File *fp;
  112. Filelist *fl;
  113. fp = f->parent;
  114. if(fp == nil){
  115. werrstr("no parent");
  116. closefile(f);
  117. return -1;
  118. }
  119. if(fp == f){
  120. werrstr("cannot remove root");
  121. closefile(f);
  122. return -1;
  123. }
  124. wlock(f);
  125. wlock(fp);
  126. if(f->nchild != 0){
  127. werrstr("has children");
  128. wunlock(fp);
  129. wunlock(f);
  130. closefile(f);
  131. return -1;
  132. }
  133. if(f->parent != fp){
  134. werrstr("parent changed underfoot");
  135. wunlock(fp);
  136. wunlock(f);
  137. closefile(f);
  138. return -1;
  139. }
  140. for(fl=fp->filelist; fl; fl=fl->link)
  141. if(fl->f == f)
  142. break;
  143. assert(fl != nil && fl->f == f);
  144. fl->f = nil;
  145. fp->nchild--;
  146. fp->nxchild++;
  147. f->parent = nil;
  148. wunlock(f);
  149. cleanfilelist(fp);
  150. wunlock(fp);
  151. closefile(fp); /* reference from child */
  152. closefile(f); /* reference from tree */
  153. closefile(f);
  154. return 0;
  155. }
  156. File*
  157. createfile(File *fp, char *name, char *uid, ulong perm, void *aux)
  158. {
  159. File *f;
  160. Filelist **l, *fl;
  161. Tree *t;
  162. if((fp->qid.type&QTDIR) == 0){
  163. werrstr("create in non-directory");
  164. return nil;
  165. }
  166. wlock(fp);
  167. /*
  168. * We might encounter blank spots along the
  169. * way due to deleted files that have not yet
  170. * been flushed from the file list. Don't reuse
  171. * those - some apps (e.g., omero) depend on
  172. * the file order reflecting creation order.
  173. * Always create at the end of the list.
  174. */
  175. for(l=&fp->filelist; fl=*l; l=&fl->link){
  176. if(fl->f && strcmp(fl->f->name, name) == 0){
  177. wunlock(fp);
  178. werrstr("file already exists");
  179. return nil;
  180. }
  181. }
  182. fl = emalloc9p(sizeof *fl);
  183. *l = fl;
  184. f = allocfile();
  185. f->name = estrdup9p(name);
  186. f->uid = estrdup9p(uid ? uid : fp->uid);
  187. f->gid = estrdup9p(fp->gid);
  188. f->muid = estrdup9p(uid ? uid : "unknown");
  189. f->aux = aux;
  190. f->mode = perm;
  191. t = fp->tree;
  192. lock(&t->genlock);
  193. f->qid.path = t->qidgen++;
  194. unlock(&t->genlock);
  195. if(perm & DMDIR)
  196. f->qid.type |= QTDIR;
  197. if(perm & DMAPPEND)
  198. f->qid.type |= QTAPPEND;
  199. if(perm & DMEXCL)
  200. f->qid.type |= QTEXCL;
  201. f->mode = perm;
  202. f->atime = f->mtime = time(0);
  203. f->length = 0;
  204. f->parent = fp;
  205. incref(fp);
  206. f->tree = fp->tree;
  207. incref(f); /* being returned */
  208. incref(f); /* for the tree */
  209. fl->f = f;
  210. fp->nchild++;
  211. wunlock(fp);
  212. return f;
  213. }
  214. static File*
  215. walkfile1(File *dir, char *elem)
  216. {
  217. File *fp;
  218. Filelist *fl;
  219. rlock(dir);
  220. if(strcmp(elem, "..") == 0){
  221. fp = dir->parent;
  222. incref(fp);
  223. runlock(dir);
  224. closefile(dir);
  225. return fp;
  226. }
  227. fp = nil;
  228. for(fl=dir->filelist; fl; fl=fl->link)
  229. if(fl->f && strcmp(fl->f->name, elem)==0){
  230. fp = fl->f;
  231. incref(fp);
  232. break;
  233. }
  234. runlock(dir);
  235. closefile(dir);
  236. return fp;
  237. }
  238. File*
  239. walkfile(File *f, char *path)
  240. {
  241. char *os, *s, *nexts;
  242. if(strchr(path, '/') == nil)
  243. return walkfile1(f, path); /* avoid malloc */
  244. os = s = estrdup9p(path);
  245. for(; *s; s=nexts){
  246. if(nexts = strchr(s, '/'))
  247. *nexts++ = '\0';
  248. else
  249. nexts = s+strlen(s);
  250. f = walkfile1(f, s);
  251. if(f == nil)
  252. break;
  253. }
  254. free(os);
  255. return f;
  256. }
  257. Tree*
  258. alloctree(char *uid, char *gid, ulong mode, void (*destroy)(File*))
  259. {
  260. char *muid;
  261. Tree *t;
  262. File *f;
  263. t = emalloc9p(sizeof *t);
  264. f = allocfile();
  265. f->name = estrdup9p("/");
  266. if(uid == nil){
  267. uid = getuser();
  268. if(uid == nil)
  269. uid = "none";
  270. }
  271. uid = estrdup9p(uid);
  272. if(gid == nil)
  273. gid = estrdup9p(uid);
  274. else
  275. gid = estrdup9p(gid);
  276. muid = estrdup9p(uid);
  277. f->qid = (Qid){0, 0, QTDIR};
  278. f->length = 0;
  279. f->atime = f->mtime = time(0);
  280. f->mode = DMDIR | mode;
  281. f->tree = t;
  282. f->parent = f;
  283. f->uid = uid;
  284. f->gid = gid;
  285. f->muid = muid;
  286. incref(f);
  287. t->root = f;
  288. t->qidgen = 0;
  289. t->dirqidgen = 1;
  290. if(destroy == nil)
  291. destroy = nop;
  292. t->destroy = destroy;
  293. return t;
  294. }
  295. static void
  296. _freefiles(File *f)
  297. {
  298. Filelist *fl, *flnext;
  299. for(fl=f->filelist; fl; fl=flnext){
  300. flnext = fl->link;
  301. _freefiles(fl->f);
  302. free(fl);
  303. }
  304. f->tree->destroy(f);
  305. freefile(f);
  306. }
  307. void
  308. freetree(Tree *t)
  309. {
  310. _freefiles(t->root);
  311. free(t);
  312. }
  313. Readdir*
  314. opendirfile(File *dir)
  315. {
  316. Readdir *r;
  317. rlock(dir);
  318. if((dir->mode & DMDIR)==0){
  319. runlock(dir);
  320. return nil;
  321. }
  322. r = emalloc9p(sizeof(*r));
  323. /*
  324. * This reference won't go away while we're
  325. * using it because file list entries are not freed
  326. * until the directory is removed and all refs to
  327. * it (our fid is one!) have gone away.
  328. */
  329. r->fl = dir->filelist;
  330. r->dir = dir;
  331. incref(&dir->readers);
  332. runlock(dir);
  333. return r;
  334. }
  335. long
  336. readdirfile(Readdir *r, uchar *buf, long n)
  337. {
  338. long x, m;
  339. Filelist *fl;
  340. for(fl=r->fl, m=0; fl && m+2<=n; fl=fl->link, m+=x){
  341. if(fl->f == nil)
  342. x = 0;
  343. else if((x=convD2M(fl->f, buf+m, n-m)) <= BIT16SZ)
  344. break;
  345. }
  346. r->fl = fl;
  347. return m;
  348. }
  349. void
  350. closedirfile(Readdir *r)
  351. {
  352. if(decref(&r->dir->readers) == 0){
  353. wlock(r->dir);
  354. cleanfilelist(r->dir);
  355. wunlock(r->dir);
  356. }
  357. free(r);
  358. }