Fixed xfstests generic/016 generic/021 generic/022 generic/041 generic/274 generic/423,

some memory leaks and panic. Also many minor fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmFoMFQACgkQqbAzH4Mk
 B7bTtQ/+KiF48deefbEEExjfT8Mm76+JE0XkdCPT0bXkhVNpqhRLSOQBR2hg5A81
 7SSFHNbSMzXxiXdh2KfcXbBmwdJtcH1N9tjwffC3zhMkCTcDKnmDczz/lo4rHd0g
 zZ3rPBP9yPCZGxo3W804XRYOeqLclrGJPI3kWQen+Rln/cZIzJMaHRUkVI22OYwj
 e0dSdtabFDxJbdewz9xcvycHrPpVlrZUsuib/ZHFu2XGtgKalccgfvwBy5cOrTVh
 N1WSBGcoy0xQGRGLP0o2hN62N2Md7/+UwWjXY+Wz4i+4gmziGvGuk8Y5uiSLu7lS
 EG12xlrUtwouf4QaeleQZLT9Ym5YU3EALtKpZxAQi6Rm4A8Z6EMNUq0WBHJcNP/u
 MRJlfK7jC25GnIFQjZtU+eMX8BT8MgMeSriv9FIY86T3ijedfxxEbb/cMvUGm2Hn
 3hoQelLCUkLSqTyMeZiAv507AJv5MjfMrSJ9r9f36OxDer3w84VCVcxDtyGH++CR
 fbRNjHvz7gYG5L5qwsFgfxSC/z+hyUXi01RalbosojsRyvg/f1p+yMxvQ57DrltY
 IfHrMGcd9FlUiijBGFvyWQoMAl/pb6EIym2IMxr9X+aXgPJiG/BhWLbmzU4MYUUP
 1PwIOpN2vhtU2Z3bVzbecxfy/TWjBhKBYe9jW1AH8KSSvLZExjk=
 =QUnM
 -----END PGP SIGNATURE-----

Merge tag 'ntfs3_for_5.15' of git://github.com/Paragon-Software-Group/linux-ntfs3

Pull ntfs3 fixes from Konstantin Komarov:
 "Use the new api for mounting as requested by Christoph.

  Also fixed:

   - some memory leaks and panic

   - xfstests (tested on x86_64) generic/016 generic/021 generic/022
     generic/041 generic/274 generic/423

   - some typos, wrong returned error codes, dead code, etc"

* tag 'ntfs3_for_5.15' of git://github.com/Paragon-Software-Group/linux-ntfs3: (70 commits)
  fs/ntfs3: Check for NULL pointers in ni_try_remove_attr_list
  fs/ntfs3: Refactor ntfs_read_mft
  fs/ntfs3: Refactor ni_parse_reparse
  fs/ntfs3: Refactor ntfs_create_inode
  fs/ntfs3: Refactor ntfs_readlink_hlp
  fs/ntfs3: Rework ntfs_utf16_to_nls
  fs/ntfs3: Fix memory leak if fill_super failed
  fs/ntfs3: Keep prealloc for all types of files
  fs/ntfs3: Remove unnecessary functions
  fs/ntfs3: Forbid FALLOC_FL_PUNCH_HOLE for normal files
  fs/ntfs3: Refactoring of ntfs_set_ea
  fs/ntfs3: Remove locked argument in ntfs_set_ea
  fs/ntfs3: Use available posix_acl_release instead of ntfs_posix_acl_release
  fs/ntfs3: Check for NULL if ATTR_EA_INFO is incorrect
  fs/ntfs3: Refactoring of ntfs_init_from_boot
  fs/ntfs3: Reject mount if boot's cluster size < media sector size
  fs/ntfs3: Refactoring lock in ntfs_init_acl
  fs/ntfs3: Change posix_acl_equiv_mode to posix_acl_update_mode
  fs/ntfs3: Pass flags to ntfs_set_ea in ntfs_set_acl_ex
  fs/ntfs3: Refactor ntfs_get_acl_ex for better readability
  ...
This commit is contained in:
Linus Torvalds 2021-10-15 09:58:11 -04:00
commit 86a44e9067
24 changed files with 792 additions and 967 deletions

View file

@ -4,103 +4,112 @@
NTFS3
=====
Summary and Features
====================
NTFS3 is fully functional NTFS Read-Write driver. The driver works with
NTFS versions up to 3.1, normal/compressed/sparse files
and journal replaying. File system type to use on mount is 'ntfs3'.
NTFS3 is fully functional NTFS Read-Write driver. The driver works with NTFS
versions up to 3.1. File system type to use on mount is *ntfs3*.
- This driver implements NTFS read/write support for normal, sparse and
compressed files.
- Supports native journal replaying;
- Supports extended attributes
Predefined extended attributes:
- 'system.ntfs_security' gets/sets security
descriptor (SECURITY_DESCRIPTOR_RELATIVE)
- 'system.ntfs_attrib' gets/sets ntfs file/dir attributes.
Note: applied to empty files, this allows to switch type between
sparse(0x200), compressed(0x800) and normal;
- Supports native journal replaying.
- Supports NFS export of mounted NTFS volumes.
- Supports extended attributes. Predefined extended attributes:
- *system.ntfs_security* gets/sets security
Descriptor: SECURITY_DESCRIPTOR_RELATIVE
- *system.ntfs_attrib* gets/sets ntfs file/dir attributes.
Note: Applied to empty files, this allows to switch type between
sparse(0x200), compressed(0x800) and normal.
Mount Options
=============
The list below describes mount options supported by NTFS3 driver in addition to
generic ones.
generic ones. You can use every mount option with **no** option. If it is in
this table marked with no it means default is without **no**.
===============================================================================
.. flat-table::
:widths: 1 5
:fill-cells:
nls=name This option informs the driver how to interpret path
strings and translate them to Unicode and back. If
this option is not set, the default codepage will be
used (CONFIG_NLS_DEFAULT).
Examples:
'nls=utf8'
* - iocharset=name
- This option informs the driver how to interpret path strings and
translate them to Unicode and back. If this option is not set, the
default codepage will be used (CONFIG_NLS_DEFAULT).
uid=
gid=
umask= Controls the default permissions for files/directories created
after the NTFS volume is mounted.
Example: iocharset=utf8
fmask=
dmask= Instead of specifying umask which applies both to
files and directories, fmask applies only to files and
dmask only to directories.
* - uid=
- :rspan:`1`
* - gid=
nohidden Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN)
attribute will not be shown under Linux.
* - umask=
- Controls the default permissions for files/directories created after
the NTFS volume is mounted.
sys_immutable Files with the Windows-specific SYSTEM
(FILE_ATTRIBUTE_SYSTEM) attribute will be marked as system
immutable files.
* - dmask=
- :rspan:`1` Instead of specifying umask which applies both to files and
directories, fmask applies only to files and dmask only to directories.
* - fmask=
discard Enable support of the TRIM command for improved performance
on delete operations, which is recommended for use with the
solid-state drives (SSD).
* - noacsrules
- "No access rules" mount option sets access rights for files/folders to
777 and owner/group to root. This mount option absorbs all other
permissions.
force Forces the driver to mount partitions even if 'dirty' flag
(volume dirty) is set. Not recommended for use.
- Permissions change for files/folders will be reported as successful,
but they will remain 777.
sparse Create new files as "sparse".
- Owner/group change will be reported as successful, butthey will stay
as root.
showmeta Use this parameter to show all meta-files (System Files) on
a mounted NTFS partition.
By default, all meta-files are hidden.
* - nohidden
- Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute
will not be shown under Linux.
prealloc Preallocate space for files excessively when file size is
increasing on writes. Decreases fragmentation in case of
parallel write operations to different files.
* - sys_immutable
- Files with the Windows-specific SYSTEM (FILE_ATTRIBUTE_SYSTEM) attribute
will be marked as system immutable files.
no_acs_rules "No access rules" mount option sets access rights for
files/folders to 777 and owner/group to root. This mount
option absorbs all other permissions:
- permissions change for files/folders will be reported
as successful, but they will remain 777;
- owner/group change will be reported as successful, but
they will stay as root
* - discard
- Enable support of the TRIM command for improved performance on delete
operations, which is recommended for use with the solid-state drives
(SSD).
acl Support POSIX ACLs (Access Control Lists). Effective if
supported by Kernel. Not to be confused with NTFS ACLs.
The option specified as acl enables support for POSIX ACLs.
* - force
- Forces the driver to mount partitions even if volume is marked dirty.
Not recommended for use.
noatime All files and directories will not update their last access
time attribute if a partition is mounted with this parameter.
This option can speed up file system operation.
* - sparse
- Create new files as sparse.
===============================================================================
* - showmeta
- Use this parameter to show all meta-files (System Files) on a mounted
NTFS partition. By default, all meta-files are hidden.
ToDo list
* - prealloc
- Preallocate space for files excessively when file size is increasing on
writes. Decreases fragmentation in case of parallel write operations to
different files.
* - acl
- Support POSIX ACLs (Access Control Lists). Effective if supported by
Kernel. Not to be confused with NTFS ACLs. The option specified as acl
enables support for POSIX ACLs.
Todo list
=========
- Full journaling support (currently journal replaying is supported) over JBD.
- Full journaling support over JBD. Currently journal replaying is supported
which is not necessarily as effectice as JBD would be.
References
==========
https://www.paragon-software.com/home/ntfs-linux-professional/
- Commercial version of the NTFS driver for Linux.
- Commercial version of the NTFS driver for Linux.
https://www.paragon-software.com/home/ntfs-linux-professional/
almaz.alexandrovich@paragon-software.com
- Direct e-mail address for feedback and requests on the NTFS3 implementation.
- Direct e-mail address for feedback and requests on the NTFS3 implementation.
almaz.alexandrovich@paragon-software.com

