forked from Minki/linux
Fixed xfstests generic/016 generic/021 generic/022 generic/041 generic/274 generic/423,
some memory leaks and panic. Also many minor fixes. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmFoMFQACgkQqbAzH4Mk B7bTtQ/+KiF48deefbEEExjfT8Mm76+JE0XkdCPT0bXkhVNpqhRLSOQBR2hg5A81 7SSFHNbSMzXxiXdh2KfcXbBmwdJtcH1N9tjwffC3zhMkCTcDKnmDczz/lo4rHd0g zZ3rPBP9yPCZGxo3W804XRYOeqLclrGJPI3kWQen+Rln/cZIzJMaHRUkVI22OYwj e0dSdtabFDxJbdewz9xcvycHrPpVlrZUsuib/ZHFu2XGtgKalccgfvwBy5cOrTVh N1WSBGcoy0xQGRGLP0o2hN62N2Md7/+UwWjXY+Wz4i+4gmziGvGuk8Y5uiSLu7lS EG12xlrUtwouf4QaeleQZLT9Ym5YU3EALtKpZxAQi6Rm4A8Z6EMNUq0WBHJcNP/u MRJlfK7jC25GnIFQjZtU+eMX8BT8MgMeSriv9FIY86T3ijedfxxEbb/cMvUGm2Hn 3hoQelLCUkLSqTyMeZiAv507AJv5MjfMrSJ9r9f36OxDer3w84VCVcxDtyGH++CR fbRNjHvz7gYG5L5qwsFgfxSC/z+hyUXi01RalbosojsRyvg/f1p+yMxvQ57DrltY IfHrMGcd9FlUiijBGFvyWQoMAl/pb6EIym2IMxr9X+aXgPJiG/BhWLbmzU4MYUUP 1PwIOpN2vhtU2Z3bVzbecxfy/TWjBhKBYe9jW1AH8KSSvLZExjk= =QUnM -----END PGP SIGNATURE----- Merge tag 'ntfs3_for_5.15' of git://github.com/Paragon-Software-Group/linux-ntfs3 Pull ntfs3 fixes from Konstantin Komarov: "Use the new api for mounting as requested by Christoph. Also fixed: - some memory leaks and panic - xfstests (tested on x86_64) generic/016 generic/021 generic/022 generic/041 generic/274 generic/423 - some typos, wrong returned error codes, dead code, etc" * tag 'ntfs3_for_5.15' of git://github.com/Paragon-Software-Group/linux-ntfs3: (70 commits) fs/ntfs3: Check for NULL pointers in ni_try_remove_attr_list fs/ntfs3: Refactor ntfs_read_mft fs/ntfs3: Refactor ni_parse_reparse fs/ntfs3: Refactor ntfs_create_inode fs/ntfs3: Refactor ntfs_readlink_hlp fs/ntfs3: Rework ntfs_utf16_to_nls fs/ntfs3: Fix memory leak if fill_super failed fs/ntfs3: Keep prealloc for all types of files fs/ntfs3: Remove unnecessary functions fs/ntfs3: Forbid FALLOC_FL_PUNCH_HOLE for normal files fs/ntfs3: Refactoring of ntfs_set_ea fs/ntfs3: Remove locked argument in ntfs_set_ea fs/ntfs3: Use available posix_acl_release instead of ntfs_posix_acl_release fs/ntfs3: Check for NULL if ATTR_EA_INFO is incorrect fs/ntfs3: Refactoring of ntfs_init_from_boot fs/ntfs3: Reject mount if boot's cluster size < media sector size fs/ntfs3: Refactoring lock in ntfs_init_acl fs/ntfs3: Change posix_acl_equiv_mode to posix_acl_update_mode fs/ntfs3: Pass flags to ntfs_set_ea in ntfs_set_acl_ex fs/ntfs3: Refactor ntfs_get_acl_ex for better readability ...
This commit is contained in:
commit
86a44e9067
@ -4,103 +4,112 @@
|
||||
NTFS3
|
||||
=====
|
||||
|
||||
|
||||
Summary and Features
|
||||
====================
|
||||
|
||||
NTFS3 is fully functional NTFS Read-Write driver. The driver works with
|
||||
NTFS versions up to 3.1, normal/compressed/sparse files
|
||||
and journal replaying. File system type to use on mount is 'ntfs3'.
|
||||
NTFS3 is fully functional NTFS Read-Write driver. The driver works with NTFS
|
||||
versions up to 3.1. File system type to use on mount is *ntfs3*.
|
||||
|
||||
- This driver implements NTFS read/write support for normal, sparse and
|
||||
compressed files.
|
||||
- Supports native journal replaying;
|
||||
- Supports extended attributes
|
||||
Predefined extended attributes:
|
||||
- 'system.ntfs_security' gets/sets security
|
||||
descriptor (SECURITY_DESCRIPTOR_RELATIVE)
|
||||
- 'system.ntfs_attrib' gets/sets ntfs file/dir attributes.
|
||||
Note: applied to empty files, this allows to switch type between
|
||||
sparse(0x200), compressed(0x800) and normal;
|
||||
- Supports native journal replaying.
|
||||
- Supports NFS export of mounted NTFS volumes.
|
||||
- Supports extended attributes. Predefined extended attributes:
|
||||
|
||||
- *system.ntfs_security* gets/sets security
|
||||
|
||||
Descriptor: SECURITY_DESCRIPTOR_RELATIVE
|
||||
|
||||
- *system.ntfs_attrib* gets/sets ntfs file/dir attributes.
|
||||
|
||||
Note: Applied to empty files, this allows to switch type between
|
||||
sparse(0x200), compressed(0x800) and normal.
|
||||
|
||||
Mount Options
|
||||
=============
|
||||
|
||||
The list below describes mount options supported by NTFS3 driver in addition to
|
||||
generic ones.
|
||||
generic ones. You can use every mount option with **no** option. If it is in
|
||||
this table marked with no it means default is without **no**.
|
||||
|
||||
===============================================================================
|
||||
.. flat-table::
|
||||
:widths: 1 5
|
||||
:fill-cells:
|
||||
|
||||
nls=name This option informs the driver how to interpret path
|
||||
strings and translate them to Unicode and back. If
|
||||
this option is not set, the default codepage will be
|
||||
used (CONFIG_NLS_DEFAULT).
|
||||
Examples:
|
||||
'nls=utf8'
|
||||
* - iocharset=name
|
||||
- This option informs the driver how to interpret path strings and
|
||||
translate them to Unicode and back. If this option is not set, the
|
||||
default codepage will be used (CONFIG_NLS_DEFAULT).
|
||||
|
||||
uid=
|
||||
gid=
|
||||
umask= Controls the default permissions for files/directories created
|
||||
after the NTFS volume is mounted.
|
||||
Example: iocharset=utf8
|
||||
|
||||
fmask=
|
||||
dmask= Instead of specifying umask which applies both to
|
||||
files and directories, fmask applies only to files and
|
||||
dmask only to directories.
|
||||
* - uid=
|
||||
- :rspan:`1`
|
||||
* - gid=
|
||||
|
||||
nohidden Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN)
|
||||
attribute will not be shown under Linux.
|
||||
* - umask=
|
||||
- Controls the default permissions for files/directories created after
|
||||
the NTFS volume is mounted.
|
||||
|
||||
sys_immutable Files with the Windows-specific SYSTEM
|
||||
(FILE_ATTRIBUTE_SYSTEM) attribute will be marked as system
|
||||
immutable files.
|
||||
* - dmask=
|
||||
- :rspan:`1` Instead of specifying umask which applies both to files and
|
||||
directories, fmask applies only to files and dmask only to directories.
|
||||
* - fmask=
|
||||
|
||||
discard Enable support of the TRIM command for improved performance
|
||||
on delete operations, which is recommended for use with the
|
||||
solid-state drives (SSD).
|
||||
* - 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.
|
||||
|
||||
force Forces the driver to mount partitions even if 'dirty' flag
|
||||
(volume dirty) is set. Not recommended for use.
|
||||
- Permissions change for files/folders will be reported as successful,
|
||||
but they will remain 777.
|
||||
|
||||
sparse Create new files as "sparse".
|
||||
- Owner/group change will be reported as successful, butthey will stay
|
||||
as root.
|
||||
|
||||
showmeta Use this parameter to show all meta-files (System Files) on
|
||||
a mounted NTFS partition.
|
||||
By default, all meta-files are hidden.
|
||||
* - nohidden
|
||||
- Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute
|
||||
will not be shown under Linux.
|
||||
|
||||
prealloc Preallocate space for files excessively when file size is
|
||||
increasing on writes. Decreases fragmentation in case of
|
||||
parallel write operations to different files.
|
||||
* - sys_immutable
|
||||
- Files with the Windows-specific SYSTEM (FILE_ATTRIBUTE_SYSTEM) attribute
|
||||
will be marked as system immutable files.
|
||||
|
||||
no_acs_rules "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, but
|
||||
they will stay as root
|
||||
* - discard
|
||||
- Enable support of the TRIM command for improved performance on delete
|
||||
operations, which is recommended for use with the solid-state drives
|
||||
(SSD).
|
||||
|
||||
acl Support POSIX ACLs (Access Control Lists). Effective if
|
||||
supported by Kernel. Not to be confused with NTFS ACLs.
|
||||
The option specified as acl enables support for POSIX ACLs.
|
||||
* - force
|
||||
- Forces the driver to mount partitions even if volume is marked dirty.
|
||||
Not recommended for use.
|
||||
|
||||
noatime All files and directories will not update their last access
|
||||
time attribute if a partition is mounted with this parameter.
|
||||
This option can speed up file system operation.
|
||||
* - sparse
|
||||
- Create new files as sparse.
|
||||
|
||||
===============================================================================
|
||||
* - showmeta
|
||||
- Use this parameter to show all meta-files (System Files) on a mounted
|
||||
NTFS partition. By default, all meta-files are hidden.
|
||||
|
||||
ToDo list
|
||||
* - prealloc
|
||||
- Preallocate space for files excessively when file size is increasing on
|
||||
writes. Decreases fragmentation in case of parallel write operations to
|
||||
different files.
|
||||
|
||||
* - acl
|
||||
- Support POSIX ACLs (Access Control Lists). Effective if supported by
|
||||
Kernel. Not to be confused with NTFS ACLs. The option specified as acl
|
||||
enables support for POSIX ACLs.
|
||||
|
||||
Todo list
|
||||
=========
|
||||
|
||||
- Full journaling support (currently journal replaying is supported) over JBD.
|
||||
|
||||
- Full journaling support over JBD. Currently journal replaying is supported
|
||||
which is not necessarily as effectice as JBD would be.
|
||||
|
||||
References
|
||||
==========
|
||||
https://www.paragon-software.com/home/ntfs-linux-professional/
|
||||
- Commercial version of the NTFS driver for Linux.
|
||||
- Commercial version of the NTFS driver for Linux.
|
||||
https://www.paragon-software.com/home/ntfs-linux-professional/
|
||||
|
||||
almaz.alexandrovich@paragon-software.com
|
||||
- Direct e-mail address for feedback and requests on the NTFS3 implementation.
|
||||
- Direct e-mail address for feedback and requests on the NTFS3 implementation.
|
||||
almaz.alexandrovich@paragon-software.com
|
||||
|
@ -6,13 +6,9 @@
|
||||
* TODO: Merge attr_set_size/attr_data_get_block/attr_allocate_frame?
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
@ -291,7 +287,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
if (!rsize) {
|
||||
/* Empty resident -> Non empty nonresident. */
|
||||
} else if (!is_data) {
|
||||
err = ntfs_sb_write_run(sbi, run, 0, data, rsize);
|
||||
err = ntfs_sb_write_run(sbi, run, 0, data, rsize, 0);
|
||||
if (err)
|
||||
goto out2;
|
||||
} else if (!page) {
|
||||
@ -451,11 +447,8 @@ again:
|
||||
again_1:
|
||||
align = sbi->cluster_size;
|
||||
|
||||
if (is_ext) {
|
||||
if (is_ext)
|
||||
align <<= attr_b->nres.c_unit;
|
||||
if (is_attr_sparsed(attr_b))
|
||||
keep_prealloc = false;
|
||||
}
|
||||
|
||||
old_valid = le64_to_cpu(attr_b->nres.valid_size);
|
||||
old_size = le64_to_cpu(attr_b->nres.data_size);
|
||||
@ -465,9 +458,6 @@ again_1:
|
||||
new_alloc = (new_size + align - 1) & ~(u64)(align - 1);
|
||||
new_alen = new_alloc >> cluster_bits;
|
||||
|
||||
if (keep_prealloc && is_ext)
|
||||
keep_prealloc = false;
|
||||
|
||||
if (keep_prealloc && new_size < old_size) {
|
||||
attr_b->nres.data_size = cpu_to_le64(new_size);
|
||||
mi_b->dirty = true;
|
||||
@ -529,7 +519,7 @@ add_alloc_in_same_attr_seg:
|
||||
} else if (pre_alloc == -1) {
|
||||
pre_alloc = 0;
|
||||
if (type == ATTR_DATA && !name_len &&
|
||||
sbi->options.prealloc) {
|
||||
sbi->options->prealloc) {
|
||||
CLST new_alen2 = bytes_to_cluster(
|
||||
sbi, get_pre_allocated(new_size));
|
||||
pre_alloc = new_alen2 - new_alen;
|
||||
@ -1966,7 +1956,7 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
|
||||
return 0;
|
||||
|
||||
from = vbo;
|
||||
to = (vbo + bytes) < data_size ? (vbo + bytes) : data_size;
|
||||
to = min_t(u64, vbo + bytes, data_size);
|
||||
memset(Add2Ptr(resident_data(attr_b), from), 0, to - from);
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,10 +5,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
@ -336,7 +333,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
|
||||
|
||||
if (attr && attr->non_res) {
|
||||
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
|
||||
al->size);
|
||||
al->size, 0);
|
||||
if (err)
|
||||
return err;
|
||||
al->dirty = false;
|
||||
@ -423,7 +420,7 @@ next:
|
||||
return true;
|
||||
}
|
||||
|
||||
int al_update(struct ntfs_inode *ni)
|
||||
int al_update(struct ntfs_inode *ni, int sync)
|
||||
{
|
||||
int err;
|
||||
struct ATTRIB *attr;
|
||||
@ -445,7 +442,7 @@ int al_update(struct ntfs_inode *ni)
|
||||
memcpy(resident_data(attr), al->le, al->size);
|
||||
} else {
|
||||
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
|
||||
al->size);
|
||||
al->size, sync);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -5,13 +5,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
#include "ntfs_fs.h"
|
||||
|
||||
#define BITS_IN_SIZE_T (sizeof(size_t) * 8)
|
||||
@ -124,8 +119,7 @@ bool are_bits_set(const ulong *lmap, size_t bit, size_t nbits)
|
||||
|
||||
pos = nbits & 7;
|
||||
if (pos) {
|
||||
u8 mask = fill_mask[pos];
|
||||
|
||||
mask = fill_mask[pos];
|
||||
if ((*map & mask) != mask)
|
||||
return false;
|
||||
}
|
||||
|
@ -10,12 +10,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
#include "ntfs_fs.h"
|
||||
|
||||
@ -435,7 +433,7 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len)
|
||||
;
|
||||
} else {
|
||||
n3 = rb_next(&e->count.node);
|
||||
max_new_len = len > new_len ? len : new_len;
|
||||
max_new_len = max(len, new_len);
|
||||
if (!n3) {
|
||||
wnd->extent_max = max_new_len;
|
||||
} else {
|
||||
@ -731,7 +729,7 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = tail < bits ? tail : bits;
|
||||
op = min_t(u32, tail, bits);
|
||||
|
||||
bh = wnd_map(wnd, iw);
|
||||
if (IS_ERR(bh)) {
|
||||
@ -784,7 +782,7 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = tail < bits ? tail : bits;
|
||||
op = min_t(u32, tail, bits);
|
||||
|
||||
bh = wnd_map(wnd, iw);
|
||||
if (IS_ERR(bh)) {
|
||||
@ -834,7 +832,7 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = tail < bits ? tail : bits;
|
||||
op = min_t(u32, tail, bits);
|
||||
|
||||
if (wbits != wnd->free_bits[iw]) {
|
||||
bool ret;
|
||||
@ -926,7 +924,7 @@ use_wnd:
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = tail < bits ? tail : bits;
|
||||
op = min_t(u32, tail, bits);
|
||||
|
||||
if (wnd->free_bits[iw]) {
|
||||
bool ret;
|
||||
|
@ -11,6 +11,9 @@
|
||||
#ifndef _LINUX_NTFS3_DEBUG_H
|
||||
#define _LINUX_NTFS3_DEBUG_H
|
||||
|
||||
struct super_block;
|
||||
struct inode;
|
||||
|
||||
#ifndef Add2Ptr
|
||||
#define Add2Ptr(P, I) ((void *)((u8 *)(P) + (I)))
|
||||
#define PtrOffset(B, O) ((size_t)((size_t)(O) - (size_t)(B)))
|
||||
|
@ -7,10 +7,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "debug.h"
|
||||
@ -18,30 +15,27 @@
|
||||
#include "ntfs_fs.h"
|
||||
|
||||
/* Convert little endian UTF-16 to NLS string. */
|
||||
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
|
||||
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len,
|
||||
u8 *buf, int buf_len)
|
||||
{
|
||||
int ret, uni_len, warn;
|
||||
const __le16 *ip;
|
||||
int ret, warn;
|
||||
u8 *op;
|
||||
struct nls_table *nls = sbi->options.nls;
|
||||
struct nls_table *nls = sbi->options->nls;
|
||||
|
||||
static_assert(sizeof(wchar_t) == sizeof(__le16));
|
||||
|
||||
if (!nls) {
|
||||
/* UTF-16 -> UTF-8 */
|
||||
ret = utf16s_to_utf8s((wchar_t *)uni->name, uni->len,
|
||||
UTF16_LITTLE_ENDIAN, buf, buf_len);
|
||||
ret = utf16s_to_utf8s(name, len, UTF16_LITTLE_ENDIAN, buf,
|
||||
buf_len);
|
||||
buf[ret] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
ip = uni->name;
|
||||
op = buf;
|
||||
uni_len = uni->len;
|
||||
warn = 0;
|
||||
|
||||
while (uni_len--) {
|
||||
while (len--) {
|
||||
u16 ec;
|
||||
int charlen;
|
||||
char dump[5];
|
||||
@ -52,7 +46,7 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
|
||||
break;
|
||||
}
|
||||
|
||||
ec = le16_to_cpu(*ip++);
|
||||
ec = le16_to_cpu(*name++);
|
||||
charlen = nls->uni2char(ec, op, buf_len);
|
||||
|
||||
if (charlen > 0) {
|
||||
@ -186,7 +180,7 @@ int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
|
||||
{
|
||||
int ret, slen;
|
||||
const u8 *end;
|
||||
struct nls_table *nls = sbi->options.nls;
|
||||
struct nls_table *nls = sbi->options->nls;
|
||||
u16 *uname = uni->name;
|
||||
|
||||
static_assert(sizeof(wchar_t) == sizeof(u16));
|
||||
@ -301,14 +295,14 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
|
||||
return 0;
|
||||
|
||||
/* Skip meta files. Unless option to show metafiles is set. */
|
||||
if (!sbi->options.showmeta && ntfs_is_meta_file(sbi, ino))
|
||||
if (!sbi->options->showmeta && ntfs_is_meta_file(sbi, ino))
|
||||
return 0;
|
||||
|
||||
if (sbi->options.nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
|
||||
if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
|
||||
return 0;
|
||||
|
||||
name_len = ntfs_utf16_to_nls(sbi, (struct le_str *)&fname->name_len,
|
||||
name, PATH_MAX);
|
||||
name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
|
||||
PATH_MAX);
|
||||
if (name_len <= 0) {
|
||||
ntfs_warn(sbi->sb, "failed to convert name for inode %lx.",
|
||||
ino);
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <linux/compat.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
@ -588,8 +587,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
||||
truncate_pagecache(inode, vbo_down);
|
||||
|
||||
if (!is_sparsed(ni) && !is_compressed(ni)) {
|
||||
/* Normal file. */
|
||||
err = ntfs_zero_range(inode, vbo, end);
|
||||
/*
|
||||
* Normal file, can't make hole.
|
||||
* TODO: Try to find way to save info about hole.
|
||||
*/
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -737,7 +739,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
umode_t mode = inode->i_mode;
|
||||
int err;
|
||||
|
||||
if (sbi->options.no_acs_rules) {
|
||||
if (sbi->options->noacsrules) {
|
||||
/* "No access rules" - Force any changes of time etc. */
|
||||
attr->ia_valid |= ATTR_FORCE;
|
||||
/* and disable for editing some attributes. */
|
||||
@ -1185,7 +1187,7 @@ 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) &&
|
||||
if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) &&
|
||||
atomic_read(&inode->i_writecount) == 1)) {
|
||||
ni_lock(ni);
|
||||
down_write(&ni->file.run_lock);
|
||||
|
@ -5,11 +5,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "debug.h"
|
||||
@ -708,18 +705,35 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
|
||||
continue;
|
||||
|
||||
mi = ni_find_mi(ni, ino_get(&le->ref));
|
||||
if (!mi) {
|
||||
/* Should never happened, 'cause already checked. */
|
||||
goto bad;
|
||||
}
|
||||
|
||||
attr = mi_find_attr(mi, NULL, le->type, le_name(le),
|
||||
le->name_len, &le->id);
|
||||
if (!attr) {
|
||||
/* Should never happened, 'cause already checked. */
|
||||
goto bad;
|
||||
}
|
||||
asize = le32_to_cpu(attr->size);
|
||||
|
||||
/* Insert into primary record. */
|
||||
attr_ins = mi_insert_attr(&ni->mi, le->type, le_name(le),
|
||||
le->name_len, asize,
|
||||
le16_to_cpu(attr->name_off));
|
||||
id = attr_ins->id;
|
||||
if (!attr_ins) {
|
||||
/*
|
||||
* Internal error.
|
||||
* Either no space in primary record (already checked).
|
||||
* Either tried to insert another
|
||||
* non indexed attribute (logic error).
|
||||
*/
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Copy all except id. */
|
||||
id = attr_ins->id;
|
||||
memcpy(attr_ins, attr, asize);
|
||||
attr_ins->id = id;
|
||||
|
||||
@ -735,6 +749,10 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
|
||||
ni->attr_list.dirty = false;
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
ntfs_inode_err(&ni->vfs_inode, "Internal error");
|
||||
make_bad_inode(&ni->vfs_inode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -956,6 +974,13 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not try to insert this attribute
|
||||
* if there is no room in record.
|
||||
*/
|
||||
if (le32_to_cpu(mi->mrec->used) + asize > sbi->record_size)
|
||||
continue;
|
||||
|
||||
/* Try to insert attribute into this subrecord. */
|
||||
attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
|
||||
name_off, svcn, ins_le);
|
||||
@ -1451,7 +1476,7 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
|
||||
attr->res.flags = RESIDENT_FLAG_INDEXED;
|
||||
|
||||
/* is_attr_indexed(attr)) == true */
|
||||
le16_add_cpu(&ni->mi.mrec->hard_links, +1);
|
||||
le16_add_cpu(&ni->mi.mrec->hard_links, 1);
|
||||
ni->mi.dirty = true;
|
||||
}
|
||||
attr->res.res = 0;
|
||||
@ -1606,7 +1631,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
|
||||
|
||||
*le = NULL;
|
||||
|
||||
if (FILE_NAME_POSIX == name_type)
|
||||
if (name_type == FILE_NAME_POSIX)
|
||||
return NULL;
|
||||
|
||||
/* Enumerate all names. */
|
||||
@ -1706,18 +1731,16 @@ out:
|
||||
/*
|
||||
* ni_parse_reparse
|
||||
*
|
||||
* Buffer is at least 24 bytes.
|
||||
* buffer - memory for reparse buffer header
|
||||
*/
|
||||
enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
void *buffer)
|
||||
struct REPARSE_DATA_BUFFER *buffer)
|
||||
{
|
||||
const struct REPARSE_DATA_BUFFER *rp = NULL;
|
||||
u8 bits;
|
||||
u16 len;
|
||||
typeof(rp->CompressReparseBuffer) *cmpr;
|
||||
|
||||
static_assert(sizeof(struct REPARSE_DATA_BUFFER) <= 24);
|
||||
|
||||
/* Try to estimate reparse point. */
|
||||
if (!attr->non_res) {
|
||||
rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER));
|
||||
@ -1803,6 +1826,9 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
return REPARSE_NONE;
|
||||
}
|
||||
|
||||
if (buffer != rp)
|
||||
memcpy(buffer, rp, sizeof(struct REPARSE_DATA_BUFFER));
|
||||
|
||||
/* Looks like normal symlink. */
|
||||
return REPARSE_LINK;
|
||||
}
|
||||
@ -2906,9 +2932,8 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
|
||||
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
|
||||
mi_get_ref(&ni->mi, &de->ref);
|
||||
|
||||
if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1)) {
|
||||
if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -3077,7 +3102,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
|
||||
const struct EA_INFO *info;
|
||||
|
||||
info = resident_data_ex(attr, sizeof(struct EA_INFO));
|
||||
dup->ea_size = info->size_pack;
|
||||
/* If ATTR_EA_INFO exists 'info' can't be NULL. */
|
||||
if (info)
|
||||
dup->ea_size = info->size_pack;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3205,7 +3232,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = al_update(ni);
|
||||
err = al_update(ni, sync);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -6,12 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "debug.h"
|
||||
@ -2219,7 +2215,7 @@ file_is_valid:
|
||||
|
||||
err = ntfs_sb_write_run(log->ni->mi.sbi,
|
||||
&log->ni->file.run, off, page,
|
||||
log->page_size);
|
||||
log->page_size, 0);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
@ -3710,7 +3706,7 @@ move_data:
|
||||
|
||||
if (a_dirty) {
|
||||
attr = oa->attr;
|
||||
err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes);
|
||||
err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
@ -5152,10 +5148,10 @@ end_reply:
|
||||
|
||||
ntfs_fix_pre_write(&rh->rhdr, log->page_size);
|
||||
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size);
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size, 0);
|
||||
if (!err)
|
||||
err = ntfs_sb_write_run(sbi, &log->ni->file.run, log->page_size,
|
||||
rh, log->page_size);
|
||||
rh, log->page_size, 0);
|
||||
|
||||
kfree(rh);
|
||||
if (err)
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
@ -358,7 +358,7 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
|
||||
enum ALLOCATE_OPT opt)
|
||||
{
|
||||
int err;
|
||||
CLST alen = 0;
|
||||
CLST alen;
|
||||
struct super_block *sb = sbi->sb;
|
||||
size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
|
||||
struct wnd_bitmap *wnd = &sbi->used.bitmap;
|
||||
@ -370,27 +370,28 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
|
||||
if (!zlen) {
|
||||
err = ntfs_refresh_zone(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
goto up_write;
|
||||
|
||||
zlen = wnd_zone_len(wnd);
|
||||
}
|
||||
|
||||
if (!zlen) {
|
||||
ntfs_err(sbi->sb, "no free space to extend mft");
|
||||
goto out;
|
||||
err = -ENOSPC;
|
||||
goto up_write;
|
||||
}
|
||||
|
||||
lcn = wnd_zone_bit(wnd);
|
||||
alen = zlen > len ? len : zlen;
|
||||
alen = min_t(CLST, len, zlen);
|
||||
|
||||
wnd_zone_set(wnd, lcn + alen, zlen - alen);
|
||||
|
||||
err = wnd_set_used(wnd, lcn, alen);
|
||||
if (err) {
|
||||
up_write(&wnd->rw_lock);
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto up_write;
|
||||
|
||||
alcn = lcn;
|
||||
goto out;
|
||||
goto space_found;
|
||||
}
|
||||
/*
|
||||
* 'Cause cluster 0 is always used this value means that we should use
|
||||
@ -404,49 +405,45 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
|
||||
|
||||
alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
|
||||
if (alen)
|
||||
goto out;
|
||||
goto space_found;
|
||||
|
||||
/* Try to use clusters from MftZone. */
|
||||
zlen = wnd_zone_len(wnd);
|
||||
zeroes = wnd_zeroes(wnd);
|
||||
|
||||
/* Check too big request */
|
||||
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE)
|
||||
goto out;
|
||||
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) {
|
||||
err = -ENOSPC;
|
||||
goto up_write;
|
||||
}
|
||||
|
||||
/* How many clusters to cat from zone. */
|
||||
zlcn = wnd_zone_bit(wnd);
|
||||
zlen2 = zlen >> 1;
|
||||
ztrim = len > zlen ? zlen : (len > zlen2 ? len : zlen2);
|
||||
new_zlen = zlen - ztrim;
|
||||
|
||||
if (new_zlen < NTFS_MIN_MFT_ZONE) {
|
||||
new_zlen = NTFS_MIN_MFT_ZONE;
|
||||
if (new_zlen > zlen)
|
||||
new_zlen = zlen;
|
||||
}
|
||||
ztrim = clamp_val(len, zlen2, zlen);
|
||||
new_zlen = max_t(size_t, zlen - ztrim, NTFS_MIN_MFT_ZONE);
|
||||
|
||||
wnd_zone_set(wnd, zlcn, new_zlen);
|
||||
|
||||
/* Allocate continues clusters. */
|
||||
alen = wnd_find(wnd, len, 0,
|
||||
BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
|
||||
|
||||
out:
|
||||
if (alen) {
|
||||
err = 0;
|
||||
*new_len = alen;
|
||||
*new_lcn = alcn;
|
||||
|
||||
ntfs_unmap_meta(sb, alcn, alen);
|
||||
|
||||
/* Set hint for next requests. */
|
||||
if (!(opt & ALLOCATE_MFT))
|
||||
sbi->used.next_free_lcn = alcn + alen;
|
||||
} else {
|
||||
if (!alen) {
|
||||
err = -ENOSPC;
|
||||
goto up_write;
|
||||
}
|
||||
|
||||
space_found:
|
||||
err = 0;
|
||||
*new_len = alen;
|
||||
*new_lcn = alcn;
|
||||
|
||||
ntfs_unmap_meta(sb, alcn, alen);
|
||||
|
||||
/* Set hint for next requests. */
|
||||
if (!(opt & ALLOCATE_MFT))
|
||||
sbi->used.next_free_lcn = alcn + alen;
|
||||
up_write:
|
||||
up_write(&wnd->rw_lock);
|
||||
return err;
|
||||
}
|
||||
@ -1080,7 +1077,7 @@ int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
|
||||
}
|
||||
|
||||
int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
||||
u64 vbo, const void *buf, size_t bytes)
|
||||
u64 vbo, const void *buf, size_t bytes, int sync)
|
||||
{
|
||||
struct super_block *sb = sbi->sb;
|
||||
u8 cluster_bits = sbi->cluster_bits;
|
||||
@ -1099,8 +1096,8 @@ int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
||||
len = ((u64)clen << cluster_bits) - off;
|
||||
|
||||
for (;;) {
|
||||
u32 op = len < bytes ? len : bytes;
|
||||
int err = ntfs_sb_write(sb, lbo, op, buf, 0);
|
||||
u32 op = min_t(u64, len, bytes);
|
||||
int err = ntfs_sb_write(sb, lbo, op, buf, sync);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
@ -1300,7 +1297,7 @@ int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
|
||||
nb->off = off = lbo & (blocksize - 1);
|
||||
|
||||
for (;;) {
|
||||
u32 len32 = len < bytes ? len : bytes;
|
||||
u32 len32 = min_t(u64, len, bytes);
|
||||
sector_t block = lbo >> sb->s_blocksize_bits;
|
||||
|
||||
do {
|
||||
@ -2175,7 +2172,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
|
||||
|
||||
/* Write main SDS bucket. */
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, sbi->security.next_off,
|
||||
d_security, aligned_sec_size);
|
||||
d_security, aligned_sec_size, 0);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
@ -2193,7 +2190,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
|
||||
|
||||
/* Write copy SDS bucket. */
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security,
|
||||
aligned_sec_size);
|
||||
aligned_sec_size, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
166
fs/ntfs3/index.c
166
fs/ntfs3/index.c
@ -8,7 +8,7 @@
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
@ -671,113 +671,17 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
|
||||
const struct INDEX_HDR *hdr, const void *key,
|
||||
size_t key_len, const void *ctx, int *diff)
|
||||
{
|
||||
struct NTFS_DE *e;
|
||||
struct NTFS_DE *e, *found = NULL;
|
||||
NTFS_CMP_FUNC cmp = indx->cmp;
|
||||
int min_idx = 0, mid_idx, max_idx = 0;
|
||||
int diff2;
|
||||
int table_size = 8;
|
||||
u32 e_size, e_key_len;
|
||||
u32 end = le32_to_cpu(hdr->used);
|
||||
u32 off = le32_to_cpu(hdr->de_off);
|
||||
u16 offs[128];
|
||||
|
||||
#ifdef NTFS3_INDEX_BINARY_SEARCH
|
||||
int max_idx = 0, fnd, min_idx;
|
||||
int nslots = 64;
|
||||
u16 *offs;
|
||||
|
||||
if (end > 0x10000)
|
||||
goto next;
|
||||
|
||||
offs = kmalloc(sizeof(u16) * nslots, GFP_NOFS);
|
||||
if (!offs)
|
||||
goto next;
|
||||
|
||||
/* Use binary search algorithm. */
|
||||
next1:
|
||||
if (off + sizeof(struct NTFS_DE) > end) {
|
||||
e = NULL;
|
||||
goto out1;
|
||||
}
|
||||
e = Add2Ptr(hdr, off);
|
||||
e_size = le16_to_cpu(e->size);
|
||||
|
||||
if (e_size < sizeof(struct NTFS_DE) || off + e_size > end) {
|
||||
e = NULL;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (max_idx >= nslots) {
|
||||
u16 *ptr;
|
||||
int new_slots = ALIGN(2 * nslots, 8);
|
||||
|
||||
ptr = kmalloc(sizeof(u16) * new_slots, GFP_NOFS);
|
||||
if (ptr)
|
||||
memcpy(ptr, offs, sizeof(u16) * max_idx);
|
||||
kfree(offs);
|
||||
offs = ptr;
|
||||
nslots = new_slots;
|
||||
if (!ptr)
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Store entry table. */
|
||||
offs[max_idx] = off;
|
||||
|
||||
if (!de_is_last(e)) {
|
||||
off += e_size;
|
||||
max_idx += 1;
|
||||
goto next1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Table of pointers is created.
|
||||
* Use binary search to find entry that is <= to the search value.
|
||||
*/
|
||||
fnd = -1;
|
||||
min_idx = 0;
|
||||
|
||||
while (min_idx <= max_idx) {
|
||||
int mid_idx = min_idx + ((max_idx - min_idx) >> 1);
|
||||
int diff2;
|
||||
|
||||
e = Add2Ptr(hdr, offs[mid_idx]);
|
||||
|
||||
e_key_len = le16_to_cpu(e->key_size);
|
||||
|
||||
diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
|
||||
|
||||
if (!diff2) {
|
||||
*diff = 0;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (diff2 < 0) {
|
||||
max_idx = mid_idx - 1;
|
||||
fnd = mid_idx;
|
||||
if (!fnd)
|
||||
break;
|
||||
} else {
|
||||
min_idx = mid_idx + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fnd == -1) {
|
||||
e = NULL;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
*diff = -1;
|
||||
e = Add2Ptr(hdr, offs[fnd]);
|
||||
|
||||
out1:
|
||||
kfree(offs);
|
||||
|
||||
return e;
|
||||
#endif
|
||||
|
||||
next:
|
||||
/*
|
||||
* Entries index are sorted.
|
||||
* Enumerate all entries until we find entry
|
||||
* that is <= to the search value.
|
||||
*/
|
||||
fill_table:
|
||||
if (off + sizeof(struct NTFS_DE) > end)
|
||||
return NULL;
|
||||
|
||||
@ -787,22 +691,54 @@ next:
|
||||
if (e_size < sizeof(struct NTFS_DE) || off + e_size > end)
|
||||
return NULL;
|
||||
|
||||
off += e_size;
|
||||
if (!de_is_last(e)) {
|
||||
offs[max_idx] = off;
|
||||
off += e_size;
|
||||
|
||||
max_idx++;
|
||||
if (max_idx < table_size)
|
||||
goto fill_table;
|
||||
|
||||
max_idx--;
|
||||
}
|
||||
|
||||
binary_search:
|
||||
e_key_len = le16_to_cpu(e->key_size);
|
||||
|
||||
*diff = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
|
||||
if (!*diff)
|
||||
return e;
|
||||
diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
|
||||
if (diff2 > 0) {
|
||||
if (found) {
|
||||
min_idx = mid_idx + 1;
|
||||
} else {
|
||||
if (de_is_last(e))
|
||||
return NULL;
|
||||
|
||||
if (*diff <= 0)
|
||||
return e;
|
||||
max_idx = 0;
|
||||
table_size = min(table_size * 2,
|
||||
(int)ARRAY_SIZE(offs));
|
||||
goto fill_table;
|
||||
}
|
||||
} else if (diff2 < 0) {
|
||||
if (found)
|
||||
max_idx = mid_idx - 1;
|
||||
else
|
||||
max_idx--;
|
||||
|
||||
if (de_is_last(e)) {
|
||||
*diff = 1;
|
||||
found = e;
|
||||
} else {
|
||||
*diff = 0;
|
||||
return e;
|
||||
}
|
||||
goto next;
|
||||
|
||||
if (min_idx > max_idx) {
|
||||
*diff = -1;
|
||||
return found;
|
||||
}
|
||||
|
||||
mid_idx = (min_idx + max_idx) >> 1;
|
||||
e = Add2Ptr(hdr, offs[mid_idx]);
|
||||
|
||||
goto binary_search;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1136,9 +1072,7 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
if (fnd)
|
||||
fnd->root_de = e;
|
||||
|
||||
fnd->root_de = e;
|
||||
err = 0;
|
||||
|
||||
for (;;) {
|
||||
@ -1401,7 +1335,7 @@ ok:
|
||||
static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||
CLST *vbn)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
int err;
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
struct ATTRIB *bitmap;
|
||||
struct ATTRIB *alloc;
|
||||
|
159
fs/ntfs3/inode.c
159
fs/ntfs3/inode.c
@ -5,10 +5,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/nls.h>
|
||||
@ -49,8 +47,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
|
||||
|
||||
inode->i_op = NULL;
|
||||
/* Setup 'uid' and 'gid' */
|
||||
inode->i_uid = sbi->options.fs_uid;
|
||||
inode->i_gid = sbi->options.fs_gid;
|
||||
inode->i_uid = sbi->options->fs_uid;
|
||||
inode->i_gid = sbi->options->fs_gid;
|
||||
|
||||
err = mi_init(&ni->mi, sbi, ino);
|
||||
if (err)
|
||||
@ -224,12 +222,9 @@ next_attr:
|
||||
if (!attr->non_res) {
|
||||
ni->i_valid = inode->i_size = rsize;
|
||||
inode_set_bytes(inode, rsize);
|
||||
t32 = asize;
|
||||
} else {
|
||||
t32 = le16_to_cpu(attr->nres.run_off);
|
||||
}
|
||||
|
||||
mode = S_IFREG | (0777 & sbi->options.fs_fmask_inv);
|
||||
mode = S_IFREG | (0777 & sbi->options->fs_fmask_inv);
|
||||
|
||||
if (!attr->non_res) {
|
||||
ni->ni_flags |= NI_FLAG_RESIDENT;
|
||||
@ -272,7 +267,7 @@ next_attr:
|
||||
goto out;
|
||||
|
||||
mode = sb->s_root
|
||||
? (S_IFDIR | (0777 & sbi->options.fs_dmask_inv))
|
||||
? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv))
|
||||
: (S_IFDIR | 0777);
|
||||
goto next_attr;
|
||||
|
||||
@ -315,17 +310,14 @@ next_attr:
|
||||
rp_fa = ni_parse_reparse(ni, attr, &rp);
|
||||
switch (rp_fa) {
|
||||
case REPARSE_LINK:
|
||||
if (!attr->non_res) {
|
||||
inode->i_size = rsize;
|
||||
inode_set_bytes(inode, rsize);
|
||||
t32 = asize;
|
||||
} else {
|
||||
inode->i_size =
|
||||
le64_to_cpu(attr->nres.data_size);
|
||||
t32 = le16_to_cpu(attr->nres.run_off);
|
||||
}
|
||||
/*
|
||||
* Normal symlink.
|
||||
* Assume one unicode symbol == one utf8.
|
||||
*/
|
||||
inode->i_size = le16_to_cpu(rp.SymbolicLinkReparseBuffer
|
||||
.PrintNameLength) /
|
||||
sizeof(u16);
|
||||
|
||||
/* Looks like normal symlink. */
|
||||
ni->i_valid = inode->i_size;
|
||||
|
||||
/* Clear directory bit. */
|
||||
@ -422,7 +414,7 @@ end_enum:
|
||||
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
||||
inode->i_op = &ntfs_link_inode_operations;
|
||||
inode->i_fop = NULL;
|
||||
inode_nohighmem(inode); // ??
|
||||
inode_nohighmem(inode);
|
||||
} else if (S_ISREG(mode)) {
|
||||
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
||||
inode->i_op = &ntfs_file_inode_operations;
|
||||
@ -443,7 +435,7 @@ end_enum:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((sbi->options.sys_immutable &&
|
||||
if ((sbi->options->sys_immutable &&
|
||||
(std5->fa & FILE_ATTRIBUTE_SYSTEM)) &&
|
||||
!S_ISFIFO(mode) && !S_ISSOCK(mode) && !S_ISLNK(mode)) {
|
||||
inode->i_flags |= S_IMMUTABLE;
|
||||
@ -1200,9 +1192,13 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
struct REPARSE_DATA_BUFFER *rp = NULL;
|
||||
bool rp_inserted = false;
|
||||
|
||||
ni_lock_dir(dir_ni);
|
||||
|
||||
dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
|
||||
if (!dir_root)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (!dir_root) {
|
||||
err = -EINVAL;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (S_ISDIR(mode)) {
|
||||
/* Use parent's directory attributes. */
|
||||
@ -1244,7 +1240,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
* }
|
||||
*/
|
||||
} else if (S_ISREG(mode)) {
|
||||
if (sbi->options.sparse) {
|
||||
if (sbi->options->sparse) {
|
||||
/* Sparsed regular file, cause option 'sparse'. */
|
||||
fa = FILE_ATTRIBUTE_SPARSE_FILE |
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
@ -1486,7 +1482,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
asize = ALIGN(SIZEOF_RESIDENT + nsize, 8);
|
||||
t16 = PtrOffset(rec, attr);
|
||||
|
||||
/* 0x78 - the size of EA + EAINFO to store WSL */
|
||||
/*
|
||||
* Below function 'ntfs_save_wsl_perm' requires 0x78 bytes.
|
||||
* It is good idea to keep extened attributes resident.
|
||||
*/
|
||||
if (asize + t16 + 0x78 + 8 > sbi->record_size) {
|
||||
CLST alen;
|
||||
CLST clst = bytes_to_cluster(sbi, nsize);
|
||||
@ -1521,14 +1520,14 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
}
|
||||
|
||||
asize = SIZEOF_NONRESIDENT + ALIGN(err, 8);
|
||||
inode->i_size = nsize;
|
||||
} else {
|
||||
attr->res.data_off = SIZEOF_RESIDENT_LE;
|
||||
attr->res.data_size = cpu_to_le32(nsize);
|
||||
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
|
||||
inode->i_size = nsize;
|
||||
nsize = 0;
|
||||
}
|
||||
/* Size of symlink equals the length of input string. */
|
||||
inode->i_size = size;
|
||||
|
||||
attr->size = cpu_to_le32(asize);
|
||||
|
||||
@ -1551,6 +1550,9 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
if (err)
|
||||
goto out6;
|
||||
|
||||
/* Unlock parent directory before ntfs_init_acl. */
|
||||
ni_unlock(dir_ni);
|
||||
|
||||
inode->i_generation = le16_to_cpu(rec->seq);
|
||||
|
||||
dir->i_mtime = dir->i_ctime = inode->i_atime;
|
||||
@ -1562,6 +1564,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
inode->i_op = &ntfs_link_inode_operations;
|
||||
inode->i_fop = NULL;
|
||||
inode->i_mapping->a_ops = &ntfs_aops;
|
||||
inode->i_size = size;
|
||||
inode_nohighmem(inode);
|
||||
} else if (S_ISREG(mode)) {
|
||||
inode->i_op = &ntfs_file_inode_operations;
|
||||
inode->i_fop = &ntfs_file_operations;
|
||||
@ -1577,7 +1581,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
|
||||
err = ntfs_init_acl(mnt_userns, inode, dir);
|
||||
if (err)
|
||||
goto out6;
|
||||
goto out7;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@ -1586,7 +1590,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
|
||||
/* Write non resident data. */
|
||||
if (nsize) {
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize);
|
||||
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0);
|
||||
if (err)
|
||||
goto out7;
|
||||
}
|
||||
@ -1607,8 +1611,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
||||
out7:
|
||||
|
||||
/* Undo 'indx_insert_entry'. */
|
||||
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);
|
||||
@ -1632,8 +1638,10 @@ out2:
|
||||
kfree(rp);
|
||||
|
||||
out1:
|
||||
if (err)
|
||||
if (err) {
|
||||
ni_unlock(dir_ni);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
unlock_new_inode(inode);
|
||||
|
||||
@ -1754,15 +1762,15 @@ void ntfs_evict_inode(struct inode *inode)
|
||||
static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
|
||||
int buflen)
|
||||
{
|
||||
int i, err = 0;
|
||||
int i, err = -EINVAL;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||
u64 i_size = inode->i_size;
|
||||
u16 nlen = 0;
|
||||
u64 size;
|
||||
u16 ulen = 0;
|
||||
void *to_free = NULL;
|
||||
struct REPARSE_DATA_BUFFER *rp;
|
||||
struct le_str *uni;
|
||||
const __le16 *uname;
|
||||
struct ATTRIB *attr;
|
||||
|
||||
/* Reparse data present. Try to parse it. */
|
||||
@ -1771,68 +1779,64 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
|
||||
|
||||
*buffer = 0;
|
||||
|
||||
/* Read into temporal buffer. */
|
||||
if (i_size > sbi->reparse.max_size || i_size <= sizeof(u32)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
attr = ni_find_attr(ni, NULL, NULL, ATTR_REPARSE, NULL, 0, NULL, NULL);
|
||||
if (!attr) {
|
||||
err = -EINVAL;
|
||||
if (!attr)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!attr->non_res) {
|
||||
rp = resident_data_ex(attr, i_size);
|
||||
if (!rp) {
|
||||
err = -EINVAL;
|
||||
rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER));
|
||||
if (!rp)
|
||||
goto out;
|
||||
}
|
||||
size = le32_to_cpu(attr->res.data_size);
|
||||
} else {
|
||||
rp = kmalloc(i_size, GFP_NOFS);
|
||||
size = le64_to_cpu(attr->nres.data_size);
|
||||
rp = NULL;
|
||||
}
|
||||
|
||||
if (size > sbi->reparse.max_size || size <= sizeof(u32))
|
||||
goto out;
|
||||
|
||||
if (!rp) {
|
||||
rp = kmalloc(size, GFP_NOFS);
|
||||
if (!rp) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
to_free = rp;
|
||||
err = ntfs_read_run_nb(sbi, &ni->file.run, 0, rp, i_size, NULL);
|
||||
/* Read into temporal buffer. */
|
||||
err = ntfs_read_run_nb(sbi, &ni->file.run, 0, rp, size, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = -EINVAL;
|
||||
|
||||
/* Microsoft Tag. */
|
||||
switch (rp->ReparseTag) {
|
||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
/* Mount points and junctions. */
|
||||
/* Can we use 'Rp->MountPointReparseBuffer.PrintNameLength'? */
|
||||
if (i_size <= offsetof(struct REPARSE_DATA_BUFFER,
|
||||
MountPointReparseBuffer.PathBuffer))
|
||||
if (size <= offsetof(struct REPARSE_DATA_BUFFER,
|
||||
MountPointReparseBuffer.PathBuffer))
|
||||
goto out;
|
||||
uni = Add2Ptr(rp,
|
||||
offsetof(struct REPARSE_DATA_BUFFER,
|
||||
MountPointReparseBuffer.PathBuffer) +
|
||||
le16_to_cpu(rp->MountPointReparseBuffer
|
||||
.PrintNameOffset) -
|
||||
2);
|
||||
nlen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength);
|
||||
uname = Add2Ptr(rp,
|
||||
offsetof(struct REPARSE_DATA_BUFFER,
|
||||
MountPointReparseBuffer.PathBuffer) +
|
||||
le16_to_cpu(rp->MountPointReparseBuffer
|
||||
.PrintNameOffset));
|
||||
ulen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength);
|
||||
break;
|
||||
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
/* FolderSymbolicLink */
|
||||
/* Can we use 'Rp->SymbolicLinkReparseBuffer.PrintNameLength'? */
|
||||
if (i_size <= offsetof(struct REPARSE_DATA_BUFFER,
|
||||
SymbolicLinkReparseBuffer.PathBuffer))
|
||||
if (size <= offsetof(struct REPARSE_DATA_BUFFER,
|
||||
SymbolicLinkReparseBuffer.PathBuffer))
|
||||
goto out;
|
||||
uni = Add2Ptr(rp,
|
||||
offsetof(struct REPARSE_DATA_BUFFER,
|
||||
SymbolicLinkReparseBuffer.PathBuffer) +
|
||||
le16_to_cpu(rp->SymbolicLinkReparseBuffer
|
||||
.PrintNameOffset) -
|
||||
2);
|
||||
nlen = le16_to_cpu(
|
||||
uname = Add2Ptr(
|
||||
rp, offsetof(struct REPARSE_DATA_BUFFER,
|
||||
SymbolicLinkReparseBuffer.PathBuffer) +
|
||||
le16_to_cpu(rp->SymbolicLinkReparseBuffer
|
||||
.PrintNameOffset));
|
||||
ulen = le16_to_cpu(
|
||||
rp->SymbolicLinkReparseBuffer.PrintNameLength);
|
||||
break;
|
||||
|
||||
@ -1864,29 +1868,28 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
|
||||
goto out;
|
||||
}
|
||||
if (!IsReparseTagNameSurrogate(rp->ReparseTag) ||
|
||||
i_size <= sizeof(struct REPARSE_POINT)) {
|
||||
size <= sizeof(struct REPARSE_POINT)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Users tag. */
|
||||
uni = Add2Ptr(rp, sizeof(struct REPARSE_POINT) - 2);
|
||||
nlen = le16_to_cpu(rp->ReparseDataLength) -
|
||||
uname = Add2Ptr(rp, sizeof(struct REPARSE_POINT));
|
||||
ulen = le16_to_cpu(rp->ReparseDataLength) -
|
||||
sizeof(struct REPARSE_POINT);
|
||||
}
|
||||
|
||||
/* Convert nlen from bytes to UNICODE chars. */
|
||||
nlen >>= 1;
|
||||
ulen >>= 1;
|
||||
|
||||
/* Check that name is available. */
|
||||
if (!nlen || &uni->name[nlen] > (__le16 *)Add2Ptr(rp, i_size))
|
||||
if (!ulen || uname + ulen > (__le16 *)Add2Ptr(rp, size))
|
||||
goto out;
|
||||
|
||||
/* If name is already zero terminated then truncate it now. */
|
||||
if (!uni->name[nlen - 1])
|
||||
nlen -= 1;
|
||||
uni->len = nlen;
|
||||
if (!uname[ulen - 1])
|
||||
ulen -= 1;
|
||||
|
||||
err = ntfs_utf16_to_nls(sbi, uni, buffer, buflen);
|
||||
err = ntfs_utf16_to_nls(sbi, uname, ulen, buffer, buflen);
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
@ -5,6 +5,9 @@
|
||||
* Copyright (C) 2015 Eric Biggers
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H
|
||||
#define _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
@ -336,3 +339,5 @@ static forceinline u8 *lz_copy(u8 *dst, u32 length, u32 offset, const u8 *bufend
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H */
|
||||
|
@ -7,6 +7,10 @@
|
||||
* - linux kernel code style
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS3_LIB_LIB_H
|
||||
#define _LINUX_NTFS3_LIB_LIB_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* globals from xpress_decompress.c */
|
||||
struct xpress_decompressor *xpress_allocate_decompressor(void);
|
||||
@ -24,3 +28,5 @@ int lzx_decompress(struct lzx_decompressor *__restrict d,
|
||||
const void *__restrict compressed_data,
|
||||
size_t compressed_size, void *__restrict uncompressed_data,
|
||||
size_t uncompressed_size);
|
||||
|
||||
#endif /* _LINUX_NTFS3_LIB_LIB_H */
|
||||
|
@ -5,13 +5,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
#include "ntfs_fs.h"
|
||||
|
||||
// clang-format off
|
||||
@ -292,7 +292,7 @@ next:
|
||||
/*
|
||||
* get_lznt_ctx
|
||||
* @level: 0 - Standard compression.
|
||||
* !0 - Best compression, requires a lot of cpu.
|
||||
* !0 - Best compression, requires a lot of cpu.
|
||||
*/
|
||||
struct lznt *get_lznt_ctx(int level)
|
||||
{
|
||||
|
@ -5,11 +5,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "debug.h"
|
||||
@ -99,16 +95,11 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
struct inode *inode;
|
||||
|
||||
ni_lock_dir(ni);
|
||||
|
||||
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFREG | mode,
|
||||
0, NULL, 0, NULL);
|
||||
|
||||
ni_unlock(ni);
|
||||
|
||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
||||
}
|
||||
|
||||
@ -120,16 +111,11 @@ static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
static int ntfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
struct inode *inode;
|
||||
|
||||
ni_lock_dir(ni);
|
||||
|
||||
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, mode, rdev,
|
||||
NULL, 0, NULL);
|
||||
|
||||
ni_unlock(ni);
|
||||
|
||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
||||
}
|
||||
|
||||
@ -200,15 +186,10 @@ static int ntfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
{
|
||||
u32 size = strlen(symname);
|
||||
struct inode *inode;
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
|
||||
ni_lock_dir(ni);
|
||||
|
||||
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFLNK | 0777,
|
||||
0, symname, size, NULL);
|
||||
|
||||
ni_unlock(ni);
|
||||
|
||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
||||
}
|
||||
|
||||
@ -219,15 +200,10 @@ static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct ntfs_inode *ni = ntfs_i(dir);
|
||||
|
||||
ni_lock_dir(ni);
|
||||
|
||||
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFDIR | mode,
|
||||
0, NULL, 0, NULL);
|
||||
|
||||
ni_unlock(ni);
|
||||
|
||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
||||
}
|
||||
|
||||
|
@ -10,19 +10,27 @@
|
||||
#ifndef _LINUX_NTFS3_NTFS_H
|
||||
#define _LINUX_NTFS3_NTFS_H
|
||||
|
||||
/* TODO: Check 4K MFT record and 512 bytes cluster. */
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Activate this define to use binary search in indexes. */
|
||||
#define NTFS3_INDEX_BINARY_SEARCH
|
||||
#include "debug.h"
|
||||
|
||||
/* TODO: Check 4K MFT record and 512 bytes cluster. */
|
||||
|
||||
/* Check each run for marked clusters. */
|
||||
#define NTFS3_CHECK_FREE_CLST
|
||||
|
||||
#define NTFS_NAME_LEN 255
|
||||
|
||||
/* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff. */
|
||||
#define NTFS_LINK_MAX 0x400
|
||||
//#define NTFS_LINK_MAX 0xffff
|
||||
/*
|
||||
* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff.
|
||||
* xfstest generic/041 creates 3003 hardlinks.
|
||||
*/
|
||||
#define NTFS_LINK_MAX 4000
|
||||
|
||||
/*
|
||||
* Activate to use 64 bit clusters instead of 32 bits in ntfs.sys.
|
||||
|
@ -9,6 +9,37 @@
|
||||
#ifndef _LINUX_NTFS3_NTFS_FS_H
|
||||
#define _LINUX_NTFS3_NTFS_FS_H
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/cleancache.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/page-flags.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/time64.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <asm/div64.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
|
||||
struct dentry;
|
||||
struct fiemap_extent_info;
|
||||
struct user_namespace;
|
||||
struct page;
|
||||
struct writeback_control;
|
||||
enum utf16_endian;
|
||||
|
||||
|
||||
#define MINUS_ONE_T ((size_t)(-1))
|
||||
/* Biggest MFT / smallest cluster */
|
||||
#define MAXIMUM_BYTES_PER_MFT 4096
|
||||
@ -52,6 +83,7 @@
|
||||
// clang-format on
|
||||
|
||||
struct ntfs_mount_options {
|
||||
char *nls_name;
|
||||
struct nls_table *nls;
|
||||
|
||||
kuid_t fs_uid;
|
||||
@ -59,19 +91,16 @@ struct ntfs_mount_options {
|
||||
u16 fs_fmask_inv;
|
||||
u16 fs_dmask_inv;
|
||||
|
||||
unsigned uid : 1, /* uid was set. */
|
||||
gid : 1, /* gid was set. */
|
||||
fmask : 1, /* fmask was set. */
|
||||
dmask : 1, /* dmask was set. */
|
||||
sys_immutable : 1, /* Immutable system files. */
|
||||
discard : 1, /* Issue discard requests on deletions. */
|
||||
sparse : 1, /* Create sparse files. */
|
||||
showmeta : 1, /* Show meta files. */
|
||||
nohidden : 1, /* Do not show hidden files. */
|
||||
force : 1, /* Rw mount dirty volume. */
|
||||
no_acs_rules : 1, /*Exclude acs rules. */
|
||||
prealloc : 1 /* Preallocate space when file is growing. */
|
||||
;
|
||||
unsigned fmask : 1; /* fmask was set. */
|
||||
unsigned dmask : 1; /*dmask was set. */
|
||||
unsigned sys_immutable : 1; /* Immutable system files. */
|
||||
unsigned discard : 1; /* Issue discard requests on deletions. */
|
||||
unsigned sparse : 1; /* Create sparse files. */
|
||||
unsigned showmeta : 1; /* Show meta files. */
|
||||
unsigned nohidden : 1; /* Do not show hidden files. */
|
||||
unsigned force : 1; /* RW mount dirty volume. */
|
||||
unsigned noacsrules : 1; /* Exclude acs rules. */
|
||||
unsigned prealloc : 1; /* Preallocate space when file is growing. */
|
||||
};
|
||||
|
||||
/* Special value to unpack and deallocate. */
|
||||
@ -182,10 +211,8 @@ struct ntfs_sb_info {
|
||||
u32 blocks_per_cluster; // cluster_size / sb->s_blocksize
|
||||
|
||||
u32 record_size;
|
||||
u32 sector_size;
|
||||
u32 index_size;
|
||||
|
||||
u8 sector_bits;
|
||||
u8 cluster_bits;
|
||||
u8 record_bits;
|
||||
|
||||
@ -279,7 +306,7 @@ struct ntfs_sb_info {
|
||||
#endif
|
||||
} compress;
|
||||
|
||||
struct ntfs_mount_options options;
|
||||
struct ntfs_mount_options *options;
|
||||
struct ratelimit_state msg_ratelimit;
|
||||
};
|
||||
|
||||
@ -436,7 +463,7 @@ bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le);
|
||||
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
|
||||
const __le16 *name, size_t name_len,
|
||||
const struct MFT_REF *ref);
|
||||
int al_update(struct ntfs_inode *ni);
|
||||
int al_update(struct ntfs_inode *ni, int sync);
|
||||
static inline size_t al_aligned(size_t size)
|
||||
{
|
||||
return (size + 1023) & ~(size_t)1023;
|
||||
@ -448,7 +475,7 @@ bool are_bits_set(const ulong *map, size_t bit, size_t nbits);
|
||||
size_t get_set_bits_ex(const ulong *map, size_t bit, size_t nbits);
|
||||
|
||||
/* Globals from dir.c */
|
||||
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
|
||||
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len,
|
||||
u8 *buf, int buf_len);
|
||||
int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
|
||||
struct cpu_str *uni, u32 max_ulen,
|
||||
@ -520,7 +547,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
|
||||
struct ATTR_LIST_ENTRY **entry);
|
||||
int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa);
|
||||
enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
void *buffer);
|
||||
struct REPARSE_DATA_BUFFER *buffer);
|
||||
int ni_write_inode(struct inode *inode, int sync, const char *hint);
|
||||
#define _ni_write_inode(i, w) ni_write_inode(i, w, __func__)
|
||||
int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
@ -577,7 +604,7 @@ int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer);
|
||||
int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
|
||||
const void *buffer, int wait);
|
||||
int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
||||
u64 vbo, const void *buf, size_t bytes);
|
||||
u64 vbo, const void *buf, size_t bytes, int sync);
|
||||
struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
|
||||
const struct runs_tree *run, u64 vbo);
|
||||
int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
||||
|
@ -5,10 +5,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
|
@ -7,10 +7,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/nls.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
|
651
fs/ntfs3/super.c
651
fs/ntfs3/super.c
File diff suppressed because it is too large
Load Diff
@ -5,13 +5,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
#include "ntfs_fs.h"
|
||||
|
||||
static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
|
||||
|
251
fs/ntfs3/xattr.c
251
fs/ntfs3/xattr.c
@ -5,10 +5,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
#include <linux/xattr.h>
|
||||
@ -78,6 +75,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
|
||||
size_t add_bytes, const struct EA_INFO **info)
|
||||
{
|
||||
int err;
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
struct ATTR_LIST_ENTRY *le = NULL;
|
||||
struct ATTRIB *attr_info, *attr_ea;
|
||||
void *ea_p;
|
||||
@ -102,10 +100,10 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
|
||||
|
||||
/* Check Ea limit. */
|
||||
size = le32_to_cpu((*info)->size);
|
||||
if (size > ni->mi.sbi->ea_max_size)
|
||||
if (size > sbi->ea_max_size)
|
||||
return -EFBIG;
|
||||
|
||||
if (attr_size(attr_ea) > ni->mi.sbi->ea_max_size)
|
||||
if (attr_size(attr_ea) > sbi->ea_max_size)
|
||||
return -EFBIG;
|
||||
|
||||
/* Allocate memory for packed Ea. */
|
||||
@ -113,15 +111,16 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
|
||||
if (!ea_p)
|
||||
return -ENOMEM;
|
||||
|
||||
if (attr_ea->non_res) {
|
||||
if (!size) {
|
||||
;
|
||||
} else if (attr_ea->non_res) {
|
||||
struct runs_tree run;
|
||||
|
||||
run_init(&run);
|
||||
|
||||
err = attr_load_runs(attr_ea, ni, &run, NULL);
|
||||
if (!err)
|
||||
err = ntfs_read_run_nb(ni->mi.sbi, &run, 0, ea_p, size,
|
||||
NULL);
|
||||
err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
|
||||
run_close(&run);
|
||||
|
||||
if (err)
|
||||
@ -260,7 +259,7 @@ 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, int locked)
|
||||
size_t val_size, int flags)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
@ -279,8 +278,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
||||
u64 new_sz;
|
||||
void *p;
|
||||
|
||||
if (!locked)
|
||||
ni_lock(ni);
|
||||
ni_lock(ni);
|
||||
|
||||
run_init(&ea_run);
|
||||
|
||||
@ -370,21 +368,22 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
||||
new_ea->name[name_len] = 0;
|
||||
memcpy(new_ea->name + name_len + 1, value, val_size);
|
||||
new_pack = le16_to_cpu(ea_info.size_pack) + packed_ea_size(new_ea);
|
||||
|
||||
/* Should fit into 16 bits. */
|
||||
if (new_pack > 0xffff) {
|
||||
err = -EFBIG; // -EINVAL?
|
||||
goto out;
|
||||
}
|
||||
ea_info.size_pack = cpu_to_le16(new_pack);
|
||||
|
||||
/* New size of ATTR_EA. */
|
||||
size += add;
|
||||
if (size > sbi->ea_max_size) {
|
||||
ea_info.size = cpu_to_le32(size);
|
||||
|
||||
/*
|
||||
* 1. Check ea_info.size_pack for overflow.
|
||||
* 2. New attibute size must fit value from $AttrDef
|
||||
*/
|
||||
if (new_pack > 0xffff || size > sbi->ea_max_size) {
|
||||
ntfs_inode_warn(
|
||||
inode,
|
||||
"The size of extended attributes must not exceed 64KiB");
|
||||
err = -EFBIG; // -EINVAL?
|
||||
goto out;
|
||||
}
|
||||
ea_info.size = cpu_to_le32(size);
|
||||
|
||||
update_ea:
|
||||
|
||||
@ -444,7 +443,7 @@ update_ea:
|
||||
/* Delete xattr, ATTR_EA */
|
||||
ni_remove_attr_le(ni, attr, mi, le);
|
||||
} else if (attr->non_res) {
|
||||
err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size);
|
||||
err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
@ -468,8 +467,7 @@ update_ea:
|
||||
mark_inode_dirty(&ni->vfs_inode);
|
||||
|
||||
out:
|
||||
if (!locked)
|
||||
ni_unlock(ni);
|
||||
ni_unlock(ni);
|
||||
|
||||
run_close(&ea_run);
|
||||
kfree(ea_all);
|
||||
@ -478,12 +476,6 @@ out:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
|
||||
static inline void ntfs_posix_acl_release(struct posix_acl *acl)
|
||||
{
|
||||
if (acl && refcount_dec_and_test(&acl->a_refcount))
|
||||
kfree(acl);
|
||||
}
|
||||
|
||||
static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int type,
|
||||
int locked)
|
||||
@ -521,12 +513,15 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
|
||||
/* Translate extended attribute to acl. */
|
||||
if (err >= 0) {
|
||||
acl = posix_acl_from_xattr(mnt_userns, buf, err);
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
} else if (err == -ENODATA) {
|
||||
acl = NULL;
|
||||
} else {
|
||||
acl = err == -ENODATA ? NULL : ERR_PTR(err);
|
||||
acl = ERR_PTR(err);
|
||||
}
|
||||
|
||||
if (!IS_ERR(acl))
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
__putname(buf);
|
||||
|
||||
return acl;
|
||||
@ -546,12 +541,13 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
|
||||
|
||||
static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, struct posix_acl *acl,
|
||||
int type, int locked)
|
||||
int type)
|
||||
{
|
||||
const char *name;
|
||||
size_t size, name_len;
|
||||
void *value = NULL;
|
||||
int err = 0;
|
||||
int flags;
|
||||
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
@ -561,22 +557,15 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
|
||||
if (acl) {
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
err = posix_acl_equiv_mode(acl, &mode);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = posix_acl_update_mode(mnt_userns, inode, &mode,
|
||||
&acl);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (inode->i_mode != mode) {
|
||||
inode->i_mode = mode;
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
/*
|
||||
* ACL can be exactly represented in the
|
||||
* traditional file mode permission bits.
|
||||
*/
|
||||
acl = NULL;
|
||||
}
|
||||
}
|
||||
name = XATTR_NAME_POSIX_ACL_ACCESS;
|
||||
name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1;
|
||||
@ -594,20 +583,24 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
|
||||
}
|
||||
|
||||
if (!acl) {
|
||||
/* Remove xattr if it can be presented via mode. */
|
||||
size = 0;
|
||||
value = NULL;
|
||||
flags = XATTR_REPLACE;
|
||||
} else {
|
||||
size = posix_acl_xattr_size(acl->a_count);
|
||||
value = kmalloc(size, GFP_NOFS);
|
||||
if (!value)
|
||||
return -ENOMEM;
|
||||
|
||||
err = posix_acl_to_xattr(mnt_userns, acl, value, size);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked);
|
||||
err = ntfs_set_ea(inode, name, name_len, value, size, flags);
|
||||
if (err == -ENODATA && !size)
|
||||
err = 0; /* Removing non existed xattr. */
|
||||
if (!err)
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
@ -623,68 +616,7 @@ out:
|
||||
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *acl, int type)
|
||||
{
|
||||
return ntfs_set_acl_ex(mnt_userns, inode, acl, type, 0);
|
||||
}
|
||||
|
||||
static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int type, void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int err;
|
||||
|
||||
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
|
||||
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
acl = ntfs_get_acl(inode, type, false);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
||||
if (!acl)
|
||||
return -ENODATA;
|
||||
|
||||
err = posix_acl_to_xattr(mnt_userns, acl, buffer, size);
|
||||
ntfs_posix_acl_release(acl);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int type, const void *value,
|
||||
size_t size)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
int err;
|
||||
|
||||
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
|
||||
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!inode_owner_or_capable(mnt_userns, inode))
|
||||
return -EPERM;
|
||||
|
||||
if (!value) {
|
||||
acl = NULL;
|
||||
} else {
|
||||
acl = posix_acl_from_xattr(mnt_userns, value, size);
|
||||
if (IS_ERR(acl))
|
||||
return PTR_ERR(acl);
|
||||
|
||||
if (acl) {
|
||||
err = posix_acl_valid(mnt_userns, acl);
|
||||
if (err)
|
||||
goto release_and_out;
|
||||
}
|
||||
}
|
||||
|
||||
err = ntfs_set_acl(mnt_userns, inode, acl, type);
|
||||
|
||||
release_and_out:
|
||||
ntfs_posix_acl_release(acl);
|
||||
return err;
|
||||
return ntfs_set_acl_ex(mnt_userns, inode, acl, type);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -698,54 +630,27 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct posix_acl *default_acl, *acl;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* TODO: Refactoring lock.
|
||||
* ni_lock(dir) ... -> posix_acl_create(dir,...) -> ntfs_get_acl -> ni_lock(dir)
|
||||
*/
|
||||
inode->i_default_acl = NULL;
|
||||
err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
default_acl = ntfs_get_acl_ex(mnt_userns, dir, ACL_TYPE_DEFAULT, 1);
|
||||
|
||||
if (!default_acl || default_acl == ERR_PTR(-EOPNOTSUPP)) {
|
||||
inode->i_mode &= ~current_umask();
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IS_ERR(default_acl)) {
|
||||
err = PTR_ERR(default_acl);
|
||||
goto out;
|
||||
}
|
||||
|
||||
acl = default_acl;
|
||||
err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
|
||||
if (err < 0)
|
||||
goto out1;
|
||||
if (!err) {
|
||||
posix_acl_release(acl);
|
||||
acl = NULL;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(inode->i_mode)) {
|
||||
posix_acl_release(default_acl);
|
||||
default_acl = NULL;
|
||||
}
|
||||
|
||||
if (default_acl)
|
||||
if (default_acl) {
|
||||
err = ntfs_set_acl_ex(mnt_userns, inode, default_acl,
|
||||
ACL_TYPE_DEFAULT, 1);
|
||||
ACL_TYPE_DEFAULT);
|
||||
posix_acl_release(default_acl);
|
||||
} else {
|
||||
inode->i_default_acl = NULL;
|
||||
}
|
||||
|
||||
if (!acl)
|
||||
inode->i_acl = NULL;
|
||||
else if (!err)
|
||||
err = ntfs_set_acl_ex(mnt_userns, inode, acl, ACL_TYPE_ACCESS,
|
||||
1);
|
||||
else {
|
||||
if (!err)
|
||||
err = ntfs_set_acl_ex(mnt_userns, inode, acl,
|
||||
ACL_TYPE_ACCESS);
|
||||
posix_acl_release(acl);
|
||||
}
|
||||
|
||||
posix_acl_release(acl);
|
||||
out1:
|
||||
posix_acl_release(default_acl);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
@ -772,7 +677,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
|
||||
int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
int mask)
|
||||
{
|
||||
if (ntfs_sb(inode->i_sb)->options.no_acs_rules) {
|
||||
if (ntfs_sb(inode->i_sb)->options->noacsrules) {
|
||||
/* "No access rules" mode - Allow all changes. */
|
||||
return 0;
|
||||
}
|
||||
@ -880,23 +785,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
|
||||
if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
|
||||
!memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
|
||||
sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
|
||||
(name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
|
||||
!memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
|
||||
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
|
||||
/* TODO: init_user_ns? */
|
||||
err = ntfs_xattr_get_acl(
|
||||
&init_user_ns, inode,
|
||||
name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
|
||||
? ACL_TYPE_ACCESS
|
||||
: ACL_TYPE_DEFAULT,
|
||||
buffer, size);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
/* Deal with NTFS extended attribute. */
|
||||
err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
|
||||
|
||||
@ -1009,24 +897,8 @@ set_new_fa:
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
|
||||
if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
|
||||
!memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
|
||||
sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
|
||||
(name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
|
||||
!memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
|
||||
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
|
||||
err = ntfs_xattr_set_acl(
|
||||
mnt_userns, inode,
|
||||
name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
|
||||
? ACL_TYPE_ACCESS
|
||||
: ACL_TYPE_DEFAULT,
|
||||
value, size);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
/* Deal with NTFS extended attribute. */
|
||||
err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
|
||||
err = ntfs_set_ea(inode, name, name_len, value, size, flags);
|
||||
|
||||
out:
|
||||
return err;
|
||||
@ -1042,28 +914,29 @@ int ntfs_save_wsl_perm(struct inode *inode)
|
||||
int err;
|
||||
__le32 value;
|
||||
|
||||
/* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */
|
||||
value = cpu_to_le32(i_uid_read(inode));
|
||||
err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
|
||||
sizeof(value), 0, 0);
|
||||
sizeof(value), 0);
|
||||
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, 0);
|
||||
sizeof(value), 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
value = cpu_to_le32(inode->i_mode);
|
||||
err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
|
||||
sizeof(value), 0, 0);
|
||||
sizeof(value), 0);
|
||||
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, 0);
|
||||
sizeof(value), 0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user