/* * linux/fs/open.c * * (C) 1991 Linus Torvalds */ #include #include #include #include #include #include #include #include #include #include extern int my_sys_read(unsigned int fd,char * buf,int count); int sys_ustat(int dev, struct ustat * ubuf) { return -ENOSYS; } int sys_utime(char * filename, struct utimbuf * times) { struct m_inode * inode; long actime,modtime; if (!(inode=namei(filename))) return -ENOENT; if (times) { actime = get_fs_long((unsigned long *) ×->actime); modtime = get_fs_long((unsigned long *) ×->modtime); } else actime = modtime = CURRENT_TIME; inode->i_atime = actime; inode->i_mtime = modtime; inode->i_dirt = 1; iput(inode); return 0; } /* * XXX should we use the real or effective uid? BSD uses the real uid, * so as to make this call useful to setuid programs. */ int sys_access(const char * filename,int mode) { struct m_inode * inode; int res, i_mode; mode &= 0007; if (!(inode=namei(filename))) return -EACCES; i_mode = res = inode->i_mode & 0777; iput(inode); if (current->uid == inode->i_uid) res >>= 6; else if (current->gid == inode->i_gid) res >>= 6; if ((res & 0007 & mode) == mode) return 0; /* * XXX we are doing this test last because we really should be * swapping the effective with the real user id (temporarily), * and then calling suser() routine. If we do call the * suser() routine, it needs to be called last. */ if ((!current->uid) && (!(mode & 1) || (i_mode & 0111))) return 0; return -EACCES; } int sys_chdir(const char * filename) { struct m_inode * inode; if (!(inode = namei(filename))) return -ENOENT; if (!S_ISDIR(inode->i_mode)) { iput(inode); return -ENOTDIR; } iput(current->pwd); current->pwd = inode; return (0); } int sys_chroot(const char * filename) { struct m_inode * inode; if (!(inode=namei(filename))) return -ENOENT; if (!S_ISDIR(inode->i_mode)) { iput(inode); return -ENOTDIR; } iput(current->root); current->root = inode; return (0); } int sys_chmod(const char * filename,int mode) { struct m_inode * inode; if (!(inode=namei(filename))) return -ENOENT; if ((current->euid != inode->i_uid) && !suser()) { iput(inode); return -EACCES; } inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); inode->i_dirt = 1; iput(inode); return 0; } int sys_chown(const char * filename,int uid,int gid) { struct m_inode * inode; if (!(inode=namei(filename))) return -ENOENT; if (!suser()) { iput(inode); return -EACCES; } inode->i_uid=uid; inode->i_gid=gid; inode->i_dirt=1; iput(inode); return 0; } int sys_open(const char * filename,int flag,int mode) { struct m_inode * inode; struct file * f; int i,fd; mode &= 0777 & ~current->umask; for(fd=0 ; fdfilp[fd]) break; if (fd>=NR_OPEN) return -EINVAL; current->close_on_exec &= ~(1<f_count) break; if (i>=NR_FILE) return -EINVAL; (current->filp[fd]=f)->f_count++; if ((i=open_namei(filename,flag,mode,&inode))<0) { current->filp[fd]=NULL; f->f_count=0; return i; } /* ttys are somewhat special (ttyxx major==4, tty major==5) */ if (S_ISCHR(inode->i_mode)) if (MAJOR(inode->i_zone[0])==4) { if (current->leader && current->tty<0) { current->tty = MINOR(inode->i_zone[0]); tty_table[current->tty].pgrp = current->pgrp; } } else if (MAJOR(inode->i_zone[0])==5) if (current->tty<0) { iput(inode); current->filp[fd]=NULL; f->f_count=0; return -EPERM; } /* Likewise with block-devices: check for floppy_change */ if (S_ISBLK(inode->i_mode)) check_disk_change(inode->i_zone[0]); f->f_mode = inode->i_mode; f->f_flags = flag; f->f_count = 1; f->f_inode = inode; f->f_pos = 0; return (fd); } int sys_creat(const char * pathname, int mode) { return sys_open(pathname, O_CREAT | O_TRUNC, mode); } int sys_close(unsigned int fd) { struct file * filp; if (fd >= NR_OPEN) return -EINVAL; current->close_on_exec &= ~(1<filp[fd])) return -EINVAL; current->filp[fd] = NULL; if (filp->f_count == 0) panic("Close: file count is 0"); if (--filp->f_count) return (0); iput(filp->f_inode); return (0); } static int get_subentry(unsigned int fd, char* cwdbuf, char** subentry){ int i, num_file = 0, read_num; if(fd == -1){ return -1; } for(i = 0; i < 512; ++i){ cwdbuf[i] = '\0'; } read_num = my_sys_read(fd, cwdbuf, 512); if(read_num == -1){ return -1; } for(i = 0; i < 512; ){ if((cwdbuf[i] == '.') || (cwdbuf[i] >= 'a' && cwdbuf[i] <= 'z') || (cwdbuf[i] >= 'A' && cwdbuf[i] <= 'Z')){ subentry[num_file++] = cwdbuf + i; while(i<512 && cwdbuf[i]){ ++i; } }else{ cwdbuf[i] = '\0'; ++i; } } subentry[num_file] = NULL; return read_num; } static int my_strlen(const char* Src){ int len = 0; int i = 0; for(; Src[i]; ++i){ ++len; } return len; } int sys_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count){ struct stat info; char content[512]; char* subdirs[128]; char* curbuf = (char*)dirp; int i, readn = 0, mod, j; unsigned short size = sizeof(struct linux_dirent); sys_fstat(fd, &info); get_subentry(fd, content, subdirs); for(i = 0; subdirs[i]; ++i){ put_fs_long(info.st_ino, &dirp->d_ino); put_fs_byte(*((char*)(&size)), (char*)(&dirp->d_reclen)); put_fs_byte(*((char*)(&size) + 1), (char*)(&dirp->d_reclen)+1); readn += size; for(j = 0; subdirs[i][j]; ++j){ put_fs_byte(*(subdirs[i] + j), dirp->d_name+j); } put_fs_byte('\0', dirp->d_name+j); dirp = (struct linux_dirent*) (curbuf + size); curbuf += size; } return readn; } long sys_getcwd(){ return 0; } long sys_mmap(){ return 0; } int sys_munmap(){ return 0; } int sys_clone(){ return 0; }