xref: /plan9/sys/src/cmd/ext2srv/xfile.c (revision dc5a79c1208f0704eeb474acc990728f8b4854f5)
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include "dat.h"
7 #include "fns.h"
8 
9 
10 static Xfs	*xhead;
11 static Xfile *freelist;
12 static Lock	xlock, freelock;
13 
14 int	client;
15 
16 Xfs *
getxfs(char * name)17 getxfs(char *name)
18 {
19 	int fd;
20 	Dir *dir;
21 	Xfs *xf, *fxf;
22 
23 	if(name==0 || name[0]==0)
24 		name = deffile;
25 	if(name == 0){
26 		errno = Enofilsys;
27 		return 0;
28 	}
29 	fd = open(name, rdonly ? OREAD : ORDWR);
30 	if(fd < 0){
31 		errno = Enonexist;
32 		return 0;
33 	}
34 	if((dir = dirfstat(fd)) == 0){
35 		errno = Eio;
36 		close(fd);
37 		return 0;
38 	}
39 	lock(&xlock);
40 	for(fxf=0, xf=xhead; xf; xf=xf->next){
41 		if(xf->ref == 0){
42 			if(fxf == 0)
43 				fxf = xf;
44 			continue;
45 		}
46 		if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
47 			continue;
48 		if(strcmp(xf->name, name) != 0 || xf->dev < 0)
49 			continue;
50 		chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
51 		++xf->ref;
52 		unlock(&xlock);
53 		close(fd);
54 		free(dir);
55 		return xf;
56 	}
57 	if(fxf==0){
58 		fxf = malloc(sizeof(Xfs));
59 		if(fxf==0){
60 			unlock(&xlock);
61 			close(fd);
62 			free(dir);
63 			errno = Enomem;
64 			return 0;
65 		}
66 		fxf->next = xhead;
67 		xhead = fxf;
68 	}
69 	chat("alloc \"%s\", dev=%d...", name, fd);
70 	fxf->name = strdup(name);
71 	fxf->ref = 1;
72 	fxf->qid = dir->qid;
73 	fxf->dev = fd;
74 	fxf->fmt = 0;
75 	fxf->ptr = 0;
76 	free(dir);
77 	if( ext2fs(fxf)<0 ){
78 		xhead = fxf->next;
79 		free(fxf);
80 		unlock(&xlock);
81 		return 0;
82 	}
83 	unlock(&xlock);
84 	return fxf;
85 }
86 
87 void
refxfs(Xfs * xf,int delta)88 refxfs(Xfs *xf, int delta)
89 {
90 	lock(&xlock);
91 	xf->ref += delta;
92 	if(xf->ref == 0){
93 		/*mchat("free \"%s\", dev=%d...", xf->name, xf->dev);
94 		dumpbuf();*/
95 		CleanSuper(xf);
96 		syncbuf();
97 		free(xf->name);
98 		purgebuf(xf);
99 		if(xf->dev >= 0){
100 			close(xf->dev);
101 			xf->dev = -1;
102 		}
103 	}
104 	unlock(&xlock);
105 }
106 
107 Xfile *
xfile(Fid * fid,int flag)108 xfile(Fid *fid, int flag)
109 {
110 	Xfile *f;
111 
112 	f = (Xfile*)fid->aux;
113 	switch(flag){
114 	default:
115 		panic("xfile");
116 	case Asis:
117 		return (f && f->xf && f->xf->dev < 0) ? 0 : f;
118 	case Clean:
119 		if (f) chat("Clean and fid->aux already exists\n");
120 		break;
121 	case Clunk:
122 		if(f){
123 			clean(f);
124 			lock(&freelock);
125 			f->next = freelist;
126 			freelist = f;
127 			unlock(&freelock);
128 			fid->aux = 0;
129 		}
130 		return 0;
131 	}
132 	if(f)
133 		return clean(f);
134 	lock(&freelock);
135 	if(f = freelist){	/* assign = */
136 		freelist = f->next;
137 		unlock(&freelock);
138 	} else {
139 		unlock(&freelock);
140 		f = malloc(sizeof(Xfile));
141 	}
142 	fid->aux = f;
143 	f->fid = fid->fid;
144 	f->client = client;
145 	f->xf = 0;
146 	f->ptr = 0;
147 	f->root = 0;
148 	return f;
149 }
150 Xfile *
clean(Xfile * f)151 clean(Xfile *f)
152 {
153 	if(f->xf && f->root){
154 		refxfs(f->xf, -1);
155 		f->xf = 0;
156 	}
157 	f->xf = 0;
158 	f->root = 0;
159 	f->dirindex = 0;
160 	return f;
161 }
162