View file

@ -6,13 +6,9 @@
* TODO: Merge attr_set_size/attr_data_get_block/attr_allocate_frame?
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/hash.h>
#include <linux/nls.h>
#include <linux/ratelimit.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include "debug.h"
#include "ntfs.h"
@ -291,7 +287,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
if (!rsize) {
/* Empty resident -> Non empty nonresident. */
} else if (!is_data) {
err = ntfs_sb_write_run(sbi, run, 0, data, rsize);
err = ntfs_sb_write_run(sbi, run, 0, data, rsize, 0);
if (err)
goto out2;
} else if (!page) {
@ -451,11 +447,8 @@ again:
again_1:
align = sbi->cluster_size;
if (is_ext) {
if (is_ext)
align <<= attr_b->nres.c_unit;
if (is_attr_sparsed(attr_b))
keep_prealloc = false;
}
old_valid = le64_to_cpu(attr_b->nres.valid_size);
old_size = le64_to_cpu(attr_b->nres.data_size);
@ -465,9 +458,6 @@ again_1:
new_alloc = (new_size + align - 1) & ~(u64)(align - 1);
new_alen = new_alloc >> cluster_bits;
if (keep_prealloc && is_ext)
keep_prealloc = false;
if (keep_prealloc && new_size < old_size) {
attr_b->nres.data_size = cpu_to_le64(new_size);
mi_b->dirty = true;
@ -529,7 +519,7 @@ add_alloc_in_same_attr_seg:
} else if (pre_alloc == -1) {
pre_alloc = 0;
if (type == ATTR_DATA && !name_len &&
sbi->options.prealloc) {
sbi->options->prealloc) {
CLST new_alen2 = bytes_to_cluster(
sbi, get_pre_allocated(new_size));
pre_alloc = new_alen2 - new_alen;
@ -1966,7 +1956,7 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
return 0;
from = vbo;
to = (vbo + bytes) < data_size ? (vbo + bytes) : data_size;
to = min_t(u64, vbo + bytes, data_size);
memset(Add2Ptr(resident_data(attr_b), from), 0, to - from);
return 0;
}

View file

@ -5,10 +5,7 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include "debug.h"
#include "ntfs.h"
@ -336,7 +333,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name,
if (attr && attr->non_res) {
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
al->size);
al->size, 0);
if (err)
return err;
al->dirty = false;
@ -423,7 +420,7 @@ next:
return true;
}
int al_update(struct ntfs_inode *ni)
int al_update(struct ntfs_inode *ni, int sync)
{
int err;
struct ATTRIB *attr;
@ -445,7 +442,7 @@ int al_update(struct ntfs_inode *ni)
memcpy(resident_data(attr), al->le, al->size);
} else {
err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le,
al->size);
al->size, sync);
if (err)
goto out;

View file

@ -5,13 +5,8 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/types.h>
#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"
#define BITS_IN_SIZE_T (sizeof(size_t) * 8)
@ -124,8 +119,7 @@ bool are_bits_set(const ulong *lmap, size_t bit, size_t nbits)
pos = nbits & 7;
if (pos) {
u8 mask = fill_mask[pos];
mask = fill_mask[pos];
if ((*map & mask) != mask)
return false;
}

View file

