driver ntfs3 for linux 6.4
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmRLZc0ACgkQqbAzH4Mk B7YWkA/+JHsryYjInVGmYfQ4oCmq1F2cEDgKdTeths+IZ+2vbk03hUbvmLBg8YR3 VvYZ2YqNAs9HuZxP6mnVZB9YOMIFEdV3Pyto68l9jwip4irpjVrABtxwn6udTAmx RXVDDLRxN53UyoWgRoOfAEJUXfmOvw7laj8T9PrsKxXKhlOKmK8mSKtq8xTt+ECo 8cJ0Nw2d0TVY6+Ou6CCfH8CzHtQjInHnKSt/KynJ+OJHxLmHRGlbDJbyjuJU0OBr grXngKPmqvHTiO3Zs14gRv5tFXNMGdvRcomy/XnztD/nIC2jEODI2uUCSedEh5vf IpzjKwQF1qRseGHwr2U0THPHOso4IP2T79WRQEuLY8DUGJClIGGmcdfeBqNnjbey 1GVUis/leBvQb1CMAkX5HjGXO9i6xEfuTxwHSlk+Wu8euEDQ8OWudyeQmOYiHnqS vKZxXY88DDjATSokSUSSb8IW63z+JEPmovsmLKLpWusvWikIKhIEnjRZUG5XhgS3 Ux66Owt9yguKgVAPX66b9PGQx4wy3GAR6FRxG1BpDX0XooGbzGRTAn213sjkBKiV JLswbQTJ5LOXv8bS1srNMPhQFeqFcEgrDbC+WxmOpzTvutimYmzUTDrOPq92Xw0f oi/i5kCoPFmOfoRsLhIl+lft1XLZ5iYFvj0faDJ5AWUOjb73Z3s= =xlIh -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
1e098dec61
@ -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.
|
||||
* - 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
|
||||
- Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute
|
||||
will not be shown under Linux.
|
||||
|
@ -405,8 +405,8 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
|
||||
int err = 0;
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
u8 cluster_bits = sbi->cluster_bits;
|
||||
bool is_mft =
|
||||
ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA && !name_len;
|
||||
bool is_mft = ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA &&
|
||||
!name_len;
|
||||
u64 old_valid, old_size, old_alloc, new_alloc, new_alloc_tmp;
|
||||
struct ATTRIB *attr = NULL, *attr_b;
|
||||
struct ATTR_LIST_ENTRY *le, *le_b;
|
||||
@ -531,11 +531,10 @@ add_alloc_in_same_attr_seg:
|
||||
pre_alloc = 0;
|
||||
if (type == ATTR_DATA && !name_len &&
|
||||
sbi->options->prealloc) {
|
||||
pre_alloc =
|
||||
bytes_to_cluster(
|
||||
sbi,
|
||||
get_pre_allocated(new_size)) -
|
||||
new_alen;
|
||||
pre_alloc = bytes_to_cluster(
|
||||
sbi, get_pre_allocated(
|
||||
new_size)) -
|
||||
new_alen;
|
||||
}
|
||||
|
||||
/* Get the last LCN to allocate from. */
|
||||
@ -573,8 +572,8 @@ add_alloc_in_same_attr_seg:
|
||||
err = attr_allocate_clusters(
|
||||
sbi, run, vcn, lcn, to_allocate, &pre_alloc,
|
||||
is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen,
|
||||
is_mft ? 0
|
||||
: (sbi->record_size -
|
||||
is_mft ? 0 :
|
||||
(sbi->record_size -
|
||||
le32_to_cpu(rec->used) + 8) /
|
||||
3 +
|
||||
1,
|
||||
|
@ -40,9 +40,9 @@ static struct kmem_cache *ntfs_enode_cachep;
|
||||
|
||||
int __init ntfs3_init_bitmap(void)
|
||||
{
|
||||
ntfs_enode_cachep =
|
||||
kmem_cache_create("ntfs3_enode_cache", sizeof(struct e_node), 0,
|
||||
SLAB_RECLAIM_ACCOUNT, NULL);
|
||||
ntfs_enode_cachep = kmem_cache_create("ntfs3_enode_cache",
|
||||
sizeof(struct e_node), 0,
|
||||
SLAB_RECLAIM_ACCOUNT, NULL);
|
||||
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,
|
||||
if (wnd->uptodated != 1) {
|
||||
/* Check bits before 'bit'. */
|
||||
ib = wnd->zone_bit == wnd->zone_end ||
|
||||
bit < wnd->zone_end
|
||||
? 0
|
||||
: wnd->zone_end;
|
||||
bit < wnd->zone_end ?
|
||||
0 :
|
||||
wnd->zone_end;
|
||||
|
||||
while (bit > ib && wnd_is_free_hlp(wnd, bit - 1, 1)) {
|
||||
bit -= 1;
|
||||
@ -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'. */
|
||||
ib = wnd->zone_bit == wnd->zone_end ||
|
||||
end_in > wnd->zone_bit
|
||||
? wnd->nbits
|
||||
: wnd->zone_bit;
|
||||
end_in > wnd->zone_bit ?
|
||||
wnd->nbits :
|
||||
wnd->zone_bit;
|
||||
|
||||
while (end_in < ib && wnd_is_free_hlp(wnd, 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)
|
||||
return;
|
||||
n3 = rb_first(&wnd->count_tree);
|
||||
wnd->extent_max =
|
||||
n3 ? rb_entry(n3, struct e_node, count.node)->count.key
|
||||
: 0;
|
||||
n3 ? rb_entry(n3, struct e_node, count.node)->count.key :
|
||||
0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -658,7 +658,8 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits)
|
||||
if (!wnd->bits_last)
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -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 range;
|
||||
struct block_device *dev;
|
||||
int err;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (!bdev_max_discard_sectors(sbi->sb->s_bdev))
|
||||
dev = sbi->sb->s_bdev;
|
||||
if (!bdev_max_discard_sectors(dev))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
user_range = (struct fstrim_range __user *)arg;
|
||||
if (copy_from_user(&range, user_range, sizeof(range)))
|
||||
return -EFAULT;
|
||||
|
||||
range.minlen = max_t(u32, range.minlen,
|
||||
bdev_discard_granularity(sbi->sb->s_bdev));
|
||||
range.minlen = max_t(u32, range.minlen, bdev_discard_granularity(dev));
|
||||
|
||||
err = ntfs_trim_fs(sbi, &range);
|
||||
if (err < 0)
|
||||
@ -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) {
|
||||
page_off = (loff_t)idx << PAGE_SHIFT;
|
||||
to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off)
|
||||
: PAGE_SIZE;
|
||||
to = (page_off + PAGE_SIZE) > vbo_to ? (vbo_to - page_off) :
|
||||
PAGE_SIZE;
|
||||
iblock = page_off >> inode->i_blkbits;
|
||||
|
||||
page = find_or_create_page(mapping, idx,
|
||||
@ -223,16 +224,10 @@ static int ntfs_zero_range(struct inode *inode, u64 vbo, u64 vbo_to)
|
||||
set_buffer_uptodate(bh);
|
||||
|
||||
if (!buffer_uptodate(bh)) {
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
get_bh(bh);
|
||||
submit_bh(REQ_OP_READ, bh);
|
||||
|
||||
wait_on_buffer(bh);
|
||||
if (!buffer_uptodate(bh)) {
|
||||
err = bh_read(bh, 0);
|
||||
if (err < 0) {
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -570,13 +565,14 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
ni_unlock(ni);
|
||||
} else {
|
||||
/* Check new size. */
|
||||
u8 cluster_bits = sbi->cluster_bits;
|
||||
|
||||
/* generic/213: expected -ENOSPC instead of -EFBIG. */
|
||||
if (!is_supported_holes) {
|
||||
loff_t to_alloc = new_size - inode_get_bytes(inode);
|
||||
|
||||
if (to_alloc > 0 &&
|
||||
(to_alloc >> sbi->cluster_bits) >
|
||||
(to_alloc >> cluster_bits) >
|
||||
wnd_zeroes(&sbi->used.bitmap)) {
|
||||
err = -ENOSPC;
|
||||
goto out;
|
||||
@ -597,7 +593,7 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
}
|
||||
|
||||
if (is_supported_holes) {
|
||||
CLST vcn = vbo >> sbi->cluster_bits;
|
||||
CLST vcn = vbo >> cluster_bits;
|
||||
CLST cend = bytes_to_cluster(sbi, end);
|
||||
CLST cend_v = bytes_to_cluster(sbi, ni->i_valid);
|
||||
CLST lcn, clen;
|
||||
@ -660,22 +656,12 @@ out:
|
||||
int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
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 ntfs_inode *ni = ntfs_i(inode);
|
||||
u32 ia_valid = attr->ia_valid;
|
||||
umode_t mode = inode->i_mode;
|
||||
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);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -719,7 +705,7 @@ int ntfs3_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
}
|
||||
|
||||
if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE))
|
||||
ntfs_save_wsl_perm(inode);
|
||||
ntfs_save_wsl_perm(inode, NULL);
|
||||
mark_inode_dirty(inode);
|
||||
out:
|
||||
return err;
|
||||
@ -1065,8 +1051,8 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = is_compressed(ni) ? ntfs_compress_write(iocb, from)
|
||||
: __generic_file_write_iter(iocb, from);
|
||||
ret = is_compressed(ni) ? ntfs_compress_write(iocb, from) :
|
||||
__generic_file_write_iter(iocb, from);
|
||||
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
@ -1118,8 +1104,9 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
|
||||
int err = 0;
|
||||
|
||||
/* If we are last writer on the inode, drop the block reservation. */
|
||||
if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) &&
|
||||
atomic_read(&inode->i_writecount) == 1)) {
|
||||
if (sbi->options->prealloc &&
|
||||
((file->f_mode & FMODE_WRITE) &&
|
||||
atomic_read(&inode->i_writecount) == 1)) {
|
||||
ni_lock(ni);
|
||||
down_write(&ni->file.run_lock);
|
||||
|
||||
@ -1159,8 +1146,7 @@ const struct inode_operations ntfs_file_inode_operations = {
|
||||
.getattr = ntfs_getattr,
|
||||
.setattr = ntfs3_setattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.permission = ntfs_permission,
|
||||
.get_inode_acl = ntfs_get_acl,
|
||||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
.fiemap = ntfs_fiemap,
|
||||
};
|
||||
|
@ -76,8 +76,8 @@ struct ATTR_STD_INFO *ni_std(struct ntfs_inode *ni)
|
||||
const struct ATTRIB *attr;
|
||||
|
||||
attr = mi_find_attr(&ni->mi, NULL, ATTR_STD, NULL, 0, NULL);
|
||||
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO))
|
||||
: NULL;
|
||||
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO)) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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);
|
||||
|
||||
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5))
|
||||
: NULL;
|
||||
return attr ? resident_data_ex(attr, sizeof(struct ATTR_STD_INFO5)) :
|
||||
NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -102,7 +102,7 @@ void ni_clear(struct ntfs_inode *ni)
|
||||
{
|
||||
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);
|
||||
|
||||
al_destroy(ni);
|
||||
@ -1439,8 +1439,8 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
|
||||
int err;
|
||||
CLST plen;
|
||||
struct ATTRIB *attr;
|
||||
bool is_ext =
|
||||
(flags & (ATTR_FLAG_SPARSED | ATTR_FLAG_COMPRESSED)) && !svcn;
|
||||
bool is_ext = (flags & (ATTR_FLAG_SPARSED | ATTR_FLAG_COMPRESSED)) &&
|
||||
!svcn;
|
||||
u32 name_size = ALIGN(name_len * sizeof(short), 8);
|
||||
u32 name_off = is_ext ? SIZEOF_NONRESIDENT_EX : SIZEOF_NONRESIDENT;
|
||||
u32 run_off = name_off + name_size;
|
||||
@ -1645,7 +1645,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
|
||||
{
|
||||
struct ATTRIB *attr = NULL;
|
||||
struct ATTR_FILE_NAME *fname;
|
||||
struct le_str *fns;
|
||||
struct le_str *fns;
|
||||
|
||||
if (le)
|
||||
*le = NULL;
|
||||
@ -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. */
|
||||
new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED))
|
||||
? (SIZEOF_NONRESIDENT_EX + 8)
|
||||
: (SIZEOF_NONRESIDENT + 8);
|
||||
new_asize = (new_aflags & (ATTR_FLAG_COMPRESSED | ATTR_FLAG_SPARSED)) ?
|
||||
(SIZEOF_NONRESIDENT_EX + 8) :
|
||||
(SIZEOF_NONRESIDENT + 8);
|
||||
|
||||
if (!mi_resize_attr(mi, attr, new_asize - le32_to_cpu(attr->size)))
|
||||
return -EOPNOTSUPP;
|
||||
@ -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 ATTRIB *attr;
|
||||
u16 de_key_size = de2 ? le16_to_cpu(de2->key_size) : 0;
|
||||
u16 de_key_size;
|
||||
|
||||
switch (undo_step) {
|
||||
case 4:
|
||||
de_key_size = le16_to_cpu(de2->key_size);
|
||||
if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
|
||||
&attr, NULL, NULL)) {
|
||||
&attr, NULL, NULL))
|
||||
return false;
|
||||
}
|
||||
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de2 + 1, de_key_size);
|
||||
|
||||
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,
|
||||
de2->flags = 0;
|
||||
de2->res = 0;
|
||||
|
||||
if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL,
|
||||
1)) {
|
||||
if (indx_insert_entry(&dir_ni->dir, dir_ni, de2, sbi, NULL, 1))
|
||||
return false;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
case 2:
|
||||
de_key_size = le16_to_cpu(de->key_size);
|
||||
|
||||
if (ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0,
|
||||
&attr, NULL, NULL)) {
|
||||
&attr, NULL, NULL))
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
|
||||
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,
|
||||
u64 data_size = le64_to_cpu(attr->nres.data_size);
|
||||
__le64 valid_le;
|
||||
|
||||
dup->alloc_size = is_attr_ext(attr)
|
||||
? attr->nres.total_size
|
||||
: attr->nres.alloc_size;
|
||||
dup->alloc_size = is_attr_ext(attr) ?
|
||||
attr->nres.total_size :
|
||||
attr->nres.alloc_size;
|
||||
dup->data_size = attr->nres.data_size;
|
||||
|
||||
if (new_valid > data_size)
|
||||
@ -3258,6 +3255,9 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ni->mi.mrec)
|
||||
goto out;
|
||||
|
||||
if (is_rec_inuse(ni->mi.mrec) &&
|
||||
!(sbi->flags & NTFS_FLAGS_LOG_REPLAYING) && inode->i_nlink) {
|
||||
bool modified = false;
|
||||
@ -3360,7 +3360,7 @@ out:
|
||||
ni_unlock(ni);
|
||||
|
||||
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);
|
||||
return err;
|
||||
}
|
||||
|
@ -827,10 +827,10 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl,
|
||||
|
||||
memcpy(rt + 1, tbl + 1, esize * used);
|
||||
|
||||
rt->free_goal = free_goal == ~0u
|
||||
? cpu_to_le32(~0u)
|
||||
: cpu_to_le32(sizeof(struct RESTART_TABLE) +
|
||||
free_goal * esize);
|
||||
rt->free_goal = free_goal == ~0u ?
|
||||
cpu_to_le32(~0u) :
|
||||
cpu_to_le32(sizeof(struct RESTART_TABLE) +
|
||||
free_goal * esize);
|
||||
|
||||
if (tbl->first_free) {
|
||||
rt->first_free = tbl->first_free;
|
||||
@ -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))
|
||||
<< log->file_data_bits) +
|
||||
((((is_log_record_end(hdr) &&
|
||||
h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn))
|
||||
? le16_to_cpu(hdr->record_hdr.next_record_off)
|
||||
: log->page_size) +
|
||||
h_lsn <= le64_to_cpu(hdr->record_hdr.last_end_lsn)) ?
|
||||
le16_to_cpu(hdr->record_hdr.next_record_off) :
|
||||
log->page_size) +
|
||||
lsn) >>
|
||||
3);
|
||||
|
||||
@ -1298,9 +1298,9 @@ static void log_init_pg_hdr(struct ntfs_log *log, u32 sys_page_size,
|
||||
if (!log->clst_per_page)
|
||||
log->clst_per_page = 1;
|
||||
|
||||
log->first_page = major_ver >= 2
|
||||
? 0x22 * page_size
|
||||
: ((sys_page_size << 1) + (page_size << 1));
|
||||
log->first_page = major_ver >= 2 ?
|
||||
0x22 * page_size :
|
||||
((sys_page_size << 1) + (page_size << 1));
|
||||
log->major_ver = major_ver;
|
||||
log->minor_ver = minor_ver;
|
||||
}
|
||||
@ -1512,20 +1512,19 @@ static u32 current_log_avail(struct ntfs_log *log)
|
||||
* have to compute the free range.
|
||||
* If there is no oldest lsn then start at the first page of the file.
|
||||
*/
|
||||
oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN)
|
||||
? log->first_page
|
||||
: (log->oldest_lsn_off & ~log->sys_page_mask);
|
||||
oldest_off = (log->l_flags & NTFSLOG_NO_OLDEST_LSN) ?
|
||||
log->first_page :
|
||||
(log->oldest_lsn_off & ~log->sys_page_mask);
|
||||
|
||||
/*
|
||||
* 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 at the first page then use the end of the file.
|
||||
*/
|
||||
next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL)
|
||||
? log->next_page + log->page_size
|
||||
: log->next_page == log->first_page
|
||||
? log->l_size
|
||||
: log->next_page;
|
||||
next_free_off = (log->l_flags & NTFSLOG_REUSE_TAIL) ?
|
||||
log->next_page + log->page_size :
|
||||
log->next_page == log->first_page ? log->l_size :
|
||||
log->next_page;
|
||||
|
||||
/* If the two offsets are the same then there is no available space. */
|
||||
if (oldest_off == next_free_off)
|
||||
@ -1535,9 +1534,9 @@ static u32 current_log_avail(struct ntfs_log *log)
|
||||
* this range from the total available pages.
|
||||
*/
|
||||
free_bytes =
|
||||
oldest_off < next_free_off
|
||||
? log->total_avail_pages - (next_free_off - oldest_off)
|
||||
: oldest_off - next_free_off;
|
||||
oldest_off < next_free_off ?
|
||||
log->total_avail_pages - (next_free_off - oldest_off) :
|
||||
oldest_off - next_free_off;
|
||||
|
||||
free_bytes >>= log->page_bits;
|
||||
return free_bytes * log->reserved;
|
||||
@ -1671,8 +1670,8 @@ next_tail:
|
||||
}
|
||||
|
||||
best_lsn1 = first_tail ? base_lsn(log, first_tail, first_file_off) : 0;
|
||||
best_lsn2 =
|
||||
second_tail ? base_lsn(log, second_tail, second_file_off) : 0;
|
||||
best_lsn2 = second_tail ? base_lsn(log, second_tail, second_file_off) :
|
||||
0;
|
||||
|
||||
if (first_tail && second_tail) {
|
||||
if (best_lsn1 > best_lsn2) {
|
||||
@ -1767,8 +1766,8 @@ tail_read:
|
||||
|
||||
page_cnt = page_pos = 1;
|
||||
|
||||
curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off)
|
||||
: log->next_page;
|
||||
curpage_off = seq_base == log->seq_num ? min(log->next_page, page_off) :
|
||||
log->next_page;
|
||||
|
||||
wrapped_file =
|
||||
curpage_off == log->first_page &&
|
||||
@ -1826,9 +1825,9 @@ use_cur_page:
|
||||
le64_to_cpu(cur_page->record_hdr.last_end_lsn) &&
|
||||
((lsn_cur >> log->file_data_bits) +
|
||||
((curpage_off <
|
||||
(lsn_to_vbo(log, lsn_cur) & ~log->page_mask))
|
||||
? 1
|
||||
: 0)) != expected_seq) {
|
||||
(lsn_to_vbo(log, lsn_cur) & ~log->page_mask)) ?
|
||||
1 :
|
||||
0)) != expected_seq) {
|
||||
goto check_tail;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
u32 min_de, de_off, used, total;
|
||||
@ -2642,9 +2641,10 @@ static inline bool check_index_root(const struct ATTRIB *attr,
|
||||
{
|
||||
bool ret;
|
||||
const struct INDEX_ROOT *root = resident_data(attr);
|
||||
u8 index_bits = le32_to_cpu(root->index_block_size) >= sbi->cluster_size
|
||||
? sbi->cluster_bits
|
||||
: SECTOR_SHIFT;
|
||||
u8 index_bits = le32_to_cpu(root->index_block_size) >=
|
||||
sbi->cluster_size ?
|
||||
sbi->cluster_bits :
|
||||
SECTOR_SHIFT;
|
||||
u8 block_clst = root->index_block_clst;
|
||||
|
||||
if (le32_to_cpu(attr->res.data_size) < sizeof(struct INDEX_ROOT) ||
|
||||
@ -3683,7 +3683,8 @@ move_data:
|
||||
|
||||
if (a_dirty) {
|
||||
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)
|
||||
goto out;
|
||||
}
|
||||
@ -3768,11 +3769,10 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
if (!log)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&rst_info, 0, sizeof(struct restart_info));
|
||||
|
||||
log->ni = ni;
|
||||
log->l_size = l_size;
|
||||
log->one_page_buf = kmalloc(page_size, GFP_NOFS);
|
||||
|
||||
if (!log->one_page_buf) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -3783,6 +3783,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
|
||||
log->page_bits = blksize_bits(page_size);
|
||||
|
||||
/* 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);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -3859,10 +3860,10 @@ check_restart_area:
|
||||
log->init_ra = !!rst_info.vbo;
|
||||
|
||||
/* If we have a valid page then grab a pointer to the restart area. */
|
||||
ra2 = rst_info.valid_page
|
||||
? Add2Ptr(rst_info.r_page,
|
||||
le16_to_cpu(rst_info.r_page->ra_off))
|
||||
: NULL;
|
||||
ra2 = rst_info.valid_page ?
|
||||
Add2Ptr(rst_info.r_page,
|
||||
le16_to_cpu(rst_info.r_page->ra_off)) :
|
||||
NULL;
|
||||
|
||||
if (rst_info.chkdsk_was_run ||
|
||||
(ra2 && ra2->client_idx[1] == LFS_NO_CLIENT_LE)) {
|
||||
@ -4256,6 +4257,10 @@ check_attribute_names:
|
||||
rec_len -= t32;
|
||||
|
||||
attr_names = kmemdup(Add2Ptr(lrh, t32), rec_len, GFP_NOFS);
|
||||
if (!attr_names) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lcb_put(lcb);
|
||||
lcb = NULL;
|
||||
|
@ -172,8 +172,8 @@ int ntfs_fix_post_read(struct NTFS_RECORD_HEADER *rhdr, size_t bytes,
|
||||
u16 sample, fo, fn;
|
||||
|
||||
fo = le16_to_cpu(rhdr->fix_off);
|
||||
fn = simple ? ((bytes >> SECTOR_SHIFT) + 1)
|
||||
: le16_to_cpu(rhdr->fix_num);
|
||||
fn = simple ? ((bytes >> SECTOR_SHIFT) + 1) :
|
||||
le16_to_cpu(rhdr->fix_num);
|
||||
|
||||
/* Check errors. */
|
||||
if ((fo & 1) || fo + fn * sizeof(short) > SECTOR_SIZE || !fn-- ||
|
||||
@ -223,7 +223,7 @@ int ntfs_extend_init(struct ntfs_sb_info *sbi)
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_EXTEND);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $Extend.");
|
||||
ntfs_err(sb, "Failed to load $Extend (%d).", err);
|
||||
inode = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -282,7 +282,7 @@ int ntfs_loadlog_and_replay(struct ntfs_inode *ni, struct ntfs_sb_info *sbi)
|
||||
|
||||
/* Check for 4GB. */
|
||||
if (ni->vfs_inode.i_size >= 0x100000000ull) {
|
||||
ntfs_err(sb, "\x24LogFile is too big");
|
||||
ntfs_err(sb, "\x24LogFile is large than 4G.");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -646,13 +646,13 @@ next:
|
||||
NULL, 0, NULL, NULL))
|
||||
goto next;
|
||||
|
||||
__clear_bit_le(ir - MFT_REC_RESERVED,
|
||||
__clear_bit(ir - MFT_REC_RESERVED,
|
||||
&sbi->mft.reserved_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (zbit >= MFT_REC_FREE) {
|
||||
sbi->mft.next_reserved = MFT_REC_FREE;
|
||||
@ -720,7 +720,7 @@ found:
|
||||
if (*rno >= MFT_REC_FREE)
|
||||
wnd_set_used(wnd, *rno, 1);
|
||||
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:
|
||||
if (!mft)
|
||||
@ -748,7 +748,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft)
|
||||
else
|
||||
wnd_set_free(wnd, rno, 1);
|
||||
} 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))
|
||||
@ -846,18 +846,16 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
|
||||
{
|
||||
int err;
|
||||
struct super_block *sb = sbi->sb;
|
||||
u32 blocksize;
|
||||
u32 blocksize, bytes;
|
||||
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;
|
||||
|
||||
blocksize = sb->s_blocksize;
|
||||
|
||||
if (!(sbi->flags & NTFS_FLAGS_MFTMIRR))
|
||||
return;
|
||||
|
||||
bytes = sbi->mft.recs_mirr << sbi->record_bits;
|
||||
block1 = sbi->mft.lbo >> 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)
|
||||
struct VOLUME_INFO *info;
|
||||
struct mft_inode *mi;
|
||||
struct ntfs_inode *ni;
|
||||
__le16 info_flags;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
goto out;
|
||||
}
|
||||
|
||||
info_flags = info->flags;
|
||||
|
||||
switch (dirty) {
|
||||
case NTFS_DIRTY_ERROR:
|
||||
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)
|
||||
break;
|
||||
}
|
||||
/* Cache current volume flags. */
|
||||
sbi->volume.flags = info->flags;
|
||||
mi->dirty = true;
|
||||
if (info_flags != info->flags) {
|
||||
sbi->volume.flags = info->flags;
|
||||
mi->dirty = true;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
@ -1683,6 +1686,7 @@ struct ntfs_inode *ntfs_new_inode(struct ntfs_sb_info *sbi, CLST rno, bool dir)
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
ni = ERR_PTR(err);
|
||||
}
|
||||
@ -1859,7 +1863,7 @@ int ntfs_security_init(struct ntfs_sb_info *sbi)
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_SECURE);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $Secure.");
|
||||
ntfs_err(sb, "Failed to load $Secure (%d).", err);
|
||||
inode = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -1870,41 +1874,43 @@ int ntfs_security_init(struct ntfs_sb_info *sbi)
|
||||
|
||||
attr = ni_find_attr(ni, NULL, &le, ATTR_ROOT, SDH_NAME,
|
||||
ARRAY_SIZE(SDH_NAME), NULL, NULL);
|
||||
if (!attr) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT));
|
||||
if (root_sdh->type != ATTR_ZERO ||
|
||||
if (!attr ||
|
||||
!(root_sdh = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
|
||||
root_sdh->type != ATTR_ZERO ||
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = indx_init(indx_sdh, sbi, attr, INDEX_MUTEX_SDH);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME,
|
||||
ARRAY_SIZE(SII_NAME), NULL, NULL);
|
||||
if (!attr) {
|
||||
err = -EINVAL;
|
||||
if (err) {
|
||||
ntfs_err(sb, "Failed to initialize $Secure::$SDH (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT));
|
||||
if (root_sii->type != ATTR_ZERO ||
|
||||
attr = ni_find_attr(ni, attr, &le, ATTR_ROOT, SII_NAME,
|
||||
ARRAY_SIZE(SII_NAME), NULL, NULL);
|
||||
if (!attr ||
|
||||
!(root_sii = resident_data_ex(attr, sizeof(struct INDEX_ROOT))) ||
|
||||
root_sii->type != ATTR_ZERO ||
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fnd_sii = fnd_get();
|
||||
if (!fnd_sii) {
|
||||
@ -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]) == '.')) {
|
||||
port_digit = le16_to_cpu(name[3]);
|
||||
if (port_digit >= '1' && port_digit <= '9')
|
||||
if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase, false) ||
|
||||
!ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase, false))
|
||||
if (!ntfs_cmp_names(name, 3, COM_NAME, 3, upcase,
|
||||
false) ||
|
||||
!ntfs_cmp_names(name, 3, LPT_NAME, 3, upcase,
|
||||
false))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -431,8 +431,9 @@ next_run:
|
||||
if (vbo + blocksize > data_size)
|
||||
nbits = 8 * (data_size - vbo);
|
||||
|
||||
ok = nbits > from ? (*fn)((ulong *)bh->b_data, from, nbits, ret)
|
||||
: false;
|
||||
ok = nbits > from ?
|
||||
(*fn)((ulong *)bh->b_data, from, nbits, ret) :
|
||||
false;
|
||||
put_bh(bh);
|
||||
|
||||
if (ok) {
|
||||
@ -725,9 +726,13 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
|
||||
u32 e_size, e_key_len;
|
||||
u32 end = le32_to_cpu(hdr->used);
|
||||
u32 off = le32_to_cpu(hdr->de_off);
|
||||
u32 total = le32_to_cpu(hdr->total);
|
||||
u16 offs[128];
|
||||
|
||||
fill_table:
|
||||
if (end > total)
|
||||
return NULL;
|
||||
|
||||
if (off + sizeof(struct NTFS_DE) > end)
|
||||
return NULL;
|
||||
|
||||
@ -760,8 +765,7 @@ binary_search:
|
||||
return NULL;
|
||||
|
||||
max_idx = 0;
|
||||
table_size = min(table_size * 2,
|
||||
(int)ARRAY_SIZE(offs));
|
||||
table_size = min(table_size * 2, (int)ARRAY_SIZE(offs));
|
||||
goto fill_table;
|
||||
}
|
||||
} else if (diff2 < 0) {
|
||||
@ -844,6 +848,10 @@ static inline struct NTFS_DE *hdr_delete_de(struct INDEX_HDR *hdr,
|
||||
u32 off = PtrOffset(hdr, re);
|
||||
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) ||
|
||||
bytes < sizeof(struct NTFS_DE))
|
||||
return NULL;
|
||||
@ -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 ATTRIB *a;
|
||||
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,
|
||||
mi);
|
||||
@ -995,7 +1004,16 @@ struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
if (attr)
|
||||
*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,
|
||||
@ -1085,7 +1103,8 @@ ok:
|
||||
}
|
||||
|
||||
/* 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;
|
||||
goto out;
|
||||
}
|
||||
@ -1151,8 +1170,10 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
|
||||
/* Read next level. */
|
||||
err = indx_read(indx, ni, de_get_vbn(e), &node);
|
||||
if (err)
|
||||
if (err) {
|
||||
/* io error? */
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Lookup entry that is <= to the search value. */
|
||||
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,
|
||||
mi->dirty = true;
|
||||
|
||||
/* Create alloc and bitmap attributes (if not). */
|
||||
err = run_is_empty(&indx->alloc_run)
|
||||
? indx_create_allocate(indx, ni, &new_vbn)
|
||||
: indx_add_allocate(indx, ni, &new_vbn);
|
||||
err = run_is_empty(&indx->alloc_run) ?
|
||||
indx_create_allocate(indx, ni, &new_vbn) :
|
||||
indx_add_allocate(indx, ni, &new_vbn);
|
||||
|
||||
/* Layout of record may be changed, so rescan root. */
|
||||
root = indx_get_root(indx, ni, &attr, &mi);
|
||||
@ -1759,10 +1780,11 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
struct indx_node *n1 = fnd->nodes[level];
|
||||
struct INDEX_HDR *hdr1 = &n1->index->ihdr;
|
||||
struct INDEX_HDR *hdr2;
|
||||
u32 to_copy, used;
|
||||
u32 to_copy, used, used1;
|
||||
CLST new_vbn;
|
||||
__le64 t_vbn, *sub_vbn;
|
||||
u16 sp_size;
|
||||
void *hdr1_saved = NULL;
|
||||
|
||||
/* Try the most easy case. */
|
||||
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,
|
||||
return -ENOMEM;
|
||||
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) {
|
||||
up_e->flags |= NTFS_IE_HAS_SUBNODES;
|
||||
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,
|
||||
hdr_insert_head(hdr2, de_t, to_copy);
|
||||
|
||||
/* 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));
|
||||
hdr1->used = cpu_to_le32(used);
|
||||
|
||||
@ -1838,9 +1867,9 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
hdr_insert_de(indx,
|
||||
(*indx->cmp)(new_de + 1, le16_to_cpu(new_de->key_size),
|
||||
up_e + 1, le16_to_cpu(up_e->key_size),
|
||||
ctx) < 0
|
||||
? hdr2
|
||||
: hdr1,
|
||||
ctx) < 0 ?
|
||||
hdr2 :
|
||||
hdr1,
|
||||
new_de, NULL, ctx);
|
||||
|
||||
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,
|
||||
if (!level) {
|
||||
/* Insert in root. */
|
||||
err = indx_insert_into_root(indx, ni, up_e, NULL, ctx, fnd, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
/*
|
||||
* 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,
|
||||
*/
|
||||
err = indx_insert_into_buffer(indx, ni, root, up_e, ctx,
|
||||
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:
|
||||
kfree(up_e);
|
||||
kfree(hdr1_saved);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -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,
|
||||
fnd, undo);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
/*
|
||||
* Found a leaf buffer, so we'll insert the new entry into it.
|
||||
*/
|
||||
err = indx_insert_into_buffer(indx, ni, root, new_de, ctx,
|
||||
fnd->level - 1, fnd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -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,
|
||||
re, ctx,
|
||||
fnd->level - 1,
|
||||
fnd)
|
||||
: indx_insert_into_root(indx, ni, re, e,
|
||||
fnd) :
|
||||
indx_insert_into_root(indx, ni, re, e,
|
||||
ctx, fnd, 0);
|
||||
kfree(re);
|
||||
|
||||
|
134
fs/ntfs3/inode.c
134
fs/ntfs3/inode.c
@ -100,6 +100,12 @@ static struct inode *ntfs_read_mft(struct inode *inode,
|
||||
/* Record should contain $I30 root. */
|
||||
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);
|
||||
|
||||
/* Enumerate all struct Attributes MFT. */
|
||||
@ -131,7 +137,13 @@ next_attr:
|
||||
rsize = attr->non_res ? 0 : le32_to_cpu(attr->res.data_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;
|
||||
|
||||
if (attr->non_res) {
|
||||
@ -250,8 +262,8 @@ next_attr:
|
||||
if (!attr->nres.alloc_size)
|
||||
goto next_attr;
|
||||
|
||||
run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run
|
||||
: &ni->file.run;
|
||||
run = ino == MFT_REC_BITMAP ? &sbi->used.bitmap.run :
|
||||
&ni->file.run;
|
||||
break;
|
||||
|
||||
case ATTR_ROOT:
|
||||
@ -259,7 +271,6 @@ next_attr:
|
||||
goto out;
|
||||
|
||||
root = Add2Ptr(attr, roff);
|
||||
is_root = true;
|
||||
|
||||
if (attr->name_len != ARRAY_SIZE(I30_NAME) ||
|
||||
memcmp(attr_name(attr), I30_NAME, sizeof(I30_NAME)))
|
||||
@ -272,15 +283,16 @@ next_attr:
|
||||
if (!is_dir)
|
||||
goto next_attr;
|
||||
|
||||
is_root = true;
|
||||
ni->ni_flags |= NI_FLAG_DIR;
|
||||
|
||||
err = indx_init(&ni->dir, sbi, attr, INDEX_MUTEX_I30);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
mode = sb->s_root
|
||||
? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv))
|
||||
: (S_IFDIR | 0777);
|
||||
mode = sb->s_root ?
|
||||
(S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) :
|
||||
(S_IFDIR | 0777);
|
||||
goto next_attr;
|
||||
|
||||
case ATTR_ALLOC:
|
||||
@ -437,8 +449,8 @@ end_enum:
|
||||
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
||||
inode->i_op = &ntfs_file_inode_operations;
|
||||
inode->i_fop = &ntfs_file_operations;
|
||||
inode->i_mapping->a_ops =
|
||||
is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops;
|
||||
inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
|
||||
&ntfs_aops;
|
||||
if (ino != MFT_REC_MFT)
|
||||
init_rwsem(&ni->file.run_lock);
|
||||
} 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,
|
||||
bh->b_size = block_size;
|
||||
off = vbo & (PAGE_SIZE - 1);
|
||||
set_bh_page(bh, page, off);
|
||||
|
||||
err = bh_read(bh, 0);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
@ -773,8 +786,8 @@ static ssize_t ntfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
}
|
||||
|
||||
ret = blockdev_direct_IO(iocb, inode, iter,
|
||||
wr ? ntfs_get_block_direct_IO_W
|
||||
: ntfs_get_block_direct_IO_R);
|
||||
wr ? ntfs_get_block_direct_IO_W :
|
||||
ntfs_get_block_direct_IO_R);
|
||||
|
||||
if (ret > 0)
|
||||
end = vbo + ret;
|
||||
@ -833,7 +846,7 @@ out:
|
||||
}
|
||||
|
||||
static int ntfs_resident_writepage(struct folio *folio,
|
||||
struct writeback_control *wbc, void *data)
|
||||
struct writeback_control *wbc, void *data)
|
||||
{
|
||||
struct address_space *mapping = data;
|
||||
struct ntfs_inode *ni = ntfs_i(mapping->host);
|
||||
@ -874,8 +887,8 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
|
||||
*pagep = NULL;
|
||||
if (is_resident(ni)) {
|
||||
struct page *page = grab_cache_page_write_begin(
|
||||
mapping, pos >> PAGE_SHIFT);
|
||||
struct page *page =
|
||||
grab_cache_page_write_begin(mapping, pos >> PAGE_SHIFT);
|
||||
|
||||
if (!page) {
|
||||
err = -ENOMEM;
|
||||
@ -907,9 +920,8 @@ out:
|
||||
/*
|
||||
* ntfs_write_end - Address_space_operations::write_end.
|
||||
*/
|
||||
int ntfs_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, u32 len, u32 copied, struct page *page,
|
||||
void *fsdata)
|
||||
int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
|
||||
u32 len, u32 copied, struct page *page, void *fsdata)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
@ -1307,8 +1319,7 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
|
||||
inode_init_owner(idmap, inode, dir, mode);
|
||||
mode = inode->i_mode;
|
||||
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = ni->i_crtime =
|
||||
current_time(inode);
|
||||
ni->i_crtime = current_time(inode);
|
||||
|
||||
rec = ni->mi.mrec;
|
||||
rec->hard_links = cpu_to_le16(1);
|
||||
@ -1349,10 +1360,9 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
|
||||
attr->res.data_size = cpu_to_le32(dsize);
|
||||
|
||||
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 = fa;
|
||||
std5->fa = ni->std_fa = fa;
|
||||
|
||||
attr = Add2Ptr(attr, asize);
|
||||
|
||||
@ -1551,11 +1561,15 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
|
||||
}
|
||||
|
||||
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 {
|
||||
attr->res.data_off = SIZEOF_RESIDENT_LE;
|
||||
attr->res.data_size = cpu_to_le32(nsize);
|
||||
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
|
||||
nsize = 0;
|
||||
}
|
||||
/* Size of symlink equals the length of input string. */
|
||||
inode->i_size = size;
|
||||
@ -1576,19 +1590,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
|
||||
rec->used = cpu_to_le32(PtrOffset(rec, attr) + 8);
|
||||
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);
|
||||
|
||||
dir->i_mtime = dir->i_ctime = inode->i_atime;
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
inode->i_op = &ntfs_dir_inode_operations;
|
||||
inode->i_fop = &ntfs_dir_operations;
|
||||
@ -1601,8 +1604,8 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
|
||||
} else if (S_ISREG(mode)) {
|
||||
inode->i_op = &ntfs_file_inode_operations;
|
||||
inode->i_fop = &ntfs_file_operations;
|
||||
inode->i_mapping->a_ops =
|
||||
is_compressed(ni) ? &ntfs_aops_cmpr : &ntfs_aops;
|
||||
inode->i_mapping->a_ops = is_compressed(ni) ? &ntfs_aops_cmpr :
|
||||
&ntfs_aops;
|
||||
init_rwsem(&ni->file.run_lock);
|
||||
} else {
|
||||
inode->i_op = &ntfs_special_inode_operations;
|
||||
@ -1613,41 +1616,58 @@ struct inode *ntfs_create_inode(struct mnt_idmap *idmap,
|
||||
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
|
||||
err = ntfs_init_acl(idmap, inode, dir);
|
||||
if (err)
|
||||
goto out7;
|
||||
goto out5;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
inode->i_flags |= S_NOSEC;
|
||||
}
|
||||
|
||||
/* Write non resident data. */
|
||||
if (nsize) {
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0);
|
||||
if (err)
|
||||
goto out7;
|
||||
/*
|
||||
* ntfs_init_acl and ntfs_save_wsl_perm update extended attribute.
|
||||
* The packed size of extended attribute is stored in direntry too.
|
||||
* 'fname' here points to inside new_de.
|
||||
*/
|
||||
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
|
||||
* but before finish_open.
|
||||
*/
|
||||
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(inode);
|
||||
|
||||
/* Normal exit. */
|
||||
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:
|
||||
if (rp_inserted)
|
||||
ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
|
||||
@ -1669,11 +1689,11 @@ out2:
|
||||
kfree(rp);
|
||||
|
||||
out1:
|
||||
if (err) {
|
||||
if (!fnd)
|
||||
ni_unlock(dir_ni);
|
||||
if (!fnd)
|
||||
ni_unlock(dir_ni);
|
||||
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
unlock_new_inode(inode);
|
||||
|
||||
@ -1770,9 +1790,6 @@ void ntfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
if (inode->i_nlink)
|
||||
_ni_write_inode(inode, inode_needs_sync(inode));
|
||||
|
||||
invalidate_inode_buffers(inode);
|
||||
clear_inode(inode);
|
||||
|
||||
@ -2057,7 +2074,6 @@ const struct inode_operations ntfs_link_inode_operations = {
|
||||
.get_link = ntfs_get_link,
|
||||
.setattr = ntfs3_setattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.permission = ntfs_permission,
|
||||
};
|
||||
|
||||
const struct address_space_operations ntfs_aops = {
|
||||
|
@ -296,8 +296,8 @@ next:
|
||||
*/
|
||||
struct lznt *get_lznt_ctx(int level)
|
||||
{
|
||||
struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash)
|
||||
: sizeof(struct lznt),
|
||||
struct lznt *r = kzalloc(level ? offsetof(struct lznt, hash) :
|
||||
sizeof(struct lznt),
|
||||
GFP_NOFS);
|
||||
|
||||
if (r)
|
||||
@ -392,9 +392,9 @@ ssize_t decompress_lznt(const void *cmpr, size_t cmpr_size, void *unc,
|
||||
unc_use = err;
|
||||
} else {
|
||||
/* This chunk does not contain compressed data. */
|
||||
unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end
|
||||
? unc_end - unc_chunk
|
||||
: LZNT_CHUNK_SIZE;
|
||||
unc_use = unc_chunk + LZNT_CHUNK_SIZE > unc_end ?
|
||||
unc_end - unc_chunk :
|
||||
LZNT_CHUNK_SIZE;
|
||||
|
||||
if (cmpr_chunk + sizeof(chunk_hdr) + unc_use >
|
||||
cmpr_end) {
|
||||
|
@ -88,6 +88,16 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
__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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
NULL, 0, fnd);
|
||||
err = IS_ERR(inode) ? PTR_ERR(inode)
|
||||
: finish_open(file, dentry, ntfs_file_open);
|
||||
err = IS_ERR(inode) ? PTR_ERR(inode) :
|
||||
finish_open(file, dentry, ntfs_file_open);
|
||||
dput(d);
|
||||
|
||||
out2:
|
||||
@ -597,8 +607,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
|
||||
.rmdir = ntfs_rmdir,
|
||||
.mknod = ntfs_mknod,
|
||||
.rename = ntfs_rename,
|
||||
.permission = ntfs_permission,
|
||||
.get_inode_acl = ntfs_get_acl,
|
||||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
.setattr = ntfs3_setattr,
|
||||
.getattr = ntfs_getattr,
|
||||
@ -611,7 +620,7 @@ const struct inode_operations ntfs_special_inode_operations = {
|
||||
.setattr = ntfs3_setattr,
|
||||
.getattr = ntfs_getattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.get_inode_acl = ntfs_get_acl,
|
||||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
};
|
||||
|
||||
|
@ -435,9 +435,6 @@ static inline u64 attr_svcn(const struct ATTRIB *attr)
|
||||
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 *)NULL)->res) == 0x08);
|
||||
static_assert(sizeof(((struct ATTRIB *)NULL)->nres) == 0x38);
|
||||
|
@ -100,7 +100,6 @@ struct ntfs_mount_options {
|
||||
unsigned hide_dot_files : 1; /* Set hidden flag on dot files. */
|
||||
unsigned windows_names : 1; /* Disallow names forbidden by Windows. */
|
||||
unsigned force : 1; /* RW mount dirty volume. */
|
||||
unsigned noacsrules : 1; /* Exclude acs rules. */
|
||||
unsigned prealloc : 1; /* Preallocate space when file is growing. */
|
||||
unsigned nocase : 1; /* case insensitive. */
|
||||
};
|
||||
@ -164,7 +163,6 @@ struct wnd_bitmap {
|
||||
size_t zone_bit;
|
||||
size_t zone_end;
|
||||
|
||||
bool set_tail; // Not necessary in driver.
|
||||
bool inited;
|
||||
};
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
@ -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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Globals from fsntfs.c */
|
||||
@ -700,9 +699,8 @@ int ntfs_get_block(struct inode *inode, sector_t vbn,
|
||||
struct buffer_head *bh_result, int create);
|
||||
int ntfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, u32 len, struct page **pagep, void **fsdata);
|
||||
int ntfs_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, u32 len, u32 copied, struct page *page,
|
||||
void *fsdata);
|
||||
int ntfs_write_end(struct file *file, struct address_space *mapping, loff_t pos,
|
||||
u32 len, u32 copied, struct page *page, void *fsdata);
|
||||
int ntfs3_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
int ntfs_sync_inode(struct inode *inode);
|
||||
int ntfs_flush_inodes(struct super_block *sb, struct inode *i1,
|
||||
@ -858,23 +856,22 @@ unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
|
||||
|
||||
/* globals from xattr.c */
|
||||
#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,
|
||||
struct posix_acl *acl, int type);
|
||||
int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct inode *dir);
|
||||
struct inode *dir);
|
||||
#else
|
||||
#define ntfs_get_acl NULL
|
||||
#define ntfs_set_acl NULL
|
||||
#endif
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
/* globals from lznt.c */
|
||||
|
@ -221,7 +221,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
}
|
||||
|
||||
if (off + asize < off) {
|
||||
/* overflow check */
|
||||
/* Overflow check. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -247,8 +247,8 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
if ((t32 & 0xf) || (t32 > 0x100))
|
||||
return NULL;
|
||||
|
||||
/* Check boundary. */
|
||||
if (off + asize > used)
|
||||
/* Check overflow and boundary. */
|
||||
if (off + asize < off || off + asize > used)
|
||||
return NULL;
|
||||
|
||||
/* Check size of attribute. */
|
||||
@ -419,10 +419,9 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
|
||||
struct ntfs_sb_info *sbi = mi->sbi;
|
||||
u32 used = le32_to_cpu(rec->used);
|
||||
const u16 *upcase = sbi->upcase;
|
||||
int diff;
|
||||
|
||||
/* Can we insert mi attribute? */
|
||||
if (used + asize > mi->sbi->record_size)
|
||||
if (used + asize > sbi->record_size)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
@ -431,7 +430,7 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
|
||||
*/
|
||||
attr = NULL;
|
||||
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)
|
||||
continue;
|
||||
@ -442,9 +441,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
|
||||
}
|
||||
|
||||
if (!attr) {
|
||||
tail = 8; /* Not used, just to suppress warning. */
|
||||
/* Append. */
|
||||
tail = 8;
|
||||
attr = Add2Ptr(rec, used - 8);
|
||||
} else {
|
||||
/* Insert before 'attr'. */
|
||||
tail = used - PtrOffset(rec, attr);
|
||||
}
|
||||
|
||||
|
@ -433,9 +433,9 @@ requires_new_range:
|
||||
should_add_tail = Tovcn < r->len;
|
||||
|
||||
if (should_add_tail) {
|
||||
tail_lcn = r->lcn == SPARSE_LCN
|
||||
? SPARSE_LCN
|
||||
: (r->lcn + Tovcn);
|
||||
tail_lcn = r->lcn == SPARSE_LCN ?
|
||||
SPARSE_LCN :
|
||||
(r->lcn + Tovcn);
|
||||
tail_vcn = r->vcn + Tovcn;
|
||||
tail_len = r->len - Tovcn;
|
||||
}
|
||||
|
330
fs/ntfs3/super.c
330
fs/ntfs3/super.c
@ -39,10 +39,10 @@
|
||||
* To mount large volumes as ntfs one should use large cluster size (up to 2M)
|
||||
* The maximum volume size in this case is 2^32 * 2^21 = 2^53 = 8P
|
||||
*
|
||||
* ntfs limits, cluster size is 2M (2^31)
|
||||
* ntfs limits, cluster size is 2M (2^21)
|
||||
* -----------------------------------------------------------------------------
|
||||
* | < 8P, 2^54 | < 2^32 | yes | yes | yes | yes | yes |
|
||||
* | > 8P, 2^54 | > 2^32 | no | no | yes | yes | yes |
|
||||
* | < 8P, 2^53 | < 2^32 | yes | yes | yes | yes | yes |
|
||||
* | > 8P, 2^53 | > 2^32 | no | no | yes | yes | yes |
|
||||
* ----------------------------------------------------------|------------------
|
||||
*
|
||||
*/
|
||||
@ -115,9 +115,9 @@ void ntfs_inode_printk(struct inode *inode, const char *fmt, ...)
|
||||
return;
|
||||
|
||||
/* Use static allocated buffer, if possible. */
|
||||
name = atomic_dec_and_test(&s_name_buf_cnt)
|
||||
? s_name_buf
|
||||
: kmalloc(sizeof(s_name_buf), GFP_NOFS);
|
||||
name = atomic_dec_and_test(&s_name_buf_cnt) ?
|
||||
s_name_buf :
|
||||
kmalloc(sizeof(s_name_buf), GFP_NOFS);
|
||||
|
||||
if (name) {
|
||||
struct dentry *de = d_find_alias(inode);
|
||||
@ -253,7 +253,6 @@ enum Opt {
|
||||
Opt_acl,
|
||||
Opt_iocharset,
|
||||
Opt_prealloc,
|
||||
Opt_noacsrules,
|
||||
Opt_nocase,
|
||||
Opt_err,
|
||||
};
|
||||
@ -271,12 +270,11 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = {
|
||||
fsparam_flag_no("hidden", Opt_nohidden),
|
||||
fsparam_flag_no("hide_dot_files", Opt_hide_dot_files),
|
||||
fsparam_flag_no("windows_names", Opt_windows_names),
|
||||
fsparam_flag_no("acl", Opt_acl),
|
||||
fsparam_flag_no("showmeta", Opt_showmeta),
|
||||
fsparam_flag_no("prealloc", Opt_prealloc),
|
||||
fsparam_flag_no("acsrules", Opt_noacsrules),
|
||||
fsparam_flag_no("nocase", Opt_nocase),
|
||||
fsparam_flag_no("acl", Opt_acl),
|
||||
fsparam_string("iocharset", Opt_iocharset),
|
||||
fsparam_flag_no("prealloc", Opt_prealloc),
|
||||
fsparam_flag_no("nocase", Opt_nocase),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -366,19 +364,20 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
|
||||
case Opt_windows_names:
|
||||
opts->windows_names = result.negated ? 0 : 1;
|
||||
break;
|
||||
case Opt_showmeta:
|
||||
opts->showmeta = result.negated ? 0 : 1;
|
||||
break;
|
||||
case Opt_acl:
|
||||
if (!result.negated)
|
||||
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
|
||||
fc->sb_flags |= SB_POSIXACL;
|
||||
#else
|
||||
return invalf(fc, "ntfs3: Support for ACL not compiled in!");
|
||||
return invalf(
|
||||
fc, "ntfs3: Support for ACL not compiled in!");
|
||||
#endif
|
||||
else
|
||||
fc->sb_flags &= ~SB_POSIXACL;
|
||||
break;
|
||||
case Opt_showmeta:
|
||||
opts->showmeta = result.negated ? 0 : 1;
|
||||
break;
|
||||
case Opt_iocharset:
|
||||
kfree(opts->nls_name);
|
||||
opts->nls_name = param->string;
|
||||
@ -387,9 +386,6 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
|
||||
case Opt_prealloc:
|
||||
opts->prealloc = result.negated ? 0 : 1;
|
||||
break;
|
||||
case Opt_noacsrules:
|
||||
opts->noacsrules = result.negated ? 1 : 0;
|
||||
break;
|
||||
case Opt_nocase:
|
||||
opts->nocase = result.negated ? 1 : 0;
|
||||
break;
|
||||
@ -409,24 +405,29 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
|
||||
|
||||
ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY);
|
||||
if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) {
|
||||
errorf(fc, "ntfs3: Couldn't remount rw because journal is not replayed. Please umount/remount instead\n");
|
||||
errorf(fc,
|
||||
"ntfs3: Couldn't remount rw because journal is not replayed. Please umount/remount instead\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
new_opts->nls = ntfs_load_nls(new_opts->nls_name);
|
||||
if (IS_ERR(new_opts->nls)) {
|
||||
new_opts->nls = NULL;
|
||||
errorf(fc, "ntfs3: Cannot load iocharset %s", new_opts->nls_name);
|
||||
errorf(fc, "ntfs3: Cannot load iocharset %s",
|
||||
new_opts->nls_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_opts->nls != sbi->options->nls)
|
||||
return invalf(fc, "ntfs3: Cannot use different iocharset when remounting!");
|
||||
return invalf(
|
||||
fc,
|
||||
"ntfs3: Cannot use different iocharset when remounting!");
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) &&
|
||||
!new_opts->force) {
|
||||
errorf(fc, "ntfs3: Volume is dirty and \"force\" flag is not set!");
|
||||
errorf(fc,
|
||||
"ntfs3: Volume is dirty and \"force\" flag is not set!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -544,40 +545,38 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root)
|
||||
struct ntfs_mount_options *opts = sbi->options;
|
||||
struct user_namespace *user_ns = seq_user_ns(m);
|
||||
|
||||
seq_printf(m, ",uid=%u",
|
||||
from_kuid_munged(user_ns, opts->fs_uid));
|
||||
seq_printf(m, ",gid=%u",
|
||||
from_kgid_munged(user_ns, opts->fs_gid));
|
||||
if (opts->fmask)
|
||||
seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff);
|
||||
seq_printf(m, ",uid=%u", from_kuid_munged(user_ns, opts->fs_uid));
|
||||
seq_printf(m, ",gid=%u", from_kgid_munged(user_ns, opts->fs_gid));
|
||||
if (opts->dmask)
|
||||
seq_printf(m, ",dmask=%04o", opts->fs_dmask_inv ^ 0xffff);
|
||||
if (opts->nls)
|
||||
seq_printf(m, ",iocharset=%s", opts->nls->charset);
|
||||
else
|
||||
seq_puts(m, ",iocharset=utf8");
|
||||
if (opts->fmask)
|
||||
seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff);
|
||||
if (opts->sys_immutable)
|
||||
seq_puts(m, ",sys_immutable");
|
||||
if (opts->discard)
|
||||
seq_puts(m, ",discard");
|
||||
if (opts->sparse)
|
||||
seq_puts(m, ",sparse");
|
||||
if (opts->showmeta)
|
||||
seq_puts(m, ",showmeta");
|
||||
if (opts->nohidden)
|
||||
seq_puts(m, ",nohidden");
|
||||
if (opts->windows_names)
|
||||
seq_puts(m, ",windows_names");
|
||||
if (opts->hide_dot_files)
|
||||
seq_puts(m, ",hide_dot_files");
|
||||
if (opts->force)
|
||||
seq_puts(m, ",force");
|
||||
if (opts->noacsrules)
|
||||
seq_puts(m, ",noacsrules");
|
||||
if (opts->prealloc)
|
||||
seq_puts(m, ",prealloc");
|
||||
if (opts->sparse)
|
||||
seq_puts(m, ",sparse");
|
||||
if (opts->nohidden)
|
||||
seq_puts(m, ",nohidden");
|
||||
if (opts->hide_dot_files)
|
||||
seq_puts(m, ",hide_dot_files");
|
||||
if (opts->windows_names)
|
||||
seq_puts(m, ",windows_names");
|
||||
if (opts->showmeta)
|
||||
seq_puts(m, ",showmeta");
|
||||
if (sb->s_flags & SB_POSIXACL)
|
||||
seq_puts(m, ",acl");
|
||||
if (opts->nls)
|
||||
seq_printf(m, ",iocharset=%s", opts->nls->charset);
|
||||
else
|
||||
seq_puts(m, ",iocharset=utf8");
|
||||
if (opts->prealloc)
|
||||
seq_puts(m, ",prealloc");
|
||||
if (opts->nocase)
|
||||
seq_puts(m, ",nocase");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -706,7 +705,7 @@ static u32 true_sectors_per_clst(const struct NTFS_BOOT *boot)
|
||||
if (boot->sectors_per_clusters <= 0x80)
|
||||
return boot->sectors_per_clusters;
|
||||
if (boot->sectors_per_clusters >= 0xf4) /* limit shift to 2MB max */
|
||||
return 1U << -(s8)boot->sectors_per_clusters;
|
||||
return 1U << (-(s8)boot->sectors_per_clusters);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -724,6 +723,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
struct buffer_head *bh;
|
||||
struct MFT_REC *rec;
|
||||
u16 fn, ao;
|
||||
u8 cluster_bits;
|
||||
|
||||
sbi->volume.blocks = dev_size >> PAGE_SHIFT;
|
||||
|
||||
@ -734,48 +734,81 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
err = -EINVAL;
|
||||
boot = (struct NTFS_BOOT *)bh->b_data;
|
||||
|
||||
if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1))
|
||||
if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1)) {
|
||||
ntfs_err(sb, "Boot's signature is not NTFS.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 0x55AA is not mandaroty. Thanks Maxim Suhanov*/
|
||||
/*if (0x55 != boot->boot_magic[0] || 0xAA != boot->boot_magic[1])
|
||||
* goto out;
|
||||
*/
|
||||
|
||||
boot_sector_size = (u32)boot->bytes_per_sector[1] << 8;
|
||||
if (boot->bytes_per_sector[0] || boot_sector_size < SECTOR_SIZE ||
|
||||
boot_sector_size = ((u32)boot->bytes_per_sector[1] << 8) |
|
||||
boot->bytes_per_sector[0];
|
||||
if (boot_sector_size < SECTOR_SIZE ||
|
||||
!is_power_of_2(boot_sector_size)) {
|
||||
ntfs_err(sb, "Invalid bytes per sector %u.", boot_sector_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* cluster size: 512, 1K, 2K, 4K, ... 2M */
|
||||
sct_per_clst = true_sectors_per_clst(boot);
|
||||
if ((int)sct_per_clst < 0)
|
||||
goto out;
|
||||
if (!is_power_of_2(sct_per_clst))
|
||||
if ((int)sct_per_clst < 0 || !is_power_of_2(sct_per_clst)) {
|
||||
ntfs_err(sb, "Invalid sectors per cluster %u.", sct_per_clst);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->cluster_size = boot_sector_size * sct_per_clst;
|
||||
sbi->cluster_bits = cluster_bits = blksize_bits(sbi->cluster_size);
|
||||
sbi->cluster_mask = sbi->cluster_size - 1;
|
||||
sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask;
|
||||
|
||||
mlcn = le64_to_cpu(boot->mft_clst);
|
||||
mlcn2 = le64_to_cpu(boot->mft2_clst);
|
||||
sectors = le64_to_cpu(boot->sectors_per_volume);
|
||||
|
||||
if (mlcn * sct_per_clst >= sectors)
|
||||
goto out;
|
||||
|
||||
if (mlcn2 * sct_per_clst >= sectors)
|
||||
goto out;
|
||||
|
||||
/* Check MFT record size. */
|
||||
if ((boot->record_size < 0 &&
|
||||
SECTOR_SIZE > (2U << (-boot->record_size))) ||
|
||||
(boot->record_size >= 0 && !is_power_of_2(boot->record_size))) {
|
||||
if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) {
|
||||
ntfs_err(
|
||||
sb,
|
||||
"Start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.",
|
||||
mlcn, mlcn2, sectors);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->record_size = record_size =
|
||||
boot->record_size < 0 ? 1 << (-boot->record_size) :
|
||||
(u32)boot->record_size << cluster_bits;
|
||||
sbi->record_bits = blksize_bits(record_size);
|
||||
sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes
|
||||
|
||||
/* Check MFT record size. */
|
||||
if (record_size < SECTOR_SIZE || !is_power_of_2(record_size)) {
|
||||
ntfs_err(sb, "Invalid bytes per MFT record %u (%d).",
|
||||
record_size, boot->record_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (record_size > MAXIMUM_BYTES_PER_MFT) {
|
||||
ntfs_err(sb, "Unsupported bytes per MFT record %u.",
|
||||
record_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->index_size = boot->index_size < 0 ?
|
||||
1u << (-boot->index_size) :
|
||||
(u32)boot->index_size << cluster_bits;
|
||||
|
||||
/* Check index record size. */
|
||||
if ((boot->index_size < 0 &&
|
||||
SECTOR_SIZE > (2U << (-boot->index_size))) ||
|
||||
(boot->index_size >= 0 && !is_power_of_2(boot->index_size))) {
|
||||
if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) {
|
||||
ntfs_err(sb, "Invalid bytes per index %u(%d).", sbi->index_size,
|
||||
boot->index_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sbi->index_size > MAXIMUM_BYTES_PER_INDEX) {
|
||||
ntfs_err(sb, "Unsupported bytes per index %u.",
|
||||
sbi->index_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -791,53 +824,36 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
if (boot_sector_size != sector_size) {
|
||||
ntfs_warn(
|
||||
sb,
|
||||
"Different NTFS' sector size (%u) and media sector size (%u)",
|
||||
"Different NTFS sector size (%u) and media sector size (%u).",
|
||||
boot_sector_size, sector_size);
|
||||
dev_size += sector_size - 1;
|
||||
}
|
||||
|
||||
sbi->cluster_size = boot_sector_size * sct_per_clst;
|
||||
sbi->cluster_bits = blksize_bits(sbi->cluster_size);
|
||||
|
||||
sbi->mft.lbo = mlcn << sbi->cluster_bits;
|
||||
sbi->mft.lbo2 = mlcn2 << sbi->cluster_bits;
|
||||
sbi->mft.lbo = mlcn << cluster_bits;
|
||||
sbi->mft.lbo2 = mlcn2 << cluster_bits;
|
||||
|
||||
/* Compare boot's cluster and sector. */
|
||||
if (sbi->cluster_size < boot_sector_size)
|
||||
if (sbi->cluster_size < boot_sector_size) {
|
||||
ntfs_err(sb, "Invalid bytes per cluster (%u).",
|
||||
sbi->cluster_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Compare boot's cluster and media sector. */
|
||||
if (sbi->cluster_size < sector_size) {
|
||||
/* No way to use ntfs_get_block in this case. */
|
||||
ntfs_err(
|
||||
sb,
|
||||
"Failed to mount 'cause NTFS's cluster size (%u) is less than media sector size (%u)",
|
||||
"Failed to mount 'cause NTFS's cluster size (%u) is less than media sector size (%u).",
|
||||
sbi->cluster_size, sector_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->cluster_mask = sbi->cluster_size - 1;
|
||||
sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask;
|
||||
sbi->record_size = record_size = boot->record_size < 0
|
||||
? 1 << (-boot->record_size)
|
||||
: (u32)boot->record_size
|
||||
<< sbi->cluster_bits;
|
||||
|
||||
if (record_size > MAXIMUM_BYTES_PER_MFT || record_size < SECTOR_SIZE)
|
||||
goto out;
|
||||
|
||||
sbi->record_bits = blksize_bits(record_size);
|
||||
sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes
|
||||
|
||||
sbi->max_bytes_per_attr =
|
||||
record_size - ALIGN(MFTRECORD_FIXUP_OFFSET_1, 8) -
|
||||
ALIGN(((record_size >> SECTOR_SHIFT) * sizeof(short)), 8) -
|
||||
ALIGN(sizeof(enum ATTR_TYPE), 8);
|
||||
|
||||
sbi->index_size = boot->index_size < 0
|
||||
? 1u << (-boot->index_size)
|
||||
: (u32)boot->index_size << sbi->cluster_bits;
|
||||
|
||||
sbi->volume.ser_num = le64_to_cpu(boot->serial_num);
|
||||
|
||||
/* Warning if RAW volume. */
|
||||
@ -847,18 +863,18 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
gb0 = format_size_gb(dev_size, &mb0);
|
||||
ntfs_warn(
|
||||
sb,
|
||||
"RAW NTFS volume: Filesystem size %u.%02u Gb > volume size %u.%02u Gb. Mount in read-only",
|
||||
"RAW NTFS volume: Filesystem size %u.%02u Gb > volume size %u.%02u Gb. Mount in read-only.",
|
||||
gb, mb, gb0, mb0);
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
}
|
||||
|
||||
clusters = sbi->volume.size >> sbi->cluster_bits;
|
||||
clusters = sbi->volume.size >> cluster_bits;
|
||||
#ifndef CONFIG_NTFS3_64BIT_CLUSTER
|
||||
/* 32 bits per cluster. */
|
||||
if (clusters >> 32) {
|
||||
ntfs_notice(
|
||||
sb,
|
||||
"NTFS %u.%02u Gb is too big to use 32 bits per cluster",
|
||||
"NTFS %u.%02u Gb is too big to use 32 bits per cluster.",
|
||||
gb, mb);
|
||||
goto out;
|
||||
}
|
||||
@ -892,17 +908,17 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
sbi->volume.blocks = sbi->volume.size >> sb->s_blocksize_bits;
|
||||
|
||||
/* Maximum size for normal files. */
|
||||
sbi->maxbytes = (clusters << sbi->cluster_bits) - 1;
|
||||
sbi->maxbytes = (clusters << cluster_bits) - 1;
|
||||
|
||||
#ifdef CONFIG_NTFS3_64BIT_CLUSTER
|
||||
if (clusters >= (1ull << (64 - sbi->cluster_bits)))
|
||||
if (clusters >= (1ull << (64 - cluster_bits)))
|
||||
sbi->maxbytes = -1;
|
||||
sbi->maxbytes_sparse = -1;
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
#else
|
||||
/* Maximum size for sparse file. */
|
||||
sbi->maxbytes_sparse = (1ull << (sbi->cluster_bits + 32)) - 1;
|
||||
sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits;
|
||||
sbi->maxbytes_sparse = (1ull << (cluster_bits + 32)) - 1;
|
||||
sb->s_maxbytes = 0xFFFFFFFFull << cluster_bits;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -910,7 +926,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
|
||||
* It would be nice if we are able to allocate 1/8 of
|
||||
* total clusters for MFT but not more then 512 MB.
|
||||
*/
|
||||
sbi->zone_max = min_t(CLST, 0x20000000 >> sbi->cluster_bits, clusters >> 3);
|
||||
sbi->zone_max = min_t(CLST, 0x20000000 >> cluster_bits, clusters >> 3);
|
||||
|
||||
err = 0;
|
||||
|
||||
@ -928,6 +944,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
int err;
|
||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
struct ntfs_mount_options *options;
|
||||
struct inode *inode;
|
||||
struct ntfs_inode *ni;
|
||||
size_t i, tt, bad_len, bad_frags;
|
||||
@ -942,7 +959,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.high = 0;
|
||||
|
||||
sbi->sb = sb;
|
||||
sbi->options = fc->fs_private;
|
||||
sbi->options = options = fc->fs_private;
|
||||
fc->fs_private = NULL;
|
||||
sb->s_flags |= SB_NODIRATIME;
|
||||
sb->s_magic = 0x7366746e; // "ntfs"
|
||||
@ -950,12 +967,12 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
sb->s_export_op = &ntfs_export_ops;
|
||||
sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec
|
||||
sb->s_xattr = ntfs_xattr_handlers;
|
||||
sb->s_d_op = sbi->options->nocase ? &ntfs_dentry_ops : NULL;
|
||||
sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL;
|
||||
|
||||
sbi->options->nls = ntfs_load_nls(sbi->options->nls_name);
|
||||
if (IS_ERR(sbi->options->nls)) {
|
||||
sbi->options->nls = NULL;
|
||||
errorf(fc, "Cannot load nls %s", sbi->options->nls_name);
|
||||
options->nls = ntfs_load_nls(options->nls_name);
|
||||
if (IS_ERR(options->nls)) {
|
||||
options->nls = NULL;
|
||||
errorf(fc, "Cannot load nls %s", options->nls_name);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -980,8 +997,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.seq = cpu_to_le16(MFT_REC_VOL);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_VOLUME);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $Volume.");
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $Volume (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1007,13 +1024,9 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
}
|
||||
|
||||
attr = ni_find_attr(ni, attr, NULL, ATTR_VOL_INFO, NULL, 0, NULL, NULL);
|
||||
if (!attr || is_attr_ext(attr)) {
|
||||
err = -EINVAL;
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO);
|
||||
if (!info) {
|
||||
if (!attr || is_attr_ext(attr) ||
|
||||
!(info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO))) {
|
||||
ntfs_err(sb, "$Volume is corrupted.");
|
||||
err = -EINVAL;
|
||||
goto put_inode_out;
|
||||
}
|
||||
@ -1028,13 +1041,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.seq = cpu_to_le16(MFT_REC_MIRR);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_MIRROR);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $MFTMirr.");
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $MFTMirr (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi->mft.recs_mirr =
|
||||
ntfs_up_cluster(sbi, inode->i_size) >> sbi->record_bits;
|
||||
sbi->mft.recs_mirr = ntfs_up_cluster(sbi, inode->i_size) >>
|
||||
sbi->record_bits;
|
||||
|
||||
iput(inode);
|
||||
|
||||
@ -1043,8 +1056,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.seq = cpu_to_le16(MFT_REC_LOG);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load \x24LogFile.");
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load \x24LogFile (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1064,7 +1077,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
goto out;
|
||||
}
|
||||
} else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) {
|
||||
if (!sb_rdonly(sb) && !sbi->options->force) {
|
||||
if (!sb_rdonly(sb) && !options->force) {
|
||||
ntfs_warn(
|
||||
sb,
|
||||
"volume is dirty and \"force\" flag is not set!");
|
||||
@ -1079,8 +1092,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_MFT);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $MFT.");
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $MFT (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1095,8 +1108,10 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
goto put_inode_out;
|
||||
|
||||
err = ni_load_all_mi(ni);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_err(sb, "Failed to load $MFT's subrecords (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
sbi->mft.ni = ni;
|
||||
|
||||
@ -1105,8 +1120,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.seq = cpu_to_le16(MFT_REC_BITMAP);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_BITMAP);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $Bitmap.");
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $Bitmap (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1120,22 +1135,25 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
/* Check bitmap boundary. */
|
||||
tt = sbi->used.bitmap.nbits;
|
||||
if (inode->i_size < bitmap_size(tt)) {
|
||||
ntfs_err(sb, "$Bitmap is corrupted.");
|
||||
err = -EINVAL;
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
/* Not necessary. */
|
||||
sbi->used.bitmap.set_tail = true;
|
||||
err = wnd_init(&sbi->used.bitmap, sb, tt);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_err(sb, "Failed to initialize $Bitmap (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
iput(inode);
|
||||
|
||||
/* Compute the MFT zone. */
|
||||
err = ntfs_refresh_zone(sbi);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_err(sb, "Failed to initialize MFT zone (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Load $BadClus. */
|
||||
ref.low = cpu_to_le32(MFT_REC_BADCLUST);
|
||||
@ -1180,15 +1198,23 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.seq = cpu_to_le16(MFT_REC_ATTR);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $AttrDef -> %d", err);
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $AttrDef (%d)", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY)) {
|
||||
/*
|
||||
* Typical $AttrDef contains up to 20 entries.
|
||||
* Check for extremely large/small size.
|
||||
*/
|
||||
if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY) ||
|
||||
inode->i_size > 100 * sizeof(struct ATTR_DEF_ENTRY)) {
|
||||
ntfs_err(sb, "Looks like $AttrDef is corrupted (size=%llu).",
|
||||
inode->i_size);
|
||||
err = -EINVAL;
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
bytes = inode->i_size;
|
||||
sbi->def_table = t = kmalloc(bytes, GFP_NOFS | __GFP_NOWARN);
|
||||
if (!t) {
|
||||
@ -1202,6 +1228,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
ntfs_err(sb, "Failed to read $AttrDef (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
memcpy(Add2Ptr(t, done), page_address(page),
|
||||
@ -1209,6 +1236,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ntfs_unmap_page(page);
|
||||
|
||||
if (!idx && ATTR_STD != t->type) {
|
||||
ntfs_err(sb, "$AttrDef is corrupted.");
|
||||
err = -EINVAL;
|
||||
goto put_inode_out;
|
||||
}
|
||||
@ -1243,13 +1271,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
ref.seq = cpu_to_le16(MFT_REC_UPCASE);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_UPCASE);
|
||||
if (IS_ERR(inode)) {
|
||||
ntfs_err(sb, "Failed to load $UpCase.");
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load $UpCase (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (inode->i_size != 0x10000 * sizeof(short)) {
|
||||
err = -EINVAL;
|
||||
ntfs_err(sb, "$UpCase is corrupted.");
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
@ -1260,6 +1289,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
ntfs_err(sb, "Failed to read $UpCase (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
@ -1285,23 +1315,31 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
if (is_ntfs3(sbi)) {
|
||||
/* Load $Secure. */
|
||||
err = ntfs_security_init(sbi);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_err(sb, "Failed to initialize $Secure (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Load $Extend. */
|
||||
err = ntfs_extend_init(sbi);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_warn(sb, "Failed to initialize $Extend.");
|
||||
goto load_root;
|
||||
}
|
||||
|
||||
/* Load $Extend\$Reparse. */
|
||||
/* Load $Extend/$Reparse. */
|
||||
err = ntfs_reparse_init(sbi);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_warn(sb, "Failed to initialize $Extend/$Reparse.");
|
||||
goto load_root;
|
||||
}
|
||||
|
||||
/* Load $Extend\$ObjId. */
|
||||
/* Load $Extend/$ObjId. */
|
||||
err = ntfs_objid_init(sbi);
|
||||
if (err)
|
||||
if (err) {
|
||||
ntfs_warn(sb, "Failed to initialize $Extend/$ObjId.");
|
||||
goto load_root;
|
||||
}
|
||||
}
|
||||
|
||||
load_root:
|
||||
@ -1309,12 +1347,21 @@ load_root:
|
||||
ref.low = cpu_to_le32(MFT_REC_ROOT);
|
||||
ref.seq = cpu_to_le16(MFT_REC_ROOT);
|
||||
inode = ntfs_iget5(sb, &ref, &NAME_ROOT);
|
||||
if (IS_ERR(inode) || !inode->i_op) {
|
||||
ntfs_err(sb, "Failed to load root.");
|
||||
err = IS_ERR(inode) ? PTR_ERR(inode) : -EINVAL;
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
ntfs_err(sb, "Failed to load root (%d).", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Final check. Looks like this case should never occurs.
|
||||
*/
|
||||
if (!inode->i_op) {
|
||||
err = -EINVAL;
|
||||
ntfs_err(sb, "Failed to load root (%d).", err);
|
||||
goto put_inode_out;
|
||||
}
|
||||
|
||||
sb->s_root = d_make_root(inode);
|
||||
if (!sb->s_root) {
|
||||
err = -ENOMEM;
|
||||
@ -1434,7 +1481,7 @@ static const struct fs_context_operations ntfs_context_ops = {
|
||||
};
|
||||
|
||||
/*
|
||||
* ntfs_init_fs_context - Initialize spi and opts
|
||||
* ntfs_init_fs_context - Initialize sbi and opts
|
||||
*
|
||||
* This will called when mount/remount. We will first initialize
|
||||
* options so that if remount we can use just that.
|
||||
@ -1507,7 +1554,8 @@ static int __init init_ntfs_fs(void)
|
||||
if (IS_ENABLED(CONFIG_NTFS3_FS_POSIX_ACL))
|
||||
pr_info("ntfs3: Enabled Linux POSIX ACLs support\n");
|
||||
if (IS_ENABLED(CONFIG_NTFS3_64BIT_CLUSTER))
|
||||
pr_notice("ntfs3: Warning: Activated 64 bits per cluster. Windows does not support this\n");
|
||||
pr_notice(
|
||||
"ntfs3: Warning: Activated 64 bits per cluster. Windows does not support this\n");
|
||||
if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
|
||||
pr_info("ntfs3: Read-only LZX/Xpress compression included\n");
|
||||
|
||||
@ -1550,7 +1598,9 @@ MODULE_DESCRIPTION("ntfs3 read/write filesystem");
|
||||
MODULE_INFO(behaviour, "Enabled Linux POSIX ACLs support");
|
||||
#endif
|
||||
#ifdef CONFIG_NTFS3_64BIT_CLUSTER
|
||||
MODULE_INFO(cluster, "Warning: Activated 64 bits per cluster. Windows does not support this");
|
||||
MODULE_INFO(
|
||||
cluster,
|
||||
"Warning: Activated 64 bits per cluster. Windows does not support this");
|
||||
#endif
|
||||
#ifdef CONFIG_NTFS3_LZX_XPRESS
|
||||
MODULE_INFO(compression, "Read-only lzx/xpress compression included");
|
||||
|
@ -23,8 +23,8 @@
|
||||
|
||||
static inline size_t unpacked_ea_size(const struct EA_FULL *ea)
|
||||
{
|
||||
return ea->size ? le32_to_cpu(ea->size)
|
||||
: ALIGN(struct_size(ea, name,
|
||||
return ea->size ? le32_to_cpu(ea->size) :
|
||||
ALIGN(struct_size(ea, name,
|
||||
1 + ea->name_len +
|
||||
le16_to_cpu(ea->elength)),
|
||||
4);
|
||||
@ -296,7 +296,8 @@ out:
|
||||
|
||||
static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
||||
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_sb_info *sbi = ni->mi.sbi;
|
||||
@ -410,7 +411,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
ntfs_inode_warn(
|
||||
@ -504,6 +505,8 @@ update_ea:
|
||||
|
||||
if (ea_info.size_pack != size_pack)
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
if (ea_size)
|
||||
*ea_size = ea_info.size_pack;
|
||||
mark_inode_dirty(&ni->vfs_inode);
|
||||
|
||||
out:
|
||||
@ -517,9 +520,14 @@ out:
|
||||
}
|
||||
|
||||
#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);
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
@ -542,13 +550,11 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
|
||||
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);
|
||||
|
||||
if (!locked)
|
||||
ni_unlock(ni);
|
||||
ni_unlock(ni);
|
||||
|
||||
/* Translate extended attribute to acl. */
|
||||
if (err >= 0) {
|
||||
@ -567,17 +573,6 @@ static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
|
||||
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,
|
||||
struct inode *inode, struct posix_acl *acl,
|
||||
int type, bool init_acl)
|
||||
@ -633,7 +628,7 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap,
|
||||
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)
|
||||
err = 0; /* Removing non existed xattr. */
|
||||
if (!err) {
|
||||
@ -711,20 +706,6 @@ int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry)
|
||||
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
|
||||
*/
|
||||
@ -780,7 +761,7 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
|
||||
err = sizeof(u32);
|
||||
*(u32 *)buffer = le32_to_cpu(ni->std_fa);
|
||||
if (!strcmp(name, SYSTEM_NTFS_ATTRIB_BE))
|
||||
*(u32 *)buffer = cpu_to_be32(*(u32 *)buffer);
|
||||
*(__be32 *)buffer = cpu_to_be32(*(u32 *)buffer);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -857,7 +838,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
|
||||
if (size != sizeof(u32))
|
||||
goto out;
|
||||
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
|
||||
new_fa = cpu_to_le32(*(u32 *)value);
|
||||
|
||||
@ -937,7 +918,8 @@ set_new_fa:
|
||||
}
|
||||
|
||||
/* 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:
|
||||
inode->i_ctime = current_time(inode);
|
||||
@ -951,7 +933,7 @@ out:
|
||||
*
|
||||
* 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;
|
||||
__le32 value;
|
||||
@ -960,26 +942,26 @@ int ntfs_save_wsl_perm(struct inode *inode)
|
||||
ni_lock(ni);
|
||||
value = cpu_to_le32(i_uid_read(inode));
|
||||
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)
|
||||
goto out;
|
||||
|
||||
value = cpu_to_le32(i_gid_read(inode));
|
||||
err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
|
||||
sizeof(value), 0, true);
|
||||
sizeof(value), 0, true, ea_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
value = cpu_to_le32(inode->i_mode);
|
||||
err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
|
||||
sizeof(value), 0, true);
|
||||
sizeof(value), 0, true, ea_size);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
||||
value = cpu_to_le32(inode->i_rdev);
|
||||
err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
|
||||
sizeof(value), 0, true);
|
||||
sizeof(value), 0, true, ea_size);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user