/* * linux/fs/open.c * * (C) 1991 Linus Torvalds */ #include #include #include #include #include #include #include #include #include #include #include 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); } int find_entry1(struct m_inode ** dir,int find_node,struct dir_entry ** res_dir){ int entries; int block,i; struct buffer_head * bh; struct dir_entry * de; struct super_block * sb; entries = (*dir)->i_size / (sizeof (struct dir_entry)); *res_dir = NULL; if (!(block = (*dir)->i_zone[0])) return NULL; if (!(bh = bread((*dir)->i_dev,block))) return NULL; i = 0; de = (struct dir_entry *) bh->b_data; while (i < entries) { if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || !(bh = bread((*dir)->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } de = (struct dir_entry *) bh->b_data; } if (de->inode == find_node) { *res_dir = de; return 0; } de++; i++; } brelse(bh); return -1; } long sys_getcwd(char *buf,size_t size){ int entries; int block,i; int num = 19; char s[20][NAME_LEN]; struct buffer_head * bh; struct dir_entry * de; struct dir_entry * res_dir; struct super_block * sb; struct m_inode * dir =current->pwd; struct m_inode * olddir =NULL; while(1){ olddir = dir; if (olddir==current->root) break; if (!dir->i_zone[0]) return NULL; if(!(bh = bread(dir->i_dev,dir->i_zone[0])))//获得i节点指向的数据块 return NULL; de = (struct dir_entry *) bh->b_data; int find = de->inode; if (!(dir = iget(dir->i_dev,(de+1)->inode))){//dir更新并判断错误 return NULL; } if(find_entry1(&dir,find,&res_dir)==-1){ printk("getcwd error\n"); return NULL; } strcpy(s[num--],res_dir->name); } char *buf1; char *buf3 = buf1; for(i=num+1;i<=19;i++){ *buf3 = '/'; *buf3++; char *w = s[i]; while(*w){ *buf3 = (*w++); *buf3++; } } int len = strlen(buf1); if(!buf) buf = (char *)malloc(len); char *buf2 = buf; int j; for(j=0;jfilp[fd]->f_inode; /*if(!(dir= current->filp[fd]->f_inode)) return -1;*/ int entries; int block,i; struct buffer_head * bh; struct dir_entry * de; struct super_block * sb; struct linux_dirent * cur = (struct linux_dirent *)malloc(count) ; char *oldcur = (char *)cur; entries = dir->i_size / (sizeof (struct dir_entry)); if (!(block = dir->i_zone[0])) return -1; if (!(bh = bread(dir->i_dev,block))) return -1; i = 0; int fixsize = sizeof(long)+sizeof(off_t)+sizeof(unsigned short); int pos = 0; de = (struct dir_entry *) bh->b_data; int nread=0; while (i < entries) { if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) || !(bh = bread(dir->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } de = (struct dir_entry *) bh->b_data; } cur->d_ino = de->inode; cur->d_off = pos; strcpy(cur->d_name,de->name); cur->d_reclen = fixsize+sizeof(de->name); pos += cur->d_reclen; nread+=sizeof(de->name); de++; char *w = (char *)cur; w = w+cur->d_reclen; cur = (struct linux_dirent *)w; i++; } brelse(bh); char *s = (char *)dirp; int j=0; for(j;j