xref: /inferno-os/liblogfs/srv.c (revision 1981fff245dfce579ef416fa767eb69d462039e9)
1 #include "logfsos.h"
2 #include "logfs.h"
3 #include "fcall.h"
4 #include "local.h"
5 
6 static char *unimp = "unimplemented";
7 char *logfsbadfid = "invalid fid";
8 
9 char *
10 logfsstrdup(char *p)
11 {
12 	int l;
13 	char *q;
14 	if(p == nil)
15 		return nil;
16 	l = strlen(p);
17 	q = logfsrealloc(nil, l + 1);
18 	if(q == nil)
19 		return nil;
20 	return strcpy(q, p);
21 }
22 
23 static
24 mkdirentry(LogfsServer *server, Entry *e, int inuse, ulong path, Entry *parent, char *name, char *uid, char *gid,
25 	ulong mtime, char *muid, ulong perm)
26 {
27 //print("mkdirentry 0x%.8lux\n", e);
28 	e->inuse = inuse;
29 	e->qid.path = path;
30 	e->qid.vers = 0;
31 	e->qid.type = QTDIR;
32 	e->parent = parent;
33 	e->name = name;
34 	e->uid = logfsisustadd(server->is, uid);
35 	e->gid = logfsisustadd(server->is, gid);
36 	e->mtime = mtime;
37 	e->muid = logfsisustadd(server->is, muid);
38 	e->perm = perm | DMDIR;
39 	e->next = nil;
40 	return e->uid != nil && e->muid != nil && e->name != nil;
41 }
42 
43 void
44 logfsentryfree(Entry *e)
45 {
46 	logfsfreemem(e->name);
47 	if((e->qid.type & QTDIR) == 0)
48 		logfsextentlistfree(&e->u.file.extent);
49 	logfsfreemem(e);
50 }
51 
52 char *
53 logfsentrynew(LogfsServer *server, int inuse, u32int path, Entry *parent, char *name, char *uid, char *gid,
54 u32int mtime, char *muid, u32int perm, ulong cvers, ulong length, Entry **ep)
55 {
56 	Entry *e;
57 	char *errmsg;
58 	e = logfsrealloc(nil, sizeof(*e));
59 	if(e == nil)
60 		return Enomem;
61 	e->inuse = inuse;
62 	e->qid.path = path;
63 	e->qid.vers = 0;
64 	e->qid.type = perm >> 24;
65 	e->parent = parent;
66 	e->name = logfsstrdup(name);
67 	e->uid = logfsisustadd(server->is, uid);
68 	e->gid = logfsisustadd(server->is, gid);
69 	e->muid = logfsisustadd(server->is, muid);
70 	if(e->uid == nil || e->gid == nil || e->muid == nil || e->name == nil) {
71 		logfsentryfree(e);
72 		return Enomem;
73 	}
74 	e->mtime = mtime;
75 	if(perm & DMDIR)
76 		e->perm = perm & (~0777 | (parent->perm & 0777));
77 	else {
78 		e->perm = perm & (~0666 | (parent->perm & 0666));
79 		e->u.file.cvers = cvers;
80 		e->u.file.length = length;
81 		errmsg = logfsextentlistnew(&e->u.file.extent);
82 		if(errmsg) {
83 			logfsentryfree(e);
84 			return errmsg;
85 		}
86 	}
87 //print("e 0x%.8lux perm 0%.uo\n", e, e->perm);
88 	*ep = e;
89 	return nil;
90 
91 }
92 
93 void
94 logfsentryclunk(Entry *e)
95 {
96 	e->inuse--;
97 	if(e->inuse <= 0)
98 		logfsentryfree(e);
99 }
100 
101 char *
102 logfsservernew(LogfsBoot *lb, LogfsLowLevel *ll, LogfsIdentityStore *is, ulong openflags, int trace, LogfsServer **srvp)
103 {
104 	LogfsServer *srv;
105 	char *errmsg;
106 	Path *p;
107 
108 	if(trace > 1)
109 		print("logfsservernew()\n");
110 	if(ll->l2pagesperblock > 5)
111 		return "more than 32 pages per block";
112 	if((1 << (ll->pathbits - L2LogSweeps - L2BlockCopies)) < ll->blocks)
113 		return "too many blocks";
114 	srv = logfsrealloc(nil, sizeof(*srv));
115 	if(srv == nil) {
116 	memerror:
117 		errmsg = Enomem;
118 	err:
119 		logfsserverfree(&srv);
120 		return errmsg;
121 	}
122 	errmsg = logfsfidmapnew(&srv->fidmap);
123 	if(errmsg)
124 		goto memerror;
125 	errmsg = logfspathmapnew(&srv->pathmap);
126 	if(errmsg)
127 		goto memerror;
128 	srv->is = is;
129 	srv->ll = ll;
130 	srv->trace = trace;
131 	srv->lb = lb;
132 	srv->openflags = openflags;
133 	if(!mkdirentry(srv, &srv->root, 1, 0, &srv->root, "", "inferno", "sys", logfsnow(), "inferno", 0777))
134 		goto memerror;
135 	errmsg = logfspathmapnewentry(srv->pathmap, 0, &srv->root, &p);
136 	/* p is guaranteed to be non null */
137 	if(errmsg)
138 		goto memerror;
139 	errmsg = logfslogsegmentnew(srv, 0, &srv->activelog);
140 	if(errmsg)
141 		goto memerror;
142 	srv->ndatablocks = 0;
143 	srv->datablock = logfsrealloc(nil, sizeof(DataBlock) * ll->blocks);
144 	if(srv->datablock == nil)
145 		goto memerror;
146 	errmsg = logfsscan(srv);
147 	if(errmsg)
148 		goto err;
149 	errmsg = logfsreplay(srv, srv->sweptlog, 0);
150 	if(errmsg)
151 		goto err;
152 	errmsg = logfsreplay(srv, srv->activelog, srv->sweptlog != nil);
153 	if(errmsg)
154 		goto err;
155 	logfsreplayfinddata(srv);
156 	*srvp = srv;
157 	return nil;
158 }
159 
160 static void
161 freeentrylist(Entry *e)
162 {
163 	Entry *next;
164 	while(e) {
165 		next = e->next;
166 		if(e->qid.type & QTDIR)
167 			freeentrylist(e->u.dir.list);
168 		logfsentryfree(e);
169 		e = next;
170 	}
171 }
172 
173 void
174 logfsserverfree(LogfsServer **serverp)
175 {
176 	LogfsServer *server = *serverp;
177 	if(server) {
178 		logfsfidmapfree(&server->fidmap);
179 		logfslogsegmentfree(&server->activelog);
180 		logfslogsegmentfree(&server->sweptlog);
181 		logfspathmapfree(&server->pathmap);
182 		logfsfreemem(server->datablock);
183 		logfsfreemem(server);
184 		freeentrylist(server->root.u.dir.list);
185 		*serverp = nil;
186 	}
187 }
188 
189 char *
190 logfsserverattach(LogfsServer *server, u32int fid, char *uname, Qid *qid)
191 {
192 	char *errmsg;
193 	Fid *f;
194 	if(server->trace > 1)
195 		print("logfsserverattach(%ud, %s)\n", fid, uname);
196 	errmsg = logfsfidmapnewentry(server->fidmap, fid, &f);
197 	if(errmsg)
198 		return errmsg;
199 	f->uname = logfsisustadd(server->is, uname);
200 	if(f->uname == nil) {
201 		logfsfidmapclunk(server->fidmap, fid);
202 		return Enomem;
203 	}
204 	f->entry = &server->root;
205 	f->entry->inuse++;
206 	*qid = f->entry->qid;
207 	return nil;
208 }
209 
210 static void
211 id2name(LogfsIdentityStore *is, char *id, char **namep, int *badp, int *lenp)
212 {
213 	char *name;
214 	if(id == logfsisgroupnonename)
215 		name = id;
216 	else {
217 		name = logfsisfindnamefromid(is, id);
218 		if(name == nil) {
219 			*badp = 2;
220 			name = id;
221 		}
222 	}
223 	*lenp = strlen(name);
224 	*namep = name;
225 }
226 
227 u32int
228 logfsflattenentry(LogfsIdentityStore *is, uchar *buf, u32int limit, Entry *e)
229 {
230 	int unamelen, gnamelen, munamelen, namelen;
231 	uint len;
232 	uchar *p;
233 	int unamebad = 0, gnamebad = 0, munamebad = 0;
234 	char *uname, *gname, *muname;
235 
236 	id2name(is, e->uid, &uname, &unamebad, &unamelen);
237 	id2name(is, e->gid, &gname, &gnamebad, &gnamelen);
238 	id2name(is, e->muid, &muname, &munamebad, &munamelen);
239 	namelen = strlen(e->name);
240 	len = 49 + unamelen + unamebad + gnamelen + gnamebad + munamelen + munamebad + namelen;
241 	if(buf == nil)
242 		return len;
243 	if(len > limit)
244 		return 0;
245 	p = buf;
246 	/* size */		PBIT16(p, len - BIT16SZ); p += BIT16SZ;
247 	/* type */		p += BIT16SZ;
248 	/* dev */		p += BIT32SZ;
249 	/* qid.type */	*p++ = e->qid.type;
250 	/* qid.vers */	PBIT32(p, e->qid.vers); p += BIT32SZ;
251 	/* qid.path */	PBIT64(p, e->qid.path); p+= 8;
252 	/* mode */	PBIT32(p, e->perm); p+= BIT32SZ;
253 	/* atime */	PBIT32(p, e->mtime); p+= BIT32SZ;
254 	/* mtime */	PBIT32(p, e->mtime); p+= BIT32SZ;
255 	/* length */	if(e->qid.type & QTDIR) {
256 					PBIT64(p, 0);
257 					p += 8;
258 				}
259 				else {
260 					PBIT32(p, e->u.file.length); p += BIT32SZ;
261 					PBIT32(p, 0); p += BIT32SZ;
262 				}
263 	/* name */	PBIT16(p, namelen); p += BIT16SZ; memmove(p, e->name, namelen); p+= namelen;
264 	/* uid */		PBIT16(p, unamelen + unamebad); p += BIT16SZ;
265 				if(unamebad)
266 					*p++ = '(';
267 				memmove(p, uname, unamelen + unamebad); p+= unamelen;
268 				if(unamebad)
269 					*p++ = ')';
270 	/* gid */		PBIT16(p, gnamelen + gnamebad); p += BIT16SZ;
271 				if(gnamebad)
272 					*p++ = '(';
273 				memmove(p, gname, gnamelen); p+= gnamelen;
274 				if(gnamebad)
275 					*p++ = ')';
276 	/* muid */	PBIT16(p, munamelen + munamebad); p += BIT16SZ;
277 				if(munamebad)
278 					*p++ = '(';
279 				memmove(p, muname, munamelen); p+= munamelen;
280 				if(munamebad)
281 					*p = ')';
282 //print("len %ud p - buf %ld\n", len, p - buf);
283 	return len;
284 }
285 
286 char *
287 logfsserverstat(LogfsServer *server, u32int fid, uchar *buf, u32int bufsize, ushort *nstat)
288 {
289 	Fid *f;
290 	if(server->trace > 1)
291 		print("logfsserverstat(%ud)\n", fid);
292 	f = logfsfidmapfindentry(server->fidmap, fid);
293 	if(f == nil)
294 		return logfsbadfid;
295 	if(f->entry->deadandgone)
296 		return Eio;
297 	*nstat = logfsflattenentry(server->is, buf, bufsize, f->entry);
298 	if(*nstat == 0)
299 		return Eshortstat;
300 	return nil;
301 }
302 
303 
304 void
305 logfsservertrace(LogfsServer *server, int level)
306 {
307 	server->trace = level;
308 }
309