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