Commit 1e098dec authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ntfs3_for_6.4' of https://github.com/Paragon-Software-Group/linux-ntfs3

Pull ntfs3 updates from Konstantin Komarov:
 "New code:

   - add missed "nocase" in ntfs_show_options

   - extend information on failures/errors

   - small optimizations

  Fixes:

   - some logic errors

   - some dead code was removed

   - code is refactored and reformatted according to the new version of
     clang-format

  Code removal:

   - 'noacsrules' option.

     Currently, this option does not work properly, and its use leads to
     unstable results. If we figure out how to implement it without
     errors, we will add it later

   - writepage"

* tag 'ntfs3_for_6.4' of https://github.com/Paragon-Software-Group/linux-ntfs3: (30 commits)
  fs/ntfs3: Fix root inode checking
  fs/ntfs3: Print details about mount fails
  fs/ntfs3: Add missed "nocase" in ntfs_show_options
  fs/ntfs3: Code formatting and refactoring
  fs/ntfs3: Changed ntfs_get_acl() to use dentry
  fs/ntfs3: Remove field sbi->used.bitmap.set_tail
  fs/ntfs3: Undo critial modificatins to keep directory consistency
  fs/ntfs3: Undo endian changes
  fs/ntfs3: Optimization in ntfs_set_state()
  fs/ntfs3: Fix ntfs_create_inode()
  fs/ntfs3: Remove noacsrules
  fs/ntfs3: Use bh_read to simplify code
  fs/ntfs3: Fix a possible null-pointer dereference in ni_clear()
  fs/ntfs3: Refactoring of various minor issues
  fs/ntfs3: Restore overflow checking for attr size in mi_enum_attr
  fs/ntfs3: Check for extremely large size of $AttrDef
  fs/ntfs3: Improved checking of attribute's name length
  fs/ntfs3: Add null pointer checks
  fs/ntfs3: fix spelling mistake "attibute" -> "attribute"
  fs/ntfs3: Add length check in indx_get_root
  ...
