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