xfile.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include "dat.h"
  6. #include "fns.h"
  7. static Xfile* clean(Xfile*);
  8. #define FIDMOD 127 /* prime */
  9. static Xdata* xhead;
  10. static Xfile* xfiles[FIDMOD];
  11. static Xfile* freelist;
  12. Xdata*
  13. getxdata(char *name)
  14. {
  15. int fd;
  16. Dir *dir;
  17. Xdata *xf, *fxf;
  18. int flag;
  19. if(name[0] == 0)
  20. name = deffile;
  21. if(name == 0)
  22. error(Enofile);
  23. flag = (access(name, 6) == 0) ? ORDWR : OREAD;
  24. fd = open(name, flag);
  25. if(fd < 0)
  26. error(Enonexist);
  27. dir = nil;
  28. if(waserror()){
  29. close(fd);
  30. free(dir);
  31. nexterror();
  32. }
  33. if((dir = dirfstat(fd)) == nil)
  34. error("I/O error");
  35. if(dir->qid.type != QTFILE)
  36. error("attach name not a plain file");
  37. for(fxf=0,xf=xhead; xf; xf=xf->next){
  38. if(xf->name == 0){
  39. if(fxf == 0)
  40. fxf = xf;
  41. continue;
  42. }
  43. if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
  44. continue;
  45. if(xf->type != dir->type || xf->fdev != dir->dev)
  46. continue;
  47. xf->ref++;
  48. chat("incref=%d, \"%s\", dev=%d...", xf->ref, xf->name, xf->dev);
  49. close(fd);
  50. poperror();
  51. free(dir);
  52. return xf;
  53. }
  54. if(fxf==0){
  55. fxf = ealloc(sizeof(Xfs));
  56. fxf->next = xhead;
  57. xhead = fxf;
  58. }
  59. chat("alloc \"%s\", dev=%d...", name, fd);
  60. fxf->ref = 1;
  61. fxf->name = strcpy(ealloc(strlen(name)+1), name);
  62. fxf->qid = dir->qid;
  63. fxf->type = dir->type;
  64. fxf->fdev = dir->dev;
  65. fxf->dev = fd;
  66. free(dir);
  67. poperror();
  68. return fxf;
  69. }
  70. static void
  71. putxdata(Xdata *d)
  72. {
  73. if(d->ref <= 0)
  74. panic(0, "putxdata");
  75. d->ref--;
  76. chat("decref=%d, \"%s\", dev=%d...", d->ref, d->name, d->dev);
  77. if(d->ref == 0){
  78. chat("purgebuf...");
  79. purgebuf(d);
  80. close(d->dev);
  81. free(d->name);
  82. d->name = 0;
  83. }
  84. }
  85. void
  86. refxfs(Xfs *xf, int delta)
  87. {
  88. xf->ref += delta;
  89. if(xf->ref == 0){
  90. if(xf->d)
  91. putxdata(xf->d);
  92. if(xf->ptr)
  93. free(xf->ptr);
  94. free(xf);
  95. }
  96. }
  97. Xfile*
  98. xfile(int fid, int flag)
  99. {
  100. int k = fid%FIDMOD;
  101. Xfile **hp=&xfiles[k], *f, *pf;
  102. for(f=*hp,pf=0; f; pf=f,f=f->next)
  103. if(f->fid == fid)
  104. break;
  105. if(f && pf){
  106. pf->next = f->next;
  107. f->next = *hp;
  108. *hp = f;
  109. }
  110. switch(flag){
  111. default:
  112. panic(0, "xfile");
  113. case Asis:
  114. if(f == 0)
  115. error("unassigned fid");
  116. return f;
  117. case Clean:
  118. break;
  119. case Clunk:
  120. if(f){
  121. *hp = f->next;
  122. clean(f);
  123. f->next = freelist;
  124. freelist = f;
  125. }
  126. return 0;
  127. }
  128. if(f)
  129. return clean(f);
  130. if(f = freelist) /* assign = */
  131. freelist = f->next;
  132. else
  133. f = ealloc(sizeof(Xfile));
  134. f->next = *hp;
  135. *hp = f;
  136. f->xf = 0;
  137. f->fid = fid;
  138. f->flags = 0;
  139. f->qid = (Qid){0,0,0};
  140. f->len = 0;
  141. f->ptr = 0;
  142. return f;
  143. }
  144. static Xfile *
  145. clean(Xfile *f)
  146. {
  147. if(f->xf){
  148. refxfs(f->xf, -1);
  149. f->xf = 0;
  150. }
  151. if(f->len){
  152. free(f->ptr);
  153. f->len = 0;
  154. }
  155. f->ptr = 0;
  156. f->flags = 0;
  157. f->qid = (Qid){0,0,0};
  158. return f;
  159. }