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