@ -10,12 +10,10 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/kernel.h>
#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"
@ -435,7 +433,7 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len)
;
} else {
n3 = rb_next(&e->count.node);
max_new_len = len > new_len ? len : new_len;
max_new_len = max(len, new_len);
if (!n3) {
wnd->extent_max = max_new_len;
} else {
@ -731,7 +729,7 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
wbits = wnd->bits_last;
tail = wbits - wbit;
op = tail < bits ? tail : bits;
op = min_t(u32, tail, bits);
bh = wnd_map(wnd, iw);
if (IS_ERR(bh)) {
@ -784,7 +782,7 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
wbits = wnd->bits_last;
tail = wbits - wbit;
op = tail < bits ? tail : bits;
op = min_t(u32, tail, bits);
bh = wnd_map(wnd, iw);
if (IS_ERR(bh)) {
@ -834,7 +832,7 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
wbits = wnd->bits_last;
tail = wbits - wbit;
op = tail < bits ? tail : bits;
op = min_t(u32, tail, bits);
if (wbits != wnd->free_bits[iw]) {
bool ret;
@ -926,7 +924,7 @@ use_wnd:
wbits = wnd->bits_last;
tail = wbits - wbit;
op = tail < bits ? tail : bits;
op = min_t(u32, tail, bits);
if (wnd->free_bits[iw]) {
bool ret;

View file

@ -11,6 +11,9 @@
#ifndef _LINUX_NTFS3_DEBUG_H
#define _LINUX_NTFS3_DEBUG_H
struct super_block;
struct inode;
#ifndef Add2Ptr
#define Add2Ptr(P, I) ((void *)((u8 *)(P) + (I)))
#define PtrOffset(B, O) ((size_t)((size_t)(O) - (size_t)(B)))

View file

@ -7,10 +7,7 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/iversion.h>
#include <linux/nls.h>
#include "debug.h"
@ -18,30 +15,27 @@
#include "ntfs_fs.h"
/* Convert little endian UTF-16 to NLS string. */
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len,
u8 *buf, int buf_len)
{
int ret, uni_len, warn;
const __le16 *ip;
int ret, warn;
u8 *op;
struct nls_table *nls = sbi->options.nls;
struct nls_table *nls = sbi->options->nls;
static_assert(sizeof(wchar_t) == sizeof(__le16));
if (!nls) {
/* UTF-16 -> UTF-8 */
ret = utf16s_to_utf8s((wchar_t *)uni->name, uni->len,
UTF16_LITTLE_ENDIAN, buf, buf_len);
ret = utf16s_to_utf8s(name, len, UTF16_LITTLE_ENDIAN, buf,
buf_len);
buf[ret] = '\0';
return ret;
}
ip = uni->name;
op = buf;
uni_len = uni->len;
warn = 0;
while (uni_len--) {
while (len--) {
u16 ec;
int charlen;
char dump[5];
@ -52,7 +46,7 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
break;
}
ec = le16_to_cpu(*ip++);
ec = le16_to_cpu(*name++);
charlen = nls->uni2char(ec, op, buf_len);
if (charlen > 0) {
@ -186,7 +180,7 @@ int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
{
int ret, slen;
const u8 *end;
struct nls_table *nls = sbi->options.nls;
struct nls_table *nls = sbi->options->nls;
u16 *uname = uni->name;
static_assert(sizeof(wchar_t) == sizeof(u16));
@ -301,14 +295,14 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni,
return 0;
/* Skip meta files. Unless option to show metafiles is set. */
if (!sbi->options.showmeta && ntfs_is_meta_file(sbi, ino))
if (!sbi->options->showmeta && ntfs_is_meta_file(sbi, ino))
return 0;
if (sbi->options.nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN))
return 0;
name_len = ntfs_utf16_to_nls(sbi, (struct le_str *)&fname->name_len,
name, PATH_MAX);
name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name,
PATH_MAX);
if (name_len <= 0) {
ntfs_warn(sbi->sb, "failed to convert name for inode %lx.",
ino);

View file

@ -12,7 +12,6 @@
#include <linux/compat.h>
#include <linux/falloc.h>
#include <linux/fiemap.h>
#include <linux/nls.h>
#include "debug.h"
#include "ntfs.h"
@ -588,8 +587,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
truncate_pagecache(inode, vbo_down);
if (!is_sparsed(ni) && !is_compressed(ni)) {
/* Normal file. */
err = ntfs_zero_range(inode, vbo, end);
/*
* Normal file, can't make hole.
* TODO: Try to find way to save info about hole.
*/
err = -EOPNOTSUPP;
goto out;
}
@ -737,7 +739,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
umode_t mode = inode->i_mode;
int err;
if (sbi->options.no_acs_rules) {
if (sbi->options->noacsrules) {
/* "No access rules" - Force any changes of time etc. */
attr->ia_valid |= ATTR_FORCE;
/* and disable for editing some attributes. */
@ -1185,7 +1187,7 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
int err = 0;
/* If we are last writer on the inode, drop the block reservation. */
if (sbi->options.prealloc && ((file->f_mode & FMODE_WRITE) &&
if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) &&
atomic_read(&inode->i_writecount) == 1)) {
ni_lock(ni);
down_write(&ni->file.run_lock);

View file

@ -5,11 +5,8 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fiemap.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/vmalloc.h>
#include "debug.h"
@ -708,18 +705,35 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
continue;
mi = ni_find_mi(ni, ino_get(&le->ref));
if (!mi) {
/* Should never happened, 'cause already checked. */
goto bad;
}
attr = mi_find_attr(mi, NULL, le->type, le_name(le),
le->name_len, &le->id);
if (!attr) {
/* Should never happened, 'cause already checked. */
goto bad;
}
asize = le32_to_cpu(attr->size);
/* Insert into primary record. */
attr_ins = mi_insert_attr(&ni->mi, le->type, le_name(le),
le->name_len, asize,
le16_to_cpu(attr->name_off));
id = attr_ins->id;
if (!attr_ins) {
/*
* Internal error.
* Either no space in primary record (already checked).
* Either tried to insert another
* non indexed attribute (logic error).
*/
goto bad;
}
/* Copy all except id. */
id = attr_ins->id;
memcpy(attr_ins, attr, asize);
attr_ins->id = id;
@ -735,6 +749,10 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
ni->attr_list.dirty = false;
return 0;
bad:
ntfs_inode_err(&ni->vfs_inode, "Internal error");
make_bad_inode(&ni->vfs_inode);
return -EINVAL;
}
/*
@ -956,6 +974,13 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
continue;
}
/*
* Do not try to insert this attribute
* if there is no room in record.
*/
if (le32_to_cpu(mi->mrec->used) + asize > sbi->record_size)
continue;
/* Try to insert attribute into this subrecord. */
attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
name_off, svcn, ins_le);
@ -1451,7 +1476,7 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
attr->res.flags = RESIDENT_FLAG_INDEXED;
/* is_attr_indexed(attr)) == true */
le16_add_cpu(&ni->mi.mrec->hard_links, +1);
le16_add_cpu(&ni->mi.mrec->hard_links, 1);
ni->mi.dirty = true;
}
attr->res.res = 0;
@ -1606,7 +1631,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
*le = NULL;
if (FILE_NAME_POSIX == name_type)
if (name_type == FILE_NAME_POSIX)
return NULL;
/* Enumerate all names. */
@ -1706,18 +1731,16 @@ out:
/*
* ni_parse_reparse
*
* Buffer is at least 24 bytes.
* buffer - memory for reparse buffer header
*/
enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
void *buffer)
struct REPARSE_DATA_BUFFER *buffer)
{
const struct REPARSE_DATA_BUFFER *rp = NULL;
u8 bits;
u16 len;
typeof(rp->CompressReparseBuffer) *cmpr;
static_assert(sizeof(struct REPARSE_DATA_BUFFER) <= 24);
/* Try to estimate reparse point. */
if (!attr->non_res) {
rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER));
@ -1803,6 +1826,9 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
return REPARSE_NONE;
}
if (buffer != rp)
memcpy(buffer, rp, sizeof(struct REPARSE_DATA_BUFFER));
/* Looks like normal symlink. */
return REPARSE_LINK;
}
@ -2906,9 +2932,8 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size);
mi_get_ref(&ni->mi, &de->ref);
if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1)) {
if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1))
return false;
}
}
return true;
@ -3077,7 +3102,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup,
const struct EA_INFO *info;
info = resident_data_ex(attr, sizeof(struct EA_INFO));
dup->ea_size = info->size_pack;
/* If ATTR_EA_INFO exists 'info' can't be NULL. */
if (info)
dup->ea_size = info->size_pack;
}
}
@ -3205,7 +3232,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
goto out;
}
err = al_update(ni);
err = al_update(ni, sync);
if (err)
goto out;
}

View file

@ -6,12 +6,8 @@
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/hash.h>
#include <linux/nls.h>
#include <linux/random.h>
#include <linux/ratelimit.h>
#include <linux/slab.h>
#include "debug.h"
@ -2219,7 +2215,7 @@ file_is_valid:
err = ntfs_sb_write_run(log->ni->mi.sbi,
&log->ni->file.run, off, page,
log->page_size);
log->page_size, 0);
if (err)
goto out;
@ -3710,7 +3706,7 @@ move_data:
if (a_dirty) {
attr = oa->attr;
err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes);
err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes, 0);
if (err)
goto out;
}
@ -5152,10 +5148,10 @@ end_reply:
ntfs_fix_pre_write(&rh->rhdr, log->page_size);
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size);
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size, 0);
if (!err)
err = ntfs_sb_write_run(sbi, &log->ni->file.run, log->page_size,
rh, log->page_size);
rh, log->page_size, 0);
kfree(rh);
if (err)

View file

@ -8,7 +8,7 @@
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/kernel.h>
#include "debug.h"
#include "ntfs.h"
@ -358,7 +358,7 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
enum ALLOCATE_OPT opt)
{
int err;
CLST alen = 0;
CLST alen;
struct super_block *sb = sbi->sb;
size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen;
struct wnd_bitmap *wnd = &sbi->used.bitmap;
@ -370,27 +370,28 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
if (!zlen) {
err = ntfs_refresh_zone(sbi);
if (err)
goto out;
goto up_write;
zlen = wnd_zone_len(wnd);
}
if (!zlen) {
ntfs_err(sbi->sb, "no free space to extend mft");
goto out;
err = -ENOSPC;
goto up_write;
}
lcn = wnd_zone_bit(wnd);
alen = zlen > len ? len : zlen;
alen = min_t(CLST, len, zlen);
wnd_zone_set(wnd, lcn + alen, zlen - alen);
err = wnd_set_used(wnd, lcn, alen);
if (err) {
up_write(&wnd->rw_lock);
return err;
}
if (err)
goto up_write;
alcn = lcn;
goto out;
goto space_found;
}
/*
* 'Cause cluster 0 is always used this value means that we should use
@ -404,49 +405,45 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn);
if (alen)
goto out;
goto space_found;
/* Try to use clusters from MftZone. */
zlen = wnd_zone_len(wnd);
zeroes = wnd_zeroes(wnd);
/* Check too big request */
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE)
goto out;
if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) {
err = -ENOSPC;
goto up_write;
}
/* How many clusters to cat from zone. */
zlcn = wnd_zone_bit(wnd);
zlen2 = zlen >> 1;
ztrim = len > zlen ? zlen : (len > zlen2 ? len : zlen2);
new_zlen = zlen - ztrim;
if (new_zlen < NTFS_MIN_MFT_ZONE) {
new_zlen = NTFS_MIN_MFT_ZONE;
if (new_zlen > zlen)
new_zlen = zlen;
}
ztrim = clamp_val(len, zlen2, zlen);
new_zlen = max_t(size_t, zlen - ztrim, NTFS_MIN_MFT_ZONE);
wnd_zone_set(wnd, zlcn, new_zlen);
/* Allocate continues clusters. */
alen = wnd_find(wnd, len, 0,
BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn);
out:
if (alen) {
err = 0;
*new_len = alen;
*new_lcn = alcn;
ntfs_unmap_meta(sb, alcn, alen);
/* Set hint for next requests. */
if (!(opt & ALLOCATE_MFT))
sbi->used.next_free_lcn = alcn + alen;
} else {
if (!alen) {
err = -ENOSPC;
goto up_write;
}
space_found:
err = 0;
*new_len = alen;
*new_lcn = alcn;
ntfs_unmap_meta(sb, alcn, alen);
/* Set hint for next requests. */
if (!(opt & ALLOCATE_MFT))
sbi->used.next_free_lcn = alcn + alen;
up_write:
up_write(&wnd->rw_lock);
return err;
}
@ -1080,7 +1077,7 @@ int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
}
int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
u64 vbo, const void *buf, size_t bytes)
u64 vbo, const void *buf, size_t bytes, int sync)
{
struct super_block *sb = sbi->sb;
u8 cluster_bits = sbi->cluster_bits;
@ -1099,8 +1096,8 @@ int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
len = ((u64)clen << cluster_bits) - off;
for (;;) {
u32 op = len < bytes ? len : bytes;
int err = ntfs_sb_write(sb, lbo, op, buf, 0);
u32 op = min_t(u64, len, bytes);
int err = ntfs_sb_write(sb, lbo, op, buf, sync);
if (err)
return err;
@ -1300,7 +1297,7 @@ int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
nb->off = off = lbo & (blocksize - 1);
for (;;) {
u32 len32 = len < bytes ? len : bytes;
u32 len32 = min_t(u64, len, bytes);
sector_t block = lbo >> sb->s_blocksize_bits;
do {
@ -2175,7 +2172,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
/* Write main SDS bucket. */
err = ntfs_sb_write_run(sbi, &ni->file.run, sbi->security.next_off,
d_security, aligned_sec_size);
d_security, aligned_sec_size, 0);
if (err)
goto out;
@ -2193,7 +2190,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi,
/* Write copy SDS bucket. */
err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security,
aligned_sec_size);
aligned_sec_size, 0);
if (err)
goto out;

View file

@ -8,7 +8,7 @@
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/kernel.h>
#include "debug.h"
#include "ntfs.h"
@ -671,113 +671,17 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx,
const struct INDEX_HDR *hdr, const void *key,
size_t key_len, const void *ctx, int *diff)
{
struct NTFS_DE *e;
struct NTFS_DE *e, *found = NULL;
NTFS_CMP_FUNC cmp = indx->cmp;
int min_idx = 0, mid_idx, max_idx = 0;
int diff2;
int table_size = 8;
u32 e_size, e_key_len;
u32 end = le32_to_cpu(hdr->used);
u32 off = le32_to_cpu(hdr->de_off);
u16 offs[128];
#ifdef NTFS3_INDEX_BINARY_SEARCH
int max_idx = 0, fnd, min_idx;
int nslots = 64;
u16 *offs;
if (end > 0x10000)
goto next;
offs = kmalloc(sizeof(u16) * nslots, GFP_NOFS);
if (!offs)
goto next;
/* Use binary search algorithm. */
next1:
if (off + sizeof(struct NTFS_DE) > end) {
e = NULL;
goto out1;
}
e = Add2Ptr(hdr, off);
e_size = le16_to_cpu(e->size);
if (e_size < sizeof(struct NTFS_DE) || off + e_size > end) {
e = NULL;
goto out1;
}
if (max_idx >= nslots) {
u16 *ptr;
int new_slots = ALIGN(2 * nslots, 8);
ptr = kmalloc(sizeof(u16) * new_slots, GFP_NOFS);
if (ptr)
memcpy(ptr, offs, sizeof(u16) * max_idx);
kfree(offs);
offs = ptr;
nslots = new_slots;
if (!ptr)
goto next;
}
/* Store entry table. */
offs[max_idx] = off;
if (!de_is_last(e)) {
off += e_size;
max_idx += 1;
goto next1;
}
/*
* Table of pointers is created.
* Use binary search to find entry that is <= to the search value.
*/
fnd = -1;
min_idx = 0;
while (min_idx <= max_idx) {
int mid_idx = min_idx + ((max_idx - min_idx) >> 1);
int diff2;
e = Add2Ptr(hdr, offs[mid_idx]);
e_key_len = le16_to_cpu(e->key_size);
diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
if (!diff2) {
*diff = 0;
goto out1;
}
if (diff2 < 0) {
max_idx = mid_idx - 1;
fnd = mid_idx;
if (!fnd)
break;
} else {
min_idx = mid_idx + 1;
}
}
if (fnd == -1) {
e = NULL;
goto out1;
}
*diff = -1;
e = Add2Ptr(hdr, offs[fnd]);
out1:
kfree(offs);
return e;
#endif
next:
/*
* Entries index are sorted.
* Enumerate all entries until we find entry
* that is <= to the search value.
*/
fill_table:
if (off + sizeof(struct NTFS_DE) > end)
return NULL;
@ -787,22 +691,54 @@ next:
if (e_size < sizeof(struct NTFS_DE) || off + e_size > end)
return NULL;
off += e_size;
if (!de_is_last(e)) {
offs[max_idx] = off;
off += e_size;
max_idx++;
if (max_idx < table_size)
goto fill_table;
max_idx--;
}
binary_search:
e_key_len = le16_to_cpu(e->key_size);
*diff = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
if (!*diff)
return e;
diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx);
if (diff2 > 0) {
if (found) {
min_idx = mid_idx + 1;
} else {
if (de_is_last(e))
return NULL;
if (*diff <= 0)
return e;
max_idx = 0;
table_size = min(table_size * 2,
(int)ARRAY_SIZE(offs));
goto fill_table;
}
} else if (diff2 < 0) {
if (found)
max_idx = mid_idx - 1;
else
max_idx--;
if (de_is_last(e)) {
*diff = 1;
found = e;
} else {
*diff = 0;
return e;
}
goto next;
if (min_idx > max_idx) {
*diff = -1;
return found;
}
mid_idx = (min_idx + max_idx) >> 1;
e = Add2Ptr(hdr, offs[mid_idx]);
goto binary_search;
}
/*
@ -1136,9 +1072,7 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
if (!e)
return -EINVAL;
if (fnd)
fnd->root_de = e;
fnd->root_de = e;
err = 0;
for (;;) {
@ -1401,7 +1335,7 @@ ok:
static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
CLST *vbn)
{
int err = -ENOMEM;
int err;
struct ntfs_sb_info *sbi = ni->mi.sbi;
struct ATTRIB *bitmap;
struct ATTRIB *alloc;

View file

@ -5,10 +5,8 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/iversion.h>
#include <linux/mpage.h>
#include <linux/namei.h>
#include <linux/nls.h>
@ -49,8 +47,8 @@ static struct inode *ntfs_read_mft(struct inode *inode,
inode->i_op = NULL;
/* Setup 'uid' and 'gid' */
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode->i_uid = sbi->options->fs_uid;
inode->i_gid = sbi->options->fs_gid;
err = mi_init(&ni->mi, sbi, ino);
if (err)
@ -224,12 +222,9 @@ next_attr:
if (!attr->non_res) {
ni->i_valid = inode->i_size = rsize;
inode_set_bytes(inode, rsize);
t32 = asize;
} else {
t32 = le16_to_cpu(attr->nres.run_off);
}
mode = S_IFREG | (0777 & sbi->options.fs_fmask_inv);
mode = S_IFREG | (0777 & sbi->options->fs_fmask_inv);
if (!attr->non_res) {
ni->ni_flags |= NI_FLAG_RESIDENT;
@ -272,7 +267,7 @@ next_attr:
goto out;
mode = sb->s_root
? (S_IFDIR | (0777 & sbi->options.fs_dmask_inv))
? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv))
: (S_IFDIR | 0777);
goto next_attr;
@ -315,17 +310,14 @@ next_attr:
rp_fa = ni_parse_reparse(ni, attr, &rp);
switch (rp_fa) {
case REPARSE_LINK:
if (!attr->non_res) {
inode->i_size = rsize;
inode_set_bytes(inode, rsize);
t32 = asize;
} else {
inode->i_size =
le64_to_cpu(attr->nres.data_size);
t32 = le16_to_cpu(attr->nres.run_off);
}
/*
* Normal symlink.
* Assume one unicode symbol == one utf8.
*/
inode->i_size = le16_to_cpu(rp.SymbolicLinkReparseBuffer
.PrintNameLength) /
sizeof(u16);
/* Looks like normal symlink. */
ni->i_valid = inode->i_size;
/* Clear directory bit. */
@ -422,7 +414,7 @@ end_enum:
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
inode->i_op = &ntfs_link_inode_operations;
inode->i_fop = NULL;
inode_nohighmem(inode); // ??
inode_nohighmem(inode);
} else if (S_ISREG(mode)) {
ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY;
inode->i_op = &ntfs_file_inode_operations;
@ -443,7 +435,7 @@ end_enum:
goto out;
}
if ((sbi->options.sys_immutable &&
if ((sbi->options->sys_immutable &&
(std5->fa & FILE_ATTRIBUTE_SYSTEM)) &&
!S_ISFIFO(mode) && !S_ISSOCK(mode) && !S_ISLNK(mode)) {
inode->i_flags |= S_IMMUTABLE;
@ -1200,9 +1192,13 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
struct REPARSE_DATA_BUFFER *rp = NULL;
bool rp_inserted = false;
ni_lock_dir(dir_ni);
dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL);
if (!dir_root)
return ERR_PTR(-EINVAL);
if (!dir_root) {
err = -EINVAL;
goto out1;
}
if (S_ISDIR(mode)) {
/* Use parent's directory attributes. */
@ -1244,7 +1240,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
* }
*/
} else if (S_ISREG(mode)) {
if (sbi->options.sparse) {
if (sbi->options->sparse) {
/* Sparsed regular file, cause option 'sparse'. */
fa = FILE_ATTRIBUTE_SPARSE_FILE |
FILE_ATTRIBUTE_ARCHIVE;
@ -1486,7 +1482,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
asize = ALIGN(SIZEOF_RESIDENT + nsize, 8);
t16 = PtrOffset(rec, attr);
/* 0x78 - the size of EA + EAINFO to store WSL */
/*
* Below function 'ntfs_save_wsl_perm' requires 0x78 bytes.
* It is good idea to keep extened attributes resident.
*/
if (asize + t16 + 0x78 + 8 > sbi->record_size) {
CLST alen;
CLST clst = bytes_to_cluster(sbi, nsize);
@ -1521,14 +1520,14 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
}
asize = SIZEOF_NONRESIDENT + ALIGN(err, 8);
inode->i_size = nsize;
} else {
attr->res.data_off = SIZEOF_RESIDENT_LE;
attr->res.data_size = cpu_to_le32(nsize);
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize);
inode->i_size = nsize;
nsize = 0;
}
/* Size of symlink equals the length of input string. */
inode->i_size = size;
attr->size = cpu_to_le32(asize);
@ -1551,6 +1550,9 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
if (err)
goto out6;
/* Unlock parent directory before ntfs_init_acl. */
ni_unlock(dir_ni);
inode->i_generation = le16_to_cpu(rec->seq);
dir->i_mtime = dir->i_ctime = inode->i_atime;
@ -1562,6 +1564,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
inode->i_op = &ntfs_link_inode_operations;
inode->i_fop = NULL;
inode->i_mapping->a_ops = &ntfs_aops;
inode->i_size = size;
inode_nohighmem(inode);
} else if (S_ISREG(mode)) {
inode->i_op = &ntfs_file_inode_operations;
inode->i_fop = &ntfs_file_operations;
@ -1577,7 +1581,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) {
err = ntfs_init_acl(mnt_userns, inode, dir);
if (err)
goto out6;
goto out7;
} else
#endif
{
@ -1586,7 +1590,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
/* Write non resident data. */
if (nsize) {
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize);
err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0);
if (err)
goto out7;
}
@ -1607,8 +1611,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
out7:
/* Undo 'indx_insert_entry'. */
ni_lock_dir(dir_ni);
indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1,
le16_to_cpu(new_de->key_size), sbi);
/* ni_unlock(dir_ni); will be called later. */
out6:
if (rp_inserted)
ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref);
@ -1632,8 +1638,10 @@ out2:
kfree(rp);
out1:
if (err)
if (err) {
ni_unlock(dir_ni);
return ERR_PTR(err);
}
unlock_new_inode(inode);
@ -1754,15 +1762,15 @@ void ntfs_evict_inode(struct inode *inode)
static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
int buflen)
{
int i, err = 0;
int i, err = -EINVAL;
struct ntfs_inode *ni = ntfs_i(inode);
struct super_block *sb = inode->i_sb;
struct ntfs_sb_info *sbi = sb->s_fs_info;
u64 i_size = inode->i_size;
u16 nlen = 0;
u64 size;
u16 ulen = 0;
void *to_free = NULL;
struct REPARSE_DATA_BUFFER *rp;
struct le_str *uni;
const __le16 *uname;
struct ATTRIB *attr;
/* Reparse data present. Try to parse it. */
@ -1771,68 +1779,64 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
*buffer = 0;
/* Read into temporal buffer. */
if (i_size > sbi->reparse.max_size || i_size <= sizeof(u32)) {
err = -EINVAL;
goto out;
}
attr = ni_find_attr(ni, NULL, NULL, ATTR_REPARSE, NULL, 0, NULL, NULL);
if (!attr) {
err = -EINVAL;
if (!attr)
goto out;
}
if (!attr->non_res) {
rp = resident_data_ex(attr, i_size);
if (!rp) {
err = -EINVAL;
rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER));
if (!rp)
goto out;
}
size = le32_to_cpu(attr->res.data_size);
} else {
rp = kmalloc(i_size, GFP_NOFS);
size = le64_to_cpu(attr->nres.data_size);
rp = NULL;
}
if (size > sbi->reparse.max_size || size <= sizeof(u32))
goto out;
if (!rp) {
rp = kmalloc(size, GFP_NOFS);
if (!rp) {
err = -ENOMEM;
goto out;
}
to_free = rp;
err = ntfs_read_run_nb(sbi, &ni->file.run, 0, rp, i_size, NULL);
/* Read into temporal buffer. */
err = ntfs_read_run_nb(sbi, &ni->file.run, 0, rp, size, NULL);
if (err)
goto out;
}
err = -EINVAL;
/* Microsoft Tag. */
switch (rp->ReparseTag) {
case IO_REPARSE_TAG_MOUNT_POINT:
/* Mount points and junctions. */
/* Can we use 'Rp->MountPointReparseBuffer.PrintNameLength'? */
if (i_size <= offsetof(struct REPARSE_DATA_BUFFER,
MountPointReparseBuffer.PathBuffer))
if (size <= offsetof(struct REPARSE_DATA_BUFFER,
MountPointReparseBuffer.PathBuffer))
goto out;
uni = Add2Ptr(rp,
offsetof(struct REPARSE_DATA_BUFFER,
MountPointReparseBuffer.PathBuffer) +
le16_to_cpu(rp->MountPointReparseBuffer
.PrintNameOffset) -
2);
nlen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength);
uname = Add2Ptr(rp,
offsetof(struct REPARSE_DATA_BUFFER,
MountPointReparseBuffer.PathBuffer) +
le16_to_cpu(rp->MountPointReparseBuffer
.PrintNameOffset));
ulen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength);
break;
case IO_REPARSE_TAG_SYMLINK:
/* FolderSymbolicLink */
/* Can we use 'Rp->SymbolicLinkReparseBuffer.PrintNameLength'? */
if (i_size <= offsetof(struct REPARSE_DATA_BUFFER,
SymbolicLinkReparseBuffer.PathBuffer))
if (size <= offsetof(struct REPARSE_DATA_BUFFER,
SymbolicLinkReparseBuffer.PathBuffer))
goto out;
uni = Add2Ptr(rp,
offsetof(struct REPARSE_DATA_BUFFER,
SymbolicLinkReparseBuffer.PathBuffer) +
le16_to_cpu(rp->SymbolicLinkReparseBuffer
.PrintNameOffset) -
2);
nlen = le16_to_cpu(
uname = Add2Ptr(
rp, offsetof(struct REPARSE_DATA_BUFFER,
SymbolicLinkReparseBuffer.PathBuffer) +
le16_to_cpu(rp->SymbolicLinkReparseBuffer
.PrintNameOffset));
ulen = le16_to_cpu(
rp->SymbolicLinkReparseBuffer.PrintNameLength);
break;
@ -1864,29 +1868,28 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer,
goto out;
}
if (!IsReparseTagNameSurrogate(rp->ReparseTag) ||
i_size <= sizeof(struct REPARSE_POINT)) {
size <= sizeof(struct REPARSE_POINT)) {
goto out;
}
/* Users tag. */
uni = Add2Ptr(rp, sizeof(struct REPARSE_POINT) - 2);
nlen = le16_to_cpu(rp->ReparseDataLength) -
uname = Add2Ptr(rp, sizeof(struct REPARSE_POINT));
ulen = le16_to_cpu(rp->ReparseDataLength) -
sizeof(struct REPARSE_POINT);
}
/* Convert nlen from bytes to UNICODE chars. */
nlen >>= 1;
ulen >>= 1;
/* Check that name is available. */
if (!nlen || &uni->name[nlen] > (__le16 *)Add2Ptr(rp, i_size))
if (!ulen || uname + ulen > (__le16 *)Add2Ptr(rp, size))
goto out;
/* If name is already zero terminated then truncate it now. */
if (!uni->name[nlen - 1])
nlen -= 1;
uni->len = nlen;
if (!uname[ulen - 1])
ulen -= 1;
err = ntfs_utf16_to_nls(sbi, uni, buffer, buflen);
err = ntfs_utf16_to_nls(sbi, uname, ulen, buffer, buflen);
if (err < 0)
goto out;

