file.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. File *f;
  14. Filelist *link;
  15. };
  16. static QLock filelk;
  17. static File *freefilelist;
  18. static File*
  19. allocfile(void)
  20. {
  21. int i, a;
  22. File *f;
  23. enum { N = 16 };
  24. qlock(&filelk);
  25. if(freefilelist == nil){
  26. f = emalloc9p(N*sizeof(*f));
  27. for(i=0; i<N-1; i++)
  28. f[i].aux = &f[i+1];
  29. f[N-1].aux = nil;
  30. f[0].allocd = 1;
  31. freefilelist = f;
  32. }
  33. f = freefilelist;
  34. freefilelist = f->aux;
  35. qunlock(&filelk);
  36. a = f->allocd;
  37. memset(f, 0, sizeof *f);
  38. f->allocd = a;
  39. return f;
  40. }
  41. static void
  42. freefile(File *f)
  43. {
  44. Filelist *fl, *flnext;
  45. for(fl=f->filelist; fl; fl=flnext){
  46. flnext = fl->link;
  47. assert(fl->f == nil);
  48. free(fl);
  49. }
  50. free(f->name);
  51. free(f->uid);
  52. free(f->gid);
  53. free(f->muid);
  54. qlock(&filelk);
  55. assert(f->ref == 0);
  56. f->aux = freefilelist;
  57. freefilelist = f;
  58. qunlock(&filelk);
  59. }
  60. void
  61. closefile(File *f)
  62. {
  63. if(decref(f) == 0){
  64. f->tree->destroy(f);
  65. freefile(f);
  66. }
  67. }
  68. static void
  69. nop(File*)
  70. {
  71. }
  72. int
  73. removefile(File *f)
  74. {
  75. File *fp;
  76. Filelist *fl;
  77. fp = f->parent;
  78. if(fp == nil){
  79. werrstr("no parent");
  80. closefile(f);
  81. return -1;
  82. }
  83. if(fp == f){
  84. werrstr("cannot remove root");
  85. closefile(f);
  86. return -1;
  87. }
  88. wlock(fp);
  89. wlock(f);
  90. if(f->nchild != 0){
  91. werrstr("has children");
  92. wunlock(f);
  93. wunlock(fp);
  94. closefile(f);
  95. return -1;
  96. }
  97. if(f->parent != fp){
  98. werrstr("parent changed underfoot");
  99. wunlock(f);
  100. wunlock(fp);
  101. closefile(f);
  102. return -1;
  103. }
  104. for(fl=fp->filelist; fl; fl=fl->link)
  105. if(fl->f == f)
  106. break;
  107. assert(fl != nil && fl->f == f);
  108. fl->f = nil;
  109. fp->nchild--;
  110. f->parent = nil;
  111. wunlock(fp);
  112. wunlock(f);
  113. closefile(fp); /* reference from child */
  114. closefile(f); /* reference from tree */
  115. closefile(f);
  116. return 0;
  117. }
  118. File*
  119. createfile(File *fp, char *name, char *uid, ulong perm, void *aux)
  120. {
  121. File *f;
  122. Filelist *fl, *freel;
  123. Tree *t;
  124. if((fp->qid.type&QTDIR) == 0){
  125. werrstr("create in non-directory");
  126. return nil;
  127. }
  128. freel = nil;
  129. wlock(fp);
  130. for(fl=fp->filelist; fl; fl=fl->link){
  131. if(fl->f == nil)
  132. freel = fl;
  133. else if(strcmp(fl->f->name, name) == 0){
  134. wunlock(fp);
  135. werrstr("file already exists");
  136. return nil;
  137. }
  138. }
  139. if(freel == nil){
  140. freel = emalloc9p(sizeof *freel);
  141. freel->link = fp->filelist;
  142. fp->filelist = freel;
  143. }
  144. f = allocfile();
  145. f->name = estrdup9p(name);
  146. f->uid = estrdup9p(uid ? uid : fp->uid);
  147. f->gid = estrdup9p(fp->gid);
  148. f->muid = estrdup9p(uid ? uid : "unknown");
  149. f->aux = aux;
  150. f->mode = perm;
  151. t = fp->tree;
  152. lock(&t->genlock);
  153. f->qid.path = t->qidgen++;
  154. unlock(&t->genlock);
  155. if(perm & DMDIR)
  156. f->qid.type |= QTDIR;
  157. if(perm & DMAPPEND)
  158. f->qid.type |= QTAPPEND;
  159. if(perm & DMEXCL)
  160. f->qid.type |= QTEXCL;
  161. f->mode = perm;
  162. f->atime = f->mtime = time(0);
  163. f->length = 0;
  164. f->parent = fp;
  165. incref(fp);
  166. f->tree = fp->tree;
  167. incref(f); /* being returned */
  168. incref(f); /* for the tree */
  169. freel->f = f;
  170. fp->nchild++;
  171. wunlock(fp);
  172. return f;
  173. }
  174. static File*
  175. walkfile1(File *dir, char *elem)
  176. {
  177. File *fp;
  178. Filelist *fl;
  179. rlock(dir);
  180. if(strcmp(elem, "..") == 0){
  181. fp = dir->parent;
  182. incref(fp);
  183. runlock(dir);
  184. closefile(dir);
  185. return fp;
  186. }
  187. fp = nil;
  188. for(fl=dir->filelist; fl; fl=fl->link)
  189. if(fl->f && strcmp(fl->f->name, elem)==0){
  190. fp = fl->f;
  191. incref(fp);
  192. break;
  193. }
  194. runlock(dir);
  195. closefile(dir);
  196. return fp;
  197. }
  198. File*
  199. walkfile(File *f, char *path)
  200. {
  201. char *os, *s, *nexts;
  202. File *nf;
  203. if(strchr(path, '/') == nil)
  204. return walkfile1(f, path); /* avoid malloc */
  205. os = s = estrdup9p(path);
  206. incref(f);
  207. for(; *s; s=nexts){
  208. if(nexts = strchr(s, '/'))
  209. *nexts++ = '\0';
  210. else
  211. nexts = s+strlen(s);
  212. nf = walkfile1(f, s);
  213. decref(f);
  214. f = nf;
  215. if(f == nil)
  216. break;
  217. }
  218. free(os);
  219. return f;
  220. }
  221. Tree*
  222. alloctree(char *uid, char *gid, ulong mode, void (*destroy)(File*))
  223. {
  224. char *muid;
  225. Tree *t;
  226. File *f;
  227. t = emalloc9p(sizeof *t);
  228. f = allocfile();
  229. f->name = estrdup9p("/");
  230. if(uid == nil){
  231. if(uid = getuser())
  232. uid = estrdup9p(uid);
  233. }
  234. if(uid == nil)
  235. uid = estrdup9p("none");
  236. else
  237. uid = estrdup9p(uid);
  238. if(gid == nil)
  239. gid = estrdup9p(uid);
  240. else
  241. gid = estrdup9p(gid);
  242. muid = estrdup9p(uid);
  243. f->qid = (Qid){0, 0, QTDIR};
  244. f->length = 0;
  245. f->atime = f->mtime = time(0);
  246. f->mode = DMDIR | mode;
  247. f->tree = t;
  248. f->parent = f;
  249. f->uid = uid;
  250. f->gid = gid;
  251. f->muid = muid;
  252. incref(f);
  253. t->root = f;
  254. t->qidgen = 0;
  255. t->dirqidgen = 1;
  256. if(destroy == nil)
  257. destroy = nop;
  258. t->destroy = destroy;
  259. return t;
  260. }
  261. static void
  262. _freefiles(File *f)
  263. {
  264. Filelist *fl, *flnext;
  265. for(fl=f->filelist; fl; fl=flnext){
  266. flnext = fl->link;
  267. _freefiles(fl->f);
  268. free(fl);
  269. }
  270. f->tree->destroy(f);
  271. freefile(f);
  272. }
  273. void
  274. freetree(Tree *t)
  275. {
  276. _freefiles(t->root);
  277. free(t);
  278. }
  279. struct Readdir {
  280. Filelist *fl;
  281. };
  282. Readdir*
  283. opendirfile(File *dir)
  284. {
  285. Readdir *r;
  286. rlock(dir);
  287. if((dir->mode & DMDIR)==0){
  288. runlock(dir);
  289. return nil;
  290. }
  291. r = emalloc9p(sizeof(*r));
  292. /*
  293. * This reference won't go away while we're using it
  294. * since we are dir->rdir.
  295. */
  296. r->fl = dir->filelist;
  297. runlock(dir);
  298. return r;
  299. }
  300. long
  301. readdirfile(Readdir *r, uchar *buf, long n)
  302. {
  303. long x, m;
  304. Filelist *fl;
  305. for(fl=r->fl, m=0; fl && m+2<=n; fl=fl->link, m+=x){
  306. if(fl->f == nil)
  307. x = 0;
  308. else if((x=convD2M(fl->f, buf+m, n-m)) <= BIT16SZ)
  309. break;
  310. }
  311. r->fl = fl;
  312. return m;
  313. }
  314. void
  315. closedirfile(Readdir *r)
  316. {
  317. free(r);
  318. }