Commit 78ab59fe authored by Konstantin Komarov's avatar Konstantin Komarov

fs/ntfs3: Rework file operations

Rename now works "Add new name and remove old name".
"Remove old name and add new name" may result in bad inode
if we can't add new name and then can't restore (add) old name.
Signed-off-by: default avatarKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
parent a97131c2
......@@ -218,9 +218,11 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
}
out:
/* Undo. */
/* Undo 'ntfs_look_for_free_space' */
if (vcn - vcn0) {
run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false);
run_truncate(run, vcn0);
}
return err;
}
......@@ -701,7 +703,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
* (list entry for std attribute always first).
* So it is safe to step back.
*/
mi_remove_attr(mi, attr);
mi_remove_attr(NULL, mi, attr);
if (!al_remove_le(ni, le)) {
err = -EINVAL;
......@@ -1004,7 +1006,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
end = next_svcn;
while (end > evcn) {
/* Remove segment [svcn : evcn). */
mi_remove_attr(mi, attr);
mi_remove_attr(NULL, mi, attr);
if (!al_remove_le(ni, le)) {
err = -EINVAL;
......@@ -1600,7 +1602,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
end = next_svcn;
while (end > evcn) {
/* Remove segment [svcn : evcn). */
mi_remove_attr(mi, attr);
mi_remove_attr(NULL, mi, attr);
if (!al_remove_le(ni, le)) {
err = -EINVAL;
......@@ -1836,13 +1838,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
u16 le_sz;
u16 roff = le16_to_cpu(attr->nres.run_off);
/* run==1 means unpack and deallocate. */
run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn,
evcn1 - 1, svcn, Add2Ptr(attr, roff),
le32_to_cpu(attr->size) - roff);
/* Delete this attribute segment. */
mi_remove_attr(mi, attr);
mi_remove_attr(NULL, mi, attr);
if (!le)
break;
......
......@@ -279,7 +279,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
struct ATTR_LIST_ENTRY *le;
size_t off;
u16 sz;
size_t asize, new_asize;
size_t asize, new_asize, old_size;
u64 new_size;
typeof(ni->attr_list) *al = &ni->attr_list;
......@@ -287,8 +287,9 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
* Compute the size of the new 'le'
*/
sz = le_size(name_len);
new_size = al->size + sz;
asize = al_aligned(al->size);
old_size = al->size;
new_size = old_size + sz;
asize = al_aligned(old_size);
new_asize = al_aligned(new_size);
/* Scan forward to the point at which the new 'le' should be inserted. */
......@@ -302,13 +303,14 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
return -ENOMEM;
memcpy(ptr, al->le, off);
memcpy(Add2Ptr(ptr, off + sz), le, al->size - off);
memcpy(Add2Ptr(ptr, off + sz), le, old_size - off);
le = Add2Ptr(ptr, off);
kfree(al->le);
al->le = ptr;
} else {
memmove(Add2Ptr(le, sz), le, al->size - off);
memmove(Add2Ptr(le, sz), le, old_size - off);
}
*new_le = le;
al->size = new_size;
......@@ -321,22 +323,24 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
le->id = id;
memcpy(le->name, name, sizeof(short) * name_len);
al->dirty = true;
err = attr_set_size(ni, ATTR_LIST, NULL, 0, &al->run, new_size,
&new_size, true, &attr);
if (err)
if (err) {
/* Undo memmove above. */
memmove(le, Add2Ptr(le, sz), old_size - off);
al->size = old_size;
return err;
}
al->dirty = true;
if (attr && attr->non_res) {
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
al->size);
if (err)
return err;
}
al->dirty = false;
*new_le = le;
}
return 0;
}
......
This diff is collapsed.
......@@ -358,30 +358,26 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
enum ALLOCATE_OPT opt)
{
int err;
CLST alen = 0;
struct super_block *sb = sbi->sb;
size_t a_lcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
struct wnd_bitmap *wnd = &sbi->used.bitmap;
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
if (opt & ALLOCATE_MFT) {
CLST alen;
zlen = wnd_zone_len(wnd);
if (!zlen) {
err = ntfs_refresh_zone(sbi);
if (err)
goto out;
zlen = wnd_zone_len(wnd);
}
if (!zlen) {
ntfs_err(sbi->sb,
"no free space to extend mft");
err = -ENOSPC;
ntfs_err(sbi->sb, "no free space to extend mft");
goto out;
}
}
lcn = wnd_zone_bit(wnd);
alen = zlen > len ? len : zlen;
......@@ -389,14 +385,13 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
wnd_zone_set(wnd, lcn + alen, zlen - alen);
err = wnd_set_used(wnd, lcn, alen);
if (err)
if (err) {
up_write(&wnd->rw_lock);
return err;
}
alcn = lcn;
goto out;
*new_lcn = lcn;
*new_len = alen;
goto ok;
}
/*
* 'Cause cluster 0 is always used this value means that we should use
* cached value of 'next_free_lcn' to improve performance.
......@@ -407,22 +402,17 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
if (lcn >= wnd->nbits)
lcn = 0;
*new_len = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &a_lcn);
if (*new_len) {
*new_lcn = a_lcn;
goto ok;
}
alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
if (alen)
goto out;
/* Try to use clusters from MftZone. */
zlen = wnd_zone_len(wnd);
zeroes = wnd_zeroes(wnd);
/* Check too big request. */
if (len > zeroes + zlen)
goto no_space;
if (zlen <= NTFS_MIN_MFT_ZONE)
goto no_space;
/* Check too big request */
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE)
goto out;
/* How many clusters to cat from zone. */
zlcn = wnd_zone_bit(wnd);
......@@ -439,31 +429,24 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
wnd_zone_set(wnd, zlcn, new_zlen);
/* Allocate continues clusters. */
*new_len =
wnd_find(wnd, len, 0,
BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &a_lcn);
if (*new_len) {
*new_lcn = a_lcn;
goto ok;
}
no_space:
up_write(&wnd->rw_lock);
return -ENOSPC;
alen = wnd_find(wnd, len, 0,
BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
ok:
out:
if (alen) {
err = 0;
*new_len = alen;
*new_lcn = alcn;
ntfs_unmap_meta(sb, *new_lcn, *new_len);
if (opt & ALLOCATE_MFT)
goto out;
ntfs_unmap_meta(sb, alcn, alen);
/* Set hint for next requests. */
sbi->used.next_free_lcn = *new_lcn + *new_len;
if (!(opt & ALLOCATE_MFT))
sbi->used.next_free_lcn = alcn + alen;
} else {
err = -ENOSPC;
}
out:
up_write(&wnd->rw_lock);
return err;
}
......@@ -2226,7 +2209,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
sii_e.sec_id = d_security->key.sec_id;
memcpy(&sii_e.sec_hdr, d_security, SIZEOF_SECURITY_HDR);
err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL);
err = indx_insert_entry(indx_sii, ni, &sii_e.de, NULL, NULL, 0);
if (err)
goto out;
......@@ -2247,7 +2230,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
fnd_clear(fnd_sdh);
err = indx_insert_entry(indx_sdh, ni, &sdh_e.de, (void *)(size_t)1,
fnd_sdh);
fnd_sdh, 0);
if (err)
goto out;
......@@ -2385,7 +2368,7 @@ int ntfs_insert_reparse(struct ntfs_sb_info *sbi, __le32 rtag,
mutex_lock_nested(&ni->ni_lock, NTFS_INODE_MUTEX_REPARSE);
err = indx_insert_entry(indx, ni, &re.de, NULL, NULL);
err = indx_insert_entry(indx, ni, &re.de, NULL, NULL, 0);
mark_inode_dirty(&ni->vfs_inode);
ni_unlock(ni);
......
......@@ -1427,7 +1427,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
alloc->nres.valid_size = alloc->nres.data_size = cpu_to_le64(data_size);
err = ni_insert_resident(ni, bitmap_size(1), ATTR_BITMAP, in->name,
in->name_len, &bitmap, NULL);
in->name_len, &bitmap, NULL, NULL);
if (err)
goto out2;
......@@ -1443,7 +1443,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
return 0;
out2:
mi_remove_attr(&ni->mi, alloc);
mi_remove_attr(NULL, &ni->mi, alloc);
out1:
run_deallocate(sbi, &run, false);
......@@ -1529,24 +1529,24 @@ static int indx_add_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
/*
* indx_insert_into_root - Attempt to insert an entry into the index root.
*
* @undo - True if we undoing previous remove.
* If necessary, it will twiddle the index b-tree.
*/
static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
const struct NTFS_DE *new_de,
struct NTFS_DE *root_de, const void *ctx,
struct ntfs_fnd *fnd)
struct ntfs_fnd *fnd, bool undo)
{
int err = 0;
struct NTFS_DE *e, *e0, *re;
struct mft_inode *mi;
struct ATTRIB *attr;
struct MFT_REC *rec;
struct INDEX_HDR *hdr;
struct indx_node *n;
CLST new_vbn;
__le64 *sub_vbn, t_vbn;
u16 new_de_size;
u32 hdr_used, hdr_total, asize, used, to_move;
u32 hdr_used, hdr_total, asize, to_move;
u32 root_size, new_root_size;
struct ntfs_sb_info *sbi;
int ds_root;
......@@ -1559,12 +1559,11 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
/*
* Try easy case:
* hdr_insert_de will succeed if there's room the root for the new entry.
* hdr_insert_de will succeed if there's
* room the root for the new entry.
*/
hdr = &root->ihdr;
sbi = ni->mi.sbi;
rec = mi->mrec;
used = le32_to_cpu(rec->used);
new_de_size = le16_to_cpu(new_de->size);
hdr_used = le32_to_cpu(hdr->used);
hdr_total = le32_to_cpu(hdr->total);
......@@ -1573,9 +1572,9 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
ds_root = new_de_size + hdr_used - hdr_total;
if (used + ds_root < sbi->max_bytes_per_attr) {
/* Make a room for new elements. */
mi_resize_attr(mi, attr, ds_root);
/* If 'undo' is set then reduce requirements. */
if ((undo || asize + ds_root < sbi->max_bytes_per_attr) &&
mi_resize_attr(mi, attr, ds_root)) {
hdr->total = cpu_to_le32(hdr_total + ds_root);
e = hdr_insert_de(indx, hdr, new_de, root_de, ctx);
WARN_ON(!e);
......@@ -1629,7 +1628,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
sizeof(u64);
ds_root = new_root_size - root_size;
if (ds_root > 0 && used + ds_root > sbi->max_bytes_per_attr) {
if (ds_root > 0 && asize + ds_root > sbi->max_bytes_per_attr) {
/* Make root external. */
err = -EOPNOTSUPP;
goto out_free_re;
......@@ -1710,7 +1709,7 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
put_indx_node(n);
fnd_clear(fnd);
err = indx_insert_entry(indx, ni, new_de, ctx, fnd);
err = indx_insert_entry(indx, ni, new_de, ctx, fnd, undo);
goto out_free_root;
}
......@@ -1854,7 +1853,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
*/
if (!level) {
/* Insert in root. */
err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd);
err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0);
if (err)
goto out;
} else {
......@@ -1876,10 +1875,12 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
/*
* indx_insert_entry - Insert new entry into index.
*
* @undo - True if we undoing previous remove.
*/
int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
const struct NTFS_DE *new_de, const void *ctx,
struct ntfs_fnd *fnd)
struct ntfs_fnd *fnd, bool undo)
{
int err;
int diff;
......@@ -1925,7 +1926,7 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
* new entry into it.
*/
err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx,
fnd);
fnd, undo);
if (err)
goto out;
} else {
......@@ -2302,7 +2303,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
fnd->level - 1,
fnd)
: indx_insert_into_root(indx, ni, re, e,
ctx, fnd);
ctx, fnd, 0);
kfree(re);
if (err)
......@@ -2507,7 +2508,7 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
* Re-insert the entry into the tree.
* Find the spot the tree where we want to insert the new entry.
*/
err = indx_insert_entry(indx, ni, me, ctx, fnd);
err = indx_insert_entry(indx, ni, me, ctx, fnd, 0);
kfree(me);
if (err)
goto out;
......@@ -2595,10 +2596,8 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
struct ntfs_index *indx = &ni->dir;
fnd = fnd_get();
if (!fnd) {
err = -ENOMEM;
goto out1;
}
if (!fnd)
return -ENOMEM;
root = indx_get_root(indx, ni, NULL, &mi);
if (!root) {
......@@ -2645,7 +2644,5 @@ int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
out:
fnd_put(fnd);
out1:
return err;
}
This diff is collapsed.
......@@ -152,12 +152,14 @@ static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de)
if (inode != dir)
ni_lock(ni);
dir->i_ctime = dir->i_mtime = inode->i_ctime = current_time(inode);
inc_nlink(inode);
ihold(inode);
err = ntfs_link_inode(inode, de);
if (!err) {
dir->i_ctime = dir->i_mtime = inode->i_ctime =
current_time(dir);
mark_inode_dirty(inode);
mark_inode_dirty(dir);
d_instantiate(de, inode);
......@@ -249,25 +251,26 @@ static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
/*
* ntfs_rename - inode_operations::rename
*/
static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
struct dentry *old_dentry, struct inode *new_dir,
static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, struct inode *new_dir,
struct dentry *new_dentry, u32 flags)
{
int err;
struct super_block *sb = old_dir->i_sb;
struct super_block *sb = dir->i_sb;
struct ntfs_sb_info *sbi = sb->s_fs_info;
struct ntfs_inode *old_dir_ni = ntfs_i(old_dir);
struct ntfs_inode *dir_ni = ntfs_i(dir);
struct ntfs_inode *new_dir_ni = ntfs_i(new_dir);
struct ntfs_inode *old_ni;
struct ATTR_FILE_NAME *old_name, *new_name, *fname;
u8 name_type;
bool is_same;
struct inode *old_inode, *new_inode;
struct NTFS_DE *old_de, *new_de;
struct ATTRIB *attr;
struct ATTR_LIST_ENTRY *le;
u16 new_de_key_size;
struct inode *inode = d_inode(dentry);
struct ntfs_inode *ni = ntfs_i(inode);
struct inode *new_inode = d_inode(new_dentry);
struct NTFS_DE *de, *new_de;
bool is_same, is_bad;
/*
* de - memory of PATH_MAX bytes:
* [0-1024) - original name (dentry->d_name)
* [1024-2048) - paired to original name, usually DOS variant of dentry->d_name
* [2048-3072) - new name (new_dentry->d_name)
*/
static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024);
static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) <
1024);
......@@ -276,24 +279,18 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
if (flags & ~RENAME_NOREPLACE)
return -EINVAL;
old_inode = d_inode(old_dentry);
new_inode = d_inode(new_dentry);
is_same = dentry->d_name.len == new_dentry->d_name.len &&
!memcmp(dentry->d_name.name, new_dentry->d_name.name,
dentry->d_name.len);
old_ni = ntfs_i(old_inode);
is_same = old_dentry->d_name.len == new_dentry->d_name.len &&
!memcmp(old_dentry->d_name.name, new_dentry->d_name.name,
old_dentry->d_name.len);
if (is_same && old_dir == new_dir) {
if (is_same && dir == new_dir) {
/* Nothing to do. */
err = 0;
goto out;
return 0;
}
if (ntfs_is_meta_file(sbi, old_inode->i_ino)) {
err = -EINVAL;
goto out;
if (ntfs_is_meta_file(sbi, inode->i_ino)) {
/* Should we print an error? */
return -EINVAL;
}
if (new_inode) {
......@@ -304,168 +301,61 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
ni_unlock(new_dir_ni);
dput(new_dentry);
if (err)
goto out;
return err;
}
/* Allocate PATH_MAX bytes. */
old_de = __getname();
if (!old_de) {
err = -ENOMEM;
goto out;
}
de = __getname();
if (!de)
return -ENOMEM;
err = fill_name_de(sbi, old_de, &old_dentry->d_name, NULL);
/* Translate dentry->d_name into unicode form. */
err = fill_name_de(sbi, de, &dentry->d_name, NULL);
if (err < 0)
goto out1;
old_name = (struct ATTR_FILE_NAME *)(old_de + 1);
goto out;
if (is_same) {
new_de = old_de;
/* Reuse 'de'. */
new_de = de;
} else {
new_de = Add2Ptr(old_de, 1024);
/* Translate new_dentry->d_name into unicode form. */
new_de = Add2Ptr(de, 2048);
err = fill_name_de(sbi, new_de, &new_dentry->d_name, NULL);
if (err < 0)
goto out1;
}
ni_lock_dir(old_dir_ni);
ni_lock(old_ni);
mi_get_ref(&old_dir_ni->mi, &old_name->home);
/* Get pointer to file_name in MFT. */
fname = ni_fname_name(old_ni, (struct cpu_str *)&old_name->name_len,
&old_name->home, &le);
if (!fname) {
err = -EINVAL;
goto out2;
goto out;
}
/* Copy fname info from record into new fname. */
new_name = (struct ATTR_FILE_NAME *)(new_de + 1);
memcpy(&new_name->dup, &fname->dup, sizeof(fname->dup));
name_type = paired_name(fname->type);
/* Remove first name from directory. */
err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1,
le16_to_cpu(old_de->key_size), sbi);
if (err)
goto out3;
/* Remove first name from MFT. */
err = ni_remove_attr_le(old_ni, attr_from_name(fname), le);
if (err)
goto out4;
le16_add_cpu(&old_ni->mi.mrec->hard_links, -1);
old_ni->mi.dirty = true;
if (name_type != FILE_NAME_POSIX) {
/* Get paired name. */
fname = ni_fname_type(old_ni, name_type, &le);
if (fname) {
/* Remove second name from directory. */
err = indx_delete_entry(&old_dir_ni->dir, old_dir_ni,
fname, fname_full_size(fname),
sbi);
if (err)
goto out5;
/* Remove second name from MFT. */
err = ni_remove_attr_le(old_ni, attr_from_name(fname),
le);
if (err)
goto out6;
ni_lock_dir(dir_ni);
ni_lock(ni);
le16_add_cpu(&old_ni->mi.mrec->hard_links, -1);
old_ni->mi.dirty = true;
}
is_bad = false;
err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
if (is_bad) {
/* Restore after failed rename failed too. */
make_bad_inode(inode);
ntfs_inode_err(inode, "failed to undo rename");
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
} else if (!err) {
inode->i_ctime = dir->i_ctime = dir->i_mtime =
current_time(dir);
mark_inode_dirty(inode);
mark_inode_dirty(dir);
if (dir != new_dir) {
new_dir->i_mtime = new_dir->i_ctime = dir->i_ctime;
mark_inode_dirty(new_dir);
}
/* Add new name. */
mi_get_ref(&old_ni->mi, &new_de->ref);
mi_get_ref(&ntfs_i(new_dir)->mi, &new_name->home);
new_de_key_size = le16_to_cpu(new_de->key_size);
/* Insert new name in MFT. */
err = ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0,
&attr, NULL);
if (err)
goto out7;
attr->res.flags = RESIDENT_FLAG_INDEXED;
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), new_name, new_de_key_size);
le16_add_cpu(&old_ni->mi.mrec->hard_links, 1);
old_ni->mi.dirty = true;
/* Insert new name in directory. */
err = indx_insert_entry(&new_dir_ni->dir, new_dir_ni, new_de, sbi,
NULL);
if (err)
goto out8;
if (IS_DIRSYNC(dir))
ntfs_sync_inode(dir);
if (IS_DIRSYNC(new_dir))
err = ntfs_sync_inode(old_inode);
else
mark_inode_dirty(old_inode);
old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
if (IS_DIRSYNC(old_dir))
(void)ntfs_sync_inode(old_dir);
else
mark_inode_dirty(old_dir);
if (old_dir != new_dir) {
new_dir->i_mtime = new_dir->i_ctime = old_dir->i_ctime;
mark_inode_dirty(new_dir);
ntfs_sync_inode(inode);
}
if (old_inode) {
old_inode->i_ctime = old_dir->i_ctime;
mark_inode_dirty(old_inode);
}
err = 0;
/* Normal way* */
goto out2;
out8:
/* undo
* ni_insert_resident(old_ni, new_de_key_size, ATTR_NAME, NULL, 0,
* &attr, NULL);
*/
mi_remove_attr(&old_ni->mi, attr);
out7:
/* undo
* ni_remove_attr_le(old_ni, attr_from_name(fname), le);
*/
out6:
/* undo
* indx_delete_entry(&old_dir_ni->dir, old_dir_ni,
* fname, fname_full_size(fname),
* sbi);
*/
out5:
/* undo
* ni_remove_attr_le(old_ni, attr_from_name(fname), le);
*/
out4:
/* undo:
* indx_delete_entry(&old_dir_ni->dir, old_dir_ni, old_de + 1,
* old_de->key_size, NULL);
*/
out3:
out2:
ni_unlock(old_ni);
ni_unlock(old_dir_ni);
out1:
__putname(old_de);
ni_unlock(ni);
ni_unlock(dir_ni);
out:
__putname(de);
return err;
}
......
......@@ -478,7 +478,7 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni);
struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni);
void ni_clear(struct ntfs_inode *ni);
int ni_load_mi_ex(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi);
int ni_load_mi(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
int ni_load_mi(struct ntfs_inode *ni, const struct ATTR_LIST_ENTRY *le,
struct mft_inode **mi);
struct ATTRIB *ni_find_attr(struct ntfs_inode *ni, struct ATTRIB *attr,
struct ATTR_LIST_ENTRY **entry_o,
......@@ -505,15 +505,18 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
struct mft_inode **mi);
int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
enum ATTR_TYPE type, const __le16 *name, u8 name_len,
struct ATTRIB **new_attr, struct mft_inode **mi);
int ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
struct ATTR_LIST_ENTRY *le);
struct ATTRIB **new_attr, struct mft_inode **mi,
struct ATTR_LIST_ENTRY **le);
void ni_remove_attr_le(struct ntfs_inode *ni, struct ATTRIB *attr,
struct mft_inode *mi, struct ATTR_LIST_ENTRY *le);
int ni_delete_all(struct ntfs_inode *ni);
struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
const struct cpu_str *uni,
const struct MFT_REF *home,
struct mft_inode **mi,
struct ATTR_LIST_ENTRY **entry);
struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
struct mft_inode **mi,
struct ATTR_LIST_ENTRY **entry);
int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa);
enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
......@@ -528,6 +531,21 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
u32 pages_per_frame);
int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
u32 pages_per_frame);
int ni_remove_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
struct NTFS_DE *de, struct NTFS_DE **de2, int *undo_step);
bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
struct NTFS_DE *de, struct NTFS_DE *de2,
int undo_step);
int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
struct NTFS_DE *de);
int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
bool *is_bad);
bool ni_is_dirty(struct inode *inode);
/* Globals from fslog.c */
int log_replay(struct ntfs_inode *ni, bool *initialized);
......@@ -631,7 +649,7 @@ int indx_find_raw(struct ntfs_index *indx, struct ntfs_inode *ni,
size_t *off, struct ntfs_fnd *fnd);
int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
const struct NTFS_DE *new_de, const void *param,
struct ntfs_fnd *fnd);
struct ntfs_fnd *fnd, bool undo);
int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
const void *key, u32 key_len, const void *param);
int indx_update_dup(struct ntfs_inode *ni, struct ntfs_sb_info *sbi,
......@@ -694,7 +712,8 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
const __le16 *name, u8 name_len, u32 asize,
u16 name_off);
bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr);
bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
struct ATTRIB *attr);
bool mi_resize_attr(struct mft_inode *mi, struct ATTRIB *attr, int bytes);
int mi_pack_runs(struct mft_inode *mi, struct ATTRIB *attr,
struct runs_tree *run, CLST len);
......
......@@ -489,7 +489,8 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
*
* NOTE: The source attr will point to next attribute.
*/
bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr)
bool mi_remove_attr(struct ntfs_inode *ni, struct mft_inode *mi,
struct ATTRIB *attr)
{
struct MFT_REC *rec = mi->mrec;
u32 aoff = PtrOffset(rec, attr);
......@@ -499,6 +500,11 @@ bool mi_remove_attr(struct mft_inode *mi, struct ATTRIB *attr)
if (aoff + asize > used)
return false;
if (ni && is_attr_indexed(attr)) {
le16_add_cpu(&ni->mi.mrec->hard_links, -1);
ni->mi.dirty = true;
}
used -= asize;
memmove(attr, Add2Ptr(attr, asize), used - aoff);
rec->used = cpu_to_le32(used);
......
......@@ -395,11 +395,13 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
}
err = ni_insert_resident(ni, sizeof(struct EA_INFO),
ATTR_EA_INFO, NULL, 0, NULL, NULL);
ATTR_EA_INFO, NULL, 0, NULL, NULL,
NULL);
if (err)
goto out;
err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL);
err = ni_insert_resident(ni, 0, ATTR_EA, NULL, 0, NULL, NULL,
NULL);
if (err)
goto out;
}
......@@ -419,9 +421,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
if (!size) {
/* Delete xattr, ATTR_EA_INFO */
err = ni_remove_attr_le(ni, attr, le);
if (err)
goto out;
ni_remove_attr_le(ni, attr, mi, le);
} else {
p = resident_data_ex(attr, sizeof(struct EA_INFO));
if (!p) {
......@@ -441,9 +441,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
if (!size) {
/* Delete xattr, ATTR_EA */
err = ni_remove_attr_le(ni, attr, le);
if (err)
goto out;
ni_remove_attr_le(ni, attr, mi, le);
} else if (attr->non_res) {
err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size);
if (err)
......@@ -605,8 +603,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
goto out;
}
err = ntfs_set_ea(inode, name, name_len, value, size,
acl ? 0 : XATTR_REPLACE, locked);
err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked);
if (!err)
set_cached_acl(inode, type, acl);
......@@ -632,8 +629,10 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
struct posix_acl *acl;
int err;
if (!(inode->i_sb->s_flags & SB_POSIXACL))
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
return -EOPNOTSUPP;
}
acl = ntfs_get_acl(inode, type);
if (IS_ERR(acl))
......@@ -655,8 +654,10 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
struct posix_acl *acl;
int err;
if (!(inode->i_sb->s_flags & SB_POSIXACL))
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
return -EOPNOTSUPP;
}
if (!inode_owner_or_capable(mnt_userns, inode))
return -EPERM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment