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:
@@ -4,103 +4,112 @@
|
|||||||
NTFS3
|
NTFS3
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
|
||||||
Summary and Features
|
Summary and Features
|
||||||
====================
|
====================
|
||||||
|
|
||||||
NTFS3 is fully functional NTFS Read-Write driver. The driver works with
|
NTFS3 is fully functional NTFS Read-Write driver. The driver works with NTFS
|
||||||
NTFS versions up to 3.1, normal/compressed/sparse files
|
versions up to 3.1. File system type to use on mount is *ntfs3*.
|
||||||
and journal replaying. File system type to use on mount is 'ntfs3'.
|
|
||||||
|
|
||||||
- This driver implements NTFS read/write support for normal, sparse and
|
- This driver implements NTFS read/write support for normal, sparse and
|
||||||
compressed files.
|
compressed files.
|
||||||
- Supports native journal replaying;
|
- 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 NFS export of mounted NTFS volumes.
|
- 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
|
Mount Options
|
||||||
=============
|
=============
|
||||||
|
|
||||||
The list below describes mount options supported by NTFS3 driver in addition to
|
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
|
* - iocharset=name
|
||||||
strings and translate them to Unicode and back. If
|
- This option informs the driver how to interpret path strings and
|
||||||
this option is not set, the default codepage will be
|
translate them to Unicode and back. If this option is not set, the
|
||||||
used (CONFIG_NLS_DEFAULT).
|
default codepage will be used (CONFIG_NLS_DEFAULT).
|
||||||
Examples:
|
|
||||||
'nls=utf8'
|
|
||||||
|
|
||||||
uid=
|
Example: iocharset=utf8
|
||||||
gid=
|
|
||||||
umask= Controls the default permissions for files/directories created
|
|
||||||
after the NTFS volume is mounted.
|
|
||||||
|
|
||||||
fmask=
|
* - uid=
|
||||||
dmask= Instead of specifying umask which applies both to
|
- :rspan:`1`
|
||||||
files and directories, fmask applies only to files and
|
* - gid=
|
||||||
dmask only to directories.
|
|
||||||
|
|
||||||
nohidden Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN)
|
* - umask=
|
||||||
attribute will not be shown under Linux.
|
- Controls the default permissions for files/directories created after
|
||||||
|
the NTFS volume is mounted.
|
||||||
|
|
||||||
sys_immutable Files with the Windows-specific SYSTEM
|
* - dmask=
|
||||||
(FILE_ATTRIBUTE_SYSTEM) attribute will be marked as system
|
- :rspan:`1` Instead of specifying umask which applies both to files and
|
||||||
immutable files.
|
directories, fmask applies only to files and dmask only to directories.
|
||||||
|
* - fmask=
|
||||||
|
|
||||||
discard Enable support of the TRIM command for improved performance
|
* - noacsrules
|
||||||
on delete operations, which is recommended for use with the
|
- "No access rules" mount option sets access rights for files/folders to
|
||||||
solid-state drives (SSD).
|
777 and owner/group to root. This mount option absorbs all other
|
||||||
|
permissions.
|
||||||
|
|
||||||
force Forces the driver to mount partitions even if 'dirty' flag
|
- Permissions change for files/folders will be reported as successful,
|
||||||
(volume dirty) is set. Not recommended for use.
|
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
|
* - nohidden
|
||||||
a mounted NTFS partition.
|
- Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute
|
||||||
By default, all meta-files are hidden.
|
will not be shown under Linux.
|
||||||
|
|
||||||
prealloc Preallocate space for files excessively when file size is
|
* - sys_immutable
|
||||||
increasing on writes. Decreases fragmentation in case of
|
- Files with the Windows-specific SYSTEM (FILE_ATTRIBUTE_SYSTEM) attribute
|
||||||
parallel write operations to different files.
|
will be marked as system immutable files.
|
||||||
|
|
||||||
no_acs_rules "No access rules" mount option sets access rights for
|
* - discard
|
||||||
files/folders to 777 and owner/group to root. This mount
|
- Enable support of the TRIM command for improved performance on delete
|
||||||
option absorbs all other permissions:
|
operations, which is recommended for use with the solid-state drives
|
||||||
- permissions change for files/folders will be reported
|
(SSD).
|
||||||
as successful, but they will remain 777;
|
|
||||||
- owner/group change will be reported as successful, but
|
|
||||||
they will stay as root
|
|
||||||
|
|
||||||
acl Support POSIX ACLs (Access Control Lists). Effective if
|
* - force
|
||||||
supported by Kernel. Not to be confused with NTFS ACLs.
|
- Forces the driver to mount partitions even if volume is marked dirty.
|
||||||
The option specified as acl enables support for POSIX ACLs.
|
Not recommended for use.
|
||||||
|
|
||||||
noatime All files and directories will not update their last access
|
* - sparse
|
||||||
time attribute if a partition is mounted with this parameter.
|
- Create new files as sparse.
|
||||||
This option can speed up file system operation.
|
|
||||||
|
|
||||||
===============================================================================
|
* - 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 over JBD. Currently journal replaying is supported
|
||||||
- Full journaling support (currently journal replaying is supported) over JBD.
|
which is not necessarily as effectice as JBD would be.
|
||||||
|
|
||||||
|
|
||||||
References
|
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?
|
* 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/fs.h>
|
||||||
#include <linux/hash.h>
|
|
||||||
#include <linux/nls.h>
|
|
||||||
#include <linux/ratelimit.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.h"
|
#include "ntfs.h"
|
||||||
@@ -291,7 +287,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
|
|||||||
if (!rsize) {
|
if (!rsize) {
|
||||||
/* Empty resident -> Non empty nonresident. */
|
/* Empty resident -> Non empty nonresident. */
|
||||||
} else if (!is_data) {
|
} 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)
|
if (err)
|
||||||
goto out2;
|
goto out2;
|
||||||
} else if (!page) {
|
} else if (!page) {
|
||||||
@@ -451,11 +447,8 @@ again:
|
|||||||
again_1:
|
again_1:
|
||||||
align = sbi->cluster_size;
|
align = sbi->cluster_size;
|
||||||
|
|
||||||
if (is_ext) {
|
if (is_ext)
|
||||||
align <<= attr_b->nres.c_unit;
|
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_valid = le64_to_cpu(attr_b->nres.valid_size);
|
||||||
old_size = le64_to_cpu(attr_b->nres.data_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_alloc = (new_size + align - 1) & ~(u64)(align - 1);
|
||||||
new_alen = new_alloc >> cluster_bits;
|
new_alen = new_alloc >> cluster_bits;
|
||||||
|
|
||||||
if (keep_prealloc && is_ext)
|
|
||||||
keep_prealloc = false;
|
|
||||||
|
|
||||||
if (keep_prealloc && new_size < old_size) {
|
if (keep_prealloc && new_size < old_size) {
|
||||||
attr_b->nres.data_size = cpu_to_le64(new_size);
|
attr_b->nres.data_size = cpu_to_le64(new_size);
|
||||||
mi_b->dirty = true;
|
mi_b->dirty = true;
|
||||||
@@ -529,7 +519,7 @@ add_alloc_in_same_attr_seg:
|
|||||||
} else if (pre_alloc == -1) {
|
} else if (pre_alloc == -1) {
|
||||||
pre_alloc = 0;
|
pre_alloc = 0;
|
||||||
if (type == ATTR_DATA && !name_len &&
|
if (type == ATTR_DATA && !name_len &&
|
||||||
sbi->options.prealloc) {
|
sbi->options->prealloc) {
|
||||||
CLST new_alen2 = bytes_to_cluster(
|
CLST new_alen2 = bytes_to_cluster(
|
||||||
sbi, get_pre_allocated(new_size));
|
sbi, get_pre_allocated(new_size));
|
||||||
pre_alloc = new_alen2 - new_alen;
|
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;
|
return 0;
|
||||||
|
|
||||||
from = vbo;
|
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);
|
memset(Add2Ptr(resident_data(attr_b), from), 0, to - from);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
#include <linux/buffer_head.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nls.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.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) {
|
if (attr && attr->non_res) {
|
||||||
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
|
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
|
||||||
al->size);
|
al->size, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
al->dirty = false;
|
al->dirty = false;
|
||||||
@@ -423,7 +420,7 @@ next:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int al_update(struct ntfs_inode *ni)
|
int al_update(struct ntfs_inode *ni, int sync)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct ATTRIB *attr;
|
struct ATTRIB *attr;
|
||||||
@@ -445,7 +442,7 @@ int al_update(struct ntfs_inode *ni)
|
|||||||
memcpy(resident_data(attr), al->le, al->size);
|
memcpy(resident_data(attr), al->le, al->size);
|
||||||
} else {
|
} else {
|
||||||
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
|
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
|
||||||
al->size);
|
al->size, sync);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
#include <linux/types.h>
|
||||||
#include <linux/buffer_head.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/nls.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "ntfs.h"
|
|
||||||
#include "ntfs_fs.h"
|
#include "ntfs_fs.h"
|
||||||
|
|
||||||
#define BITS_IN_SIZE_T (sizeof(size_t) * 8)
|
#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;
|
pos = nbits & 7;
|
||||||
if (pos) {
|
if (pos) {
|
||||||
u8 mask = fill_mask[pos];
|
mask = fill_mask[pos];
|
||||||
|
|
||||||
if ((*map & mask) != mask)
|
if ((*map & mask) != mask)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "ntfs.h"
|
#include "ntfs.h"
|
||||||
#include "ntfs_fs.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 {
|
} else {
|
||||||
n3 = rb_next(&e->count.node);
|
n3 = rb_next(&e->count.node);
|
||||||
max_new_len = len > new_len ? len : new_len;
|
max_new_len = max(len, new_len);
|
||||||
if (!n3) {
|
if (!n3) {
|
||||||
wnd->extent_max = max_new_len;
|
wnd->extent_max = max_new_len;
|
||||||
} else {
|
} else {
|
||||||
@@ -731,7 +729,7 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
|||||||
wbits = wnd->bits_last;
|
wbits = wnd->bits_last;
|
||||||
|
|
||||||
tail = wbits - wbit;
|
tail = wbits - wbit;
|
||||||
op = tail < bits ? tail : bits;
|
op = min_t(u32, tail, bits);
|
||||||
|
|
||||||
bh = wnd_map(wnd, iw);
|
bh = wnd_map(wnd, iw);
|
||||||
if (IS_ERR(bh)) {
|
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;
|
wbits = wnd->bits_last;
|
||||||
|
|
||||||
tail = wbits - wbit;
|
tail = wbits - wbit;
|
||||||
op = tail < bits ? tail : bits;
|
op = min_t(u32, tail, bits);
|
||||||
|
|
||||||
bh = wnd_map(wnd, iw);
|
bh = wnd_map(wnd, iw);
|
||||||
if (IS_ERR(bh)) {
|
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;
|
wbits = wnd->bits_last;
|
||||||
|
|
||||||
tail = wbits - wbit;
|
tail = wbits - wbit;
|
||||||
op = tail < bits ? tail : bits;
|
op = min_t(u32, tail, bits);
|
||||||
|
|
||||||
if (wbits != wnd->free_bits[iw]) {
|
if (wbits != wnd->free_bits[iw]) {
|
||||||
bool ret;
|
bool ret;
|
||||||
@@ -926,7 +924,7 @@ use_wnd:
|
|||||||
wbits = wnd->bits_last;
|
wbits = wnd->bits_last;
|
||||||
|
|
||||||
tail = wbits - wbit;
|
tail = wbits - wbit;
|
||||||
op = tail < bits ? tail : bits;
|
op = min_t(u32, tail, bits);
|
||||||
|
|
||||||
if (wnd->free_bits[iw]) {
|
if (wnd->free_bits[iw]) {
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
#ifndef _LINUX_NTFS3_DEBUG_H
|
#ifndef _LINUX_NTFS3_DEBUG_H
|
||||||
#define _LINUX_NTFS3_DEBUG_H
|
#define _LINUX_NTFS3_DEBUG_H
|
||||||
|
|
||||||
|
struct super_block;
|
||||||
|
struct inode;
|
||||||
|
|
||||||
#ifndef Add2Ptr
|
#ifndef Add2Ptr
|
||||||
#define Add2Ptr(P, I) ((void *)((u8 *)(P) + (I)))
|
#define Add2Ptr(P, I) ((void *)((u8 *)(P) + (I)))
|
||||||
#define PtrOffset(B, O) ((size_t)((size_t)(O) - (size_t)(B)))
|
#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/fs.h>
|
||||||
#include <linux/iversion.h>
|
|
||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -18,30 +15,27 @@
|
|||||||
#include "ntfs_fs.h"
|
#include "ntfs_fs.h"
|
||||||
|
|
||||||
/* Convert little endian UTF-16 to NLS string. */
|
/* 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)
|
u8 *buf, int buf_len)
|
||||||
{
|
{
|
||||||
int ret, uni_len, warn;
|
int ret, warn;
|
||||||
const __le16 *ip;
|
|
||||||
u8 *op;
|
u8 *op;
|
||||||
struct nls_table *nls = sbi->options.nls;
|
struct nls_table *nls = sbi->options->nls;
|
||||||
|
|
||||||
static_assert(sizeof(wchar_t) == sizeof(__le16));
|
static_assert(sizeof(wchar_t) == sizeof(__le16));
|
||||||
|
|
||||||
if (!nls) {
|
if (!nls) {
|
||||||
/* UTF-16 -> UTF-8 */
|
/* UTF-16 -> UTF-8 */
|
||||||
ret = utf16s_to_utf8s((wchar_t *)uni->name, uni->len,
|
ret = utf16s_to_utf8s(name, len, UTF16_LITTLE_ENDIAN, buf,
|
||||||
UTF16_LITTLE_ENDIAN, buf, buf_len);
|
buf_len);
|
||||||
buf[ret] = '\0';
|
buf[ret] = '\0';
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = uni->name;
|
|
||||||
op = buf;
|
op = buf;
|
||||||
uni_len = uni->len;
|
|
||||||
warn = 0;
|
warn = 0;
|
||||||
|
|
||||||
while (uni_len--) {
|
while (len--) {
|
||||||
u16 ec;
|
u16 ec;
|
||||||
int charlen;
|
int charlen;
|
||||||
char dump[5];
|
char dump[5];
|
||||||
@@ -52,7 +46,7 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ec = le16_to_cpu(*ip++);
|
ec = le16_to_cpu(*name++);
|
||||||
charlen = nls->uni2char(ec, op, buf_len);
|
charlen = nls->uni2char(ec, op, buf_len);
|
||||||
|
|
||||||
if (charlen > 0) {
|
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;
|
int ret, slen;
|
||||||
const u8 *end;
|
const u8 *end;
|
||||||
struct nls_table *nls = sbi->options.nls;
|
struct nls_table *nls = sbi->options->nls;
|
||||||
u16 *uname = uni->name;
|
u16 *uname = uni->name;
|
||||||
|
|
||||||
static_assert(sizeof(wchar_t) == sizeof(u16));
|
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;
|
return 0;
|
||||||
|
|
||||||
/* Skip meta files. Unless option to show metafiles is set. */
|
/* 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;
|
return 0;
|
||||||
|
|
||||||
if (sbi->options.nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
|
if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
name_len = ntfs_utf16_to_nls(sbi, (struct le_str *)&fname->name_len,
|
name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
|
||||||
name, PATH_MAX);
|
PATH_MAX);
|
||||||
if (name_len <= 0) {
|
if (name_len <= 0) {
|
||||||
ntfs_warn(sbi->sb, "failed to convert name for inode %lx.",
|
ntfs_warn(sbi->sb, "failed to convert name for inode %lx.",
|
||||||
ino);
|
ino);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/falloc.h>
|
#include <linux/falloc.h>
|
||||||
#include <linux/fiemap.h>
|
#include <linux/fiemap.h>
|
||||||
#include <linux/nls.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.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);
|
truncate_pagecache(inode, vbo_down);
|
||||||
|
|
||||||
if (!is_sparsed(ni) && !is_compressed(ni)) {
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +739,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
|||||||
umode_t mode = inode->i_mode;
|
umode_t mode = inode->i_mode;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (sbi->options.no_acs_rules) {
|
if (sbi->options->noacsrules) {
|
||||||
/* "No access rules" - Force any changes of time etc. */
|
/* "No access rules" - Force any changes of time etc. */
|
||||||
attr->ia_valid |= ATTR_FORCE;
|
attr->ia_valid |= ATTR_FORCE;
|
||||||
/* and disable for editing some attributes. */
|
/* and disable for editing some attributes. */
|
||||||
@@ -1185,7 +1187,7 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/* If we are last writer on the inode, drop the block reservation. */
|
/* If we are last writer on the inode, drop the block reservation. */
|
||||||
if (sbi->options.prealloc && ((file->f_mode & FMODE_WRITE) &&
|
if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) &&
|
||||||
atomic_read(&inode->i_writecount) == 1)) {
|
atomic_read(&inode->i_writecount) == 1)) {
|
||||||
ni_lock(ni);
|
ni_lock(ni);
|
||||||
down_write(&ni->file.run_lock);
|
down_write(&ni->file.run_lock);
|
||||||
|
|||||||
@@ -5,11 +5,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
#include <linux/buffer_head.h>
|
|
||||||
#include <linux/fiemap.h>
|
#include <linux/fiemap.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nls.h>
|
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -708,18 +705,35 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
mi = ni_find_mi(ni, ino_get(&le->ref));
|
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),
|
attr = mi_find_attr(mi, NULL, le->type, le_name(le),
|
||||||
le->name_len, &le->id);
|
le->name_len, &le->id);
|
||||||
|
if (!attr) {
|
||||||
|
/* Should never happened, 'cause already checked. */
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
asize = le32_to_cpu(attr->size);
|
asize = le32_to_cpu(attr->size);
|
||||||
|
|
||||||
/* Insert into primary record. */
|
/* Insert into primary record. */
|
||||||
attr_ins = mi_insert_attr(&ni->mi, le->type, le_name(le),
|
attr_ins = mi_insert_attr(&ni->mi, le->type, le_name(le),
|
||||||
le->name_len, asize,
|
le->name_len, asize,
|
||||||
le16_to_cpu(attr->name_off));
|
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. */
|
/* Copy all except id. */
|
||||||
|
id = attr_ins->id;
|
||||||
memcpy(attr_ins, attr, asize);
|
memcpy(attr_ins, attr, asize);
|
||||||
attr_ins->id = id;
|
attr_ins->id = id;
|
||||||
|
|
||||||
@@ -735,6 +749,10 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
|
|||||||
ni->attr_list.dirty = false;
|
ni->attr_list.dirty = false;
|
||||||
|
|
||||||
return 0;
|
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;
|
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. */
|
/* Try to insert attribute into this subrecord. */
|
||||||
attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
|
attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
|
||||||
name_off, svcn, ins_le);
|
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;
|
attr->res.flags = RESIDENT_FLAG_INDEXED;
|
||||||
|
|
||||||
/* is_attr_indexed(attr)) == true */
|
/* 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;
|
ni->mi.dirty = true;
|
||||||
}
|
}
|
||||||
attr->res.res = 0;
|
attr->res.res = 0;
|
||||||
@@ -1606,7 +1631,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
|
|||||||
|
|
||||||
*le = NULL;
|
*le = NULL;
|
||||||
|
|
||||||
if (FILE_NAME_POSIX == name_type)
|
if (name_type == FILE_NAME_POSIX)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Enumerate all names. */
|
/* Enumerate all names. */
|
||||||
@@ -1706,18 +1731,16 @@ out:
|
|||||||
/*
|
/*
|
||||||
* ni_parse_reparse
|
* 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,
|
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;
|
const struct REPARSE_DATA_BUFFER *rp = NULL;
|
||||||
u8 bits;
|
u8 bits;
|
||||||
u16 len;
|
u16 len;
|
||||||
typeof(rp->CompressReparseBuffer) *cmpr;
|
typeof(rp->CompressReparseBuffer) *cmpr;
|
||||||
|
|
||||||
static_assert(sizeof(struct REPARSE_DATA_BUFFER) <= 24);
|
|
||||||
|
|
||||||
/* Try to estimate reparse point. */
|
/* Try to estimate reparse point. */
|
||||||
if (!attr->non_res) {
|
if (!attr->non_res) {
|
||||||
rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER));
|
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;
|
return REPARSE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buffer != rp)
|
||||||
|
memcpy(buffer, rp, sizeof(struct REPARSE_DATA_BUFFER));
|
||||||
|
|
||||||
/* Looks like normal symlink. */
|
/* Looks like normal symlink. */
|
||||||
return REPARSE_LINK;
|
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);
|
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
|
||||||
mi_get_ref(&ni->mi, &de->ref);
|
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 false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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;
|
const struct EA_INFO *info;
|
||||||
|
|
||||||
info = resident_data_ex(attr, sizeof(struct EA_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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = al_update(ni);
|
err = al_update(ni, sync);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/buffer_head.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/hash.h>
|
|
||||||
#include <linux/nls.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/ratelimit.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -2219,7 +2215,7 @@ file_is_valid:
|
|||||||
|
|
||||||
err = ntfs_sb_write_run(log->ni->mi.sbi,
|
err = ntfs_sb_write_run(log->ni->mi.sbi,
|
||||||
&log->ni->file.run, off, page,
|
&log->ni->file.run, off, page,
|
||||||
log->page_size);
|
log->page_size, 0);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -3710,7 +3706,7 @@ move_data:
|
|||||||
|
|
||||||
if (a_dirty) {
|
if (a_dirty) {
|
||||||
attr = oa->attr;
|
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)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -5152,10 +5148,10 @@ end_reply:
|
|||||||
|
|
||||||
ntfs_fix_pre_write(&rh->rhdr, log->page_size);
|
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)
|
if (!err)
|
||||||
err = ntfs_sb_write_run(sbi, &log->ni->file.run, log->page_size,
|
err = ntfs_sb_write_run(sbi, &log->ni->file.run, log->page_size,
|
||||||
rh, log->page_size);
|
rh, log->page_size, 0);
|
||||||
|
|
||||||
kfree(rh);
|
kfree(rh);
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.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)
|
enum ALLOCATE_OPT opt)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
CLST alen = 0;
|
CLST alen;
|
||||||
struct super_block *sb = sbi->sb;
|
struct super_block *sb = sbi->sb;
|
||||||
size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
|
size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
|
||||||
struct wnd_bitmap *wnd = &sbi->used.bitmap;
|
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) {
|
if (!zlen) {
|
||||||
err = ntfs_refresh_zone(sbi);
|
err = ntfs_refresh_zone(sbi);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto up_write;
|
||||||
|
|
||||||
zlen = wnd_zone_len(wnd);
|
zlen = wnd_zone_len(wnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!zlen) {
|
if (!zlen) {
|
||||||
ntfs_err(sbi->sb, "no free space to extend mft");
|
ntfs_err(sbi->sb, "no free space to extend mft");
|
||||||
goto out;
|
err = -ENOSPC;
|
||||||
|
goto up_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
lcn = wnd_zone_bit(wnd);
|
lcn = wnd_zone_bit(wnd);
|
||||||
alen = zlen > len ? len : zlen;
|
alen = min_t(CLST, len, zlen);
|
||||||
|
|
||||||
wnd_zone_set(wnd, lcn + alen, zlen - alen);
|
wnd_zone_set(wnd, lcn + alen, zlen - alen);
|
||||||
|
|
||||||
err = wnd_set_used(wnd, lcn, alen);
|
err = wnd_set_used(wnd, lcn, alen);
|
||||||
if (err) {
|
if (err)
|
||||||
up_write(&wnd->rw_lock);
|
goto up_write;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
alcn = lcn;
|
alcn = lcn;
|
||||||
goto out;
|
goto space_found;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* 'Cause cluster 0 is always used this value means that we should use
|
* '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);
|
alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
|
||||||
if (alen)
|
if (alen)
|
||||||
goto out;
|
goto space_found;
|
||||||
|
|
||||||
/* Try to use clusters from MftZone. */
|
/* Try to use clusters from MftZone. */
|
||||||
zlen = wnd_zone_len(wnd);
|
zlen = wnd_zone_len(wnd);
|
||||||
zeroes = wnd_zeroes(wnd);
|
zeroes = wnd_zeroes(wnd);
|
||||||
|
|
||||||
/* Check too big request */
|
/* Check too big request */
|
||||||
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE)
|
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) {
|
||||||
goto out;
|
err = -ENOSPC;
|
||||||
|
goto up_write;
|
||||||
|
}
|
||||||
|
|
||||||
/* How many clusters to cat from zone. */
|
/* How many clusters to cat from zone. */
|
||||||
zlcn = wnd_zone_bit(wnd);
|
zlcn = wnd_zone_bit(wnd);
|
||||||
zlen2 = zlen >> 1;
|
zlen2 = zlen >> 1;
|
||||||
ztrim = len > zlen ? zlen : (len > zlen2 ? len : zlen2);
|
ztrim = clamp_val(len, zlen2, zlen);
|
||||||
new_zlen = zlen - ztrim;
|
new_zlen = max_t(size_t, zlen - ztrim, NTFS_MIN_MFT_ZONE);
|
||||||
|
|
||||||
if (new_zlen < NTFS_MIN_MFT_ZONE) {
|
|
||||||
new_zlen = NTFS_MIN_MFT_ZONE;
|
|
||||||
if (new_zlen > zlen)
|
|
||||||
new_zlen = zlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
wnd_zone_set(wnd, zlcn, new_zlen);
|
wnd_zone_set(wnd, zlcn, new_zlen);
|
||||||
|
|
||||||
/* Allocate continues clusters. */
|
/* Allocate continues clusters. */
|
||||||
alen = wnd_find(wnd, len, 0,
|
alen = wnd_find(wnd, len, 0,
|
||||||
BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
|
BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
|
||||||
|
if (!alen) {
|
||||||
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 {
|
|
||||||
err = -ENOSPC;
|
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);
|
up_write(&wnd->rw_lock);
|
||||||
return err;
|
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,
|
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;
|
struct super_block *sb = sbi->sb;
|
||||||
u8 cluster_bits = sbi->cluster_bits;
|
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;
|
len = ((u64)clen << cluster_bits) - off;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
u32 op = len < bytes ? len : bytes;
|
u32 op = min_t(u64, len, bytes);
|
||||||
int err = ntfs_sb_write(sb, lbo, op, buf, 0);
|
int err = ntfs_sb_write(sb, lbo, op, buf, sync);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return 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);
|
nb->off = off = lbo & (blocksize - 1);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
u32 len32 = len < bytes ? len : bytes;
|
u32 len32 = min_t(u64, len, bytes);
|
||||||
sector_t block = lbo >> sb->s_blocksize_bits;
|
sector_t block = lbo >> sb->s_blocksize_bits;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@@ -2175,7 +2172,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
|
|||||||
|
|
||||||
/* Write main SDS bucket. */
|
/* Write main SDS bucket. */
|
||||||
err = ntfs_sb_write_run(sbi, &ni->file.run, sbi->security.next_off,
|
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)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -2193,7 +2190,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
|
|||||||
|
|
||||||
/* Write copy SDS bucket. */
|
/* Write copy SDS bucket. */
|
||||||
err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security,
|
err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security,
|
||||||
aligned_sec_size);
|
aligned_sec_size, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
166
fs/ntfs3/index.c
166
fs/ntfs3/index.c
@@ -8,7 +8,7 @@
|
|||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.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,
|
const struct INDEX_HDR *hdr, const void *key,
|
||||||
size_t key_len, const void *ctx, int *diff)
|
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;
|
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 e_size, e_key_len;
|
||||||
u32 end = le32_to_cpu(hdr->used);
|
u32 end = le32_to_cpu(hdr->used);
|
||||||
u32 off = le32_to_cpu(hdr->de_off);
|
u32 off = le32_to_cpu(hdr->de_off);
|
||||||
|
u16 offs[128];
|
||||||
|
|
||||||
#ifdef NTFS3_INDEX_BINARY_SEARCH
|
fill_table:
|
||||||
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.
|
|
||||||
*/
|
|
||||||
if (off + sizeof(struct NTFS_DE) > end)
|
if (off + sizeof(struct NTFS_DE) > end)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -787,22 +691,54 @@ next:
|
|||||||
if (e_size < sizeof(struct NTFS_DE) || off + e_size > end)
|
if (e_size < sizeof(struct NTFS_DE) || off + e_size > end)
|
||||||
return NULL;
|
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);
|
e_key_len = le16_to_cpu(e->key_size);
|
||||||
|
|
||||||
*diff = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
|
diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
|
||||||
if (!*diff)
|
if (diff2 > 0) {
|
||||||
return e;
|
if (found) {
|
||||||
|
min_idx = mid_idx + 1;
|
||||||
|
} else {
|
||||||
|
if (de_is_last(e))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (*diff <= 0)
|
max_idx = 0;
|
||||||
return e;
|
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)) {
|
found = e;
|
||||||
*diff = 1;
|
} else {
|
||||||
|
*diff = 0;
|
||||||
return e;
|
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)
|
if (!e)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (fnd)
|
fnd->root_de = e;
|
||||||
fnd->root_de = e;
|
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -1401,7 +1335,7 @@ ok:
|
|||||||
static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
|
||||||
CLST *vbn)
|
CLST *vbn)
|
||||||
{
|
{
|
||||||
int err = -ENOMEM;
|
int err;
|
||||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||||
struct ATTRIB *bitmap;
|
struct ATTRIB *bitmap;
|
||||||
struct ATTRIB *alloc;
|
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/buffer_head.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/iversion.h>
|
|
||||||
#include <linux/mpage.h>
|
#include <linux/mpage.h>
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
@@ -49,8 +47,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
|
|||||||
|
|
||||||
inode->i_op = NULL;
|
inode->i_op = NULL;
|
||||||
/* Setup 'uid' and 'gid' */
|
/* Setup 'uid' and 'gid' */
|
||||||
inode->i_uid = sbi->options.fs_uid;
|
inode->i_uid = sbi->options->fs_uid;
|
||||||
inode->i_gid = sbi->options.fs_gid;
|
inode->i_gid = sbi->options->fs_gid;
|
||||||
|
|
||||||
err = mi_init(&ni->mi, sbi, ino);
|
err = mi_init(&ni->mi, sbi, ino);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -224,12 +222,9 @@ next_attr:
|
|||||||
if (!attr->non_res) {
|
if (!attr->non_res) {
|
||||||
ni->i_valid = inode->i_size = rsize;
|
ni->i_valid = inode->i_size = rsize;
|
||||||
inode_set_bytes(inode, 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) {
|
if (!attr->non_res) {
|
||||||
ni->ni_flags |= NI_FLAG_RESIDENT;
|
ni->ni_flags |= NI_FLAG_RESIDENT;
|
||||||
@@ -272,7 +267,7 @@ next_attr:
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
mode = sb->s_root
|
mode = sb->s_root
|
||||||
? (S_IFDIR | (0777 & sbi->options.fs_dmask_inv))
|
? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv))
|
||||||
: (S_IFDIR | 0777);
|
: (S_IFDIR | 0777);
|
||||||
goto next_attr;
|
goto next_attr;
|
||||||
|
|
||||||
@@ -315,17 +310,14 @@ next_attr:
|
|||||||
rp_fa = ni_parse_reparse(ni, attr, &rp);
|
rp_fa = ni_parse_reparse(ni, attr, &rp);
|
||||||
switch (rp_fa) {
|
switch (rp_fa) {
|
||||||
case REPARSE_LINK:
|
case REPARSE_LINK:
|
||||||
if (!attr->non_res) {
|
/*
|
||||||
inode->i_size = rsize;
|
* Normal symlink.
|
||||||
inode_set_bytes(inode, rsize);
|
* Assume one unicode symbol == one utf8.
|
||||||
t32 = asize;
|
*/
|
||||||
} else {
|
inode->i_size = le16_to_cpu(rp.SymbolicLinkReparseBuffer
|
||||||
inode->i_size =
|
.PrintNameLength) /
|
||||||
le64_to_cpu(attr->nres.data_size);
|
sizeof(u16);
|
||||||
t32 = le16_to_cpu(attr->nres.run_off);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Looks like normal symlink. */
|
|
||||||
ni->i_valid = inode->i_size;
|
ni->i_valid = inode->i_size;
|
||||||
|
|
||||||
/* Clear directory bit. */
|
/* Clear directory bit. */
|
||||||
@@ -422,7 +414,7 @@ end_enum:
|
|||||||
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
||||||
inode->i_op = &ntfs_link_inode_operations;
|
inode->i_op = &ntfs_link_inode_operations;
|
||||||
inode->i_fop = NULL;
|
inode->i_fop = NULL;
|
||||||
inode_nohighmem(inode); // ??
|
inode_nohighmem(inode);
|
||||||
} else if (S_ISREG(mode)) {
|
} else if (S_ISREG(mode)) {
|
||||||
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
|
||||||
inode->i_op = &ntfs_file_inode_operations;
|
inode->i_op = &ntfs_file_inode_operations;
|
||||||
@@ -443,7 +435,7 @@ end_enum:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sbi->options.sys_immutable &&
|
if ((sbi->options->sys_immutable &&
|
||||||
(std5->fa & FILE_ATTRIBUTE_SYSTEM)) &&
|
(std5->fa & FILE_ATTRIBUTE_SYSTEM)) &&
|
||||||
!S_ISFIFO(mode) && !S_ISSOCK(mode) && !S_ISLNK(mode)) {
|
!S_ISFIFO(mode) && !S_ISSOCK(mode) && !S_ISLNK(mode)) {
|
||||||
inode->i_flags |= S_IMMUTABLE;
|
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;
|
struct REPARSE_DATA_BUFFER *rp = NULL;
|
||||||
bool rp_inserted = false;
|
bool rp_inserted = false;
|
||||||
|
|
||||||
|
ni_lock_dir(dir_ni);
|
||||||
|
|
||||||
dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
|
dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
|
||||||
if (!dir_root)
|
if (!dir_root) {
|
||||||
return ERR_PTR(-EINVAL);
|
err = -EINVAL;
|
||||||
|
goto out1;
|
||||||
|
}
|
||||||
|
|
||||||
if (S_ISDIR(mode)) {
|
if (S_ISDIR(mode)) {
|
||||||
/* Use parent's directory attributes. */
|
/* Use parent's directory attributes. */
|
||||||
@@ -1244,7 +1240,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
} else if (S_ISREG(mode)) {
|
} else if (S_ISREG(mode)) {
|
||||||
if (sbi->options.sparse) {
|
if (sbi->options->sparse) {
|
||||||
/* Sparsed regular file, cause option 'sparse'. */
|
/* Sparsed regular file, cause option 'sparse'. */
|
||||||
fa = FILE_ATTRIBUTE_SPARSE_FILE |
|
fa = FILE_ATTRIBUTE_SPARSE_FILE |
|
||||||
FILE_ATTRIBUTE_ARCHIVE;
|
FILE_ATTRIBUTE_ARCHIVE;
|
||||||
@@ -1486,7 +1482,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
|||||||
asize = ALIGN(SIZEOF_RESIDENT + nsize, 8);
|
asize = ALIGN(SIZEOF_RESIDENT + nsize, 8);
|
||||||
t16 = PtrOffset(rec, attr);
|
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) {
|
if (asize + t16 + 0x78 + 8 > sbi->record_size) {
|
||||||
CLST alen;
|
CLST alen;
|
||||||
CLST clst = bytes_to_cluster(sbi, nsize);
|
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);
|
asize = SIZEOF_NONRESIDENT + ALIGN(err, 8);
|
||||||
inode->i_size = nsize;
|
|
||||||
} else {
|
} else {
|
||||||
attr->res.data_off = SIZEOF_RESIDENT_LE;
|
attr->res.data_off = SIZEOF_RESIDENT_LE;
|
||||||
attr->res.data_size = cpu_to_le32(nsize);
|
attr->res.data_size = cpu_to_le32(nsize);
|
||||||
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
|
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
|
||||||
inode->i_size = nsize;
|
|
||||||
nsize = 0;
|
nsize = 0;
|
||||||
}
|
}
|
||||||
|
/* Size of symlink equals the length of input string. */
|
||||||
|
inode->i_size = size;
|
||||||
|
|
||||||
attr->size = cpu_to_le32(asize);
|
attr->size = cpu_to_le32(asize);
|
||||||
|
|
||||||
@@ -1551,6 +1550,9 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
|||||||
if (err)
|
if (err)
|
||||||
goto out6;
|
goto out6;
|
||||||
|
|
||||||
|
/* Unlock parent directory before ntfs_init_acl. */
|
||||||
|
ni_unlock(dir_ni);
|
||||||
|
|
||||||
inode->i_generation = le16_to_cpu(rec->seq);
|
inode->i_generation = le16_to_cpu(rec->seq);
|
||||||
|
|
||||||
dir->i_mtime = dir->i_ctime = inode->i_atime;
|
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_op = &ntfs_link_inode_operations;
|
||||||
inode->i_fop = NULL;
|
inode->i_fop = NULL;
|
||||||
inode->i_mapping->a_ops = &ntfs_aops;
|
inode->i_mapping->a_ops = &ntfs_aops;
|
||||||
|
inode->i_size = size;
|
||||||
|
inode_nohighmem(inode);
|
||||||
} else if (S_ISREG(mode)) {
|
} else if (S_ISREG(mode)) {
|
||||||
inode->i_op = &ntfs_file_inode_operations;
|
inode->i_op = &ntfs_file_inode_operations;
|
||||||
inode->i_fop = &ntfs_file_operations;
|
inode->i_fop = &ntfs_file_operations;
|
||||||
@@ -1577,7 +1581,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
|||||||
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
|
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
|
||||||
err = ntfs_init_acl(mnt_userns, inode, dir);
|
err = ntfs_init_acl(mnt_userns, inode, dir);
|
||||||
if (err)
|
if (err)
|
||||||
goto out6;
|
goto out7;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
@@ -1586,7 +1590,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
|||||||
|
|
||||||
/* Write non resident data. */
|
/* Write non resident data. */
|
||||||
if (nsize) {
|
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)
|
if (err)
|
||||||
goto out7;
|
goto out7;
|
||||||
}
|
}
|
||||||
@@ -1607,8 +1611,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
|
|||||||
out7:
|
out7:
|
||||||
|
|
||||||
/* Undo 'indx_insert_entry'. */
|
/* Undo 'indx_insert_entry'. */
|
||||||
|
ni_lock_dir(dir_ni);
|
||||||
indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
|
indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
|
||||||
le16_to_cpu(new_de->key_size), sbi);
|
le16_to_cpu(new_de->key_size), sbi);
|
||||||
|
/* ni_unlock(dir_ni); will be called later. */
|
||||||
out6:
|
out6:
|
||||||
if (rp_inserted)
|
if (rp_inserted)
|
||||||
ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
|
ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
|
||||||
@@ -1632,8 +1638,10 @@ out2:
|
|||||||
kfree(rp);
|
kfree(rp);
|
||||||
|
|
||||||
out1:
|
out1:
|
||||||
if (err)
|
if (err) {
|
||||||
|
ni_unlock(dir_ni);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
unlock_new_inode(inode);
|
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,
|
static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
|
||||||
int buflen)
|
int buflen)
|
||||||
{
|
{
|
||||||
int i, err = 0;
|
int i, err = -EINVAL;
|
||||||
struct ntfs_inode *ni = ntfs_i(inode);
|
struct ntfs_inode *ni = ntfs_i(inode);
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
struct ntfs_sb_info *sbi = sb->s_fs_info;
|
||||||
u64 i_size = inode->i_size;
|
u64 size;
|
||||||
u16 nlen = 0;
|
u16 ulen = 0;
|
||||||
void *to_free = NULL;
|
void *to_free = NULL;
|
||||||
struct REPARSE_DATA_BUFFER *rp;
|
struct REPARSE_DATA_BUFFER *rp;
|
||||||
struct le_str *uni;
|
const __le16 *uname;
|
||||||
struct ATTRIB *attr;
|
struct ATTRIB *attr;
|
||||||
|
|
||||||
/* Reparse data present. Try to parse it. */
|
/* Reparse data present. Try to parse it. */
|
||||||
@@ -1771,68 +1779,64 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
|
|||||||
|
|
||||||
*buffer = 0;
|
*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);
|
attr = ni_find_attr(ni, NULL, NULL, ATTR_REPARSE, NULL, 0, NULL, NULL);
|
||||||
if (!attr) {
|
if (!attr)
|
||||||
err = -EINVAL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
if (!attr->non_res) {
|
if (!attr->non_res) {
|
||||||
rp = resident_data_ex(attr, i_size);
|
rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER));
|
||||||
if (!rp) {
|
if (!rp)
|
||||||
err = -EINVAL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
size = le32_to_cpu(attr->res.data_size);
|
||||||
} else {
|
} 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) {
|
if (!rp) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
to_free = rp;
|
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)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -EINVAL;
|
|
||||||
|
|
||||||
/* Microsoft Tag. */
|
/* Microsoft Tag. */
|
||||||
switch (rp->ReparseTag) {
|
switch (rp->ReparseTag) {
|
||||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||||
/* Mount points and junctions. */
|
/* Mount points and junctions. */
|
||||||
/* Can we use 'Rp->MountPointReparseBuffer.PrintNameLength'? */
|
/* Can we use 'Rp->MountPointReparseBuffer.PrintNameLength'? */
|
||||||
if (i_size <= offsetof(struct REPARSE_DATA_BUFFER,
|
if (size <= offsetof(struct REPARSE_DATA_BUFFER,
|
||||||
MountPointReparseBuffer.PathBuffer))
|
MountPointReparseBuffer.PathBuffer))
|
||||||
goto out;
|
goto out;
|
||||||
uni = Add2Ptr(rp,
|
uname = Add2Ptr(rp,
|
||||||
offsetof(struct REPARSE_DATA_BUFFER,
|
offsetof(struct REPARSE_DATA_BUFFER,
|
||||||
MountPointReparseBuffer.PathBuffer) +
|
MountPointReparseBuffer.PathBuffer) +
|
||||||
le16_to_cpu(rp->MountPointReparseBuffer
|
le16_to_cpu(rp->MountPointReparseBuffer
|
||||||
.PrintNameOffset) -
|
.PrintNameOffset));
|
||||||
2);
|
ulen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength);
|
||||||
nlen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_REPARSE_TAG_SYMLINK:
|
case IO_REPARSE_TAG_SYMLINK:
|
||||||
/* FolderSymbolicLink */
|
/* FolderSymbolicLink */
|
||||||
/* Can we use 'Rp->SymbolicLinkReparseBuffer.PrintNameLength'? */
|
/* Can we use 'Rp->SymbolicLinkReparseBuffer.PrintNameLength'? */
|
||||||
if (i_size <= offsetof(struct REPARSE_DATA_BUFFER,
|
if (size <= offsetof(struct REPARSE_DATA_BUFFER,
|
||||||
SymbolicLinkReparseBuffer.PathBuffer))
|
SymbolicLinkReparseBuffer.PathBuffer))
|
||||||
goto out;
|
goto out;
|
||||||
uni = Add2Ptr(rp,
|
uname = Add2Ptr(
|
||||||
offsetof(struct REPARSE_DATA_BUFFER,
|
rp, offsetof(struct REPARSE_DATA_BUFFER,
|
||||||
SymbolicLinkReparseBuffer.PathBuffer) +
|
SymbolicLinkReparseBuffer.PathBuffer) +
|
||||||
le16_to_cpu(rp->SymbolicLinkReparseBuffer
|
le16_to_cpu(rp->SymbolicLinkReparseBuffer
|
||||||
.PrintNameOffset) -
|
.PrintNameOffset));
|
||||||
2);
|
ulen = le16_to_cpu(
|
||||||
nlen = le16_to_cpu(
|
|
||||||
rp->SymbolicLinkReparseBuffer.PrintNameLength);
|
rp->SymbolicLinkReparseBuffer.PrintNameLength);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1864,29 +1868,28 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!IsReparseTagNameSurrogate(rp->ReparseTag) ||
|
if (!IsReparseTagNameSurrogate(rp->ReparseTag) ||
|
||||||
i_size <= sizeof(struct REPARSE_POINT)) {
|
size <= sizeof(struct REPARSE_POINT)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Users tag. */
|
/* Users tag. */
|
||||||
uni = Add2Ptr(rp, sizeof(struct REPARSE_POINT) - 2);
|
uname = Add2Ptr(rp, sizeof(struct REPARSE_POINT));
|
||||||
nlen = le16_to_cpu(rp->ReparseDataLength) -
|
ulen = le16_to_cpu(rp->ReparseDataLength) -
|
||||||
sizeof(struct REPARSE_POINT);
|
sizeof(struct REPARSE_POINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert nlen from bytes to UNICODE chars. */
|
/* Convert nlen from bytes to UNICODE chars. */
|
||||||
nlen >>= 1;
|
ulen >>= 1;
|
||||||
|
|
||||||
/* Check that name is available. */
|
/* 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;
|
goto out;
|
||||||
|
|
||||||
/* If name is already zero terminated then truncate it now. */
|
/* If name is already zero terminated then truncate it now. */
|
||||||
if (!uni->name[nlen - 1])
|
if (!uname[ulen - 1])
|
||||||
nlen -= 1;
|
ulen -= 1;
|
||||||
uni->len = nlen;
|
|
||||||
|
|
||||||
err = ntfs_utf16_to_nls(sbi, uni, buffer, buflen);
|
err = ntfs_utf16_to_nls(sbi, uname, ulen, buffer, buflen);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
* Copyright (C) 2015 Eric Biggers
|
* 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/string.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/types.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;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H */
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
* - linux kernel code style
|
* - 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 */
|
/* globals from xpress_decompress.c */
|
||||||
struct xpress_decompressor *xpress_allocate_decompressor(void);
|
struct xpress_decompressor *xpress_allocate_decompressor(void);
|
||||||
@@ -24,3 +28,5 @@ int lzx_decompress(struct lzx_decompressor *__restrict d,
|
|||||||
const void *__restrict compressed_data,
|
const void *__restrict compressed_data,
|
||||||
size_t compressed_size, void *__restrict uncompressed_data,
|
size_t compressed_size, void *__restrict uncompressed_data,
|
||||||
size_t uncompressed_size);
|
size_t uncompressed_size);
|
||||||
|
|
||||||
|
#endif /* _LINUX_NTFS3_LIB_LIB_H */
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/nls.h>
|
#include <linux/string.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.h"
|
|
||||||
#include "ntfs_fs.h"
|
#include "ntfs_fs.h"
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@@ -292,7 +292,7 @@ next:
|
|||||||
/*
|
/*
|
||||||
* get_lznt_ctx
|
* get_lznt_ctx
|
||||||
* @level: 0 - Standard compression.
|
* @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)
|
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/fs.h>
|
||||||
#include <linux/iversion.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
|
|
||||||
#include "debug.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,
|
static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||||
struct dentry *dentry, umode_t mode, bool excl)
|
struct dentry *dentry, umode_t mode, bool excl)
|
||||||
{
|
{
|
||||||
struct ntfs_inode *ni = ntfs_i(dir);
|
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
|
||||||
ni_lock_dir(ni);
|
|
||||||
|
|
||||||
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFREG | mode,
|
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFREG | mode,
|
||||||
0, NULL, 0, NULL);
|
0, NULL, 0, NULL);
|
||||||
|
|
||||||
ni_unlock(ni);
|
|
||||||
|
|
||||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
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,
|
static int ntfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||||
{
|
{
|
||||||
struct ntfs_inode *ni = ntfs_i(dir);
|
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
|
||||||
ni_lock_dir(ni);
|
|
||||||
|
|
||||||
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, mode, rdev,
|
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, mode, rdev,
|
||||||
NULL, 0, NULL);
|
NULL, 0, NULL);
|
||||||
|
|
||||||
ni_unlock(ni);
|
|
||||||
|
|
||||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
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);
|
u32 size = strlen(symname);
|
||||||
struct inode *inode;
|
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,
|
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFLNK | 0777,
|
||||||
0, symname, size, NULL);
|
0, symname, size, NULL);
|
||||||
|
|
||||||
ni_unlock(ni);
|
|
||||||
|
|
||||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
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 dentry *dentry, umode_t mode)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
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,
|
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFDIR | mode,
|
||||||
0, NULL, 0, NULL);
|
0, NULL, 0, NULL);
|
||||||
|
|
||||||
ni_unlock(ni);
|
|
||||||
|
|
||||||
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,19 +10,27 @@
|
|||||||
#ifndef _LINUX_NTFS3_NTFS_H
|
#ifndef _LINUX_NTFS3_NTFS_H
|
||||||
#define _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. */
|
#include "debug.h"
|
||||||
#define NTFS3_INDEX_BINARY_SEARCH
|
|
||||||
|
/* TODO: Check 4K MFT record and 512 bytes cluster. */
|
||||||
|
|
||||||
/* Check each run for marked clusters. */
|
/* Check each run for marked clusters. */
|
||||||
#define NTFS3_CHECK_FREE_CLST
|
#define NTFS3_CHECK_FREE_CLST
|
||||||
|
|
||||||
#define NTFS_NAME_LEN 255
|
#define NTFS_NAME_LEN 255
|
||||||
|
|
||||||
/* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff. */
|
/*
|
||||||
#define NTFS_LINK_MAX 0x400
|
* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff.
|
||||||
//#define NTFS_LINK_MAX 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.
|
* Activate to use 64 bit clusters instead of 32 bits in ntfs.sys.
|
||||||
|
|||||||
@@ -9,6 +9,37 @@
|
|||||||
#ifndef _LINUX_NTFS3_NTFS_FS_H
|
#ifndef _LINUX_NTFS3_NTFS_FS_H
|
||||||
#define _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))
|
#define MINUS_ONE_T ((size_t)(-1))
|
||||||
/* Biggest MFT / smallest cluster */
|
/* Biggest MFT / smallest cluster */
|
||||||
#define MAXIMUM_BYTES_PER_MFT 4096
|
#define MAXIMUM_BYTES_PER_MFT 4096
|
||||||
@@ -52,6 +83,7 @@
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
struct ntfs_mount_options {
|
struct ntfs_mount_options {
|
||||||
|
char *nls_name;
|
||||||
struct nls_table *nls;
|
struct nls_table *nls;
|
||||||
|
|
||||||
kuid_t fs_uid;
|
kuid_t fs_uid;
|
||||||
@@ -59,19 +91,16 @@ struct ntfs_mount_options {
|
|||||||
u16 fs_fmask_inv;
|
u16 fs_fmask_inv;
|
||||||
u16 fs_dmask_inv;
|
u16 fs_dmask_inv;
|
||||||
|
|
||||||
unsigned uid : 1, /* uid was set. */
|
unsigned fmask : 1; /* fmask was set. */
|
||||||
gid : 1, /* gid was set. */
|
unsigned dmask : 1; /*dmask was set. */
|
||||||
fmask : 1, /* fmask was set. */
|
unsigned sys_immutable : 1; /* Immutable system files. */
|
||||||
dmask : 1, /* dmask was set. */
|
unsigned discard : 1; /* Issue discard requests on deletions. */
|
||||||
sys_immutable : 1, /* Immutable system files. */
|
unsigned sparse : 1; /* Create sparse files. */
|
||||||
discard : 1, /* Issue discard requests on deletions. */
|
unsigned showmeta : 1; /* Show meta files. */
|
||||||
sparse : 1, /* Create sparse files. */
|
unsigned nohidden : 1; /* Do not show hidden files. */
|
||||||
showmeta : 1, /* Show meta files. */
|
unsigned force : 1; /* RW mount dirty volume. */
|
||||||
nohidden : 1, /* Do not show hidden files. */
|
unsigned noacsrules : 1; /* Exclude acs rules. */
|
||||||
force : 1, /* Rw mount dirty volume. */
|
unsigned prealloc : 1; /* Preallocate space when file is growing. */
|
||||||
no_acs_rules : 1, /*Exclude acs rules. */
|
|
||||||
prealloc : 1 /* Preallocate space when file is growing. */
|
|
||||||
;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Special value to unpack and deallocate. */
|
/* Special value to unpack and deallocate. */
|
||||||
@@ -182,10 +211,8 @@ struct ntfs_sb_info {
|
|||||||
u32 blocks_per_cluster; // cluster_size / sb->s_blocksize
|
u32 blocks_per_cluster; // cluster_size / sb->s_blocksize
|
||||||
|
|
||||||
u32 record_size;
|
u32 record_size;
|
||||||
u32 sector_size;
|
|
||||||
u32 index_size;
|
u32 index_size;
|
||||||
|
|
||||||
u8 sector_bits;
|
|
||||||
u8 cluster_bits;
|
u8 cluster_bits;
|
||||||
u8 record_bits;
|
u8 record_bits;
|
||||||
|
|
||||||
@@ -279,7 +306,7 @@ struct ntfs_sb_info {
|
|||||||
#endif
|
#endif
|
||||||
} compress;
|
} compress;
|
||||||
|
|
||||||
struct ntfs_mount_options options;
|
struct ntfs_mount_options *options;
|
||||||
struct ratelimit_state msg_ratelimit;
|
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,
|
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
|
||||||
const __le16 *name, size_t name_len,
|
const __le16 *name, size_t name_len,
|
||||||
const struct MFT_REF *ref);
|
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)
|
static inline size_t al_aligned(size_t size)
|
||||||
{
|
{
|
||||||
return (size + 1023) & ~(size_t)1023;
|
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);
|
size_t get_set_bits_ex(const ulong *map, size_t bit, size_t nbits);
|
||||||
|
|
||||||
/* Globals from dir.c */
|
/* 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);
|
u8 *buf, int buf_len);
|
||||||
int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
|
int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
|
||||||
struct cpu_str *uni, u32 max_ulen,
|
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);
|
struct ATTR_LIST_ENTRY **entry);
|
||||||
int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa);
|
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,
|
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);
|
int ni_write_inode(struct inode *inode, int sync, const char *hint);
|
||||||
#define _ni_write_inode(i, w) ni_write_inode(i, w, __func__)
|
#define _ni_write_inode(i, w) ni_write_inode(i, w, __func__)
|
||||||
int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
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,
|
int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
|
||||||
const void *buffer, int wait);
|
const void *buffer, int wait);
|
||||||
int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
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,
|
struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
|
||||||
const struct runs_tree *run, u64 vbo);
|
const struct runs_tree *run, u64 vbo);
|
||||||
int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
|
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/fs.h>
|
||||||
#include <linux/nls.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.h"
|
#include "ntfs.h"
|
||||||
|
|||||||
@@ -7,10 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/buffer_head.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
#include <linux/nls.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "ntfs.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/kernel.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/types.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/nls.h>
|
|
||||||
|
|
||||||
#include "debug.h"
|
|
||||||
#include "ntfs.h"
|
|
||||||
#include "ntfs_fs.h"
|
#include "ntfs_fs.h"
|
||||||
|
|
||||||
static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)
|
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/fs.h>
|
||||||
#include <linux/nls.h>
|
|
||||||
#include <linux/posix_acl.h>
|
#include <linux/posix_acl.h>
|
||||||
#include <linux/posix_acl_xattr.h>
|
#include <linux/posix_acl_xattr.h>
|
||||||
#include <linux/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)
|
size_t add_bytes, const struct EA_INFO **info)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||||
struct ATTR_LIST_ENTRY *le = NULL;
|
struct ATTR_LIST_ENTRY *le = NULL;
|
||||||
struct ATTRIB *attr_info, *attr_ea;
|
struct ATTRIB *attr_info, *attr_ea;
|
||||||
void *ea_p;
|
void *ea_p;
|
||||||
@@ -102,10 +100,10 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
|
|||||||
|
|
||||||
/* Check Ea limit. */
|
/* Check Ea limit. */
|
||||||
size = le32_to_cpu((*info)->size);
|
size = le32_to_cpu((*info)->size);
|
||||||
if (size > ni->mi.sbi->ea_max_size)
|
if (size > sbi->ea_max_size)
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
|
|
||||||
if (attr_size(attr_ea) > ni->mi.sbi->ea_max_size)
|
if (attr_size(attr_ea) > sbi->ea_max_size)
|
||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
|
|
||||||
/* Allocate memory for packed Ea. */
|
/* 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)
|
if (!ea_p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (attr_ea->non_res) {
|
if (!size) {
|
||||||
|
;
|
||||||
|
} else if (attr_ea->non_res) {
|
||||||
struct runs_tree run;
|
struct runs_tree run;
|
||||||
|
|
||||||
run_init(&run);
|
run_init(&run);
|
||||||
|
|
||||||
err = attr_load_runs(attr_ea, ni, &run, NULL);
|
err = attr_load_runs(attr_ea, ni, &run, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = ntfs_read_run_nb(ni->mi.sbi, &run, 0, ea_p, size,
|
err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
|
||||||
NULL);
|
|
||||||
run_close(&run);
|
run_close(&run);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
@@ -260,7 +259,7 @@ out:
|
|||||||
|
|
||||||
static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
||||||
size_t name_len, const void *value,
|
size_t name_len, const void *value,
|
||||||
size_t val_size, int flags, int locked)
|
size_t val_size, int flags)
|
||||||
{
|
{
|
||||||
struct ntfs_inode *ni = ntfs_i(inode);
|
struct ntfs_inode *ni = ntfs_i(inode);
|
||||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||||
@@ -279,8 +278,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
|
|||||||
u64 new_sz;
|
u64 new_sz;
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
if (!locked)
|
ni_lock(ni);
|
||||||
ni_lock(ni);
|
|
||||||
|
|
||||||
run_init(&ea_run);
|
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;
|
new_ea->name[name_len] = 0;
|
||||||
memcpy(new_ea->name + name_len + 1, value, val_size);
|
memcpy(new_ea->name + name_len + 1, value, val_size);
|
||||||
new_pack = le16_to_cpu(ea_info.size_pack) + packed_ea_size(new_ea);
|
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);
|
ea_info.size_pack = cpu_to_le16(new_pack);
|
||||||
|
|
||||||
/* New size of ATTR_EA. */
|
/* New size of ATTR_EA. */
|
||||||
size += add;
|
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?
|
err = -EFBIG; // -EINVAL?
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ea_info.size = cpu_to_le32(size);
|
|
||||||
|
|
||||||
update_ea:
|
update_ea:
|
||||||
|
|
||||||
@@ -444,7 +443,7 @@ update_ea:
|
|||||||
/* Delete xattr, ATTR_EA */
|
/* Delete xattr, ATTR_EA */
|
||||||
ni_remove_attr_le(ni, attr, mi, le);
|
ni_remove_attr_le(ni, attr, mi, le);
|
||||||
} else if (attr->non_res) {
|
} 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)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
@@ -468,8 +467,7 @@ update_ea:
|
|||||||
mark_inode_dirty(&ni->vfs_inode);
|
mark_inode_dirty(&ni->vfs_inode);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (!locked)
|
ni_unlock(ni);
|
||||||
ni_unlock(ni);
|
|
||||||
|
|
||||||
run_close(&ea_run);
|
run_close(&ea_run);
|
||||||
kfree(ea_all);
|
kfree(ea_all);
|
||||||
@@ -478,12 +476,6 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
|
#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,
|
static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
|
||||||
struct inode *inode, int type,
|
struct inode *inode, int type,
|
||||||
int locked)
|
int locked)
|
||||||
@@ -521,12 +513,15 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
|
|||||||
/* Translate extended attribute to acl. */
|
/* Translate extended attribute to acl. */
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
acl = posix_acl_from_xattr(mnt_userns, buf, err);
|
acl = posix_acl_from_xattr(mnt_userns, buf, err);
|
||||||
if (!IS_ERR(acl))
|
} else if (err == -ENODATA) {
|
||||||
set_cached_acl(inode, type, acl);
|
acl = NULL;
|
||||||
} else {
|
} else {
|
||||||
acl = err == -ENODATA ? NULL : ERR_PTR(err);
|
acl = ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IS_ERR(acl))
|
||||||
|
set_cached_acl(inode, type, acl);
|
||||||
|
|
||||||
__putname(buf);
|
__putname(buf);
|
||||||
|
|
||||||
return acl;
|
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,
|
static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
|
||||||
struct inode *inode, struct posix_acl *acl,
|
struct inode *inode, struct posix_acl *acl,
|
||||||
int type, int locked)
|
int type)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
size_t size, name_len;
|
size_t size, name_len;
|
||||||
void *value = NULL;
|
void *value = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
int flags;
|
||||||
|
|
||||||
if (S_ISLNK(inode->i_mode))
|
if (S_ISLNK(inode->i_mode))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
@@ -561,22 +557,15 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
|
|||||||
if (acl) {
|
if (acl) {
|
||||||
umode_t mode = inode->i_mode;
|
umode_t mode = inode->i_mode;
|
||||||
|
|
||||||
err = posix_acl_equiv_mode(acl, &mode);
|
err = posix_acl_update_mode(mnt_userns, inode, &mode,
|
||||||
if (err < 0)
|
&acl);
|
||||||
return err;
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (inode->i_mode != mode) {
|
if (inode->i_mode != mode) {
|
||||||
inode->i_mode = mode;
|
inode->i_mode = mode;
|
||||||
mark_inode_dirty(inode);
|
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 = XATTR_NAME_POSIX_ACL_ACCESS;
|
||||||
name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1;
|
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) {
|
if (!acl) {
|
||||||
|
/* Remove xattr if it can be presented via mode. */
|
||||||
size = 0;
|
size = 0;
|
||||||
value = NULL;
|
value = NULL;
|
||||||
|
flags = XATTR_REPLACE;
|
||||||
} else {
|
} else {
|
||||||
size = posix_acl_xattr_size(acl->a_count);
|
size = posix_acl_xattr_size(acl->a_count);
|
||||||
value = kmalloc(size, GFP_NOFS);
|
value = kmalloc(size, GFP_NOFS);
|
||||||
if (!value)
|
if (!value)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = posix_acl_to_xattr(mnt_userns, acl, value, size);
|
err = posix_acl_to_xattr(mnt_userns, acl, value, size);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
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)
|
if (!err)
|
||||||
set_cached_acl(inode, type, acl);
|
set_cached_acl(inode, type, acl);
|
||||||
|
|
||||||
@@ -623,68 +616,7 @@ out:
|
|||||||
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
||||||
struct posix_acl *acl, int type)
|
struct posix_acl *acl, int type)
|
||||||
{
|
{
|
||||||
return ntfs_set_acl_ex(mnt_userns, inode, acl, type, 0);
|
return ntfs_set_acl_ex(mnt_userns, inode, acl, type);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -698,54 +630,27 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
|
|||||||
struct posix_acl *default_acl, *acl;
|
struct posix_acl *default_acl, *acl;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/*
|
err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
|
||||||
* TODO: Refactoring lock.
|
if (err)
|
||||||
* ni_lock(dir) ... -> posix_acl_create(dir,...) -> ntfs_get_acl -> ni_lock(dir)
|
return err;
|
||||||
*/
|
|
||||||
inode->i_default_acl = NULL;
|
|
||||||
|
|
||||||
default_acl = ntfs_get_acl_ex(mnt_userns, dir, ACL_TYPE_DEFAULT, 1);
|
if (default_acl) {
|
||||||
|
|
||||||
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)
|
|
||||||
err = ntfs_set_acl_ex(mnt_userns, inode, 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)
|
if (!acl)
|
||||||
inode->i_acl = NULL;
|
inode->i_acl = NULL;
|
||||||
else if (!err)
|
else {
|
||||||
err = ntfs_set_acl_ex(mnt_userns, inode, acl, ACL_TYPE_ACCESS,
|
if (!err)
|
||||||
1);
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
#endif
|
#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 ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
|
||||||
int mask)
|
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. */
|
/* "No access rules" mode - Allow all changes. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -880,23 +785,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
|
|||||||
goto out;
|
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. */
|
/* Deal with NTFS extended attribute. */
|
||||||
err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
|
err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
|
||||||
|
|
||||||
@@ -1009,24 +897,8 @@ set_new_fa:
|
|||||||
goto out;
|
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. */
|
/* 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:
|
out:
|
||||||
return err;
|
return err;
|
||||||
@@ -1042,28 +914,29 @@ int ntfs_save_wsl_perm(struct inode *inode)
|
|||||||
int err;
|
int err;
|
||||||
__le32 value;
|
__le32 value;
|
||||||
|
|
||||||
|
/* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */
|
||||||
value = cpu_to_le32(i_uid_read(inode));
|
value = cpu_to_le32(i_uid_read(inode));
|
||||||
err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
|
err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
|
||||||
sizeof(value), 0, 0);
|
sizeof(value), 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
value = cpu_to_le32(i_gid_read(inode));
|
value = cpu_to_le32(i_gid_read(inode));
|
||||||
err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
|
err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
|
||||||
sizeof(value), 0, 0);
|
sizeof(value), 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
value = cpu_to_le32(inode->i_mode);
|
value = cpu_to_le32(inode->i_mode);
|
||||||
err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
|
err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
|
||||||
sizeof(value), 0, 0);
|
sizeof(value), 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
||||||
value = cpu_to_le32(inode->i_rdev);
|
value = cpu_to_le32(inode->i_rdev);
|
||||||
err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
|
err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
|
||||||
sizeof(value), 0, 0);
|
sizeof(value), 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user