static int affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) { unsigned int (*toupper)(unsigned int) = affs_toupper; int alen = a->len; int blen = b->len; int i; /* 'a' is the qstr of an already existing dentry, so the name * must be valid. 'b' must be validated first. */ if (affs_check_name(b->name,b->len)) return 1; /* If the names are longer than the allowed 30 chars, * the excess is ignored, so their length may differ. */ if (alen > 30) alen = 30; if (blen > 30) blen = 30; if (alen != blen) return 1; /* Check whether to use the international 'toupper' routine */ if (AFFS_I2FSTYPE(dentry->d_inode)) toupper = affs_intl_toupper; for (i = 0; i < alen; i++) if (toupper(a->name[i]) != toupper(b->name[i])) return 1; return 0; }
static inline int __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper) { const u8 *aname = a->name; const u8 *bname = b->name; int len; /* 'a' is the qstr of an already existing dentry, so the name * must be valid. 'b' must be validated first. */ if (affs_check_name(b->name,b->len)) return 1; /* If the names are longer than the allowed 30 chars, * the excess is ignored, so their length may differ. */ len = a->len; if (len >= 30) { if (b->len < 30) return 1; len = 30; } else if (len != b->len) return 1; for (; len > 0; len--) if (toupper(*aname++) != toupper(*bname++)) return 1; return 0; }
static inline int __affs_compare_dentry(unsigned int len, const char *str, const struct qstr *name, toupper_t toupper, bool notruncate) { const u8 *aname = str; const u8 *bname = name->name; /* * 'str' is the name of an already existing dentry, so the name * must be valid. 'name' must be validated first. */ if (affs_check_name(name->name, name->len, notruncate)) return 1; /* * If the names are longer than the allowed 30 chars, * the excess is ignored, so their length may differ. */ if (len >= AFFSNAMEMAX) { if (name->len < AFFSNAMEMAX) return 1; len = AFFSNAMEMAX; } else if (len != name->len) return 1; for (; len > 0; len--) if (toupper(*aname++) != toupper(*bname++)) return 1; return 0; }
int affs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct super_block *sb = old_dir->i_sb; struct buffer_head *bh = NULL; int retval; pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); retval = affs_check_name(new_dentry->d_name.name, new_dentry->d_name.len, affs_nofilenametruncate(old_dentry)); if (retval) return retval; /* Unlink destination if it already exists */ if (new_dentry->d_inode) { retval = affs_remove_header(new_dentry); if (retval) return retval; } bh = affs_bread(sb, old_dentry->d_inode->i_ino); if (!bh) return -EIO; /* Remove header from its parent directory. */ affs_lock_dir(old_dir); retval = affs_remove_hash(old_dir, bh); affs_unlock_dir(old_dir); if (retval) goto done; /* And insert it into the new directory with the new name. */ affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry); affs_fix_checksum(sb, bh); affs_lock_dir(new_dir); retval = affs_insert_hash(new_dir, bh); affs_unlock_dir(new_dir); /* TODO: move it back to old_dir, if error? */ done: mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir); affs_brelse(bh); return retval; }
/* * Note: the dentry argument is the parent dentry. */ static inline int __affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper) { const u8 *name = qstr->name; unsigned long hash; int i; i = affs_check_name(qstr->name,qstr->len); if (i) return i; hash = init_name_hash(); i = min(qstr->len, 30u); for (; i > 0; name++, i--) hash = partial_name_hash(toupper(*name), hash); qstr->hash = end_name_hash(hash); return 0; }
/* * Note: the dentry argument is the parent dentry. */ static inline int __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) { const u8 *name = qstr->name; unsigned long hash; int retval; u32 len; retval = affs_check_name(qstr->name, qstr->len, notruncate); if (retval) return retval; hash = init_name_hash(); len = min(qstr->len, AFFSNAMEMAX); for (; len > 0; name++, len--) hash = partial_name_hash(toupper(*name), hash); qstr->hash = end_name_hash(hash); return 0; }
/* * Note: the dentry argument is the parent dentry. */ static int affs_hash_dentry(struct dentry *dentry, struct qstr *qstr) { unsigned int (*toupper)(unsigned int) = affs_toupper; unsigned long hash; int i; if ((i = affs_check_name(qstr->name,qstr->len))) return i; /* Check whether to use the international 'toupper' routine */ if (AFFS_I2FSTYPE(dentry->d_inode)) toupper = affs_intl_toupper; hash = init_name_hash(); for (i = 0; i < qstr->len && i < 30; i++) hash = partial_name_hash(toupper(qstr->name[i]), hash); qstr->hash = end_name_hash(hash); return 0; }
int affs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct buffer_head *old_bh; struct buffer_head *new_bh; unsigned long old_ino; unsigned long new_ino; int retval; pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n", old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode, new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode); if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len))) goto out; new_bh = NULL; retval = -ENOENT; old_bh = affs_find_entry(old_dir,old_dentry,&old_ino); if (!old_bh) goto end_rename; new_bh = affs_find_entry(new_dir,new_dentry,&new_ino); if (new_bh && !new_inode) { affs_error(old_inode->i_sb,"affs_rename", "No inode for entry found (key=%lu)\n",new_ino); goto end_rename; } if (S_ISDIR(old_inode->i_mode)) { if (new_inode) { retval = -ENOTEMPTY; if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; } retval = -ENOENT; if (affs_parent_ino(old_inode) != old_dir->i_ino) goto end_rename; } /* Unlink destination if it already exists */ if (new_inode) { if ((retval = affs_remove_header(new_bh,new_dir)) < 0) goto end_rename; new_inode->i_nlink = retval; mark_inode_dirty(new_inode); if (new_inode->i_ino == new_ino) new_inode->i_nlink = 0; } /* Remove header from its parent directory. */ if ((retval = affs_remove_hash(old_bh,old_dir))) goto end_rename; /* And insert it into the new directory with the new name. */ affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name); if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir))) goto end_rename; affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5); new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; new_dir->i_version = ++event; old_dir->i_version = ++event; retval = 0; mark_inode_dirty(new_dir); mark_inode_dirty(old_dir); mark_buffer_dirty(old_bh,1); end_rename: affs_brelse(old_bh); affs_brelse(new_bh); out: return retval; }
int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, struct dentry *dentry, int type) { struct buffer_head *dir_bh; struct buffer_head *inode_bh; struct buffer_head *link_bh; int retval; const unsigned char *name = dentry->d_name.name; int len = dentry->d_name.len; pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino, len,name,type); if ((retval = affs_check_name(name,len))) return retval; if (len > 30) len = 30; dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); link_bh = NULL; retval = -EIO; if (!dir_bh || !inode_bh) goto addentry_done; if (link) { link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link)); if (!link_bh) goto addentry_done; } ((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT); ((struct dir_front *)inode_bh->b_data)->own_key = cpu_to_be32(inode->i_ino); DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len); DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type); DIR_END(inode_bh->b_data,inode)->parent = cpu_to_be32(dir->i_ino); lock_super(inode->i_sb); retval = affs_insert_hash(dir->i_ino,inode_bh,dir); if (link_bh) { LINK_END(inode_bh->b_data,inode)->original = cpu_to_be32(link->i_ino); LINK_END(inode_bh->b_data,inode)->link_chain = FILE_END(link_bh->b_data,link)->link_chain; FILE_END(link_bh->b_data,link)->link_chain = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5); link->i_version = ++global_event; mark_inode_dirty(link); mark_buffer_dirty(link_bh,1); } affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5); affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5); dir->i_version = ++global_event; dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME; unlock_super(inode->i_sb); mark_inode_dirty(dir); mark_inode_dirty(inode); mark_buffer_dirty(dir_bh,1); mark_buffer_dirty(inode_bh,1); addentry_done: affs_brelse(dir_bh); affs_brelse(inode_bh); affs_brelse(link_bh); return retval; }