int hmfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *inode; struct hmfs_sb_info *sbi = HMFS_SB(dir->i_sb); void *data_blk; size_t symlen = strlen(symname) + 1; int ilock; if (symlen > HMFS_MAX_SYMLINK_NAME_LEN) return -ENAMETOOLONG; ilock = mutex_lock_op(sbi); inode = hmfs_make_dentry(dir, dentry, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) return PTR_ERR(inode); inode->i_op = &hmfs_symlink_inode_operations; inode->i_mapping->a_ops = &hmfs_dblock_aops; data_blk = alloc_new_data_block(inode, 0); if (IS_ERR(data_blk)) return PTR_ERR(data_blk); hmfs_memcpy(data_blk, (void *)symname, symlen); mutex_unlock_op(sbi, ilock); d_instantiate(dentry, inode); unlock_new_inode(inode); return 0; }
static int __hmfs_setxattr(struct inode *inode, int index, const char *name, const void *value, size_t size, int flags) { struct hmfs_xattr_entry *this, *last, *next; void *base_addr, *new_xattr_blk; int newsize, cpy_size; size_t name_len; int error = -ENOMEM; if (name == NULL) return -EINVAL; if (value == NULL) size = 0; name_len = strlen(name); if (name_len > HMFS_NAME_LEN) return -ERANGE; if (name_len + size > HMFS_XATTR_VALUE_LEN) return -E2BIG; base_addr = get_xattr_block(inode); if (!base_addr) { error = -ENODATA; goto out; } if (!base_addr) { if (flags & XATTR_CREATE) goto create; error = -ENODATA; goto out; } this = __find_xattr(base_addr, index, name_len, name); if (this->e_name_index == HMFS_XATTR_INDEX_END && (flags & XATTR_REPLACE)) { error = -ENODATA; goto out; } else if ((flags & XATTR_CREATE) && this->e_name_index != HMFS_XATTR_INDEX_END) { error = -EEXIST; goto out; } newsize = XATTR_RAW_SIZE + name_len + size; /* Check Space */ if (value) { /* If value is NULL, it's a remove operation */ /* Add another hmfs_xattr_entry for end entry */ last = XATTR_ENTRY(JUMP(this, newsize + XATTR_RAW_SIZE)); if (DISTANCE(base_addr, last) > HMFS_XATTR_BLOCK_SIZE) { error = -ENOSPC; goto out; } } create: /* Allocate new xattr block */ new_xattr_blk = alloc_new_x_block(inode, HMFS_X_BLOCK_TAG_XATTR, false); init_xattr_block(new_xattr_blk); /* Remove old entry in old xattr block */ if (base_addr) { /* Copy first part */ next = XATTR_FIRST_ENTRY(base_addr); cpy_size = DISTANCE(next, this); hmfs_memcpy(XATTR_FIRST_ENTRY(new_xattr_blk), next, cpy_size); /* Get last xattr in source xattr block */ last = this; while (!IS_XATTR_LAST_ENTRY(last)) last = XATTR_NEXT_ENTRY(last); /* Copy second part */ next = XATTR_NEXT_ENTRY(this); cpy_size = DISTANCE(next, last); next = XATTR_ENTRY(JUMP(new_xattr_blk, DISTANCE(base_addr, this))); hmfs_memcpy(next, XATTR_NEXT_ENTRY(this), cpy_size); next = XATTR_ENTRY(JUMP(next, cpy_size)); } else { next = XATTR_FIRST_ENTRY(new_xattr_blk); } /* Write new entry */ if (value) { next->e_name_index = index; next->e_name_len = name_len; next->e_value_len = size; memcpy(next->e_name, name, name_len); memcpy(next->e_name + name_len, value, size); next = XATTR_ENTRY(next->e_name + name_len + size); } /* Write End entry */ next->e_name_index = HMFS_XATTR_INDEX_END; hmfs_bug_on(HMFS_I_SB(inode), DISTANCE(new_xattr_blk, JUMP(next, XATTR_RAW_SIZE)) > HMFS_XATTR_BLOCK_SIZE); inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); out: return error; }