xref: /inferno-os/tools/styxtest/styxtest.c (revision 9fefa9c8ca5bfc402d56cb3b49ba7dfbe198822b)
1 #include <lib9.h>
2 #include "styxserver.h"
3 
4 /*
5  * An in-memory file server
6  * allowing truncation, removal on closure, wstat and
7  * all other file operations
8  */
9 
10 char *fsremove(Qid);
11 
12 Styxserver *server;
13 
14 char*
15 fsopen(Qid *qid, int mode)
16 {
17 	Styxfile *f;
18 
19 	f = styxfindfile(server, qid->path);
20 	if(mode&OTRUNC){	/* truncate on open */
21 		styxfree(f->u);
22 		f->u = nil;
23 		f->d.length = 0;
24 	}
25 	return nil;
26 }
27 
28 char*
29 fsclose(Qid qid, int mode)
30 {
31 	if(mode&ORCLOSE)	/* remove on close */
32 		return fsremove(qid);
33 	return nil;
34 }
35 
36 char *
37 fscreate(Qid *qid, char *name, int perm, int mode)
38 {
39 	int isdir;
40 	Styxfile *f;
41 
42 	USED(mode);
43 	isdir = perm&DMDIR;
44 	if(isdir)
45 		f = styxadddir(server, qid->path, -1, name, perm, "inferno");
46 	else
47 		f = styxaddfile(server, qid->path, -1, name, perm, "inferno");
48 	if(f == nil)
49 		return Eexist;
50 	f->u = nil;
51 	f->d.length = 0;
52 	*qid = f->d.qid;
53 	return nil;
54 }
55 
56 char *
57 fsremove(Qid qid)
58 {
59 	Styxfile *f;
60 
61 	f = styxfindfile(server, qid.path);
62 	if((f->d.qid.type&QTDIR) && f->child != nil)
63 		return "directory not empty";
64 	styxfree(f->u);
65 	styxrmfile(server, qid.path);
66 	return nil;
67 }
68 
69 char *
70 fsread(Qid qid, char *buf, ulong *n, vlong off)
71 {
72 	int m;
73 	Styxfile *f;
74 
75 	f = styxfindfile(server, qid.path);
76 	m = f->d.length;
77 	if(off >= m)
78 		*n = 0;
79 	else{
80 		if(off + *n > m)
81 			*n = m-off;
82 		memmove(buf, (char*)f->u+off, *n);
83 	}
84 	return nil;
85 }
86 
87 char*
88 fswrite(Qid qid, char *buf, ulong *n, vlong off)
89 {
90 	Styxfile *f;
91 	vlong m, p;
92 	char *u;
93 
94 	f = styxfindfile(server, qid.path);
95 	m = f->d.length;
96 	p = off + *n;
97 	if(p > m){	/* just grab a larger piece of memory */
98 		u = styxmalloc(p);
99 		if(u == nil)
100 			return "out of memory";
101 		memset(u, 0, p);
102 		memmove(u, f->u, m);
103 		styxfree(f->u);
104 		f->u = u;
105 		f->d.length = p;
106 	}
107 	memmove((char*)f->u+off, buf, *n);
108 	return nil;
109 }
110 
111 char*
112 fswstat(Qid qid, Dir *d)
113 {
114 	Styxfile *f, *tf;
115 	Client *c;
116 	int owner;
117 
118 	/* the most complicated operation when fully allowed */
119 
120 	c = styxclient(server);
121 	f = styxfindfile(server, qid.path);
122 	owner = strcmp(c->uname, f->d.uid) == 0;
123 	if(d->name != nil && strcmp(d->name, f->d.name) != 0){
124 		/* need write permission in parent directory */
125 		if(!styxperm(f->parent, c->uname, OWRITE))
126 			return Eperm;
127 		if((tf = styxaddfile(server, f->parent->d.qid.path, -1, d->name, 0, "")) == nil){
128 			/* file with same name exists */
129 			return Eexist;
130 		}
131 		else{
132 			/* undo above addfile */
133 			styxrmfile(server, tf->d.qid.path);
134 		}
135 		/* ok to change name now */
136 		styxfree(f->d.name);
137 		f->d.name = strdup(d->name);
138 	}
139 	if(d->uid != nil && strcmp(d->uid, f->d.uid) != 0){
140 		if(!owner)
141 			return Eperm;
142 		styxfree(f->d.uid);
143 		f->d.uid = strdup(d->uid);
144 	}
145 	if(d->gid != nil && strcmp(d->gid, f->d.gid) != 0){
146 		if(!owner)
147 			return Eperm;
148 		styxfree(f->d.gid);
149 		f->d.gid = strdup(d->gid);
150 	}
151 	if(d->mode != ~0 && d->mode != f->d.mode){
152 		if(!owner)
153 			return Eperm;
154 		if((d->mode&DMDIR) != (f->d.mode&DMDIR))
155 			return Eperm;	/* cannot change file->directory or vice-verse */
156 		f->d.mode = d->mode;
157 	}
158 	if(d->mtime != ~0 && d->mtime != f->d.mtime){
159 		if(!owner)
160 			return Eperm;
161 		f->d.mtime = d->mtime;
162 	}
163 	/* all other file attributes cannot be changed by wstat */
164 	return nil;
165 }
166 
167 Styxops ops = {
168 	nil,			/* newclient */
169 	nil,			/* freeclient */
170 
171 	nil,			/* attach */
172 	nil,			/* walk */
173 	fsopen,		/* open */
174 	fscreate,		/* create */
175 	fsread,		/* read */
176 	fswrite,		/* write */
177 	fsclose,		/* close */
178 	fsremove,	/* remove */
179 	nil,			/* stat */
180 	fswstat,		/* wstat */
181 };
182 
183 void
184 main(int argc, char **argv)
185 {
186 	Styxserver s;
187 
188 	USED(argc);
189 	USED(argv);
190 	server = &s;
191 	styxdebug();
192 	styxinit(&s, &ops, "6701", 0777, 1);
193 	for(;;){
194 		styxwait(&s);
195 		styxprocess(&s);
196 	}
197 	exits(nil);
198 }
199