int sys_readdir(unsigned int fd, char *dirent, unsigned int count /* ignored and unused, noted in Linux man page */ ) { int error; struct file *file; register struct file *filp; register struct file_operations *fop; struct readdir_callback buf; if ((error = fd_check(fd, dirent, sizeof(struct linux_dirent), FMODE_READ, &file)) >= 0) { error = -ENOTDIR; filp = file; fop = filp->f_op; if (fop && fop->readdir) { buf.count = 0; buf.dirent = (struct linux_dirent *) dirent; if ((error = fop->readdir(filp->f_inode, filp, &buf, fillonedir)) >= 0) return buf.count; } } return error; }
int sys_read(unsigned int fd, char *buf, size_t count) { register struct file_operations *fop; struct file *file; int retval; if (((retval = fd_check(fd, buf, count, FMODE_READ, &file)) == 0) && count) { retval = -EINVAL; fop = file->f_op; if (fop->read) { retval = (int) fop->read(file->f_inode, file, buf, count); schedule(); } } return retval; }
int sys_write(unsigned int fd, char *buf, size_t count) { register struct file_operations *fop; struct file *file; register struct inode *inode; int written; if (((written = fd_check(fd, buf, count, FMODE_WRITE, &file)) == 0) && (count != 0)) { written = -EINVAL; fop = file->f_op; if (fop->write) { inode = file->f_inode; /* * If data has been written to the file, remove the setuid and * the setgid bits. We do it anyway otherwise there is an * extremely exploitable race - does your OS get it right |-> * * Set ATTR_FORCE so it will always be changed. */ if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) { #ifdef USE_NOTIFY_CHANGE struct iattr newattrs; newattrs.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE; notify_change(inode, &newattrs); #else inode->i_mode = inode->i_mode & ~(S_ISUID | S_ISGID); #endif } written = (int) fop->write(inode, file, buf, count); schedule(); } } return written; }