parents 56c455b3 788ee160
...@@ -61,17 +61,6 @@ this table marked with no it means default is without **no**. ...@@ -61,17 +61,6 @@ this table marked with no it means default is without **no**.
directories, fmask applies only to files and dmask only to directories. directories, fmask applies only to files and dmask only to directories.
* - fmask= * - fmask=
* - noacsrules
- "No access rules" mount option sets access rights for files/folders to
777 and owner/group to root. This mount option absorbs all other
permissions.
- Permissions change for files/folders will be reported as successful,
but they will remain 777.
- Owner/group change will be reported as successful, butthey will stay
as root.
* - nohidden * - nohidden
- Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute - Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute
will not be shown under Linux. will not be shown under Linux.
......
...@@ -405,8 +405,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -405,8 +405,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
int err = 0; int err = 0;
struct ntfs_sb_info *sbi = ni->mi.sbi; struct ntfs_sb_info *sbi = ni->mi.sbi;
u8 cluster_bits = sbi->cluster_bits; u8 cluster_bits = sbi->cluster_bits;
bool is_mft = bool is_mft = ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA &&
ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA && !name_len; !name_len;
u64 old_valid, old_size, old_alloc, new_alloc, new_alloc_tmp; u64 old_valid, old_size, old_alloc, new_alloc, new_alloc_tmp;
struct ATTRIB *attr = NULL, *attr_b; struct ATTRIB *attr = NULL, *attr_b;
struct ATTR_LIST_ENTRY *le, *le_b; struct ATTR_LIST_ENTRY *le, *le_b;
...@@ -531,10 +531,9 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -531,10 +531,9 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
pre_alloc = 0; pre_alloc = 0;
if (type == ATTR_DATA && !name_len && if (type == ATTR_DATA && !name_len &&
sbi->options->prealloc) { sbi->options->prealloc) {
pre_alloc = pre_alloc = bytes_to_cluster(
bytes_to_cluster( sbi, get_pre_allocated(
sbi, new_size)) -
get_pre_allocated(new_size)) -
new_alen; new_alen;
} }
...@@ -573,8 +572,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -573,8 +572,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
err = attr_allocate_clusters( err = attr_allocate_clusters(
sbi, run, vcn, lcn, to_allocate, &pre_alloc, sbi, run, vcn, lcn, to_allocate, &pre_alloc,
is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen, is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen,
is_mft ? 0 is_mft ? 0 :
: (sbi->record_size - (sbi->record_size -
le32_to_cpu(rec->used) + 8) / le32_to_cpu(rec->used) + 8) /
3 + 3 +
1, 1,
......
...@@ -40,8 +40,8 @@ static struct kmem_cache *ntfs_enode_cachep; ...@@ -40,8 +40,8 @@ static struct kmem_cache *ntfs_enode_cachep;
int __init ntfs3_init_bitmap(void) int __init ntfs3_init_bitmap(void)
{ {
ntfs_enode_cachep = ntfs_enode_cachep = kmem_cache_create("ntfs3_enode_cache",
kmem_cache_create("ntfs3_enode_cache", sizeof(struct e_node), 0, sizeof(struct e_node), 0,
SLAB_RECLAIM_ACCOUNT, NULL); SLAB_RECLAIM_ACCOUNT, NULL);
return ntfs_enode_cachep ? 0 : -ENOMEM; return ntfs_enode_cachep ? 0 : -ENOMEM;
} }
...@@ -286,9 +286,9 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len, ...@@ -286,9 +286,9 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len,
if (wnd->uptodated != 1) { if (wnd->uptodated != 1) {
/* Check bits before 'bit'. */ /* Check bits before 'bit'. */
ib = wnd->zone_bit == wnd->zone_end || ib = wnd->zone_bit == wnd->zone_end ||
bit < wnd->zone_end bit < wnd->zone_end ?
? 0 0 :
: wnd->zone_end; wnd->zone_end;
while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) { while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) {
bit -= 1; bit -= 1;
...@@ -297,9 +297,9 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len, ...@@ -297,9 +297,9 @@ static void wnd_add_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len,
/* Check bits after 'end_in'. */ /* Check bits after 'end_in'. */
ib = wnd->zone_bit == wnd->zone_end || ib = wnd->zone_bit == wnd->zone_end ||
end_in > wnd->zone_bit end_in > wnd->zone_bit ?
? wnd->nbits wnd->nbits :
: wnd->zone_bit; wnd->zone_bit;
while (end_in < ib && wnd_is_free_hlp(wnd, end_in, 1)) { while (end_in < ib && wnd_is_free_hlp(wnd, end_in, 1)) {
end_in += 1; end_in += 1;
...@@ -417,8 +417,8 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len) ...@@ -417,8 +417,8 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len)
return; return;
n3 = rb_first(&wnd->count_tree); n3 = rb_first(&wnd->count_tree);
wnd->extent_max = wnd->extent_max =
n3 ? rb_entry(n3, struct e_node, count.node)->count.key n3 ? rb_entry(n3, struct e_node, count.node)->count.key :
: 0; 0;
return; return;
} }
...@@ -658,7 +658,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits) ...@@ -658,7 +658,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits)
if (!wnd->bits_last) if (!wnd->bits_last)
wnd->bits_last = wbits; wnd->bits_last = wbits;
wnd->free_bits = kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN); wnd->free_bits =
kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN);
if (!wnd->free_bits) if (!wnd->free_bits)
return -ENOMEM; return -ENOMEM;
......
...@@ -22,20 +22,21 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, unsigned long arg) ...@@ -22,20 +22,21 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, unsigned long arg)
{ {
struct fstrim_range __user *user_range; struct fstrim_range __user *user_range;
struct fstrim_range range; struct fstrim_range range;
struct block_device *dev;
int err; int err;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (!bdev_max_discard_sectors(sbi->sb->s_bdev)) dev = sbi->sb->s_bdev;
if (!bdev_max_discard_sectors(dev))
return -EOPNOTSUPP; return -EOPNOTSUPP;
user_range = (struct fstrim_range __user *)arg; user_range = (struct fstrim_range __user *)arg;
if (copy_from_user(&range, user_range, sizeof(range))) if (copy_from_user(&range, user_range, sizeof(range)))
return -EFAULT; return -EFAULT;
range.minlen = max_t(u32, range.minlen, range.minlen = max_t(u32, range.minlen, bdev_discard_granularity(dev));
bdev_discard_granularity(sbi->sb->s_bdev));
err = ntfs_trim_fs(sbi, &range); err = ntfs_trim_fs(sbi, &range);
if (err < 0) if (err < 0)
...@@ -190,8 +191,8 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to) ...@@ -190,8 +191,8 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
for (; idx < idx_end; idx += 1, from = 0) { for (; idx < idx_end; idx += 1, from = 0) {
page_off = (loff_t)idx << PAGE_SHIFT; page_off = (loff_t)idx << PAGE_SHIFT;
to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) :
: PAGE_SIZE; PAGE_SIZE;
iblock = page_off >> inode->i_blkbits; iblock = page_off >> inode->i_blkbits;
page = find_or_create_page(mapping, idx, page = find_or_create_page(mapping, idx,
...@@ -223,16 +224,10 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to) ...@@ -223,16 +224,10 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
if (!buffer_uptodate(bh)) { if (!buffer_uptodate(bh)) {
lock_buffer(bh); err = bh_read(bh, 0);
bh->b_end_io = end_buffer_read_sync; if (err < 0) {
get_bh(bh);
submit_bh(REQ_OP_READ, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
unlock_page(page); unlock_page(page);
put_page(page); put_page(page);
err = -EIO;
goto out; goto out;
} }
} }
...@@ -570,13 +565,14 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -570,13 +565,14 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
ni_unlock(ni); ni_unlock(ni);
} else { } else {
/* Check new size. */ /* Check new size. */
u8 cluster_bits = sbi->cluster_bits;
/* generic/213: expected -ENOSPC instead of -EFBIG. */ /* generic/213: expected -ENOSPC instead of -EFBIG. */
if (!is_supported_holes) { if (!is_supported_holes) {
loff_t to_alloc = new_size - inode_get_bytes(inode); loff_t to_alloc = new_size - inode_get_bytes(inode);
if (to_alloc > 0 && if (to_alloc > 0 &&
(to_alloc >> sbi->cluster_bits) > (to_alloc >> cluster_bits) >
wnd_zeroes(&sbi->used.bitmap)) { wnd_zeroes(&sbi->used.bitmap)) {
err = -ENOSPC; err = -ENOSPC;
goto out; goto out;
...@@ -597,7 +593,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -597,7 +593,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
} }
if (is_supported_holes) { if (is_supported_holes) {
CLST vcn = vbo >> sbi->cluster_bits; CLST vcn = vbo >> cluster_bits;
CLST cend = bytes_to_cluster(sbi, end); CLST cend = bytes_to_cluster(sbi, end);
CLST cend_v = bytes_to_cluster(sbi, ni->i_valid); CLST cend_v = bytes_to_cluster(sbi, ni->i_valid);
CLST lcn, clen; CLST lcn, clen;
...@@ -660,22 +656,12 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -660,22 +656,12 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry, int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr) struct iattr *attr)
{ {
struct super_block *sb = dentry->d_sb;
struct ntfs_sb_info *sbi = sb->s_fs_info;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
u32 ia_valid = attr->ia_valid; u32 ia_valid = attr->ia_valid;
umode_t mode = inode->i_mode; umode_t mode = inode->i_mode;
int err; int err;
if (sbi->options->noacsrules) {
/* "No access rules" - Force any changes of time etc. */
attr->ia_valid |= ATTR_FORCE;
/* and disable for editing some attributes. */
attr->ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE);
ia_valid = attr->ia_valid;
}
err = setattr_prepare(idmap, dentry, attr); err = setattr_prepare(idmap, dentry, attr);
if (err) if (err)
goto out; goto out;
...@@ -719,7 +705,7 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry, ...@@ -719,7 +705,7 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
} }
if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE))
ntfs_save_wsl_perm(inode); ntfs_save_wsl_perm(inode, NULL);
mark_inode_dirty(inode); mark_inode_dirty(inode);
out: out:
return err; return err;
...@@ -1065,8 +1051,8 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1065,8 +1051,8 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (ret) if (ret)
goto out; goto out;
ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) :
: __generic_file_write_iter(iocb, from); __generic_file_write_iter(iocb, from);
out: out:
inode_unlock(inode); inode_unlock(inode);
...@@ -1118,7 +1104,8 @@ static int ntfs_file_release(struct inode *inode, struct file *file) ...@@ -1118,7 +1104,8 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
int err = 0; int err = 0;
/* If we are last writer on the inode, drop the block reservation. */ /* If we are last writer on the inode, drop the block reservation. */
if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) && if (sbi->options->prealloc &&
((file->f_mode & FMODE_WRITE) &&
atomic_read(&inode->i_writecount) == 1)) { atomic_read(&inode->i_writecount) == 1)) {
ni_lock(ni); ni_lock(ni);
down_write(&ni->file.run_lock); down_write(&ni->file.run_lock);
...@@ -1159,8 +1146,7 @@ const struct inode_operations ntfs_file_inode_operations = { ...@@ -1159,8 +1146,7 @@ const struct inode_operations ntfs_file_inode_operations = {
.getattr = ntfs_getattr, .getattr = ntfs_getattr,
.setattr = ntfs3_setattr, .setattr = ntfs3_setattr,
.listxattr = ntfs_listxattr, .listxattr = ntfs_listxattr,
.permission = ntfs_permission, .get_acl = ntfs_get_acl,
.get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl, .set_acl = ntfs_set_acl,
.fiemap = ntfs_fiemap, .fiemap = ntfs_fiemap,
}; };
......
...@@ -76,8 +76,8 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni) ...@@ -76,8 +76,8 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni)
const struct ATTRIB *attr; const struct ATTRIB *attr;
attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL); attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) :
: NULL; NULL;
} }
/* /*
...@@ -91,8 +91,8 @@ struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni) ...@@ -91,8 +91,8 @@ struct ATTR_STD_INFO5 *ni_std5(struct ntfs_inode *ni)
attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL); attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) :
: NULL; NULL;
} }
/* /*
...@@ -102,7 +102,7 @@ void ni_clear(struct ntfs_inode *ni) ...@@ -102,7 +102,7 @@ void ni_clear(struct ntfs_inode *ni)
{ {
struct rb_node *node; struct rb_node *node;
if (!ni->vfs_inode.i_nlink && is_rec_inuse(ni->mi.mrec)) if (!ni->vfs_inode.i_nlink && ni->mi.mrec && is_rec_inuse(ni->mi.mrec))
ni_delete_all(ni); ni_delete_all(ni);
al_destroy(ni); al_destroy(ni);
...@@ -1439,8 +1439,8 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1439,8 +1439,8 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
int err; int err;
CLST plen; CLST plen;
struct ATTRIB *attr; struct ATTRIB *attr;
bool is_ext = bool is_ext = (flags & (ATTR_FLAG_SPARSED | ATTR_FLAG_COMPRESSED)) &&
(flags & (ATTR_FLAG_SPARSED | ATTR_FLAG_COMPRESSED)) && !svcn; !svcn;
u32 name_size = ALIGN(name_len * sizeof(short), 8); u32 name_size = ALIGN(name_len * sizeof(short), 8);
u32 name_off = is_ext ? SIZEOF_NONRESIDENT_EX : SIZEOF_NONRESIDENT; u32 name_off = is_ext ? SIZEOF_NONRESIDENT_EX : SIZEOF_NONRESIDENT;
u32 run_off = name_off + name_size; u32 run_off = name_off + name_size;
...@@ -1756,9 +1756,9 @@ int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa) ...@@ -1756,9 +1756,9 @@ int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa)
} }
/* Resize nonresident empty attribute in-place only. */ /* Resize nonresident empty attribute in-place only. */
new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) ?
? (SIZEOF_NONRESIDENT_EX + 8) (SIZEOF_NONRESIDENT_EX + 8) :
: (SIZEOF_NONRESIDENT + 8); (SIZEOF_NONRESIDENT + 8);
if (!mi_resize_attr(mi, attr, new_asize - le32_to_cpu(attr->size))) if (!mi_resize_attr(mi, attr, new_asize - le32_to_cpu(attr->size)))
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -2965,14 +2965,14 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, ...@@ -2965,14 +2965,14 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
{ {
struct ntfs_sb_info *sbi = ni->mi.sbi; struct ntfs_sb_info *sbi = ni->mi.sbi;
struct ATTRIB *attr; struct ATTRIB *attr;
u16 de_key_size = de2 ? le16_to_cpu(de2->key_size) : 0; u16 de_key_size;
switch (undo_step) { switch (undo_step) {
case 4: case 4:
de_key_size = le16_to_cpu(de2->key_size);
if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
&attr, NULL, NULL)) { &attr, NULL, NULL))
return false; return false;
}
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de2 + 1, de_key_size); memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de2 + 1, de_key_size);
mi_get_ref(&ni->mi, &de2->ref); mi_get_ref(&ni->mi, &de2->ref);
...@@ -2981,19 +2981,16 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, ...@@ -2981,19 +2981,16 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
de2->flags = 0; de2->flags = 0;
de2->res = 0; de2->res = 0;
if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL, if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL, 1))
1)) {
return false; return false;
}
fallthrough; fallthrough;
case 2: case 2:
de_key_size = le16_to_cpu(de->key_size); de_key_size = le16_to_cpu(de->key_size);
if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
&attr, NULL, NULL)) { &attr, NULL, NULL))
return false; return false;
}
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size); memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
mi_get_ref(&ni->mi, &de->ref); mi_get_ref(&ni->mi, &de->ref);
...@@ -3162,9 +3159,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup, ...@@ -3162,9 +3159,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
u64 data_size = le64_to_cpu(attr->nres.data_size); u64 data_size = le64_to_cpu(attr->nres.data_size);
__le64 valid_le; __le64 valid_le;
dup->alloc_size = is_attr_ext(attr) dup->alloc_size = is_attr_ext(attr) ?
? attr->nres.total_size attr->nres.total_size :
: attr->nres.alloc_size; attr->nres.alloc_size;
dup->data_size = attr->nres.data_size; dup->data_size = attr->nres.data_size;
if (new_valid > data_size) if (new_valid > data_size)
...@@ -3258,6 +3255,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) ...@@ -3258,6 +3255,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
return 0; return 0;
} }
if (!ni->mi.mrec)
goto out;
if (is_rec_inuse(ni->mi.mrec) && if (is_rec_inuse(ni->mi.mrec) &&
!(sbi->flags & NTFS_FLAGS_LOG_REPLAYING) && inode->i_nlink) { !(sbi->flags & NTFS_FLAGS_LOG_REPLAYING) && inode->i_nlink) {
bool modified = false; bool modified = false;
...@@ -3360,7 +3360,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) ...@@ -3360,7 +3360,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
ni_unlock(ni); ni_unlock(ni);
if (err) { if (err) {
ntfs_err(sb, "%s r=%lx failed, %d.", hint, inode->i_ino, err); ntfs_inode_err(inode, "%s failed, %d.", hint, err);
ntfs_set_state(sbi, NTFS_DIRTY_ERROR); ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
return err; return err;
} }
......
...@@ -827,9 +827,9 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl, ...@@ -827,9 +827,9 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl,
memcpy(rt + 1, tbl + 1, esize * used); memcpy(rt + 1, tbl + 1, esize * used);
rt->free_goal = free_goal == ~0u rt->free_goal = free_goal == ~0u ?
? cpu_to_le32(~0u) cpu_to_le32(~0u) :
: cpu_to_le32(sizeof(struct RESTART_TABLE) + cpu_to_le32(sizeof(struct RESTART_TABLE) +
free_goal * esize); free_goal * esize);
if (tbl->first_free) { if (tbl->first_free) {
...@@ -1089,9 +1089,9 @@ static inline u64 base_lsn(struct ntfs_log *log, ...@@ -1089,9 +1089,9 @@ static inline u64 base_lsn(struct ntfs_log *log,
(lsn < (lsn_to_vbo(log, h_lsn) & ~log->page_mask) ? 1 : 0)) (lsn < (lsn_to_vbo(log, h_lsn) & ~log->page_mask) ? 1 : 0))
<< log->file_data_bits) + << log->file_data_bits) +
((((is_log_record_end(hdr) && ((((is_log_record_end(hdr) &&
h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) ?
? le16_to_cpu(hdr->record_hdr.next_record_off) le16_to_cpu(hdr->record_hdr.next_record_off) :
: log->page_size) + log->page_size) +
lsn) >> lsn) >>
3); 3);
...@@ -1298,9 +1298,9 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size, ...@@ -1298,9 +1298,9 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size,
if (!log->clst_per_page) if (!log->clst_per_page)
log->clst_per_page = 1; log->clst_per_page = 1;
log->first_page = major_ver >= 2 log->first_page = major_ver >= 2 ?
? 0x22 * page_size 0x22 * page_size :
: ((sys_page_size << 1) + (page_size << 1)); ((sys_page_size << 1) + (page_size << 1));
log->major_ver = major_ver; log->major_ver = major_ver;
log->minor_ver = minor_ver; log->minor_ver = minor_ver;
} }
...@@ -1512,20 +1512,19 @@ static u32 current_log_avail(struct ntfs_log *log) ...@@ -1512,20 +1512,19 @@ static u32 current_log_avail(struct ntfs_log *log)
* have to compute the free range. * have to compute the free range.
* If there is no oldest lsn then start at the first page of the file. * If there is no oldest lsn then start at the first page of the file.
*/ */
oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) ?
? log->first_page log->first_page :
: (log->oldest_lsn_off & ~log->sys_page_mask); (log->oldest_lsn_off & ~log->sys_page_mask);
/* /*
* We will use the next log page offset to compute the next free page. * We will use the next log page offset to compute the next free page.
* If we are going to reuse this page go to the next page. * If we are going to reuse this page go to the next page.
* If we are at the first page then use the end of the file. * If we are at the first page then use the end of the file.
*/ */
next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) ?
? log->next_page + log->page_size log->next_page + log->page_size :
: log->next_page == log->first_page log->next_page == log->first_page ? log->l_size :
? log->l_size log->next_page;
: log->next_page;
/* If the two offsets are the same then there is no available space. */ /* If the two offsets are the same then there is no available space. */
if (oldest_off == next_free_off) if (oldest_off == next_free_off)
...@@ -1535,9 +1534,9 @@ static u32 current_log_avail(struct ntfs_log *log) ...@@ -1535,9 +1534,9 @@ static u32 current_log_avail(struct ntfs_log *log)
* this range from the total available pages. * this range from the total available pages.
*/ */
free_bytes = free_bytes =
oldest_off < next_free_off oldest_off < next_free_off ?
? log->total_avail_pages - (next_free_off - oldest_off) log->total_avail_pages - (next_free_off - oldest_off) :
: oldest_off - next_free_off; oldest_off - next_free_off;
free_bytes >>= log->page_bits; free_bytes >>= log->page_bits;
return free_bytes * log->reserved; return free_bytes * log->reserved;
...@@ -1671,8 +1670,8 @@ static int last_log_lsn(struct ntfs_log *log) ...@@ -1671,8 +1670,8 @@ static int last_log_lsn(struct ntfs_log *log)
} }
best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0; best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0;
best_lsn2 = best_lsn2 = second_tail ? base_lsn(log, second_tail, second_file_off) :
second_tail ? base_lsn(log, second_tail, second_file_off) : 0; 0;
if (first_tail && second_tail) { if (first_tail && second_tail) {
if (best_lsn1 > best_lsn2) { if (best_lsn1 > best_lsn2) {
...@@ -1767,8 +1766,8 @@ static int last_log_lsn(struct ntfs_log *log) ...@@ -1767,8 +1766,8 @@ static int last_log_lsn(struct ntfs_log *log)
page_cnt = page_pos = 1; page_cnt = page_pos = 1;
curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) :
: log->next_page; log->next_page;
wrapped_file = wrapped_file =
curpage_off == log->first_page && curpage_off == log->first_page &&
...@@ -1826,9 +1825,9 @@ static int last_log_lsn(struct ntfs_log *log) ...@@ -1826,9 +1825,9 @@ static int last_log_lsn(struct ntfs_log *log)
le64_to_cpu(cur_page->record_hdr.last_end_lsn) && le64_to_cpu(cur_page->record_hdr.last_end_lsn) &&
((lsn_cur >> log->file_data_bits) + ((lsn_cur >> log->file_data_bits) +
((curpage_off < ((curpage_off <
(lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) (lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) ?
? 1 1 :
: 0)) != expected_seq) { 0)) != expected_seq) {
goto check_tail; goto check_tail;
} }
...@@ -2575,7 +2574,7 @@ static int read_next_log_rec(struct ntfs_log *log, struct lcb *lcb, u64 *lsn) ...@@ -2575,7 +2574,7 @@ static int read_next_log_rec(struct ntfs_log *log, struct lcb *lcb, u64 *lsn)
return find_log_rec(log, *lsn, lcb); return find_log_rec(log, *lsn, lcb);
} }
static inline bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes) bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes)
{ {
__le16 mask; __le16 mask;
u32 min_de, de_off, used, total; u32 min_de, de_off, used, total;
...@@ -2642,9 +2641,10 @@ static inline bool check_index_root(const struct ATTRIB *attr, ...@@ -2642,9 +2641,10 @@ static inline bool check_index_root(const struct ATTRIB *attr,
{ {
bool ret; bool ret;
const struct INDEX_ROOT *root = resident_data(attr); const struct INDEX_ROOT *root = resident_data(attr);
u8 index_bits = le32_to_cpu(root->index_block_size) >= sbi->cluster_size u8 index_bits = le32_to_cpu(root->index_block_size) >=
? sbi->cluster_bits sbi->cluster_size ?
: SECTOR_SHIFT; sbi->cluster_bits :
SECTOR_SHIFT;
u8 block_clst = root->index_block_clst; u8 block_clst = root->index_block_clst;
if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) || if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) ||
...@@ -3683,7 +3683,8 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe, ...@@ -3683,7 +3683,8 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
if (a_dirty) { if (a_dirty) {
attr = oa->attr; attr = oa->attr;
err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes, 0); err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes,
0);
if (err) if (err)
goto out; goto out;
} }
...@@ -3768,11 +3769,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -3768,11 +3769,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
if (!log) if (!log)
return -ENOMEM; return -ENOMEM;
memset(&rst_info, 0, sizeof(struct restart_info));
log->ni = ni; log->ni = ni;
log->l_size = l_size; log->l_size = l_size;
log->one_page_buf = kmalloc(page_size, GFP_NOFS); log->one_page_buf = kmalloc(page_size, GFP_NOFS);
if (!log->one_page_buf) { if (!log->one_page_buf) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -3783,6 +3783,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -3783,6 +3783,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
log->page_bits = blksize_bits(page_size); log->page_bits = blksize_bits(page_size);
/* Look for a restart area on the disk. */ /* Look for a restart area on the disk. */
memset(&rst_info, 0, sizeof(struct restart_info));
err = log_read_rst(log, l_size, true, &rst_info); err = log_read_rst(log, l_size, true, &rst_info);
if (err) if (err)
goto out; goto out;
...@@ -3859,10 +3860,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -3859,10 +3860,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
log->init_ra = !!rst_info.vbo; log->init_ra = !!rst_info.vbo;
/* If we have a valid page then grab a pointer to the restart area. */ /* If we have a valid page then grab a pointer to the restart area. */
ra2 = rst_info.valid_page ra2 = rst_info.valid_page ?
? Add2Ptr(rst_info.r_page, Add2Ptr(rst_info.r_page,
le16_to_cpu(rst_info.r_page->ra_off)) le16_to_cpu(rst_info.r_page->ra_off)) :
: NULL; NULL;
if (rst_info.chkdsk_was_run || if (rst_info.chkdsk_was_run ||
(ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) { (ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) {
...@@ -4256,6 +4257,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -4256,6 +4257,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
rec_len -= t32; rec_len -= t32;
attr_names = kmemdup(Add2Ptr(lrh, t32), rec_len, GFP_NOFS); attr_names = kmemdup(Add2Ptr(lrh, t32), rec_len, GFP_NOFS);
if (!attr_names) {
err = -ENOMEM;
goto out;
}
lcb_put(lcb); lcb_put(lcb);
lcb = NULL; lcb = NULL;
......
...@@ -172,8 +172,8 @@ int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes, ...@@ -172,8 +172,8 @@ int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes,
u16 sample, fo, fn; u16 sample, fo, fn;
fo = le16_to_cpu(rhdr->fix_off); fo = le16_to_cpu(rhdr->fix_off);
fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) :
: le16_to_cpu(rhdr->fix_num); le16_to_cpu(rhdr->fix_num);
/* Check errors. */ /* Check errors. */
if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- || if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
...@@ -223,7 +223,7 @@ int ntfs_extend_init(struct ntfs_sb_info *sbi) ...@@ -223,7 +223,7 @@ int ntfs_extend_init(struct ntfs_sb_info *sbi)
inode = ntfs_iget5(sb, &ref, &NAME_EXTEND); inode = ntfs_iget5(sb, &ref, &NAME_EXTEND);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
ntfs_err(sb, "Failed to load $Extend."); ntfs_err(sb, "Failed to load $Extend (%d).", err);
inode = NULL; inode = NULL;
goto out; goto out;
} }
...@@ -282,7 +282,7 @@ int ntfs_loadlog_and_replay(struct ntfs_inode *ni, struct ntfs_sb_info *sbi) ...@@ -282,7 +282,7 @@ int ntfs_loadlog_and_replay(struct ntfs_inode *ni, struct ntfs_sb_info *sbi)
/* Check for 4GB. */ /* Check for 4GB. */
if (ni->vfs_inode.i_size >= 0x100000000ull) { if (ni->vfs_inode.i_size >= 0x100000000ull) {
ntfs_err(sb, "\x24LogFile is too big"); ntfs_err(sb, "\x24LogFile is large than 4G.");
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -646,13 +646,13 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft, ...@@ -646,13 +646,13 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
NULL, 0, NULL, NULL)) NULL, 0, NULL, NULL))
goto next; goto next;
__clear_bit_le(ir - MFT_REC_RESERVED, __clear_bit(ir - MFT_REC_RESERVED,
&sbi->mft.reserved_bitmap); &sbi->mft.reserved_bitmap);
} }
} }
/* Scan 5 bits for zero. Bit 0 == MFT_REC_RESERVED */ /* Scan 5 bits for zero. Bit 0 == MFT_REC_RESERVED */
zbit = find_next_zero_bit_le(&sbi->mft.reserved_bitmap, zbit = find_next_zero_bit(&sbi->mft.reserved_bitmap,
MFT_REC_FREE, MFT_REC_RESERVED); MFT_REC_FREE, MFT_REC_RESERVED);
if (zbit >= MFT_REC_FREE) { if (zbit >= MFT_REC_FREE) {
sbi->mft.next_reserved = MFT_REC_FREE; sbi->mft.next_reserved = MFT_REC_FREE;
...@@ -720,7 +720,7 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft, ...@@ -720,7 +720,7 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
if (*rno >= MFT_REC_FREE) if (*rno >= MFT_REC_FREE)
wnd_set_used(wnd, *rno, 1); wnd_set_used(wnd, *rno, 1);
else if (*rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) else if (*rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited)
__set_bit_le(*rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); __set_bit(*rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap);
out: out:
if (!mft) if (!mft)
...@@ -748,7 +748,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft) ...@@ -748,7 +748,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft)
else else
wnd_set_free(wnd, rno, 1); wnd_set_free(wnd, rno, 1);
} else if (rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) { } else if (rno >= MFT_REC_RESERVED && sbi->mft.reserved_bitmap_inited) {
__clear_bit_le(rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap); __clear_bit(rno - MFT_REC_RESERVED, &sbi->mft.reserved_bitmap);
} }
if (rno < wnd_zone_bit(wnd)) if (rno < wnd_zone_bit(wnd))
...@@ -846,18 +846,16 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait) ...@@ -846,18 +846,16 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
{ {
int err; int err;
struct super_block *sb = sbi->sb; struct super_block *sb = sbi->sb;
u32 blocksize; u32 blocksize, bytes;
sector_t block1, block2; sector_t block1, block2;
u32 bytes;
if (!sb) /*
* sb can be NULL here. In this case sbi->flags should be 0 too.
*/
if (!sb || !(sbi->flags & NTFS_FLAGS_MFTMIRR))
return; return;
blocksize = sb->s_blocksize; blocksize = sb->s_blocksize;
if (!(sbi->flags & NTFS_FLAGS_MFTMIRR))
return;
bytes = sbi->mft.recs_mirr << sbi->record_bits; bytes = sbi->mft.recs_mirr << sbi->record_bits;
block1 = sbi->mft.lbo >> sb->s_blocksize_bits; block1 = sbi->mft.lbo >> sb->s_blocksize_bits;
block2 = sbi->mft.lbo2 >> sb->s_blocksize_bits; block2 = sbi->mft.lbo2 >> sb->s_blocksize_bits;
...@@ -925,6 +923,7 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty) ...@@ -925,6 +923,7 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
struct VOLUME_INFO *info; struct VOLUME_INFO *info;
struct mft_inode *mi; struct mft_inode *mi;
struct ntfs_inode *ni; struct ntfs_inode *ni;
__le16 info_flags;
/* /*
* Do not change state if fs was real_dirty. * Do not change state if fs was real_dirty.
...@@ -957,6 +956,8 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty) ...@@ -957,6 +956,8 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
goto out; goto out;
} }
info_flags = info->flags;
switch (dirty) { switch (dirty) {
case NTFS_DIRTY_ERROR: case NTFS_DIRTY_ERROR:
ntfs_notice(sbi->sb, "Mark volume as dirty due to NTFS errors"); ntfs_notice(sbi->sb, "Mark volume as dirty due to NTFS errors");
...@@ -970,8 +971,10 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty) ...@@ -970,8 +971,10 @@ int ntfs_set_state(struct ntfs_sb_info *sbi, enum NTFS_DIRTY_FLAGS dirty)
break; break;
} }
/* Cache current volume flags. */ /* Cache current volume flags. */
if (info_flags != info->flags) {
sbi->volume.flags = info->flags; sbi->volume.flags = info->flags;
mi->dirty = true; mi->dirty = true;
}
err = 0; err = 0;
out: out:
...@@ -1683,6 +1686,7 @@ struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir) ...@@ -1683,6 +1686,7 @@ struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir)
out: out:
if (err) { if (err) {
make_bad_inode(inode);
iput(inode); iput(inode);
ni = ERR_PTR(err); ni = ERR_PTR(err);
} }
...@@ -1859,7 +1863,7 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) ...@@ -1859,7 +1863,7 @@ int ntfs_security_init(struct ntfs_sb_info *sbi)
inode = ntfs_iget5(sb, &ref, &NAME_SECURE); inode = ntfs_iget5(sb, &ref, &NAME_SECURE);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
ntfs_err(sb, "Failed to load $Secure."); ntfs_err(sb, "Failed to load $Secure (%d).", err);
inode = NULL; inode = NULL;
goto out; goto out;
} }
...@@ -1870,41 +1874,43 @@ int ntfs_security_init(struct ntfs_sb_info *sbi) ...@@ -1870,41 +1874,43 @@ int ntfs_security_init(struct ntfs_sb_info *sbi)
attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SDH_NAME, attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SDH_NAME,
ARRAY_SIZE(SDH_NAME), NULL, NULL); ARRAY_SIZE(SDH_NAME), NULL, NULL);
if (!attr) { if (!attr ||
err = -EINVAL; !(root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
goto out; root_sdh->type != ATTR_ZERO ||
}
root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT));
if (root_sdh->type != ATTR_ZERO ||
root_sdh->rule != NTFS_COLLATION_TYPE_SECURITY_HASH || root_sdh->rule != NTFS_COLLATION_TYPE_SECURITY_HASH ||
offsetof(struct INDEX_ROOT, ihdr) + root_sdh->ihdr.used > attr->res.data_size) { offsetof(struct INDEX_ROOT, ihdr) +
le32_to_cpu(root_sdh->ihdr.used) >
le32_to_cpu(attr->res.data_size)) {
ntfs_err(sb, "$Secure::$SDH is corrupted.");
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
err = indx_init(indx_sdh, sbi, attr, INDEX_MUTEX_SDH); err = indx_init(indx_sdh, sbi, attr, INDEX_MUTEX_SDH);
if (err) if (err) {
ntfs_err(sb, "Failed to initialize $Secure::$SDH (%d).", err);
goto out; goto out;
}
attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME, attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME,
ARRAY_SIZE(SII_NAME), NULL, NULL); ARRAY_SIZE(SII_NAME), NULL, NULL);
if (!attr) { if (!attr ||
err = -EINVAL; !(root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
goto out; root_sii->type != ATTR_ZERO ||
}
root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT));
if (root_sii->type != ATTR_ZERO ||
root_sii->rule != NTFS_COLLATION_TYPE_UINT || root_sii->rule != NTFS_COLLATION_TYPE_UINT ||
offsetof(struct INDEX_ROOT, ihdr) + root_sii->ihdr.used > attr->res.data_size) { offsetof(struct INDEX_ROOT, ihdr) +
le32_to_cpu(root_sii->ihdr.used) >
le32_to_cpu(attr->res.data_size)) {
ntfs_err(sb, "$Secure::$SII is corrupted.");
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
err = indx_init(indx_sii, sbi, attr, INDEX_MUTEX_SII); err = indx_init(indx_sii, sbi, attr, INDEX_MUTEX_SII);
if (err) if (err) {
ntfs_err(sb, "Failed to initialize $Secure::$SII (%d).", err);
goto out; goto out;
}
fnd_sii = fnd_get(); fnd_sii = fnd_get();
if (!fnd_sii) { if (!fnd_sii) {
...@@ -2594,8 +2600,10 @@ static inline bool is_reserved_name(struct ntfs_sb_info *sbi, ...@@ -2594,8 +2600,10 @@ static inline bool is_reserved_name(struct ntfs_sb_info *sbi,
if (len == 4 || (len > 4 && le16_to_cpu(name[4]) == '.')) { if (len == 4 || (len > 4 && le16_to_cpu(name[4]) == '.')) {
port_digit = le16_to_cpu(name[3]); port_digit = le16_to_cpu(name[3]);
if (port_digit >= '1' && port_digit <= '9') if (port_digit >= '1' && port_digit <= '9')
if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase, false) || if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase,
!ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase, false)) false) ||
!ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase,
false))
return true; return true;
} }
......
...@@ -431,8 +431,9 @@ static int scan_nres_bitmap(struct ntfs_inode *ni, struct ATTRIB *bitmap, ...@@ -431,8 +431,9 @@ static int scan_nres_bitmap(struct ntfs_inode *ni, struct ATTRIB *bitmap,
if (vbo + blocksize > data_size) if (vbo + blocksize > data_size)
nbits = 8 * (data_size - vbo); nbits = 8 * (data_size - vbo);
ok = nbits > from ? (*fn)((ulong *)bh->b_data, from, nbits, ret) ok = nbits > from ?
: false; (*fn)((ulong *)bh->b_data, from, nbits, ret) :
false;
put_bh(bh); put_bh(bh);
if (ok) { if (ok) {
...@@ -725,9 +726,13 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx, ...@@ -725,9 +726,13 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
u32 e_size, e_key_len; u32 e_size, e_key_len;
u32 end = le32_to_cpu(hdr->used); u32 end = le32_to_cpu(hdr->used);
u32 off = le32_to_cpu(hdr->de_off); u32 off = le32_to_cpu(hdr->de_off);
u32 total = le32_to_cpu(hdr->total);
u16 offs[128]; u16 offs[128];
fill_table: fill_table:
if (end > total)
return NULL;
if (off + sizeof(struct NTFS_DE) > end) if (off + sizeof(struct NTFS_DE) > end)
return NULL; return NULL;
...@@ -760,8 +765,7 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx, ...@@ -760,8 +765,7 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
return NULL; return NULL;
max_idx = 0; max_idx = 0;
table_size = min(table_size * 2, table_size = min(table_size * 2, (int)ARRAY_SIZE(offs));
(int)ARRAY_SIZE(offs));
goto fill_table; goto fill_table;
} }
} else if (diff2 < 0) { } else if (diff2 < 0) {
...@@ -844,6 +848,10 @@ static inline struct NTFS_DE *hdr_delete_de(struct INDEX_HDR *hdr, ...@@ -844,6 +848,10 @@ static inline struct NTFS_DE *hdr_delete_de(struct INDEX_HDR *hdr,
u32 off = PtrOffset(hdr, re); u32 off = PtrOffset(hdr, re);
int bytes = used - (off + esize); int bytes = used - (off + esize);
/* check INDEX_HDR valid before using INDEX_HDR */
if (!check_index_header(hdr, le32_to_cpu(hdr->total)))
return NULL;
if (off >= used || esize < sizeof(struct NTFS_DE) || if (off >= used || esize < sizeof(struct NTFS_DE) ||
bytes < sizeof(struct NTFS_DE)) bytes < sizeof(struct NTFS_DE))
return NULL; return NULL;
...@@ -986,6 +994,7 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -986,6 +994,7 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni,
struct ATTR_LIST_ENTRY *le = NULL; struct ATTR_LIST_ENTRY *le = NULL;
struct ATTRIB *a; struct ATTRIB *a;
const struct INDEX_NAMES *in = &s_index_names[indx->type]; const struct INDEX_NAMES *in = &s_index_names[indx->type];
struct INDEX_ROOT *root;
a = ni_find_attr(ni, NULL, &le, ATTR_ROOT, in->name, in->name_len, NULL, a = ni_find_attr(ni, NULL, &le, ATTR_ROOT, in->name, in->name_len, NULL,
mi); mi);
...@@ -995,7 +1004,16 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -995,7 +1004,16 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni,
if (attr) if (attr)
*attr = a; *attr = a;
return resident_data_ex(a, sizeof(struct INDEX_ROOT)); root = resident_data_ex(a, sizeof(struct INDEX_ROOT));
/* length check */
if (root &&
offsetof(struct INDEX_ROOT, ihdr) + le32_to_cpu(root->ihdr.used) >
le32_to_cpu(a->res.data_size)) {
return NULL;
}
return root;
} }
static int indx_write(struct ntfs_index *indx, struct ntfs_inode *ni, static int indx_write(struct ntfs_index *indx, struct ntfs_inode *ni,
...@@ -1085,7 +1103,8 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn, ...@@ -1085,7 +1103,8 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
} }
/* check for index header length */ /* check for index header length */
if (offsetof(struct INDEX_BUFFER, ihdr) + ib->ihdr.used > bytes) { if (offsetof(struct INDEX_BUFFER, ihdr) + le32_to_cpu(ib->ihdr.used) >
bytes) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -1151,8 +1170,10 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1151,8 +1170,10 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
/* Read next level. */ /* Read next level. */
err = indx_read(indx, ni, de_get_vbn(e), &node); err = indx_read(indx, ni, de_get_vbn(e), &node);
if (err) if (err) {
/* io error? */
return err; return err;
}
/* Lookup entry that is <= to the search value. */ /* Lookup entry that is <= to the search value. */
e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx, e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx,
...@@ -1654,9 +1675,9 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1654,9 +1675,9 @@ static int indx_insert_into_root(struct ntfs_index *indx, struct ntfs_inode *ni,
mi->dirty = true; mi->dirty = true;
/* Create alloc and bitmap attributes (if not). */ /* Create alloc and bitmap attributes (if not). */
err = run_is_empty(&indx->alloc_run) err = run_is_empty(&indx->alloc_run) ?
? indx_create_allocate(indx, ni, &new_vbn) indx_create_allocate(indx, ni, &new_vbn) :
: indx_add_allocate(indx, ni, &new_vbn); indx_add_allocate(indx, ni, &new_vbn);
/* Layout of record may be changed, so rescan root. */ /* Layout of record may be changed, so rescan root. */
root = indx_get_root(indx, ni, &attr, &mi); root = indx_get_root(indx, ni, &attr, &mi);
...@@ -1759,10 +1780,11 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1759,10 +1780,11 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
struct indx_node *n1 = fnd->nodes[level]; struct indx_node *n1 = fnd->nodes[level];
struct INDEX_HDR *hdr1 = &n1->index->ihdr; struct INDEX_HDR *hdr1 = &n1->index->ihdr;
struct INDEX_HDR *hdr2; struct INDEX_HDR *hdr2;
u32 to_copy, used; u32 to_copy, used, used1;
CLST new_vbn; CLST new_vbn;
__le64 t_vbn, *sub_vbn; __le64 t_vbn, *sub_vbn;
u16 sp_size; u16 sp_size;
void *hdr1_saved = NULL;
/* Try the most easy case. */ /* Try the most easy case. */
e = fnd->level - 1 == level ? fnd->de[level] : NULL; e = fnd->level - 1 == level ? fnd->de[level] : NULL;
...@@ -1795,6 +1817,13 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1795,6 +1817,13 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
return -ENOMEM; return -ENOMEM;
memcpy(up_e, sp, sp_size); memcpy(up_e, sp, sp_size);
used1 = le32_to_cpu(hdr1->used);
hdr1_saved = kmemdup(hdr1, used1, GFP_NOFS);
if (!hdr1_saved) {
err = -ENOMEM;
goto out;
}
if (!hdr1->flags) { if (!hdr1->flags) {
up_e->flags |= NTFS_IE_HAS_SUBNODES; up_e->flags |= NTFS_IE_HAS_SUBNODES;
up_e->size = cpu_to_le16(sp_size + sizeof(u64)); up_e->size = cpu_to_le16(sp_size + sizeof(u64));
...@@ -1827,7 +1856,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1827,7 +1856,7 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
hdr_insert_head(hdr2, de_t, to_copy); hdr_insert_head(hdr2, de_t, to_copy);
/* Remove all entries (sp including) from hdr1. */ /* Remove all entries (sp including) from hdr1. */
used = le32_to_cpu(hdr1->used) - to_copy - sp_size; used = used1 - to_copy - sp_size;
memmove(de_t, Add2Ptr(sp, sp_size), used - le32_to_cpu(hdr1->de_off)); memmove(de_t, Add2Ptr(sp, sp_size), used - le32_to_cpu(hdr1->de_off));
hdr1->used = cpu_to_le32(used); hdr1->used = cpu_to_le32(used);
...@@ -1838,9 +1867,9 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1838,9 +1867,9 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
hdr_insert_de(indx, hdr_insert_de(indx,
(*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size), (*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size),
up_e + 1, le16_to_cpu(up_e->key_size), up_e + 1, le16_to_cpu(up_e->key_size),
ctx) < 0 ctx) < 0 ?
? hdr2 hdr2 :
: hdr1, hdr1,
new_de, NULL, ctx); new_de, NULL, ctx);
indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits); indx_mark_used(indx, ni, new_vbn >> indx->idx2vbn_bits);
...@@ -1857,8 +1886,6 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1857,8 +1886,6 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
if (!level) { if (!level) {
/* Insert in root. */ /* Insert in root. */
err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0); err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0);
if (err)
goto out;
} else { } else {
/* /*
* The target buffer's parent is another index buffer. * The target buffer's parent is another index buffer.
...@@ -1866,12 +1893,20 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1866,12 +1893,20 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
*/ */
err = indx_insert_into_buffer(indx, ni, root, up_e, ctx, err = indx_insert_into_buffer(indx, ni, root, up_e, ctx,
level - 1, fnd); level - 1, fnd);
if (err) }
goto out;
if (err) {
/*
* Undo critical operations.
*/
indx_mark_free(indx, ni, new_vbn >> indx->idx2vbn_bits);
memcpy(hdr1, hdr1_saved, used1);
indx_write(indx, ni, n1, 0);
} }
out: out:
kfree(up_e); kfree(up_e);
kfree(hdr1_saved);
return err; return err;
} }
...@@ -1930,16 +1965,12 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1930,16 +1965,12 @@ int indx_insert_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
*/ */
err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx, err = indx_insert_into_root(indx, ni, new_de, fnd->root_de, ctx,
fnd, undo); fnd, undo);
if (err)
goto out;
} else { } else {
/* /*
* Found a leaf buffer, so we'll insert the new entry into it. * Found a leaf buffer, so we'll insert the new entry into it.
*/ */
err = indx_insert_into_buffer(indx, ni, root, new_de, ctx, err = indx_insert_into_buffer(indx, ni, root, new_de, ctx,
fnd->level - 1, fnd); fnd->level - 1, fnd);
if (err)
goto out;
} }
out: out:
...@@ -2308,8 +2339,8 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -2308,8 +2339,8 @@ int indx_delete_entry(struct ntfs_index *indx, struct ntfs_inode *ni,
err = level ? indx_insert_into_buffer(indx, ni, root, err = level ? indx_insert_into_buffer(indx, ni, root,
re, ctx, re, ctx,
fnd->level - 1, fnd->level - 1,
fnd) fnd) :
: indx_insert_into_root(indx, ni, re, e, indx_insert_into_root(indx, ni, re, e,
ctx, fnd, 0); ctx, fnd, 0);
kfree(re); kfree(re);
......
...@@ -100,6 +100,12 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -100,6 +100,12 @@ static struct inode *ntfs_read_mft(struct inode *inode,
/* Record should contain $I30 root. */ /* Record should contain $I30 root. */
is_dir = rec->flags & RECORD_FLAG_DIR; is_dir = rec->flags & RECORD_FLAG_DIR;
/* MFT_REC_MFT is not a dir */
if (is_dir && ino == MFT_REC_MFT) {
err = -EINVAL;
goto out;
}
inode->i_generation = le16_to_cpu(rec->seq); inode->i_generation = le16_to_cpu(rec->seq);
/* Enumerate all struct Attributes MFT. */ /* Enumerate all struct Attributes MFT. */
...@@ -131,7 +137,13 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -131,7 +137,13 @@ static struct inode *ntfs_read_mft(struct inode *inode,
rsize = attr->non_res ? 0 : le32_to_cpu(attr->res.data_size); rsize = attr->non_res ? 0 : le32_to_cpu(attr->res.data_size);
asize = le32_to_cpu(attr->size); asize = le32_to_cpu(attr->size);
if (le16_to_cpu(attr->name_off) + attr->name_len > asize) /*
* Really this check was done in 'ni_enum_attr_ex' -> ... 'mi_enum_attr'.
* There not critical to check this case again
*/
if (attr->name_len &&
sizeof(short) * attr->name_len + le16_to_cpu(attr->name_off) >
asize)
goto out; goto out;
if (attr->non_res) { if (attr->non_res) {
...@@ -250,8 +262,8 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -250,8 +262,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
if (!attr->nres.alloc_size) if (!attr->nres.alloc_size)
goto next_attr; goto next_attr;
run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run :
: &ni->file.run; &ni->file.run;
break; break;
case ATTR_ROOT: case ATTR_ROOT:
...@@ -259,7 +271,6 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -259,7 +271,6 @@ static struct inode *ntfs_read_mft(struct inode *inode,
goto out; goto out;
root = Add2Ptr(attr, roff); root = Add2Ptr(attr, roff);
is_root = true;
if (attr->name_len != ARRAY_SIZE(I30_NAME) || if (attr->name_len != ARRAY_SIZE(I30_NAME) ||
memcmp(attr_name(attr), I30_NAME, sizeof(I30_NAME))) memcmp(attr_name(attr), I30_NAME, sizeof(I30_NAME)))
...@@ -272,15 +283,16 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -272,15 +283,16 @@ static struct inode *ntfs_read_mft(struct inode *inode,
if (!is_dir) if (!is_dir)
goto next_attr; goto next_attr;
is_root = true;
ni->ni_flags |= NI_FLAG_DIR; ni->ni_flags |= NI_FLAG_DIR;
err = indx_init(&ni->dir, sbi, attr, INDEX_MUTEX_I30); err = indx_init(&ni->dir, sbi, attr, INDEX_MUTEX_I30);
if (err) if (err)
goto out; goto out;
mode = sb->s_root mode = sb->s_root ?
? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) :
: (S_IFDIR | 0777); (S_IFDIR | 0777);
goto next_attr; goto next_attr;
case ATTR_ALLOC: case ATTR_ALLOC:
...@@ -437,8 +449,8 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -437,8 +449,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
inode->i_op = &ntfs_file_inode_operations; inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations; inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops; &ntfs_aops;
if (ino != MFT_REC_MFT) if (ino != MFT_REC_MFT)
init_rwsem(&ni->file.run_lock); init_rwsem(&ni->file.run_lock);
} else if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) || } else if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode) ||
...@@ -636,6 +648,7 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo, ...@@ -636,6 +648,7 @@ static noinline int ntfs_get_block_vbo(struct inode *inode, u64 vbo,
bh->b_size = block_size; bh->b_size = block_size;
off = vbo & (PAGE_SIZE - 1); off = vbo & (PAGE_SIZE - 1);
set_bh_page(bh, page, off); set_bh_page(bh, page, off);
err = bh_read(bh, 0); err = bh_read(bh, 0);
if (err < 0) if (err < 0)
goto out; goto out;
...@@ -773,8 +786,8 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -773,8 +786,8 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
} }
ret = blockdev_direct_IO(iocb, inode, iter, ret = blockdev_direct_IO(iocb, inode, iter,
wr ? ntfs_get_block_direct_IO_W wr ? ntfs_get_block_direct_IO_W :
: ntfs_get_block_direct_IO_R); ntfs_get_block_direct_IO_R);
if (ret > 0) if (ret > 0)
end = vbo + ret; end = vbo + ret;
...@@ -874,8 +887,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping, ...@@ -874,8 +887,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
*pagep = NULL; *pagep = NULL;
if (is_resident(ni)) { if (is_resident(ni)) {
struct page *page = grab_cache_page_write_begin( struct page *page =
mapping, pos >> PAGE_SHIFT); grab_cache_page_write_begin(mapping, pos >> PAGE_SHIFT);
if (!page) { if (!page) {
err = -ENOMEM; err = -ENOMEM;
...@@ -907,9 +920,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping, ...@@ -907,9 +920,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
/* /*
* ntfs_write_end - Address_space_operations::write_end. * ntfs_write_end - Address_space_operations::write_end.
*/ */
int ntfs_write_end(struct file *file, struct address_space *mapping, int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
loff_t pos, u32 len, u32 copied, struct page *page, u32 len, u32 copied, struct page *page, void *fsdata)
void *fsdata)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
...@@ -1307,8 +1319,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1307,8 +1319,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
inode_init_owner(idmap, inode, dir, mode); inode_init_owner(idmap, inode, dir, mode);
mode = inode->i_mode; mode = inode->i_mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = ni->i_crtime = ni->i_crtime = current_time(inode);
current_time(inode);
rec = ni->mi.mrec; rec = ni->mi.mrec;
rec->hard_links = cpu_to_le16(1); rec->hard_links = cpu_to_le16(1);
...@@ -1349,10 +1360,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1349,10 +1360,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
attr->res.data_size = cpu_to_le32(dsize); attr->res.data_size = cpu_to_le32(dsize);
std5->cr_time = std5->m_time = std5->c_time = std5->a_time = std5->cr_time = std5->m_time = std5->c_time = std5->a_time =
kernel2nt(&inode->i_atime); kernel2nt(&ni->i_crtime);
ni->std_fa = fa; std5->fa = ni->std_fa = fa;
std5->fa = fa;
attr = Add2Ptr(attr, asize); attr = Add2Ptr(attr, asize);
...@@ -1551,11 +1561,15 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1551,11 +1561,15 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
} }
asize = SIZEOF_NONRESIDENT + ALIGN(err, 8); asize = SIZEOF_NONRESIDENT + ALIGN(err, 8);
/* Write non resident data. */
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp,
nsize, 0);
if (err)
goto out5;
} else { } else {
attr->res.data_off = SIZEOF_RESIDENT_LE; attr->res.data_off = SIZEOF_RESIDENT_LE;
attr->res.data_size = cpu_to_le32(nsize); attr->res.data_size = cpu_to_le32(nsize);
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize); memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
nsize = 0;
} }
/* Size of symlink equals the length of input string. */ /* Size of symlink equals the length of input string. */
inode->i_size = size; inode->i_size = size;
...@@ -1576,19 +1590,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1576,19 +1590,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
rec->used = cpu_to_le32(PtrOffset(rec, attr) + 8); rec->used = cpu_to_le32(PtrOffset(rec, attr) + 8);
rec->next_attr_id = cpu_to_le16(aid); rec->next_attr_id = cpu_to_le16(aid);
/* Step 2: Add new name in index. */
err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0);
if (err)
goto out6;
/* Unlock parent directory before ntfs_init_acl. */
if (!fnd)
ni_unlock(dir_ni);
inode->i_generation = le16_to_cpu(rec->seq); inode->i_generation = le16_to_cpu(rec->seq);
dir->i_mtime = dir->i_ctime = inode->i_atime;
if (S_ISDIR(mode)) { if (S_ISDIR(mode)) {
inode->i_op = &ntfs_dir_inode_operations; inode->i_op = &ntfs_dir_inode_operations;
inode->i_fop = &ntfs_dir_operations; inode->i_fop = &ntfs_dir_operations;
...@@ -1601,8 +1604,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1601,8 +1604,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
} else if (S_ISREG(mode)) { } else if (S_ISREG(mode)) {
inode->i_op = &ntfs_file_inode_operations; inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations; inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops; &ntfs_aops;
init_rwsem(&ni->file.run_lock); init_rwsem(&ni->file.run_lock);
} else { } else {
inode->i_op = &ntfs_special_inode_operations; inode->i_op = &ntfs_special_inode_operations;
...@@ -1613,41 +1616,58 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1613,41 +1616,58 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) { if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
err = ntfs_init_acl(idmap, inode, dir); err = ntfs_init_acl(idmap, inode, dir);
if (err) if (err)
goto out7; goto out5;
} else } else
#endif #endif
{ {
inode->i_flags |= S_NOSEC; inode->i_flags |= S_NOSEC;
} }
/* Write non resident data. */ /*
if (nsize) { * ntfs_init_acl and ntfs_save_wsl_perm update extended attribute.
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0); * The packed size of extended attribute is stored in direntry too.
if (err) * 'fname' here points to inside new_de.
goto out7; */
ntfs_save_wsl_perm(inode, &fname->dup.ea_size);
/*
* update ea_size in file_name attribute too.
* Use ni_find_attr cause layout of MFT record may be changed
* in ntfs_init_acl and ntfs_save_wsl_perm.
*/
attr = ni_find_attr(ni, NULL, NULL, ATTR_NAME, NULL, 0, NULL, NULL);
if (attr) {
struct ATTR_FILE_NAME *fn;
fn = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
if (fn)
fn->dup.ea_size = fname->dup.ea_size;
} }
/* We do not need to update parent directory later */
ni->ni_flags &= ~NI_FLAG_UPDATE_PARENT;
/* Step 2: Add new name in index. */
err = indx_insert_entry(&dir_ni->dir, dir_ni, new_de, sbi, fnd, 0);
if (err)
goto out6;
/* /*
* Call 'd_instantiate' after inode->i_op is set * Call 'd_instantiate' after inode->i_op is set
* but before finish_open. * but before finish_open.
*/ */
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
ntfs_save_wsl_perm(inode); /* Set original time. inode times (i_ctime) may be changed in ntfs_init_acl. */
inode->i_atime = inode->i_mtime = inode->i_ctime = dir->i_mtime =
dir->i_ctime = ni->i_crtime;
mark_inode_dirty(dir); mark_inode_dirty(dir);
mark_inode_dirty(inode); mark_inode_dirty(inode);
/* Normal exit. */ /* Normal exit. */
goto out2; goto out2;
out7:
/* Undo 'indx_insert_entry'. */
if (!fnd)
ni_lock_dir(dir_ni);
indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
le16_to_cpu(new_de->key_size), sbi);
/* ni_unlock(dir_ni); will be called later. */
out6: out6:
if (rp_inserted) if (rp_inserted)
ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref); ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
...@@ -1669,11 +1689,11 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap, ...@@ -1669,11 +1689,11 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
kfree(rp); kfree(rp);
out1: out1:
if (err) {
if (!fnd) if (!fnd)
ni_unlock(dir_ni); ni_unlock(dir_ni);
if (err)
return ERR_PTR(err); return ERR_PTR(err);
}
unlock_new_inode(inode); unlock_new_inode(inode);
...@@ -1770,9 +1790,6 @@ void ntfs_evict_inode(struct inode *inode) ...@@ -1770,9 +1790,6 @@ void ntfs_evict_inode(struct inode *inode)
{ {
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);
if (inode->i_nlink)
_ni_write_inode(inode, inode_needs_sync(inode));
invalidate_inode_buffers(inode); invalidate_inode_buffers(inode);
clear_inode(inode); clear_inode(inode);
...@@ -2057,7 +2074,6 @@ const struct inode_operations ntfs_link_inode_operations = { ...@@ -2057,7 +2074,6 @@ const struct inode_operations ntfs_link_inode_operations = {
.get_link = ntfs_get_link, .get_link = ntfs_get_link,
.setattr = ntfs3_setattr, .setattr = ntfs3_setattr,
.listxattr = ntfs_listxattr, .listxattr = ntfs_listxattr,
.permission = ntfs_permission,
}; };
const struct address_space_operations ntfs_aops = { const struct address_space_operations ntfs_aops = {
......
...@@ -296,8 +296,8 @@ static inline ssize_t decompress_chunk(u8 *unc, u8 *unc_end, const u8 *cmpr, ...@@ -296,8 +296,8 @@ static inline ssize_t decompress_chunk(u8 *unc, u8 *unc_end, const u8 *cmpr,
*/ */
struct lznt *get_lznt_ctx(int level) struct lznt *get_lznt_ctx(int level)
{ {
struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) :
: sizeof(struct lznt), sizeof(struct lznt),
GFP_NOFS); GFP_NOFS);
if (r) if (r)
...@@ -392,9 +392,9 @@ ssize_t decompress_lznt(const void *cmpr, size_t cmpr_size, void *unc, ...@@ -392,9 +392,9 @@ ssize_t decompress_lznt(const void *cmpr, size_t cmpr_size, void *unc,
unc_use = err; unc_use = err;
} else { } else {
/* This chunk does not contain compressed data. */ /* This chunk does not contain compressed data. */
unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end ?
? unc_end - unc_chunk unc_end - unc_chunk :
: LZNT_CHUNK_SIZE; LZNT_CHUNK_SIZE;
if (cmpr_chunk + sizeof(chunk_hdr) + unc_use > if (cmpr_chunk + sizeof(chunk_hdr) + unc_use >
cmpr_end) { cmpr_end) {
......
...@@ -88,6 +88,16 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -88,6 +88,16 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
__putname(uni); __putname(uni);
} }
/*
* Check for a null pointer
* If the MFT record of ntfs inode is not a base record, inode->i_op can be NULL.
* This causes null pointer dereference in d_splice_alias().
*/
if (!IS_ERR_OR_NULL(inode) && !inode->i_op) {
iput(inode);
inode = ERR_PTR(-EINVAL);
}
return d_splice_alias(inode, dentry); return d_splice_alias(inode, dentry);
} }
...@@ -423,8 +433,8 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -423,8 +433,8 @@ static int ntfs_atomic_open(struct inode *dir, struct dentry *dentry,
inode = ntfs_create_inode(&nop_mnt_idmap, dir, dentry, uni, mode, 0, inode = ntfs_create_inode(&nop_mnt_idmap, dir, dentry, uni, mode, 0,
NULL, 0, fnd); NULL, 0, fnd);
err = IS_ERR(inode) ? PTR_ERR(inode) err = IS_ERR(inode) ? PTR_ERR(inode) :
: finish_open(file, dentry, ntfs_file_open); finish_open(file, dentry, ntfs_file_open);
dput(d); dput(d);
out2: out2:
...@@ -597,8 +607,7 @@ const struct inode_operations ntfs_dir_inode_operations = { ...@@ -597,8 +607,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
.rmdir = ntfs_rmdir, .rmdir = ntfs_rmdir,
.mknod = ntfs_mknod, .mknod = ntfs_mknod,
.rename = ntfs_rename, .rename = ntfs_rename,
.permission = ntfs_permission, .get_acl = ntfs_get_acl,
.get_inode_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl, .set_acl = ntfs_set_acl,
.setattr = ntfs3_setattr, .setattr = ntfs3_setattr,
.getattr = ntfs_getattr, .getattr = ntfs_getattr,
...@@ -611,7 +620,7 @@ const struct inode_operations ntfs_special_inode_operations = { ...@@ -611,7 +620,7 @@ const struct inode_operations ntfs_special_inode_operations = {
.setattr = ntfs3_setattr, .setattr = ntfs3_setattr,
.getattr = ntfs_getattr, .getattr = ntfs_getattr,
.listxattr = ntfs_listxattr, .listxattr = ntfs_listxattr,
.get_inode_acl = ntfs_get_acl, .get_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl, .set_acl = ntfs_set_acl,
}; };
......
...@@ -435,9 +435,6 @@ static inline u64 attr_svcn(const struct ATTRIB *attr) ...@@ -435,9 +435,6 @@ static inline u64 attr_svcn(const struct ATTRIB *attr)
return attr->non_res ? le64_to_cpu(attr->nres.svcn) : 0; return attr->non_res ? le64_to_cpu(attr->nres.svcn) : 0;
} }
/* The size of resident attribute by its resident size. */
#define BYTES_PER_RESIDENT(b) (0x18 + (b))
static_assert(sizeof(struct ATTRIB) == 0x48); static_assert(sizeof(struct ATTRIB) == 0x48);
static_assert(sizeof(((struct ATTRIB *)NULL)->res) == 0x08); static_assert(sizeof(((struct ATTRIB *)NULL)->res) == 0x08);
static_assert(sizeof(((struct ATTRIB *)NULL)->nres) == 0x38); static_assert(sizeof(((struct ATTRIB *)NULL)->nres) == 0x38);
......
...@@ -100,7 +100,6 @@ struct ntfs_mount_options { ...@@ -100,7 +100,6 @@ struct ntfs_mount_options {
unsigned hide_dot_files : 1; /* Set hidden flag on dot files. */ unsigned hide_dot_files : 1; /* Set hidden flag on dot files. */
unsigned windows_names : 1; /* Disallow names forbidden by Windows. */ unsigned windows_names : 1; /* Disallow names forbidden by Windows. */
unsigned force : 1; /* RW mount dirty volume. */ unsigned force : 1; /* RW mount dirty volume. */
unsigned noacsrules : 1; /* Exclude acs rules. */
unsigned prealloc : 1; /* Preallocate space when file is growing. */ unsigned prealloc : 1; /* Preallocate space when file is growing. */
unsigned nocase : 1; /* case insensitive. */ unsigned nocase : 1; /* case insensitive. */
}; };
...@@ -164,7 +163,6 @@ struct wnd_bitmap { ...@@ -164,7 +163,6 @@ struct wnd_bitmap {
size_t zone_bit; size_t zone_bit;
size_t zone_end; size_t zone_end;
bool set_tail; // Not necessary in driver.
bool inited; bool inited;
}; };
...@@ -340,7 +338,7 @@ enum ntfs_inode_mutex_lock_class { ...@@ -340,7 +338,7 @@ enum ntfs_inode_mutex_lock_class {
}; };
/* /*
* sturct ntfs_inode * struct ntfs_inode
* *
* Ntfs inode - extends linux inode. consists of one or more MFT inodes. * Ntfs inode - extends linux inode. consists of one or more MFT inodes.
*/ */
...@@ -581,6 +579,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, ...@@ -581,6 +579,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
bool ni_is_dirty(struct inode *inode); bool ni_is_dirty(struct inode *inode);
/* Globals from fslog.c */ /* Globals from fslog.c */
bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes);
int log_replay(struct ntfs_inode *ni, bool *initialized); int log_replay(struct ntfs_inode *ni, bool *initialized);
/* Globals from fsntfs.c */ /* Globals from fsntfs.c */
...@@ -700,9 +699,8 @@ int ntfs_get_block(struct inode *inode, sector_t vbn, ...@@ -700,9 +699,8 @@ int ntfs_get_block(struct inode *inode, sector_t vbn,
struct buffer_head *bh_result, int create); struct buffer_head *bh_result, int create);
int ntfs_write_begin(struct file *file, struct address_space *mapping, int ntfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, u32 len, struct page **pagep, void **fsdata); loff_t pos, u32 len, struct page **pagep, void **fsdata);
int ntfs_write_end(struct file *file, struct address_space *mapping, int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
loff_t pos, u32 len, u32 copied, struct page *page, u32 len, u32 copied, struct page *page, void *fsdata);
void *fsdata);
int ntfs3_write_inode(struct inode *inode, struct writeback_control *wbc); int ntfs3_write_inode(struct inode *inode, struct writeback_control *wbc);
int ntfs_sync_inode(struct inode *inode); int ntfs_sync_inode(struct inode *inode);
int ntfs_flush_inodes(struct super_block *sb, struct inode *i1, int ntfs_flush_inodes(struct super_block *sb, struct inode *i1,
...@@ -858,7 +856,8 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, ...@@ -858,7 +856,8 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
/* globals from xattr.c */ /* globals from xattr.c */
#ifdef CONFIG_NTFS3_FS_POSIX_ACL #ifdef CONFIG_NTFS3_FS_POSIX_ACL
struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu); struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap,
struct dentry *dentry, int type);
int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
struct posix_acl *acl, int type); struct posix_acl *acl, int type);
int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
...@@ -869,12 +868,10 @@ int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode, ...@@ -869,12 +868,10 @@ int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
#endif #endif
int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry); int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry);
int ntfs_permission(struct mnt_idmap *idmap, struct inode *inode,
int mask);
ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size); ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
extern const struct xattr_handler *ntfs_xattr_handlers[]; extern const struct xattr_handler *ntfs_xattr_handlers[];
int ntfs_save_wsl_perm(struct inode *inode); int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size);
void ntfs_get_wsl_perm(struct inode *inode); void ntfs_get_wsl_perm(struct inode *inode);
/* globals from lznt.c */ /* globals from lznt.c */
......
...@@ -221,7 +221,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) ...@@ -221,7 +221,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
} }
if (off + asize < off) { if (off + asize < off) {
/* overflow check */ /* Overflow check. */
return NULL; return NULL;
} }
...@@ -247,8 +247,8 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr) ...@@ -247,8 +247,8 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
if ((t32 & 0xf) || (t32 > 0x100)) if ((t32 & 0xf) || (t32 > 0x100))
return NULL; return NULL;
/* Check boundary. */ /* Check overflow and boundary. */
if (off + asize > used) if (off + asize < off || off + asize > used)
return NULL; return NULL;
/* Check size of attribute. */ /* Check size of attribute. */
...@@ -419,10 +419,9 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, ...@@ -419,10 +419,9 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
struct ntfs_sb_info *sbi = mi->sbi; struct ntfs_sb_info *sbi = mi->sbi;
u32 used = le32_to_cpu(rec->used); u32 used = le32_to_cpu(rec->used);
const u16 *upcase = sbi->upcase; const u16 *upcase = sbi->upcase;
int diff;
/* Can we insert mi attribute? */ /* Can we insert mi attribute? */
if (used + asize > mi->sbi->record_size) if (used + asize > sbi->record_size)
return NULL; return NULL;
/* /*
...@@ -431,7 +430,7 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, ...@@ -431,7 +430,7 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
*/ */
attr = NULL; attr = NULL;
while ((attr = mi_enum_attr(mi, attr))) { while ((attr = mi_enum_attr(mi, attr))) {
diff = compare_attr(attr, type, name, name_len, upcase); int diff = compare_attr(attr, type, name, name_len, upcase);
if (diff < 0) if (diff < 0)
continue; continue;
...@@ -442,9 +441,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, ...@@ -442,9 +441,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
} }
if (!attr) { if (!attr) {
tail = 8; /* Not used, just to suppress warning. */ /* Append. */
tail = 8;
attr = Add2Ptr(rec, used - 8); attr = Add2Ptr(rec, used - 8);
} else { } else {
/* Insert before 'attr'. */
tail = used - PtrOffset(rec, attr); tail = used - PtrOffset(rec, attr);
} }
......
...@@ -433,9 +433,9 @@ bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len, ...@@ -433,9 +433,9 @@ bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len,
should_add_tail = Tovcn < r->len; should_add_tail = Tovcn < r->len;
if (should_add_tail) { if (should_add_tail) {
tail_lcn = r->lcn == SPARSE_LCN tail_lcn = r->lcn == SPARSE_LCN ?
? SPARSE_LCN SPARSE_LCN :
: (r->lcn + Tovcn); (r->lcn + Tovcn);
tail_vcn = r->vcn + Tovcn; tail_vcn = r->vcn + Tovcn;
tail_len = r->len - Tovcn; tail_len = r->len - Tovcn;
} }
......
This diff is collapsed.
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
static inline size_t unpacked_ea_size(const struct EA_FULL *ea) static inline size_t unpacked_ea_size(const struct EA_FULL *ea)
{ {
return ea->size ? le32_to_cpu(ea->size) return ea->size ? le32_to_cpu(ea->size) :
: ALIGN(struct_size(ea, name, ALIGN(struct_size(ea, name,
1 + ea->name_len + 1 + ea->name_len +
le16_to_cpu(ea->elength)), le16_to_cpu(ea->elength)),
4); 4);
...@@ -296,7 +296,8 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len, ...@@ -296,7 +296,8 @@ static int ntfs_get_ea(struct inode *inode, const char *name, size_t name_len,
static noinline int ntfs_set_ea(struct inode *inode, const char *name, static noinline int ntfs_set_ea(struct inode *inode, const char *name,
size_t name_len, const void *value, size_t name_len, const void *value,
size_t val_size, int flags, bool locked) size_t val_size, int flags, bool locked,
__le16 *ea_size)
{ {
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
struct ntfs_sb_info *sbi = ni->mi.sbi; struct ntfs_sb_info *sbi = ni->mi.sbi;
...@@ -410,7 +411,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, ...@@ -410,7 +411,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
/* /*
* 1. Check ea_info.size_pack for overflow. * 1. Check ea_info.size_pack for overflow.
* 2. New attibute size must fit value from $AttrDef * 2. New attribute size must fit value from $AttrDef
*/ */
if (new_pack > 0xffff || size > sbi->ea_max_size) { if (new_pack > 0xffff || size > sbi->ea_max_size) {
ntfs_inode_warn( ntfs_inode_warn(
...@@ -504,6 +505,8 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, ...@@ -504,6 +505,8 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
if (ea_info.size_pack != size_pack) if (ea_info.size_pack != size_pack)
ni->ni_flags |= NI_FLAG_UPDATE_PARENT; ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
if (ea_size)
*ea_size = ea_info.size_pack;
mark_inode_dirty(&ni->vfs_inode); mark_inode_dirty(&ni->vfs_inode);
out: out:
...@@ -517,9 +520,14 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, ...@@ -517,9 +520,14 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
} }
#ifdef CONFIG_NTFS3_FS_POSIX_ACL #ifdef CONFIG_NTFS3_FS_POSIX_ACL
static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
int locked) /*
* ntfs_get_acl - inode_operations::get_acl
*/
struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap,
struct dentry *dentry, int type)
{ {
struct inode *inode = d_inode(dentry);
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
const char *name; const char *name;
size_t name_len; size_t name_len;
...@@ -542,12 +550,10 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type, ...@@ -542,12 +550,10 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
name_len = sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1; name_len = sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1;
} }
if (!locked)
ni_lock(ni); ni_lock(ni);
err = ntfs_get_ea(inode, name, name_len, buf, PATH_MAX, &req); err = ntfs_get_ea(inode, name, name_len, buf, PATH_MAX, &req);
if (!locked)
ni_unlock(ni); ni_unlock(ni);
/* Translate extended attribute to acl. */ /* Translate extended attribute to acl. */
...@@ -567,17 +573,6 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type, ...@@ -567,17 +573,6 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
return acl; return acl;
} }
/*
* ntfs_get_acl - inode_operations::get_acl
*/
struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
{
if (rcu)
return ERR_PTR(-ECHILD);
return ntfs_get_acl_ex(inode, type, 0);
}
static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap,
struct inode *inode, struct posix_acl *acl, struct inode *inode, struct posix_acl *acl,
int type, bool init_acl) int type, bool init_acl)
...@@ -633,7 +628,7 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap, ...@@ -633,7 +628,7 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap,
flags = 0; flags = 0;
} }
err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0); err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0, NULL);
if (err == -ENODATA && !size) if (err == -ENODATA && !size)
err = 0; /* Removing non existed xattr. */ err = 0; /* Removing non existed xattr. */
if (!err) { if (!err) {
...@@ -711,20 +706,6 @@ int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry) ...@@ -711,20 +706,6 @@ int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry)
return posix_acl_chmod(idmap, dentry, inode->i_mode); return posix_acl_chmod(idmap, dentry, inode->i_mode);
} }
/*
* ntfs_permission - inode_operations::permission
*/
int ntfs_permission(struct mnt_idmap *idmap, struct inode *inode,
int mask)
{
if (ntfs_sb(inode->i_sb)->options->noacsrules) {
/* "No access rules" mode - Allow all changes. */
return 0;
}
return generic_permission(idmap, inode, mask);
}
/* /*
* ntfs_listxattr - inode_operations::listxattr * ntfs_listxattr - inode_operations::listxattr
*/ */
...@@ -780,7 +761,7 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de, ...@@ -780,7 +761,7 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
err = sizeof(u32); err = sizeof(u32);
*(u32 *)buffer = le32_to_cpu(ni->std_fa); *(u32 *)buffer = le32_to_cpu(ni->std_fa);
if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE))
*(u32 *)buffer = cpu_to_be32(*(u32 *)buffer); *(__be32 *)buffer = cpu_to_be32(*(u32 *)buffer);
} }
goto out; goto out;
} }
...@@ -857,7 +838,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler, ...@@ -857,7 +838,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
if (size != sizeof(u32)) if (size != sizeof(u32))
goto out; goto out;
if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE)) if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE))
new_fa = cpu_to_le32(be32_to_cpu(*(u32 *)value)); new_fa = cpu_to_le32(be32_to_cpu(*(__be32 *)value));
else else
new_fa = cpu_to_le32(*(u32 *)value); new_fa = cpu_to_le32(*(u32 *)value);
...@@ -937,7 +918,8 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler, ...@@ -937,7 +918,8 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
} }
/* Deal with NTFS extended attribute. */ /* Deal with NTFS extended attribute. */
err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0); err = ntfs_set_ea(inode, name, strlen(name), value, size, flags, 0,
NULL);
out: out:
inode->i_ctime = current_time(inode); inode->i_ctime = current_time(inode);
...@@ -951,7 +933,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler, ...@@ -951,7 +933,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
* *
* save uid/gid/mode in xattr * save uid/gid/mode in xattr
*/ */
int ntfs_save_wsl_perm(struct inode *inode) int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size)
{ {
int err; int err;
__le32 value; __le32 value;
...@@ -960,26 +942,26 @@ int ntfs_save_wsl_perm(struct inode *inode) ...@@ -960,26 +942,26 @@ int ntfs_save_wsl_perm(struct inode *inode)
ni_lock(ni); ni_lock(ni);
value = cpu_to_le32(i_uid_read(inode)); value = cpu_to_le32(i_uid_read(inode));
err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value, err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
sizeof(value), 0, true); /* true == already locked. */ sizeof(value), 0, true, ea_size);
if (err) if (err)
goto out; goto out;
value = cpu_to_le32(i_gid_read(inode)); value = cpu_to_le32(i_gid_read(inode));
err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value, err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
sizeof(value), 0, true); sizeof(value), 0, true, ea_size);
if (err) if (err)
goto out; goto out;
value = cpu_to_le32(inode->i_mode); value = cpu_to_le32(inode->i_mode);
err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value, err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
sizeof(value), 0, true); sizeof(value), 0, true, ea_size);
if (err) if (err)
goto out; goto out;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
value = cpu_to_le32(inode->i_rdev); value = cpu_to_le32(inode->i_rdev);
err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value, err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
sizeof(value), 0, true); sizeof(value), 0, true, ea_size);
if (err) if (err)
goto out; goto out;
} }
......
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