xref: /plan9/sys/src/cmd/9660srv/xfile.c (revision 4f28177105e14bc5c70ae9ec986773133c757004)
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*
getxdata(char * name)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
putxdata(Xdata * d)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
refxfs(Xfs * xf,int delta)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*
xfile(int fid,int flag)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 *
clean(Xfile * f)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 }
170 
171