root/sysfile.c
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- argfd
- fdalloc
- sys_dup
- sys_read
- sys_write
- sys_close
- sys_fstat
- sys_link
- isdirempty
- sys_unlink
- create
- sys_open
- sys_mkdir
- sys_mknod
- sys_chdir
- sys_exec
- sys_pipe
1 //
2 // File-system system calls.
3 // Mostly argument checking, since we don't trust
4 // user code, and calls into file.c and fs.c.
5 //
6
7 #include "types.h"
8 #include "defs.h"
9 #include "param.h"
10 #include "stat.h"
11 #include "mmu.h"
12 #include "proc.h"
13 #include "fs.h"
14 #include "file.h"
15 #include "fcntl.h"
16
17 // Fetch the nth word-sized system call argument as a file descriptor
18 // and return both the descriptor and the corresponding struct file.
19 static int
20 argfd(int n, int *pfd, struct file **pf)
21 {
22 int fd;
23 struct file *f;
24
25 if(argint(n, &fd) < 0)
26 return -1;
27 if(fd < 0 || fd >= NOFILE || (f=proc->ofile[fd]) == 0)
28 return -1;
29 if(pfd)
30 *pfd = fd;
31 if(pf)
32 *pf = f;
33 return 0;
34 }
35
36 // Allocate a file descriptor for the given file.
37 // Takes over file reference from caller on success.
38 static int
39 fdalloc(struct file *f)
40 {
41 int fd;
42
43 for(fd = 0; fd < NOFILE; fd++){
44 if(proc->ofile[fd] == 0){
45 proc->ofile[fd] = f;
46 return fd;
47 }
48 }
49 return -1;
50 }
51
52 int
53 sys_dup(void)
54 {
55 struct file *f;
56 int fd;
57
58 if(argfd(0, 0, &f) < 0)
59 return -1;
60 if((fd=fdalloc(f)) < 0)
61 return -1;
62 filedup(f);
63 return fd;
64 }
65
66 int
67 sys_read(void)
68 {
69 struct file *f;
70 int n;
71 char *p;
72
73 if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
74 return -1;
75 return fileread(f, p, n);
76 }
77
78 int
79 sys_write(void)
80 {
81 struct file *f;
82 int n;
83 char *p;
84
85 if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
86 return -1;
87 return filewrite(f, p, n);
88 }
89
90 int
91 sys_close(void)
92 {
93 int fd;
94 struct file *f;
95
96 if(argfd(0, &fd, &f) < 0)
97 return -1;
98 proc->ofile[fd] = 0;
99 fileclose(f);
100 return 0;
101 }
102
103 int
104 sys_fstat(void)
105 {
106 struct file *f;
107 struct stat *st;
108
109 if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
110 return -1;
111 return filestat(f, st);
112 }
113
114 // Create the path new as a link to the same inode as old.
115 int
116 sys_link(void)
117 {
118 char name[DIRSIZ], *new, *old;
119 struct inode *dp, *ip;
120
121 if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
122 return -1;
123
124 begin_op();
125 if((ip = namei(old)) == 0){
126 end_op();
127 return -1;
128 }
129
130 ilock(ip);
131 if(ip->type == T_DIR){
132 iunlockput(ip);
133 end_op();
134 return -1;
135 }
136
137 ip->nlink++;
138 iupdate(ip);
139 iunlock(ip);
140
141 if((dp = nameiparent(new, name)) == 0)
142 goto bad;
143 ilock(dp);
144 if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
145 iunlockput(dp);
146 goto bad;
147 }
148 iunlockput(dp);
149 iput(ip);
150
151 end_op();
152
153 return 0;
154
155 bad:
156 ilock(ip);
157 ip->nlink--;
158 iupdate(ip);
159 iunlockput(ip);
160 end_op();
161 return -1;
162 }
163
164 // Is the directory dp empty except for "." and ".." ?
165 static int
166 isdirempty(struct inode *dp)
167 {
168 int off;
169 struct dirent de;
170
171 for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
172 if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
173 panic("isdirempty: readi");
174 if(de.inum != 0)
175 return 0;
176 }
177 return 1;
178 }
179
180 //PAGEBREAK!
181 int
182 sys_unlink(void)
183 {
184 struct inode *ip, *dp;
185 struct dirent de;
186 char name[DIRSIZ], *path;
187 uint off;
188
189 if(argstr(0, &path) < 0)
190 return -1;
191
192 begin_op();
193 if((dp = nameiparent(path, name)) == 0){
194 end_op();
195 return -1;
196 }
197
198 ilock(dp);
199
200 // Cannot unlink "." or "..".
201 if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0)
202 goto bad;
203
204 if((ip = dirlookup(dp, name, &off)) == 0)
205 goto bad;
206 ilock(ip);
207
208 if(ip->nlink < 1)
209 panic("unlink: nlink < 1");
210 if(ip->type == T_DIR && !isdirempty(ip)){
211 iunlockput(ip);
212 goto bad;
213 }
214
215 memset(&de, 0, sizeof(de));
216 if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
217 panic("unlink: writei");
218 if(ip->type == T_DIR){
219 dp->nlink--;
220 iupdate(dp);
221 }
222 iunlockput(dp);
223
224 ip->nlink--;
225 iupdate(ip);
226 iunlockput(ip);
227
228 end_op();
229
230 return 0;
231
232 bad:
233 iunlockput(dp);
234 end_op();
235 return -1;
236 }
237
238 static struct inode*
239 create(char *path, short type, short major, short minor)
240 {
241 uint off;
242 struct inode *ip, *dp;
243 char name[DIRSIZ];
244
245 if((dp = nameiparent(path, name)) == 0)
246 return 0;
247 ilock(dp);
248
249 if((ip = dirlookup(dp, name, &off)) != 0){
250 iunlockput(dp);
251 ilock(ip);
252 if(type == T_FILE && ip->type == T_FILE)
253 return ip;
254 iunlockput(ip);
255 return 0;
256 }
257
258 if((ip = ialloc(dp->dev, type)) == 0)
259 panic("create: ialloc");
260
261 ilock(ip);
262 ip->major = major;
263 ip->minor = minor;
264 ip->nlink = 1;
265 iupdate(ip);
266
267 if(type == T_DIR){ // Create . and .. entries.
268 dp->nlink++; // for ".."
269 iupdate(dp);
270 // No ip->nlink++ for ".": avoid cyclic ref count.
271 if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
272 panic("create dots");
273 }
274
275 if(dirlink(dp, name, ip->inum) < 0)
276 panic("create: dirlink");
277
278 iunlockput(dp);
279
280 return ip;
281 }
282
283 int
284 sys_open(void)
285 {
286 char *path;
287 int fd, omode;
288 struct file *f;
289 struct inode *ip;
290
291 if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
292 return -1;
293
294 begin_op();
295
296 if(omode & O_CREATE){
297 ip = create(path, T_FILE, 0, 0);
298 if(ip == 0){
299 end_op();
300 return -1;
301 }
302 } else {
303 if((ip = namei(path)) == 0){
304 end_op();
305 return -1;
306 }
307 ilock(ip);
308 if(ip->type == T_DIR && omode != O_RDONLY){
309 iunlockput(ip);
310 end_op();
311 return -1;
312 }
313 }
314
315 if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
316 if(f)
317 fileclose(f);
318 iunlockput(ip);
319 end_op();
320 return -1;
321 }
322 iunlock(ip);
323 end_op();
324
325 f->type = FD_INODE;
326 f->ip = ip;
327 f->off = 0;
328 f->readable = !(omode & O_WRONLY);
329 f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
330 return fd;
331 }
332
333 int
334 sys_mkdir(void)
335 {
336 char *path;
337 struct inode *ip;
338
339 begin_op();
340 if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){
341 end_op();
342 return -1;
343 }
344 iunlockput(ip);
345 end_op();
346 return 0;
347 }
348
349 int
350 sys_mknod(void)
351 {
352 struct inode *ip;
353 char *path;
354 int len;
355 int major, minor;
356
357 begin_op();
358 if((len=argstr(0, &path)) < 0 ||
359 argint(1, &major) < 0 ||
360 argint(2, &minor) < 0 ||
361 (ip = create(path, T_DEV, major, minor)) == 0){
362 end_op();
363 return -1;
364 }
365 iunlockput(ip);
366 end_op();
367 return 0;
368 }
369
370 int
371 sys_chdir(void)
372 {
373 char *path;
374 struct inode *ip;
375
376 begin_op();
377 if(argstr(0, &path) < 0 || (ip = namei(path)) == 0){
378 end_op();
379 return -1;
380 }
381 ilock(ip);
382 if(ip->type != T_DIR){
383 iunlockput(ip);
384 end_op();
385 return -1;
386 }
387 iunlock(ip);
388 iput(proc->cwd);
389 end_op();
390 proc->cwd = ip;
391 return 0;
392 }
393
394 int
395 sys_exec(void)
396 {
397 char *path, *argv[MAXARG];
398 int i;
399 uint uargv, uarg;
400
401 if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0){
402 return -1;
403 }
404 memset(argv, 0, sizeof(argv));
405 for(i=0;; i++){
406 if(i >= NELEM(argv))
407 return -1;
408 if(fetchint(uargv+4*i, (int*)&uarg) < 0)
409 return -1;
410 if(uarg == 0){
411 argv[i] = 0;
412 break;
413 }
414 if(fetchstr(uarg, &argv[i]) < 0)
415 return -1;
416 }
417 return exec(path, argv);
418 }
419
420 int
421 sys_pipe(void)
422 {
423 int *fd;
424 struct file *rf, *wf;
425 int fd0, fd1;
426
427 if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
428 return -1;
429 if(pipealloc(&rf, &wf) < 0)
430 return -1;
431 fd0 = -1;
432 if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
433 if(fd0 >= 0)
434 proc->ofile[fd0] = 0;
435 fileclose(rf);
436 fileclose(wf);
437 return -1;
438 }
439 fd[0] = fd0;
440 fd[1] = fd1;
441 return 0;
442 }