static int msdos_readdir(struct inode *inode,struct file *filp, struct dirent *dirent,int count) { int ino,i,i2,last; char c,*walk; struct buffer_head *bh; struct msdos_dir_entry *de; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; if (inode->i_ino == MSDOS_ROOT_INO) { /* Fake . and .. for the root directory. */ if (filp->f_pos == 2) filp->f_pos = 0; else if (filp->f_pos < 2) { walk = filp->f_pos++ ? ".." : "."; for (i = 0; *walk; walk++) put_fs_byte(*walk,dirent->d_name+i++); put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino); put_fs_byte(0,dirent->d_name+i); put_fs_word(i,&dirent->d_reclen); return i; } } if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT; bh = NULL; while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) { if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) { for (i = last = 0; i < 8; i++) { if (!(c = de->name[i])) break; if (c >= 'A' && c <= 'Z') c += 32; if (c != ' ') last = i+1; put_fs_byte(c,i+dirent->d_name); } i = last; put_fs_byte('.',i+dirent->d_name); i++; for (i2 = 0; i2 < 3; i2++) { if (!(c = de->ext[i2])) break; if (c >= 'A' && c <= 'Z') c += 32; if (c != ' ') last = i+1; put_fs_byte(c,i+dirent->d_name); i++; } if ((i = last) != 0) { if (!strcmp(de->name,MSDOS_DOT)) ino = inode->i_ino; else if (!strcmp(de->name,MSDOS_DOTDOT)) ino = msdos_parent_ino(inode,0); put_fs_long(ino,&dirent->d_ino); put_fs_byte(0,i+dirent->d_name); put_fs_word(i,&dirent->d_reclen); brelse(bh); return i; } } } if (bh) brelse(bh); return 0; }
int msdos_lookup(struct inode *dir,const char *name,int len, struct inode **result) { int ino,res; struct msdos_dir_entry *de; struct buffer_head *bh; struct inode *next; *result = NULL; if (!dir) return -ENOENT; if (!S_ISDIR(dir->i_mode)) { iput(dir); return -ENOENT; } if (len == 1 && get_fs_byte(name) == '.') { *result = dir; return 0; } if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.') { ino = msdos_parent_ino(dir,0); iput(dir); if (ino < 0) return ino; if (!(*result = iget(dir->i_dev,ino))) return -EACCES; return 0; } if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) { iput(dir); return res; } if (bh) brelse(bh); /* printk("lookup: ino=%d\r\n",ino); */ if (!(*result = iget(dir->i_dev,ino))) { iput(dir); return -EACCES; } if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */ iput(*result); iput(dir); return -ENOENT; } while (MSDOS_I(*result)->i_old) { next = MSDOS_I(*result)->i_old; iput(*result); if (!(*result = iget(next->i_dev,next->i_ino))) panic("msdos_lookup: Can't happen"); } iput(dir); return 0; }
static int rename_diff_dir(struct inode *old_dir,char *old_name, struct inode *new_dir,char *new_name,struct buffer_head *old_bh, struct msdos_dir_entry *old_de,int old_ino) { struct buffer_head *new_bh,*free_bh,*dotdot_bh; struct msdos_dir_entry *new_de,*free_de,*dotdot_de; struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk; int new_ino,free_ino,dotdot_ino; int error,exists,ino; if (old_dir->i_dev != new_dir->i_dev) return -EINVAL; if (old_ino == new_dir->i_ino) return -EINVAL; if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO; while (walk->i_ino != MSDOS_ROOT_INO) { ino = msdos_parent_ino(walk,1); iput(walk); if (ino < 0) return ino; if (ino == old_ino) return -EINVAL; if (!(walk = iget(new_dir->i_dev,ino))) return -EIO; } iput(walk); if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0) return error; exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0; if (!(old_inode = iget(old_dir->i_dev,old_ino))) { brelse(free_bh); if (exists) brelse(new_bh); return -EIO; } if (*(unsigned char *) old_de->name == DELETED_FLAG) { iput(old_inode); brelse(free_bh); if (exists) brelse(new_bh); return -ENOENT; } new_inode = NULL; /* to make GCC happy */ if (exists) { if (!(new_inode = iget(new_dir->i_dev,new_ino))) { iput(old_inode); brelse(new_bh); return -EIO; } if (S_ISDIR(new_inode->i_mode)) { iput(new_inode); iput(old_inode); brelse(new_bh); return -EPERM; } new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; new_bh->b_dirt = 1; } memcpy(free_de,old_de,sizeof(struct msdos_dir_entry)); memcpy(free_de->name,new_name,MSDOS_NAME); if (!(free_inode = iget(new_dir->i_dev,free_ino))) { free_de->name[0] = DELETED_FLAG; /* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */ brelse(free_bh); if (exists) { iput(new_inode); brelse(new_bh); } return -EIO; } msdos_read_inode(free_inode); MSDOS_I(old_inode)->i_busy = 1; cache_inval_inode(old_inode); old_inode->i_dirt = 1; old_de->name[0] = DELETED_FLAG; old_bh->b_dirt = 1; free_bh->b_dirt = 1; if (!exists) iput(free_inode); else { MSDOS_I(new_inode)->i_depend = free_inode; MSDOS_I(free_inode)->i_old = new_inode; /* free_inode is put when putting new_inode */ iput(new_inode); brelse(new_bh); } if (S_ISDIR(old_inode->i_mode)) { if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, &dotdot_de,&dotdot_ino)) < 0) goto rename_done; if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) { brelse(dotdot_bh); error = -EIO; goto rename_done; } dotdot_de->start = MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start; dotdot_inode->i_dirt = 1; dotdot_bh->b_dirt = 1; iput(dotdot_inode); brelse(dotdot_bh); old_dir->i_nlink--; new_dir->i_nlink++; /* no need to mark them dirty */ } error = 0; rename_done: brelse(free_bh); iput(old_inode); return error; }