00001 #include "types.h"
00002 #include "defs.h"
00003 #include "param.h"
00004 #include "stat.h"
00005 #include "mmu.h"
00006 #include "proc.h"
00007 #include "fs.h"
00008 #include "file.h"
00009 #include "fcntl.h"
00010
00011
00012
00013 static int
00014 argfd(int n, int *pfd, struct file **pf)
00015 {
00016 int fd;
00017 struct file *f;
00018
00019 if(argint(n, &fd) < 0)
00020 return -1;
00021 if(fd < 0 || fd >= NOFILE || (f=proc->ofile[fd]) == 0)
00022 return -1;
00023 if(pfd)
00024 *pfd = fd;
00025 if(pf)
00026 *pf = f;
00027 return 0;
00028 }
00029
00030
00031
00032 static int
00033 fdalloc(struct file *f)
00034 {
00035 int fd;
00036
00037 for(fd = 0; fd < NOFILE; fd++){
00038 if(proc->ofile[fd] == 0){
00039 proc->ofile[fd] = f;
00040 return fd;
00041 }
00042 }
00043 return -1;
00044 }
00045
00046 int
00047 sys_dup(void)
00048 {
00049 struct file *f;
00050 int fd;
00051
00052 if(argfd(0, 0, &f) < 0)
00053 return -1;
00054 if((fd=fdalloc(f)) < 0)
00055 return -1;
00056 filedup(f);
00057 return fd;
00058 }
00059
00060 int
00061 sys_read(void)
00062 {
00063 struct file *f;
00064 int n;
00065 char *p;
00066
00067 if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
00068 return -1;
00069 return fileread(f, p, n);
00070 }
00071
00072 int
00073 sys_write(void)
00074 {
00075 struct file *f;
00076 int n;
00077 char *p;
00078
00079 if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
00080 return -1;
00081 return filewrite(f, p, n);
00082 }
00083
00084 int
00085 sys_close(void)
00086 {
00087 int fd;
00088 struct file *f;
00089
00090 if(argfd(0, &fd, &f) < 0)
00091 return -1;
00092 proc->ofile[fd] = 0;
00093 fileclose(f);
00094 return 0;
00095 }
00096
00097 int
00098 sys_fstat(void)
00099 {
00100 struct file *f;
00101 struct stat *st;
00102
00103 if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
00104 return -1;
00105 return filestat(f, st);
00106 }
00107
00108
00109 int
00110 sys_link(void)
00111 {
00112 char name[DIRSIZ], *new, *old;
00113 struct inode *dp, *ip;
00114
00115 if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
00116 return -1;
00117 if((ip = namei(old)) == 0)
00118 return -1;
00119 ilock(ip);
00120 if(ip->type == T_DIR){
00121 iunlockput(ip);
00122 return -1;
00123 }
00124 ip->nlink++;
00125 iupdate(ip);
00126 iunlock(ip);
00127
00128 if((dp = nameiparent(new, name)) == 0)
00129 goto bad;
00130 ilock(dp);
00131 if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
00132 iunlockput(dp);
00133 goto bad;
00134 }
00135 iunlockput(dp);
00136 iput(ip);
00137 return 0;
00138
00139 bad:
00140 ilock(ip);
00141 ip->nlink--;
00142 iupdate(ip);
00143 iunlockput(ip);
00144 return -1;
00145 }
00146
00147
00148 static int
00149 isdirempty(struct inode *dp)
00150 {
00151 int off;
00152 struct dirent de;
00153
00154 for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
00155 if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00156 panic("isdirempty: readi");
00157 if(de.inum != 0)
00158 return 0;
00159 }
00160 return 1;
00161 }
00162
00163 int
00164 sys_unlink(void)
00165 {
00166 struct inode *ip, *dp;
00167 struct dirent de;
00168 char name[DIRSIZ], *path;
00169 uint off;
00170
00171 if(argstr(0, &path) < 0)
00172 return -1;
00173 if((dp = nameiparent(path, name)) == 0)
00174 return -1;
00175 ilock(dp);
00176
00177
00178 if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
00179 iunlockput(dp);
00180 return -1;
00181 }
00182
00183 if((ip = dirlookup(dp, name, &off)) == 0){
00184 iunlockput(dp);
00185 return -1;
00186 }
00187 ilock(ip);
00188
00189 if(ip->nlink < 1)
00190 panic("unlink: nlink < 1");
00191 if(ip->type == T_DIR && !isdirempty(ip)){
00192 iunlockput(ip);
00193 iunlockput(dp);
00194 return -1;
00195 }
00196
00197 memset(&de, 0, sizeof(de));
00198 if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
00199 panic("unlink: writei");
00200 if(ip->type == T_DIR){
00201 dp->nlink--;
00202 iupdate(dp);
00203 }
00204 iunlockput(dp);
00205
00206 ip->nlink--;
00207 iupdate(ip);
00208 iunlockput(ip);
00209 return 0;
00210 }
00211
00212 static struct inode*
00213 create(char *path, short type, short major, short minor)
00214 {
00215 uint off;
00216 struct inode *ip, *dp;
00217 char name[DIRSIZ];
00218
00219 if((dp = nameiparent(path, name)) == 0)
00220 return 0;
00221 ilock(dp);
00222
00223 if((ip = dirlookup(dp, name, &off)) != 0){
00224 iunlockput(dp);
00225 ilock(ip);
00226 if(type == T_FILE && ip->type == T_FILE)
00227 return ip;
00228 iunlockput(ip);
00229 return 0;
00230 }
00231
00232 if((ip = ialloc(dp->dev, type)) == 0)
00233 panic("create: ialloc");
00234
00235 ilock(ip);
00236 ip->major = major;
00237 ip->minor = minor;
00238 ip->nlink = 1;
00239 iupdate(ip);
00240
00241 if(type == T_DIR){
00242 dp->nlink++;
00243 iupdate(dp);
00244
00245 if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
00246 panic("create dots");
00247 }
00248
00249 if(dirlink(dp, name, ip->inum) < 0)
00250 panic("create: dirlink");
00251
00252 iunlockput(dp);
00253 return ip;
00254 }
00255
00256 int
00257 sys_open(void)
00258 {
00259 char *path;
00260 int fd, omode;
00261 struct file *f;
00262 struct inode *ip;
00263
00264 if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
00265 return -1;
00266
00267 if(omode & O_CREATE){
00268 if((ip = create(path, T_FILE, 0, 0)) == 0)
00269 return -1;
00270 } else {
00271 if((ip = namei(path)) == 0)
00272 return -1;
00273 ilock(ip);
00274 if(ip->type == T_DIR && omode != O_RDONLY){
00275 iunlockput(ip);
00276 return -1;
00277 }
00278 }
00279
00280 if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
00281 if(f)
00282 fileclose(f);
00283 iunlockput(ip);
00284 return -1;
00285 }
00286 iunlock(ip);
00287
00288 f->type = FD_INODE;
00289 f->ip = ip;
00290 f->off = 0;
00291 f->readable = !(omode & O_WRONLY);
00292 f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
00293
00294 return fd;
00295 }
00296
00297 int
00298 sys_mkdir(void)
00299 {
00300 char *path;
00301 struct inode *ip;
00302
00303 if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0)
00304 return -1;
00305 iunlockput(ip);
00306 return 0;
00307 }
00308
00309 int
00310 sys_mknod(void)
00311 {
00312 struct inode *ip;
00313 char *path;
00314 int len;
00315 int major, minor;
00316
00317 if((len=argstr(0, &path)) < 0 ||
00318 argint(1, &major) < 0 ||
00319 argint(2, &minor) < 0 ||
00320 (ip = create(path, T_DEV, major, minor)) == 0)
00321 return -1;
00322 iunlockput(ip);
00323 return 0;
00324 }
00325
00326 int
00327 sys_chdir(void)
00328 {
00329 char *path;
00330 struct inode *ip;
00331
00332 if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
00333 return -1;
00334 ilock(ip);
00335 if(ip->type != T_DIR){
00336 iunlockput(ip);
00337 return -1;
00338 }
00339 iunlock(ip);
00340 iput(proc->cwd);
00341 proc->cwd = ip;
00342 return 0;
00343 }
00344
00345 int
00346 sys_exec(void)
00347 {
00348 char *path, *argv[20];
00349 int i;
00350 uint uargv, uarg;
00351
00352 if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0)
00353 return -1;
00354 memset(argv, 0, sizeof(argv));
00355 for(i=0;; i++){
00356 if(i >= NELEM(argv))
00357 return -1;
00358 if(fetchint(proc, uargv+4*i, (int*)&uarg) < 0)
00359 return -1;
00360 if(uarg == 0){
00361 argv[i] = 0;
00362 break;
00363 }
00364 if(fetchstr(proc, uarg, &argv[i]) < 0)
00365 return -1;
00366 }
00367 return exec(path, argv);
00368 }
00369
00370 int
00371 sys_pipe(void)
00372 {
00373 int *fd;
00374 struct file *rf, *wf;
00375 int fd0, fd1;
00376
00377 if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
00378 return -1;
00379 if(pipealloc(&rf, &wf) < 0)
00380 return -1;
00381 fd0 = -1;
00382 if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
00383 if(fd0 >= 0)
00384 proc->ofile[fd0] = 0;
00385 fileclose(rf);
00386 fileclose(wf);
00387 return -1;
00388 }
00389 fd[0] = fd0;
00390 fd[1] = fd1;
00391 return 0;
00392 }