View file

@ -5,6 +5,9 @@
* Copyright (C) 2015 Eric Biggers
*/
#ifndef _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H
#define _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H
#include <linux/string.h>
#include <linux/compiler.h>
#include <linux/types.h>
@ -336,3 +339,5 @@ static forceinline u8 *lz_copy(u8 *dst, u32 length, u32 offset, const u8 *bufend
return dst;
}
#endif /* _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H */

View file

@ -7,6 +7,10 @@
* - linux kernel code style
*/
#ifndef _LINUX_NTFS3_LIB_LIB_H
#define _LINUX_NTFS3_LIB_LIB_H
#include <linux/types.h>
/* globals from xpress_decompress.c */
struct xpress_decompressor *xpress_allocate_decompressor(void);
@ -24,3 +28,5 @@ int lzx_decompress(struct lzx_decompressor *__restrict d,
const void *__restrict compressed_data,
size_t compressed_size, void *__restrict uncompressed_data,
size_t uncompressed_size);
#endif /* _LINUX_NTFS3_LIB_LIB_H */

View file

@ -5,13 +5,13 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"
// clang-format off
@ -292,7 +292,7 @@ next:
/*
* get_lznt_ctx
* @level: 0 - Standard compression.
* !0 - Best compression, requires a lot of cpu.
* !0 - Best compression, requires a lot of cpu.
*/
struct lznt *get_lznt_ctx(int level)
{

View file

@ -5,11 +5,7 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/iversion.h>
#include <linux/namei.h>
#include <linux/nls.h>
#include "debug.h"
@ -99,16 +95,11 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry,
static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode, bool excl)
{
struct ntfs_inode *ni = ntfs_i(dir);
struct inode *inode;
ni_lock_dir(ni);
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFREG | mode,
0, NULL, 0, NULL);
ni_unlock(ni);
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
}
@ -120,16 +111,11 @@ static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir,
static int ntfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t rdev)
{
struct ntfs_inode *ni = ntfs_i(dir);
struct inode *inode;
ni_lock_dir(ni);
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, mode, rdev,
NULL, 0, NULL);
ni_unlock(ni);
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
}
@ -200,15 +186,10 @@ static int ntfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
{
u32 size = strlen(symname);
struct inode *inode;
struct ntfs_inode *ni = ntfs_i(dir);
ni_lock_dir(ni);
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFLNK | 0777,
0, symname, size, NULL);
ni_unlock(ni);
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
}
@ -219,15 +200,10 @@ static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode)
{
struct inode *inode;
struct ntfs_inode *ni = ntfs_i(dir);
ni_lock_dir(ni);
inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFDIR | mode,
0, NULL, 0, NULL);
ni_unlock(ni);
return IS_ERR(inode) ? PTR_ERR(inode) : 0;
}

