xref: /plan9/sys/src/cmd/9660srv/xfile.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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 	if(waserror()){
33 		close(fd);
34 		nexterror();
35 	}
36 	if(dirfstat(fd, &dir) < 0)
37 		error("I/O error");
38 	for(fxf=0,xf=xhead; xf; xf=xf->next){
39 		if(xf->name == 0){
40 			if(fxf == 0)
41 				fxf = xf;
42 			continue;
43 		}
44 		if(xf->qid.path != dir.qid.path || xf->qid.vers != dir.qid.vers)
45 			continue;
46 		if(xf->type != dir.type || xf->fdev != dir.dev)
47 			continue;
48 		xf->ref++;
49 		chat("incref=%d, \"%s\", dev=%d...", xf->ref, xf->name, xf->dev);
50 		close(fd);
51 		poperror();
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 	poperror();
67 	return fxf;
68 }
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 
86 void
87 refxfs(Xfs *xf, int delta)
88 {
89 	xf->ref += delta;
90 	if(xf->ref == 0){
91 		if(xf->d)
92 			putxdata(xf->d);
93 		if(xf->ptr)
94 			free(xf->ptr);
95 		free(xf);
96 	}
97 }
98 
99 Xfile*
100 xfile(int fid, int flag)
101 {
102 	int k = fid%FIDMOD;
103 	Xfile **hp=&xfiles[k], *f, *pf;
104 
105 	for(f=*hp,pf=0; f; pf=f,f=f->next)
106 		if(f->fid == fid)
107 			break;
108 	if(f && pf){
109 		pf->next = f->next;
110 		f->next = *hp;
111 		*hp = f;
112 	}
113 	switch(flag){
114 	default:
115 		panic(0, "xfile");
116 	case Asis:
117 		if(f == 0)
118 			error("unassigned fid");
119 		return f;
120 	case Clean:
121 		break;
122 	case Clunk:
123 		if(f){
124 			*hp = f->next;
125 			clean(f);
126 			f->next = freelist;
127 			freelist = f;
128 		}
129 		return 0;
130 	}
131 	if(f)
132 		return clean(f);
133 	if(f = freelist)	/* assign = */
134 		freelist = f->next;
135 	else
136 		f = ealloc(sizeof(Xfile));
137 	f->next = *hp;
138 	*hp = f;
139 	f->xf = 0;
140 	f->fid = fid;
141 	f->flags = 0;
142 	f->qid = (Qid){0,0};
143 	f->len = 0;
144 	f->ptr = 0;
145 	return f;
146 }
147 
148 static Xfile *
149 clean(Xfile *f)
150 {
151 	if(f->xf){
152 		refxfs(f->xf, -1);
153 		f->xf = 0;
154 	}
155 	if(f->len){
156 		free(f->ptr);
157 		f->len = 0;
158 	}
159 	f->ptr = 0;
160 	f->flags = 0;
161 	f->qid = (Qid){0,0};
162 	return f;
163 }
164 
165 void
166 xread(Iobuf *p)
167 {
168 	Xdata *dev;
169 	long addr;
170 
171 	dev = p->dev;
172 	addr = p->addr;
173 	chat("xread %d,%d...", dev->dev, addr);
174 
175 	seek(dev->dev, addr*Sectorsize, 0);
176 	if(read(dev->dev, p->iobuf, Sectorsize) != Sectorsize)
177 		error("I/O read error");
178 }
179