Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include "iotrack.h"
4
#include "dat.h"
5
#include "fns.h"
6
 
7
#define	FIDMOD	127	/* prime */
8
 
9
static Xfs	*xhead;
10
static Xfile	*xfiles[FIDMOD], *freelist;
11
static MLock	xlock, xlocks[FIDMOD], freelock;
12
 
13
static int
14
okmode(int omode, int fmode)
15
{
16
	if(omode == OREAD)
17
		return fmode & 4;
18
	/* else ORDWR */
19
	return (fmode & 6) == 6;
20
}
21
 
22
Xfs *
23
getxfs(char *user, char *name)
24
{
25
	Xfs *xf, *fxf;
26
	Dir *dir;
27
	Qid dqid;
28
	char *p, *q;
29
	long offset;
30
	int fd, omode;
31
 
32
	USED(user);
33
	if(name==nil || name[0]==0)
34
		name = deffile;
35
	if(name == nil){
36
		errno = Enofilsys;
37
		return 0;
38
	}
39
 
40
	/*
41
	 * If the name passed is of the form 'name:offset' then
42
	 * offset is used to prime xf->offset. This allows accessing
43
	 * a FAT-based filesystem anywhere within a partition.
44
	 * Typical use would be to mount a filesystem in the presence
45
	 * of a boot manager programme at the beginning of the disc.
46
	 */
47
	offset = 0;
48
	if(p = strrchr(name, ':')){
49
		*p++ = 0;
50
		offset = strtol(p, &q, 0);
51
		chat("name %s, offset %ld\n", p, offset);
52
		if(offset < 0 || p == q){
53
			errno = Enofilsys;
54
			return 0;
55
		}
56
		offset *= Sectorsize;
57
	}
58
 
59
	if(readonly)
60
		omode = OREAD;
61
	else
62
		omode = ORDWR;
63
	fd = open(name, omode);
64
 
65
	if(fd < 0 && omode==ORDWR){
66
		omode = OREAD;
67
		fd = open(name, omode);
68
	}
69
 
70
	if(fd < 0){
71
		chat("can't open %s: %r\n", name);
72
		errno = Eerrstr;
73
		return 0;
74
	}
75
	dir = dirfstat(fd);
76
	if(dir == nil){
77
		errno = Eio;
78
		close(fd);
79
		return 0;
80
	}
81
 
82
	dqid = dir->qid;
83
	free(dir);
84
	mlock(&xlock);
85
	for(fxf=0,xf=xhead; xf; xf=xf->next){
86
		if(xf->ref == 0){
87
			if(fxf == 0)
88
				fxf = xf;
89
			continue;
90
		}
91
		if(!eqqid(xf->qid, dqid))
92
			continue;
93
		if(strcmp(xf->name, name) != 0 || xf->dev < 0)
94
			continue;
95
		if(devcheck(xf) < 0) /* look for media change */
96
			continue;
97
		if(offset && xf->offset != offset)
98
			continue;
99
		chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
100
		++xf->ref;
101
		unmlock(&xlock);
102
		close(fd);
103
		return xf;
104
	}
105
	if(fxf == nil){
106
		fxf = malloc(sizeof(Xfs));
107
		if(fxf == nil){
108
			unmlock(&xlock);
109
			close(fd);
110
			errno = Enomem;
111
			return nil;
112
		}
113
		fxf->next = xhead;
114
		xhead = fxf;
115
	}
116
	chat("alloc \"%s\", dev=%d...", name, fd);
117
	fxf->name = strdup(name);
118
	fxf->ref = 1;
119
	fxf->qid = dqid;
120
	fxf->dev = fd;
121
	fxf->fmt = 0;
122
	fxf->offset = offset;
123
	fxf->ptr = nil;
124
	fxf->isfat32 = 0;
125
	fxf->omode = omode;
126
	unmlock(&xlock);
127
	return fxf;
128
}
129
 
130
void
131
refxfs(Xfs *xf, int delta)
132
{
133
	mlock(&xlock);
134
	xf->ref += delta;
135
	if(xf->ref == 0){
136
		chat("free \"%s\", dev=%d...", xf->name, xf->dev);
137
		free(xf->name);
138
		free(xf->ptr);
139
		purgebuf(xf);
140
		if(xf->dev >= 0){
141
			close(xf->dev);
142
			xf->dev = -1;
143
		}
144
	}
145
	unmlock(&xlock);
146
}
147
 
148
Xfile *
149
xfile(int fid, int flag)
150
{
151
	Xfile **hp, *f, *pf;
152
	int k;
153
 
154
	k = ((ulong)fid) % FIDMOD;
155
	hp = &xfiles[k];
156
	mlock(&xlocks[k]);
157
	pf = nil;
158
	for(f=*hp; f; f=f->next){
159
		if(f->fid == fid)
160
			break;
161
		pf = f;
162
	}
163
	if(f && pf){
164
		pf->next = f->next;
165
		f->next = *hp;
166
		*hp = f;
167
	}
168
	switch(flag){
169
	default:
170
		panic("xfile");
171
	case Asis:
172
		unmlock(&xlocks[k]);
173
		return (f && f->xf && f->xf->dev < 0) ? nil : f;
174
	case Clean:
175
		break;
176
	case Clunk:
177
		if(f){
178
			*hp = f->next;
179
			unmlock(&xlocks[k]);
180
			clean(f);
181
			mlock(&freelock);
182
			f->next = freelist;
183
			freelist = f;
184
			unmlock(&freelock);
185
		} else
186
			unmlock(&xlocks[k]);
187
		return nil;
188
	}
189
	unmlock(&xlocks[k]);
190
	if(f)
191
		return clean(f);
192
	mlock(&freelock);
193
	if(f = freelist){	/* assign = */
194
		freelist = f->next;
195
		unmlock(&freelock);
196
	} else {
197
		unmlock(&freelock);
198
		f = malloc(sizeof(Xfile));
199
		if(f == nil){
200
			errno = Enomem;
201
			return nil;
202
		}
203
	}
204
	mlock(&xlocks[k]);
205
	f->next = *hp;
206
	*hp = f;
207
	unmlock(&xlocks[k]);
208
	f->fid = fid;
209
	f->flags = 0;
210
	f->qid = (Qid){0,0,0};
211
	f->xf = nil;
212
	f->ptr = nil;
213
	return f;
214
}
215
 
216
Xfile *
217
clean(Xfile *f)
218
{
219
	if(f->ptr){
220
		free(f->ptr);
221
		f->ptr = nil;
222
	}
223
	if(f->xf){
224
		refxfs(f->xf, -1);
225
		f->xf = nil;
226
	}
227
	f->flags = 0;
228
	f->qid = (Qid){0,0,0};
229
	return f;
230
}
231
 
232
/*
233
 * the file at <addr, offset> has moved
234
 * relocate the dos entries of all fids in the same file
235
 */
236
void
237
dosptrreloc(Xfile *f, Dosptr *dp, ulong addr, ulong offset)
238
{
239
	int i;
240
	Xfile *p;
241
	Dosptr *xdp;
242
 
243
	for(i=0; i < FIDMOD; i++){
244
		for(p = xfiles[i]; p != nil; p = p->next){
245
			xdp = p->ptr;
246
			if(p != f && p->xf == f->xf
247
			&& xdp != nil && xdp->addr == addr && xdp->offset == offset){
248
				memmove(xdp, dp, sizeof(Dosptr));
249
				xdp->p = nil;
250
				xdp->d = nil;
251
				p->qid.path = QIDPATH(xdp);
252
			}
253
		}
254
	}
255
}