View file

@ -10,19 +10,27 @@
#ifndef _LINUX_NTFS3_NTFS_H
#define _LINUX_NTFS3_NTFS_H
/* TODO: Check 4K MFT record and 512 bytes cluster. */
#include <linux/blkdev.h>
#include <linux/build_bug.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
/* Activate this define to use binary search in indexes. */
#define NTFS3_INDEX_BINARY_SEARCH
#include "debug.h"
/* TODO: Check 4K MFT record and 512 bytes cluster. */
/* Check each run for marked clusters. */
#define NTFS3_CHECK_FREE_CLST
#define NTFS_NAME_LEN 255
/* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff. */
#define NTFS_LINK_MAX 0x400
//#define NTFS_LINK_MAX 0xffff
/*
* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff.
* xfstest generic/041 creates 3003 hardlinks.
*/
#define NTFS_LINK_MAX 4000
/*
* Activate to use 64 bit clusters instead of 32 bits in ntfs.sys.

View file

@ -9,6 +9,37 @@
#ifndef _LINUX_NTFS3_NTFS_FS_H
#define _LINUX_NTFS3_NTFS_FS_H
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/cleancache.h>
#include <linux/fs.h>
#include <linux/highmem.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/page-flags.h>
#include <linux/pagemap.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/time64.h>
#include <linux/types.h>
#include <linux/uidgid.h>
#include <asm/div64.h>
#include <asm/page.h>
#include "debug.h"
#include "ntfs.h"
struct dentry;
struct fiemap_extent_info;
struct user_namespace;
struct page;
struct writeback_control;
enum utf16_endian;
#define MINUS_ONE_T ((size_t)(-1))
/* Biggest MFT / smallest cluster */
#define MAXIMUM_BYTES_PER_MFT 4096
@ -52,6 +83,7 @@
// clang-format on
struct ntfs_mount_options {
char *nls_name;
struct nls_table *nls;
kuid_t fs_uid;
@ -59,19 +91,16 @@ struct ntfs_mount_options {
u16 fs_fmask_inv;
u16 fs_dmask_inv;
unsigned uid : 1, /* uid was set. */
gid : 1, /* gid was set. */
fmask : 1, /* fmask was set. */
dmask : 1, /* dmask was set. */
sys_immutable : 1, /* Immutable system files. */
discard : 1, /* Issue discard requests on deletions. */
sparse : 1, /* Create sparse files. */
showmeta : 1, /* Show meta files. */
nohidden : 1, /* Do not show hidden files. */
force : 1, /* Rw mount dirty volume. */
no_acs_rules : 1, /*Exclude acs rules. */
prealloc : 1 /* Preallocate space when file is growing. */
;
unsigned fmask : 1; /* fmask was set. */
unsigned dmask : 1; /*dmask was set. */
unsigned sys_immutable : 1; /* Immutable system files. */
unsigned discard : 1; /* Issue discard requests on deletions. */
unsigned sparse : 1; /* Create sparse files. */
unsigned showmeta : 1; /* Show meta files. */
unsigned nohidden : 1; /* Do not show hidden files. */
unsigned force : 1; /* RW mount dirty volume. */
unsigned noacsrules : 1; /* Exclude acs rules. */
unsigned prealloc : 1; /* Preallocate space when file is growing. */
};
/* Special value to unpack and deallocate. */
@ -182,10 +211,8 @@ struct ntfs_sb_info {
u32 blocks_per_cluster; // cluster_size / sb->s_blocksize
u32 record_size;
u32 sector_size;
u32 index_size;
u8 sector_bits;
u8 cluster_bits;
u8 record_bits;
@ -279,7 +306,7 @@ struct ntfs_sb_info {
#endif
} compress;
struct ntfs_mount_options options;
struct ntfs_mount_options *options;
struct ratelimit_state msg_ratelimit;
};
@ -436,7 +463,7 @@ bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le);
bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn,
const __le16 *name, size_t name_len,
const struct MFT_REF *ref);
int al_update(struct ntfs_inode *ni);
int al_update(struct ntfs_inode *ni, int sync);
static inline size_t al_aligned(size_t size)
{
return (size + 1023) & ~(size_t)1023;
@ -448,7 +475,7 @@ bool are_bits_set(const ulong *map, size_t bit, size_t nbits);
size_t get_set_bits_ex(const ulong *map, size_t bit, size_t nbits);
/* Globals from dir.c */
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni,
int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len,
u8 *buf, int buf_len);
int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len,
struct cpu_str *uni, u32 max_ulen,
@ -520,7 +547,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type,
struct ATTR_LIST_ENTRY **entry);
int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa);
enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
void *buffer);
struct REPARSE_DATA_BUFFER *buffer);
int ni_write_inode(struct inode *inode, int sync, const char *hint);
#define _ni_write_inode(i, w) ni_write_inode(i, w, __func__)
int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
@ -577,7 +604,7 @@ int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer);
int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes,
const void *buffer, int wait);
int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
u64 vbo, const void *buf, size_t bytes);
u64 vbo, const void *buf, size_t bytes, int sync);
struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
const struct runs_tree *run, u64 vbo);
int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,

