mirror of
https://github.com/torvalds/linux.git
synced 2026-07-30 11:11:26 +02:00
Changes for 6.17-rc1
Added:
sanity check for file name;
mark live inode as bad and avoid any operations.
Fixed:
handling of symlinks created in windows;
creation of symlinks for relative path.
Changed:
cancel setting inode as bad after removing name fails;
revert "replace inode_trylock with inode_lock".
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmiDiMwACgkQqbAzH4Mk
B7aJFg//Q/L5xNxtXf3bUDCGhEYfex2qvvSnMg8MZEcLXJI9DW/Z701Xs7ay8BBL
Gp982rSX87hnnA/+1YutzAEiyTCnwRWPKNocrfPEqzXDFl4t/4Rua1Wf+Bw2/p5C
YjGd8zFbFel3NDkZa94KSCV6ATsPMnF3UN3Zj0+izyoaxQPnpoAaaOsxS2PlK+97
ePZ9PWeAe6vjW3myKQzSKz8vjeb2bNK3R67Z27igCi78jjsuI6BomBhKjGN3iOk5
eZjCrWL+DesTN43EyV8yL72Mha+BvT5XQx83gzBKghhKCBXa2BMZo3l+KDI4pGr6
Mmynw1i+o1Z+P+xvCAPEiil6x6DNauUCUtgKJEEoRatGjGOPRM4U/NWZiXITZuFD
zkSmToA3ZtJA0XBHRnoPSDg0wEQ965sy6lsGs/O1sUfURJ51lc9EwmnWmGmq4Fs+
HZ3aNbaizi1TEx89R+BEaE7bZqSK0cv4nHHtcepTgVimgSzz02uvCpz9SLLs3JsB
g9a3b6M68Rtex2+unos5Cw9Afq1Y34wcPFn9rAK8+LashAgKKhRuUqwTaZ1k7nMU
hZIFsXCxvgnQgmbF5Dod8uA/2eO+U7BXixZWvGqhAliPuLSrubhb7dZrSANRkFlt
lv9qLmrcD/cpa/JvnrqOf6NyEc9vFoowvio3JQxkIhf7wQviv44=
=OGQG
-----END PGP SIGNATURE-----
Merge tag 'ntfs3_for_6.17' of https://github.com/Paragon-Software-Group/linux-ntfs3
Pull ntfs3 updates from Konstantin Komarov:
"Added:
- sanity check for file name
- mark live inode as bad and avoid any operations
Fixed:
- handling of symlinks created in windows
- creation of symlinks for relative path
Changed:
- cancel setting inode as bad after removing name fails
- revert 'replace inode_trylock with inode_lock'"
* tag 'ntfs3_for_6.17' of https://github.com/Paragon-Software-Group/linux-ntfs3:
Revert "fs/ntfs3: Replace inode_trylock with inode_lock"
fs/ntfs3: Exclude call make_bad_inode for live nodes.
fs/ntfs3: cancle set bad inode after removing name fails
fs/ntfs3: Add sanity check for file name
fs/ntfs3: correctly create symlink for relative path
fs/ntfs3: fix symlinks cannot be handled correctly
This commit is contained in:
commit
a11b4fa602
|
|
@ -304,6 +304,9 @@ static inline bool ntfs_dir_emit(struct ntfs_sb_info *sbi,
|
|||
if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
|
||||
return true;
|
||||
|
||||
if (fname->name_len + sizeof(struct NTFS_DE) > le16_to_cpu(e->size))
|
||||
return true;
|
||||
|
||||
name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
|
||||
PATH_MAX);
|
||||
if (name_len <= 0) {
|
||||
|
|
@ -329,8 +332,7 @@ static inline bool ntfs_dir_emit(struct ntfs_sb_info *sbi,
|
|||
* It does additional locks/reads just to get the type of name.
|
||||
* Should we use additional mount option to enable branch below?
|
||||
*/
|
||||
if (((fname->dup.fa & FILE_ATTRIBUTE_REPARSE_POINT) ||
|
||||
fname->dup.ea_size) &&
|
||||
if (fname->dup.extend_data &&
|
||||
ino != ni->mi.rno) {
|
||||
struct inode *inode = ntfs_iget5(sbi->sb, &e->ref, NULL);
|
||||
if (!IS_ERR_OR_NULL(inode)) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
|||
struct inode *inode = file_inode(filp);
|
||||
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ntfs_i(inode))))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case FITRIM:
|
||||
return ntfs_ioctl_fitrim(sbi, arg);
|
||||
|
|
@ -81,6 +85,10 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
|||
struct inode *inode = d_inode(path->dentry);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
stat->result_mask |= STATX_BTIME;
|
||||
stat->btime = ni->i_crtime;
|
||||
stat->blksize = ni->mi.sbi->cluster_size; /* 512, 1K, ..., 2M */
|
||||
|
|
@ -271,6 +279,10 @@ static int ntfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
bool rw = vma->vm_flags & VM_WRITE;
|
||||
int err;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -310,7 +322,10 @@ static int ntfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
}
|
||||
|
||||
if (ni->i_valid < to) {
|
||||
inode_lock(inode);
|
||||
if (!inode_trylock(inode)) {
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
err = ntfs_extend_initialized_size(file, ni,
|
||||
ni->i_valid, to);
|
||||
inode_unlock(inode);
|
||||
|
|
@ -735,6 +750,10 @@ int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
umode_t mode = inode->i_mode;
|
||||
int err;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -795,6 +814,10 @@ static int check_read_restriction(struct inode *inode)
|
|||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -1130,6 +1153,10 @@ static int check_write_restriction(struct inode *inode)
|
|||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -1212,6 +1239,10 @@ int ntfs_file_open(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -1281,6 +1312,10 @@ int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
|||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
err = fiemap_prep(inode, fieinfo, start, &len, ~FIEMAP_FLAG_XATTR);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -3003,8 +3003,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
|
|||
* ni_rename - Remove one name and insert new name.
|
||||
*/
|
||||
int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
|
||||
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
|
||||
bool *is_bad)
|
||||
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de)
|
||||
{
|
||||
int err;
|
||||
struct NTFS_DE *de2 = NULL;
|
||||
|
|
@ -3027,8 +3026,8 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
|
|||
err = ni_add_name(new_dir_ni, ni, new_de);
|
||||
if (!err) {
|
||||
err = ni_remove_name(dir_ni, ni, de, &de2, &undo);
|
||||
if (err && ni_remove_name(new_dir_ni, ni, new_de, &de2, &undo))
|
||||
*is_bad = true;
|
||||
WARN_ON(err && ni_remove_name(new_dir_ni, ni, new_de, &de2,
|
||||
&undo));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3119,11 +3118,21 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: Fill reparse info. */
|
||||
dup->reparse = 0;
|
||||
dup->ea_size = 0;
|
||||
dup->extend_data = 0;
|
||||
|
||||
if (ni->ni_flags & NI_FLAG_EA) {
|
||||
if (dup->fa & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
attr = ni_find_attr(ni, NULL, NULL, ATTR_REPARSE, NULL, 0, NULL,
|
||||
NULL);
|
||||
|
||||
if (attr) {
|
||||
const struct REPARSE_POINT *rp;
|
||||
|
||||
rp = resident_data_ex(attr, sizeof(struct REPARSE_POINT));
|
||||
/* If ATTR_REPARSE exists 'rp' can't be NULL. */
|
||||
if (rp)
|
||||
dup->extend_data = rp->ReparseTag;
|
||||
}
|
||||
} else if (ni->ni_flags & NI_FLAG_EA) {
|
||||
attr = ni_find_attr(ni, attr, &le, ATTR_EA_INFO, NULL, 0, NULL,
|
||||
NULL);
|
||||
if (attr) {
|
||||
|
|
@ -3132,7 +3141,7 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
|
|||
info = resident_data_ex(attr, sizeof(struct EA_INFO));
|
||||
/* If ATTR_EA_INFO exists 'info' can't be NULL. */
|
||||
if (info)
|
||||
dup->ea_size = info->size_pack;
|
||||
dup->extend_data = info->size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3199,6 +3208,10 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
|
|||
if (is_bad_inode(inode) || sb_rdonly(sb))
|
||||
return 0;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
|
|||
|
|
@ -905,9 +905,13 @@ void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
|
|||
void ntfs_bad_inode(struct inode *inode, const char *hint)
|
||||
{
|
||||
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
ntfs_inode_err(inode, "%s", hint);
|
||||
make_bad_inode(inode);
|
||||
|
||||
/* Do not call make_bad_inode()! */
|
||||
ni->ni_bad = true;
|
||||
|
||||
/* Avoid recursion if bad inode is $Volume. */
|
||||
if (inode->i_ino != MFT_REC_VOL &&
|
||||
!(sbi->flags & NTFS_FLAGS_LOG_REPLAYING)) {
|
||||
|
|
|
|||
|
|
@ -878,6 +878,10 @@ static int ntfs_resident_writepage(struct folio *folio,
|
|||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
int ret;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -896,6 +900,10 @@ static int ntfs_writepages(struct address_space *mapping,
|
|||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ntfs_i(inode))))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -919,6 +927,10 @@ int ntfs_write_begin(struct file *file, struct address_space *mapping,
|
|||
struct inode *inode = mapping->host;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -1062,10 +1074,10 @@ int inode_read_data(struct inode *inode, void *data, size_t bytes)
|
|||
* Number of bytes for REPARSE_DATA_BUFFER(IO_REPARSE_TAG_SYMLINK)
|
||||
* for unicode string of @uni_len length.
|
||||
*/
|
||||
static inline u32 ntfs_reparse_bytes(u32 uni_len)
|
||||
static inline u32 ntfs_reparse_bytes(u32 uni_len, bool is_absolute)
|
||||
{
|
||||
/* Header + unicode string + decorated unicode string. */
|
||||
return sizeof(short) * (2 * uni_len + 4) +
|
||||
return sizeof(short) * (2 * uni_len + (is_absolute ? 4 : 0)) +
|
||||
offsetof(struct REPARSE_DATA_BUFFER,
|
||||
SymbolicLinkReparseBuffer.PathBuffer);
|
||||
}
|
||||
|
|
@ -1078,8 +1090,11 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
|
|||
struct REPARSE_DATA_BUFFER *rp;
|
||||
__le16 *rp_name;
|
||||
typeof(rp->SymbolicLinkReparseBuffer) *rs;
|
||||
bool is_absolute;
|
||||
|
||||
rp = kzalloc(ntfs_reparse_bytes(2 * size + 2), GFP_NOFS);
|
||||
is_absolute = (strlen(symname) > 1 && symname[1] == ':');
|
||||
|
||||
rp = kzalloc(ntfs_reparse_bytes(2 * size + 2, is_absolute), GFP_NOFS);
|
||||
if (!rp)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
|
@ -1094,7 +1109,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
|
|||
goto out;
|
||||
|
||||
/* err = the length of unicode name of symlink. */
|
||||
*nsize = ntfs_reparse_bytes(err);
|
||||
*nsize = ntfs_reparse_bytes(err, is_absolute);
|
||||
|
||||
if (*nsize > sbi->reparse.max_size) {
|
||||
err = -EFBIG;
|
||||
|
|
@ -1114,7 +1129,7 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
|
|||
|
||||
/* PrintName + SubstituteName. */
|
||||
rs->SubstituteNameOffset = cpu_to_le16(sizeof(short) * err);
|
||||
rs->SubstituteNameLength = cpu_to_le16(sizeof(short) * err + 8);
|
||||
rs->SubstituteNameLength = cpu_to_le16(sizeof(short) * err + (is_absolute ? 8 : 0));
|
||||
rs->PrintNameLength = rs->SubstituteNameOffset;
|
||||
|
||||
/*
|
||||
|
|
@ -1122,16 +1137,18 @@ ntfs_create_reparse_buffer(struct ntfs_sb_info *sbi, const char *symname,
|
|||
* parse this path.
|
||||
* 0-absolute path 1- relative path (SYMLINK_FLAG_RELATIVE).
|
||||
*/
|
||||
rs->Flags = 0;
|
||||
rs->Flags = cpu_to_le32(is_absolute ? 0 : SYMLINK_FLAG_RELATIVE);
|
||||
|
||||
memmove(rp_name + err + 4, rp_name, sizeof(short) * err);
|
||||
memmove(rp_name + err + (is_absolute ? 4 : 0), rp_name, sizeof(short) * err);
|
||||
|
||||
/* Decorate SubstituteName. */
|
||||
rp_name += err;
|
||||
rp_name[0] = cpu_to_le16('\\');
|
||||
rp_name[1] = cpu_to_le16('?');
|
||||
rp_name[2] = cpu_to_le16('?');
|
||||
rp_name[3] = cpu_to_le16('\\');
|
||||
if (is_absolute) {
|
||||
/* Decorate SubstituteName. */
|
||||
rp_name += err;
|
||||
rp_name[0] = cpu_to_le16('\\');
|
||||
rp_name[1] = cpu_to_le16('?');
|
||||
rp_name[2] = cpu_to_le16('?');
|
||||
rp_name[3] = cpu_to_le16('\\');
|
||||
}
|
||||
|
||||
return rp;
|
||||
out:
|
||||
|
|
@ -1260,6 +1277,12 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
|
|||
goto out1;
|
||||
}
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(dir_ni))) {
|
||||
err = -EINVAL;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb))) {
|
||||
err = -EIO;
|
||||
goto out2;
|
||||
|
|
@ -1350,7 +1373,7 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
|
|||
fname->dup.a_time = std5->cr_time;
|
||||
fname->dup.alloc_size = fname->dup.data_size = 0;
|
||||
fname->dup.fa = std5->fa;
|
||||
fname->dup.ea_size = fname->dup.reparse = 0;
|
||||
fname->dup.extend_data = S_ISLNK(mode) ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
|
||||
dsize = le16_to_cpu(new_de->key_size);
|
||||
asize = ALIGN(SIZEOF_RESIDENT + dsize, 8);
|
||||
|
|
@ -1590,27 +1613,29 @@ int ntfs_create_inode(struct mnt_idmap *idmap, struct inode *dir,
|
|||
inode->i_flags |= S_NOSEC;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
err = ntfs_save_wsl_perm(inode, &fname->dup.ea_size);
|
||||
if (err)
|
||||
goto out6;
|
||||
if (!S_ISLNK(mode)) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
err = ntfs_save_wsl_perm(inode, &fname->dup.extend_data);
|
||||
if (err)
|
||||
goto out6;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/*
|
||||
* 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;
|
||||
fn = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
|
||||
if (fn)
|
||||
fn->dup.extend_data = fname->dup.extend_data;
|
||||
}
|
||||
}
|
||||
|
||||
/* We do not need to update parent directory later */
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ static int ntfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
int err;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -191,6 +195,10 @@ static int ntfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
|||
{
|
||||
u32 size = strlen(symname);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ntfs_i(dir))))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -216,6 +224,10 @@ static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
int err;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(dir->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -244,7 +256,7 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
|
|||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
struct inode *new_inode = d_inode(new_dentry);
|
||||
struct NTFS_DE *de, *new_de;
|
||||
bool is_same, is_bad;
|
||||
bool is_same;
|
||||
/*
|
||||
* de - memory of PATH_MAX bytes:
|
||||
* [0-1024) - original name (dentry->d_name)
|
||||
|
|
@ -256,6 +268,10 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
|
|||
1024);
|
||||
static_assert(PATH_MAX >= 4 * 1024);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -313,12 +329,8 @@ static int ntfs_rename(struct mnt_idmap *idmap, struct inode *dir,
|
|||
if (dir_ni != new_dir_ni)
|
||||
ni_lock_dir2(new_dir_ni);
|
||||
|
||||
is_bad = false;
|
||||
err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
|
||||
if (is_bad) {
|
||||
/* Restore after failed rename failed too. */
|
||||
_ntfs_bad_inode(inode);
|
||||
} else if (!err) {
|
||||
err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de);
|
||||
if (!err) {
|
||||
simple_rename_timestamp(dir, dentry, new_dir, new_dentry);
|
||||
mark_inode_dirty(inode);
|
||||
mark_inode_dirty(dir);
|
||||
|
|
|
|||
|
|
@ -561,8 +561,7 @@ struct NTFS_DUP_INFO {
|
|||
__le64 alloc_size; // 0x20: Data attribute allocated size, multiple of cluster size.
|
||||
__le64 data_size; // 0x28: Data attribute size <= Dataalloc_size.
|
||||
enum FILE_ATTRIBUTE fa; // 0x30: Standard DOS attributes & more.
|
||||
__le16 ea_size; // 0x34: Packed EAs.
|
||||
__le16 reparse; // 0x36: Used by Reparse.
|
||||
__le32 extend_data; // 0x34: Extended data.
|
||||
|
||||
}; // 0x38
|
||||
|
||||
|
|
|
|||
|
|
@ -377,6 +377,13 @@ struct ntfs_inode {
|
|||
*/
|
||||
u8 mi_loaded;
|
||||
|
||||
/*
|
||||
* Use this field to avoid any write(s).
|
||||
* If inode is bad during initialization - use make_bad_inode
|
||||
* If inode is bad during operations - use this field
|
||||
*/
|
||||
u8 ni_bad;
|
||||
|
||||
union {
|
||||
struct ntfs_index dir;
|
||||
struct {
|
||||
|
|
@ -577,8 +584,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
|
|||
struct NTFS_DE *de);
|
||||
|
||||
int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
|
||||
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de,
|
||||
bool *is_bad);
|
||||
struct ntfs_inode *ni, struct NTFS_DE *de, struct NTFS_DE *new_de);
|
||||
|
||||
bool ni_is_dirty(struct inode *inode);
|
||||
|
||||
|
|
@ -874,7 +880,7 @@ int ntfs_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry);
|
|||
ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
extern const struct xattr_handler *const ntfs_xattr_handlers[];
|
||||
|
||||
int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size);
|
||||
int ntfs_save_wsl_perm(struct inode *inode, __le32 *ea_size);
|
||||
void ntfs_get_wsl_perm(struct inode *inode);
|
||||
|
||||
/* globals from lznt.c */
|
||||
|
|
@ -1025,6 +1031,11 @@ static inline bool is_compressed(const struct ntfs_inode *ni)
|
|||
(ni->ni_flags & NI_FLAG_COMPRESSED_MASK);
|
||||
}
|
||||
|
||||
static inline bool is_bad_ni(const struct ntfs_inode *ni)
|
||||
{
|
||||
return ni->ni_bad;
|
||||
}
|
||||
|
||||
static inline int ni_ext_compress_bits(const struct ntfs_inode *ni)
|
||||
{
|
||||
return 0xb + (ni->ni_flags & NI_FLAG_COMPRESSED_MASK);
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ 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,
|
||||
size_t name_len, const void *value,
|
||||
size_t val_size, int flags, bool locked,
|
||||
__le16 *ea_size)
|
||||
__le32 *ea_size)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
|
|
@ -522,7 +522,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
|||
if (ea_info.size_pack != size_pack)
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
if (ea_size)
|
||||
*ea_size = ea_info.size_pack;
|
||||
*ea_size = ea_info.size;
|
||||
mark_inode_dirty(&ni->vfs_inode);
|
||||
|
||||
out:
|
||||
|
|
@ -552,6 +552,10 @@ struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
int err;
|
||||
void *buf;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Allocate PATH_MAX bytes. */
|
||||
buf = __getname();
|
||||
if (!buf)
|
||||
|
|
@ -600,6 +604,10 @@ static noinline int ntfs_set_acl_ex(struct mnt_idmap *idmap,
|
|||
int flags;
|
||||
umode_t mode;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ntfs_i(inode))))
|
||||
return -EINVAL;
|
||||
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
@ -730,6 +738,10 @@ ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
ssize_t ret;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(ni->ni_flags & NI_FLAG_EA)) {
|
||||
/* no xattr in file */
|
||||
return 0;
|
||||
|
|
@ -751,6 +763,10 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
|
|||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ni)))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -950,7 +966,7 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
|
|||
*
|
||||
* save uid/gid/mode in xattr
|
||||
*/
|
||||
int ntfs_save_wsl_perm(struct inode *inode, __le16 *ea_size)
|
||||
int ntfs_save_wsl_perm(struct inode *inode, __le32 *ea_size)
|
||||
{
|
||||
int err;
|
||||
__le32 value;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user