sysfile.c (7183B)
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 if((ip = namei(old)) == 0) 124 return -1; 125 126 begin_trans(); 127 128 ilock(ip); 129 if(ip->type == T_DIR){ 130 iunlockput(ip); 131 commit_trans(); 132 return -1; 133 } 134 135 ip->nlink++; 136 iupdate(ip); 137 iunlock(ip); 138 139 if((dp = nameiparent(new, name)) == 0) 140 goto bad; 141 ilock(dp); 142 if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){ 143 iunlockput(dp); 144 goto bad; 145 } 146 iunlockput(dp); 147 iput(ip); 148 149 commit_trans(); 150 151 return 0; 152 153 bad: 154 ilock(ip); 155 ip->nlink--; 156 iupdate(ip); 157 iunlockput(ip); 158 commit_trans(); 159 return -1; 160 } 161 162 // Is the directory dp empty except for "." and ".." ? 163 static int 164 isdirempty(struct inode *dp) 165 { 166 int off; 167 struct dirent de; 168 169 for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 170 if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 171 panic("isdirempty: readi"); 172 if(de.inum != 0) 173 return 0; 174 } 175 return 1; 176 } 177 178 //PAGEBREAK! 179 int 180 sys_unlink(void) 181 { 182 struct inode *ip, *dp; 183 struct dirent de; 184 char name[DIRSIZ], *path; 185 uint off; 186 187 if(argstr(0, &path) < 0) 188 return -1; 189 if((dp = nameiparent(path, name)) == 0) 190 return -1; 191 192 begin_trans(); 193 194 ilock(dp); 195 196 // Cannot unlink "." or "..". 197 if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0) 198 goto bad; 199 200 if((ip = dirlookup(dp, name, &off)) == 0) 201 goto bad; 202 ilock(ip); 203 204 if(ip->nlink < 1) 205 panic("unlink: nlink < 1"); 206 if(ip->type == T_DIR && !isdirempty(ip)){ 207 iunlockput(ip); 208 goto bad; 209 } 210 211 memset(&de, 0, sizeof(de)); 212 if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 213 panic("unlink: writei"); 214 if(ip->type == T_DIR){ 215 dp->nlink--; 216 iupdate(dp); 217 } 218 iunlockput(dp); 219 220 ip->nlink--; 221 iupdate(ip); 222 iunlockput(ip); 223 224 commit_trans(); 225 226 return 0; 227 228 bad: 229 iunlockput(dp); 230 commit_trans(); 231 return -1; 232 } 233 234 static struct inode* 235 create(char *path, short type, short major, short minor) 236 { 237 uint off; 238 struct inode *ip, *dp; 239 char name[DIRSIZ]; 240 241 if((dp = nameiparent(path, name)) == 0) 242 return 0; 243 ilock(dp); 244 245 if((ip = dirlookup(dp, name, &off)) != 0){ 246 iunlockput(dp); 247 ilock(ip); 248 if(type == T_FILE && ip->type == T_FILE) 249 return ip; 250 iunlockput(ip); 251 return 0; 252 } 253 254 if((ip = ialloc(dp->dev, type)) == 0) 255 panic("create: ialloc"); 256 257 ilock(ip); 258 ip->major = major; 259 ip->minor = minor; 260 ip->nlink = 1; 261 iupdate(ip); 262 263 if(type == T_DIR){ // Create . and .. entries. 264 dp->nlink++; // for ".." 265 iupdate(dp); 266 // No ip->nlink++ for ".": avoid cyclic ref count. 267 if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 268 panic("create dots"); 269 } 270 271 if(dirlink(dp, name, ip->inum) < 0) 272 panic("create: dirlink"); 273 274 iunlockput(dp); 275 276 return ip; 277 } 278 279 int 280 sys_open(void) 281 { 282 char *path; 283 int fd, omode; 284 struct file *f; 285 struct inode *ip; 286 287 if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 288 return -1; 289 if(omode & O_CREATE){ 290 begin_trans(); 291 ip = create(path, T_FILE, 0, 0); 292 commit_trans(); 293 if(ip == 0) 294 return -1; 295 } else { 296 if((ip = namei(path)) == 0) 297 return -1; 298 ilock(ip); 299 if(ip->type == T_DIR && omode != O_RDONLY){ 300 iunlockput(ip); 301 return -1; 302 } 303 } 304 305 if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 306 if(f) 307 fileclose(f); 308 iunlockput(ip); 309 return -1; 310 } 311 iunlock(ip); 312 313 f->type = FD_INODE; 314 f->ip = ip; 315 f->off = 0; 316 f->readable = !(omode & O_WRONLY); 317 f->writable = (omode & O_WRONLY) || (omode & O_RDWR); 318 return fd; 319 } 320 321 int 322 sys_mkdir(void) 323 { 324 char *path; 325 struct inode *ip; 326 327 begin_trans(); 328 if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0){ 329 commit_trans(); 330 return -1; 331 } 332 iunlockput(ip); 333 commit_trans(); 334 return 0; 335 } 336 337 int 338 sys_mknod(void) 339 { 340 struct inode *ip; 341 char *path; 342 int len; 343 int major, minor; 344 345 begin_trans(); 346 if((len=argstr(0, &path)) < 0 || 347 argint(1, &major) < 0 || 348 argint(2, &minor) < 0 || 349 (ip = create(path, T_DEV, major, minor)) == 0){ 350 commit_trans(); 351 return -1; 352 } 353 iunlockput(ip); 354 commit_trans(); 355 return 0; 356 } 357 358 int 359 sys_chdir(void) 360 { 361 char *path; 362 struct inode *ip; 363 364 if(argstr(0, &path) < 0 || (ip = namei(path)) == 0) 365 return -1; 366 ilock(ip); 367 if(ip->type != T_DIR){ 368 iunlockput(ip); 369 return -1; 370 } 371 iunlock(ip); 372 iput(proc->cwd); 373 proc->cwd = ip; 374 return 0; 375 } 376 377 int 378 sys_exec(void) 379 { 380 char *path, *argv[MAXARG]; 381 int i; 382 uintp uargv, uarg; 383 384 if(argstr(0, &path) < 0 || arguintp(1, &uargv) < 0){ 385 return -1; 386 } 387 memset(argv, 0, sizeof(argv)); 388 for(i=0;; i++){ 389 if(i >= NELEM(argv)) 390 return -1; 391 if(fetchuintp(uargv+sizeof(uintp)*i, &uarg) < 0) 392 return -1; 393 if(uarg == 0){ 394 argv[i] = 0; 395 break; 396 } 397 if(fetchstr(uarg, &argv[i]) < 0) 398 return -1; 399 } 400 return exec(path, argv); 401 } 402 403 int 404 sys_pipe(void) 405 { 406 int *fd; 407 struct file *rf, *wf; 408 int fd0, fd1; 409 410 if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 411 return -1; 412 if(pipealloc(&rf, &wf) < 0) 413 return -1; 414 fd0 = -1; 415 if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 416 if(fd0 >= 0) 417 proc->ofile[fd0] = 0; 418 fileclose(rf); 419 fileclose(wf); 420 return -1; 421 } 422 fd[0] = fd0; 423 fd[1] = fd1; 424 return 0; 425 }