View file

@ -5,10 +5,7 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include "debug.h"
#include "ntfs.h"

View file

@ -7,10 +7,8 @@
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/log2.h>
#include <linux/nls.h>
#include "debug.h"
#include "ntfs.h"

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,9 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"
static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr)

View file

@ -5,10 +5,7 @@
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/xattr.h>
@ -78,6 +75,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
size_t add_bytes, const struct EA_INFO **info)
{
int err;
struct ntfs_sb_info *sbi = ni->mi.sbi;
struct ATTR_LIST_ENTRY *le = NULL;
struct ATTRIB *attr_info, *attr_ea;
void *ea_p;
@ -102,10 +100,10 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
/* Check Ea limit. */
size = le32_to_cpu((*info)->size);
if (size > ni->mi.sbi->ea_max_size)
if (size > sbi->ea_max_size)
return -EFBIG;
if (attr_size(attr_ea) > ni->mi.sbi->ea_max_size)
if (attr_size(attr_ea) > sbi->ea_max_size)
return -EFBIG;
/* Allocate memory for packed Ea. */
@ -113,15 +111,16 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
if (!ea_p)
return -ENOMEM;
if (attr_ea->non_res) {
if (!size) {
;
} else if (attr_ea->non_res) {
struct runs_tree run;
run_init(&run);
err = attr_load_runs(attr_ea, ni, &run, NULL);
if (!err)
err = ntfs_read_run_nb(ni->mi.sbi, &run, 0, ea_p, size,
NULL);
err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
run_close(&run);
if (err)
@ -260,7 +259,7 @@ out:
static noinline int ntfs_set_ea(struct inode *inode, const char *name,
size_t name_len, const void *value,
size_t val_size, int flags, int locked)
size_t val_size, int flags)
{
struct ntfs_inode *ni = ntfs_i(inode);
struct ntfs_sb_info *sbi = ni->mi.sbi;
@ -279,8 +278,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
u64 new_sz;
void *p;
if (!locked)
ni_lock(ni);
ni_lock(ni);
run_init(&ea_run);
@ -370,21 +368,22 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
new_ea->name[name_len] = 0;
memcpy(new_ea->name + name_len + 1, value, val_size);
new_pack = le16_to_cpu(ea_info.size_pack) + packed_ea_size(new_ea);
/* Should fit into 16 bits. */
if (new_pack > 0xffff) {
err = -EFBIG; // -EINVAL?
goto out;
}
ea_info.size_pack = cpu_to_le16(new_pack);
/* New size of ATTR_EA. */
size += add;
if (size > sbi->ea_max_size) {
ea_info.size = cpu_to_le32(size);
/*
* 1. Check ea_info.size_pack for overflow.
* 2. New attibute size must fit value from $AttrDef
*/
if (new_pack > 0xffff || size > sbi->ea_max_size) {
ntfs_inode_warn(
inode,
"The size of extended attributes must not exceed 64KiB");
err = -EFBIG; // -EINVAL?
goto out;
}
ea_info.size = cpu_to_le32(size);
update_ea:
@ -444,7 +443,7 @@ update_ea:
/* Delete xattr, ATTR_EA */
ni_remove_attr_le(ni, attr, mi, le);
} else if (attr->non_res) {
err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size);
err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0);
if (err)
goto out;
} else {
@ -468,8 +467,7 @@ update_ea:
mark_inode_dirty(&ni->vfs_inode);
out:
if (!locked)
ni_unlock(ni);
ni_unlock(ni);
run_close(&ea_run);
kfree(ea_all);
@ -478,12 +476,6 @@ out:
}
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
static inline void ntfs_posix_acl_release(struct posix_acl *acl)
{
if (acl && refcount_dec_and_test(&acl->a_refcount))
kfree(acl);
}
static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
struct inode *inode, int type,
int locked)
@ -521,12 +513,15 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
/* Translate extended attribute to acl. */
if (err >= 0) {
acl = posix_acl_from_xattr(mnt_userns, buf, err);
if (!IS_ERR(acl))
set_cached_acl(inode, type, acl);
} else if (err == -ENODATA) {
acl = NULL;
} else {
acl = err == -ENODATA ? NULL : ERR_PTR(err);
acl = ERR_PTR(err);
}
if (!IS_ERR(acl))
set_cached_acl(inode, type, acl);
__putname(buf);
return acl;
@ -546,12 +541,13 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
struct inode *inode, struct posix_acl *acl,
int type, int locked)
int type)
{
const char *name;
size_t size, name_len;
void *value = NULL;
int err = 0;
int flags;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
@ -561,22 +557,15 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
if (acl) {
umode_t mode = inode->i_mode;
err = posix_acl_equiv_mode(acl, &mode);
if (err < 0)
return err;
err = posix_acl_update_mode(mnt_userns, inode, &mode,
&acl);
if (err)
goto out;
if (inode->i_mode != mode) {
inode->i_mode = mode;
mark_inode_dirty(inode);
}
if (!err) {
/*
* ACL can be exactly represented in the
* traditional file mode permission bits.
*/
acl = NULL;
}
}
name = XATTR_NAME_POSIX_ACL_ACCESS;
name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1;
@ -594,20 +583,24 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
}
if (!acl) {
/* Remove xattr if it can be presented via mode. */
size = 0;
value = NULL;
flags = XATTR_REPLACE;
} else {
size = posix_acl_xattr_size(acl->a_count);
value = kmalloc(size, GFP_NOFS);
if (!value)
return -ENOMEM;
err = posix_acl_to_xattr(mnt_userns, acl, value, size);
if (err < 0)
goto out;
flags = 0;
}
err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked);
err = ntfs_set_ea(inode, name, name_len, value, size, flags);
if (err == -ENODATA && !size)
err = 0; /* Removing non existed xattr. */
if (!err)
set_cached_acl(inode, type, acl);
@ -623,68 +616,7 @@ out:
int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
struct posix_acl *acl, int type)
{
return ntfs_set_acl_ex(mnt_userns, inode, acl, type, 0);
}
static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
struct inode *inode, int type, void *buffer,
size_t size)
{
struct posix_acl *acl;
int err;
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
return -EOPNOTSUPP;
}
acl = ntfs_get_acl(inode, type, false);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl)
return -ENODATA;
err = posix_acl_to_xattr(mnt_userns, acl, buffer, size);
ntfs_posix_acl_release(acl);
return err;
}
static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
struct inode *inode, int type, const void *value,
size_t size)
{
struct posix_acl *acl;
int err;
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
return -EOPNOTSUPP;
}
if (!inode_owner_or_capable(mnt_userns, inode))
return -EPERM;
if (!value) {
acl = NULL;
} else {
acl = posix_acl_from_xattr(mnt_userns, value, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
err = posix_acl_valid(mnt_userns, acl);
if (err)
goto release_and_out;
}
}
err = ntfs_set_acl(mnt_userns, inode, acl, type);
release_and_out:
ntfs_posix_acl_release(acl);
return err;
return ntfs_set_acl_ex(mnt_userns, inode, acl, type);
}
/*
@ -698,54 +630,27 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
struct posix_acl *default_acl, *acl;
int err;
/*
* TODO: Refactoring lock.
* ni_lock(dir) ... -> posix_acl_create(dir,...) -> ntfs_get_acl -> ni_lock(dir)
*/
inode->i_default_acl = NULL;
err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
if (err)
return err;
default_acl = ntfs_get_acl_ex(mnt_userns, dir, ACL_TYPE_DEFAULT, 1);
if (!default_acl || default_acl == ERR_PTR(-EOPNOTSUPP)) {
inode->i_mode &= ~current_umask();
err = 0;
goto out;
}
if (IS_ERR(default_acl)) {
err = PTR_ERR(default_acl);
goto out;
}
acl = default_acl;
err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
if (err < 0)
goto out1;
if (!err) {
posix_acl_release(acl);
acl = NULL;
}
if (!S_ISDIR(inode->i_mode)) {
posix_acl_release(default_acl);
default_acl = NULL;
}
if (default_acl)
if (default_acl) {
err = ntfs_set_acl_ex(mnt_userns, inode, default_acl,
ACL_TYPE_DEFAULT, 1);
ACL_TYPE_DEFAULT);
posix_acl_release(default_acl);
} else {
inode->i_default_acl = NULL;
}
if (!acl)
inode->i_acl = NULL;
else if (!err)
err = ntfs_set_acl_ex(mnt_userns, inode, acl, ACL_TYPE_ACCESS,
1);
else {
if (!err)
err = ntfs_set_acl_ex(mnt_userns, inode, acl,
ACL_TYPE_ACCESS);
posix_acl_release(acl);
}
posix_acl_release(acl);
out1:
posix_acl_release(default_acl);
out:
return err;
}
#endif
@ -772,7 +677,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
int mask)
{
if (ntfs_sb(inode->i_sb)->options.no_acs_rules) {
if (ntfs_sb(inode->i_sb)->options->noacsrules) {
/* "No access rules" mode - Allow all changes. */
return 0;
}
@ -880,23 +785,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
goto out;
}
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
(name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
/* TODO: init_user_ns? */
err = ntfs_xattr_get_acl(
&init_user_ns, inode,
name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
? ACL_TYPE_ACCESS
: ACL_TYPE_DEFAULT,
buffer, size);
goto out;
}
#endif
/* Deal with NTFS extended attribute. */
err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
@ -1009,24 +897,8 @@ set_new_fa:
goto out;
}
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
(name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
err = ntfs_xattr_set_acl(
mnt_userns, inode,
name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
? ACL_TYPE_ACCESS
: ACL_TYPE_DEFAULT,
value, size);
goto out;
}
#endif
/* Deal with NTFS extended attribute. */
err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
err = ntfs_set_ea(inode, name, name_len, value, size, flags);
out:
return err;
@ -1042,28 +914,29 @@ int ntfs_save_wsl_perm(struct inode *inode)
int err;
__le32 value;
/* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */
value = cpu_to_le32(i_uid_read(inode));
err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
sizeof(value), 0, 0);
sizeof(value), 0);
if (err)
goto out;
value = cpu_to_le32(i_gid_read(inode));
err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
sizeof(value), 0, 0);
sizeof(value), 0);
if (err)
goto out;
value = cpu_to_le32(inode->i_mode);
err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
sizeof(value), 0, 0);
sizeof(value), 0);
if (err)
goto out;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
value = cpu_to_le32(inode->i_rdev);
err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
sizeof(value), 0, 0);
sizeof(value), 0);
if (err)
goto out;
}