mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
ntfs: update in-memory, on-disk structures and headers
Update the NTFS filesystem driver's in-memory and on-disk structures:
- Introduce the infrastructure and initial support for reparse
points and EA attribute.
- Refactor the core ntfs_inode and ntfs_volume structures to support
new features such as iomap.
- Remove the unnecessary types.h and endian.h headers.
- Reorganize the comments in headers for better readability, including
fixing warnings from checkpatch.pl.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Acked-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
@@ -1,88 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* aops.h - Defines for NTFS kernel address space operations and page cache
|
||||
* handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_AOPS_H
|
||||
#define _LINUX_NTFS_AOPS_H
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "inode.h"
|
||||
|
||||
/**
|
||||
* ntfs_unmap_page - release a page that was mapped using ntfs_map_page()
|
||||
* @page: the page to release
|
||||
*
|
||||
* Unpin, unmap and release a page that was obtained from ntfs_map_page().
|
||||
*/
|
||||
static inline void ntfs_unmap_page(struct page *page)
|
||||
{
|
||||
kunmap(page);
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_map_page - map a page into accessible memory, reading it if necessary
|
||||
* @mapping: address space for which to obtain the page
|
||||
* @index: index into the page cache for @mapping of the page to map
|
||||
*
|
||||
* Read a page from the page cache of the address space @mapping at position
|
||||
* @index, where @index is in units of PAGE_SIZE, and not in bytes.
|
||||
*
|
||||
* If the page is not in memory it is loaded from disk first using the
|
||||
* read_folio method defined in the address space operations of @mapping
|
||||
* and the page is added to the page cache of @mapping in the process.
|
||||
*
|
||||
* If the page belongs to an mst protected attribute and it is marked as such
|
||||
* in its ntfs inode (NInoMstProtected()) the mst fixups are applied but no
|
||||
* error checking is performed. This means the caller has to verify whether
|
||||
* the ntfs record(s) contained in the page are valid or not using one of the
|
||||
* ntfs_is_XXXX_record{,p}() macros, where XXXX is the record type you are
|
||||
* expecting to see. (For details of the macros, see fs/ntfs/layout.h.)
|
||||
*
|
||||
* If the page is in high memory it is mapped into memory directly addressible
|
||||
* by the kernel.
|
||||
*
|
||||
* Finally the page count is incremented, thus pinning the page into place.
|
||||
*
|
||||
* The above means that page_address(page) can be used on all pages obtained
|
||||
* with ntfs_map_page() to get the kernel virtual address of the page.
|
||||
*
|
||||
* When finished with the page, the caller has to call ntfs_unmap_page() to
|
||||
* unpin, unmap and release the page.
|
||||
*
|
||||
* Note this does not grant exclusive access. If such is desired, the caller
|
||||
* must provide it independently of the ntfs_{un}map_page() calls by using
|
||||
* a {rw_}semaphore or other means of serialization. A spin lock cannot be
|
||||
* used as ntfs_map_page() can block.
|
||||
*
|
||||
* The unlocked and uptodate page is returned on success or an encoded error
|
||||
* on failure. Caller has to test for error using the IS_ERR() macro on the
|
||||
* return value. If that evaluates to 'true', the negative error code can be
|
||||
* obtained using PTR_ERR() on the return value of ntfs_map_page().
|
||||
*/
|
||||
static inline struct page *ntfs_map_page(struct address_space *mapping,
|
||||
unsigned long index)
|
||||
{
|
||||
struct page *page = read_mapping_page(mapping, index, NULL);
|
||||
|
||||
if (!IS_ERR(page))
|
||||
kmap(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
extern void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
#endif /* _LINUX_NTFS_AOPS_H */
|
||||
188
fs/ntfs/attrib.h
188
fs/ntfs/attrib.h
@@ -1,27 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
* Defines for attribute handling in NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_ATTRIB_H
|
||||
#define _LINUX_NTFS_ATTRIB_H
|
||||
|
||||
#include "endian.h"
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "runlist.h"
|
||||
#include "volume.h"
|
||||
#include "ntfs.h"
|
||||
#include "dir.h"
|
||||
|
||||
/**
|
||||
extern __le16 AT_UNNAMED[];
|
||||
|
||||
/*
|
||||
* ntfs_attr_search_ctx - used in attribute search functions
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @is_first: if true ntfs_attr_lookup() begins search with @attr, else after
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @mapped_mrec: true if @mrec was mapped by the search functions
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @is_first: if true ntfs_attr_lookup() begins search with @attr, else after
|
||||
* @ntfs_ino: Inode owning this attribute search
|
||||
* @al_entry: Current attribute list entry
|
||||
* @base_ntfs_ino: Base inode
|
||||
* @mapped_base_mrec: true if @base_mrec was mapped by the search
|
||||
* @base_attr: Base attribute record pointer
|
||||
*
|
||||
* Structure must be initialized to zero before the first call to one of the
|
||||
* attribute search functions. Initialize @mrec to point to the mft record to
|
||||
@@ -35,68 +39,126 @@
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
typedef struct {
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
struct ntfs_attr_search_ctx {
|
||||
struct mft_record *mrec;
|
||||
bool mapped_mrec;
|
||||
struct attr_record *attr;
|
||||
bool is_first;
|
||||
ntfs_inode *ntfs_ino;
|
||||
ATTR_LIST_ENTRY *al_entry;
|
||||
ntfs_inode *base_ntfs_ino;
|
||||
MFT_RECORD *base_mrec;
|
||||
ATTR_RECORD *base_attr;
|
||||
} ntfs_attr_search_ctx;
|
||||
struct ntfs_inode *ntfs_ino;
|
||||
struct attr_list_entry *al_entry;
|
||||
struct ntfs_inode *base_ntfs_ino;
|
||||
struct mft_record *base_mrec;
|
||||
bool mapped_base_mrec;
|
||||
struct attr_record *base_attr;
|
||||
};
|
||||
|
||||
extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
|
||||
enum { /* ways of processing holes when expanding */
|
||||
HOLES_NO,
|
||||
HOLES_OK,
|
||||
};
|
||||
|
||||
extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
|
||||
int ntfs_map_runlist_nolock(struct ntfs_inode *ni, s64 vcn,
|
||||
struct ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_map_runlist(struct ntfs_inode *ni, s64 vcn);
|
||||
s64 ntfs_attr_vcn_to_lcn_nolock(struct ntfs_inode *ni, const s64 vcn,
|
||||
const bool write_locked);
|
||||
struct runlist_element *ntfs_attr_find_vcn_nolock(struct ntfs_inode *ni,
|
||||
const s64 vcn, struct ntfs_attr_search_ctx *ctx);
|
||||
struct runlist_element *__ntfs_attr_find_vcn_nolock(struct runlist *runlist,
|
||||
const s64 vcn);
|
||||
int ntfs_attr_map_whole_runlist(struct ntfs_inode *ni);
|
||||
int ntfs_attr_lookup(const __le32 type, const __le16 *name,
|
||||
const u32 name_len, const u32 ic,
|
||||
const s64 lowest_vcn, const u8 *val, const u32 val_len,
|
||||
struct ntfs_attr_search_ctx *ctx);
|
||||
int load_attribute_list(struct ntfs_inode *base_ni,
|
||||
u8 *al_start, const s64 size);
|
||||
|
||||
extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
|
||||
const VCN vcn, ntfs_attr_search_ctx *ctx);
|
||||
|
||||
int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern int load_attribute_list(ntfs_volume *vol, runlist *rl, u8 *al_start,
|
||||
const s64 size, const s64 initialized_size);
|
||||
|
||||
static inline s64 ntfs_attr_size(const ATTR_RECORD *a)
|
||||
static inline s64 ntfs_attr_size(const struct attr_record *a)
|
||||
{
|
||||
if (!a->non_resident)
|
||||
return (s64)le32_to_cpu(a->data.resident.value_length);
|
||||
return sle64_to_cpu(a->data.non_resident.data_size);
|
||||
return le64_to_cpu(a->data.non_resident.data_size);
|
||||
}
|
||||
|
||||
extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
|
||||
MFT_RECORD *mrec);
|
||||
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPE type, const s64 size);
|
||||
extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPE type);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPE type);
|
||||
|
||||
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
|
||||
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
void ntfs_attr_reinit_search_ctx(struct ntfs_attr_search_ctx *ctx);
|
||||
struct ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(struct ntfs_inode *ni,
|
||||
struct mft_record *mrec);
|
||||
void ntfs_attr_put_search_ctx(struct ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_attr_size_bounds_check(const struct ntfs_volume *vol,
|
||||
const __le32 type, const s64 size);
|
||||
int ntfs_attr_can_be_resident(const struct ntfs_volume *vol,
|
||||
const __le32 type);
|
||||
int ntfs_attr_map_cluster(struct ntfs_inode *ni, s64 vcn_start, s64 *lcn_start,
|
||||
s64 *lcn_count, s64 max_clu_count, bool *balloc, bool update_mp, bool skip_holes);
|
||||
int ntfs_attr_record_resize(struct mft_record *m, struct attr_record *a, u32 new_size);
|
||||
int ntfs_resident_attr_value_resize(struct mft_record *m, struct attr_record *a,
|
||||
const u32 new_size);
|
||||
|
||||
extern int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size);
|
||||
|
||||
extern s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
|
||||
const s64 new_data_size, const s64 data_start);
|
||||
|
||||
extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt,
|
||||
int ntfs_attr_make_non_resident(struct ntfs_inode *ni, const u32 data_size);
|
||||
int ntfs_attr_set(struct ntfs_inode *ni, const s64 ofs, const s64 cnt,
|
||||
const u8 val);
|
||||
int ntfs_attr_set_initialized_size(struct ntfs_inode *ni, loff_t new_size);
|
||||
int ntfs_attr_open(struct ntfs_inode *ni, const __le32 type,
|
||||
__le16 *name, u32 name_len);
|
||||
void ntfs_attr_close(struct ntfs_inode *n);
|
||||
int ntfs_attr_fallocate(struct ntfs_inode *ni, loff_t start, loff_t byte_len, bool keep_size);
|
||||
int ntfs_non_resident_attr_insert_range(struct ntfs_inode *ni, s64 start_vcn, s64 len);
|
||||
int ntfs_non_resident_attr_collapse_range(struct ntfs_inode *ni, s64 start_vcn, s64 len);
|
||||
int ntfs_non_resident_attr_punch_hole(struct ntfs_inode *ni, s64 start_vcn, s64 len);
|
||||
int __ntfs_attr_truncate_vfs(struct ntfs_inode *ni, const s64 newsize,
|
||||
const s64 i_size);
|
||||
int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 prealloc_size);
|
||||
int ntfs_attr_truncate_i(struct ntfs_inode *ni, const s64 newsize, unsigned int holes);
|
||||
int ntfs_attr_truncate(struct ntfs_inode *ni, const s64 newsize);
|
||||
int ntfs_attr_rm(struct ntfs_inode *ni);
|
||||
int ntfs_attr_exist(struct ntfs_inode *ni, const __le32 type, __le16 *name,
|
||||
u32 name_len);
|
||||
int ntfs_attr_remove(struct ntfs_inode *ni, const __le32 type, __le16 *name,
|
||||
u32 name_len);
|
||||
int ntfs_attr_record_rm(struct ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_attr_record_move_to(struct ntfs_attr_search_ctx *ctx, struct ntfs_inode *ni);
|
||||
int ntfs_attr_add(struct ntfs_inode *ni, __le32 type,
|
||||
__le16 *name, u8 name_len, u8 *val, s64 size);
|
||||
int ntfs_attr_record_move_away(struct ntfs_attr_search_ctx *ctx, int extra);
|
||||
char *ntfs_attr_name_get(const struct ntfs_volume *vol, const __le16 *uname,
|
||||
const int uname_len);
|
||||
void ntfs_attr_name_free(unsigned char **name);
|
||||
void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type,
|
||||
__le16 *name, u32 name_len, s64 *data_size);
|
||||
int ntfs_resident_attr_record_add(struct ntfs_inode *ni, __le32 type,
|
||||
__le16 *name, u8 name_len, u8 *val, u32 size,
|
||||
__le16 flags);
|
||||
int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn);
|
||||
struct runlist_element *ntfs_attr_vcn_to_rl(struct ntfs_inode *ni, s64 vcn, s64 *lcn);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
/*
|
||||
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
||||
* @ctx: initialised attribute search context
|
||||
*
|
||||
* Syntactic sugar for walking attributes in an inode.
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code from
|
||||
* ntfs_attr_lookup().
|
||||
*
|
||||
* Example: When you want to enumerate all attributes in an open ntfs inode
|
||||
* @ni, you can simply do:
|
||||
*
|
||||
* int err;
|
||||
* struct ntfs_attr_search_ctx *ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
* if (!ctx)
|
||||
* // Error code is in errno. Handle this case.
|
||||
* while (!(err = ntfs_attrs_walk(ctx))) {
|
||||
* struct attr_record *attr = ctx->attr;
|
||||
* // attr now contains the next attribute. Do whatever you want
|
||||
* // with it and then just continue with the while loop.
|
||||
* }
|
||||
* if (err && errno != ENOENT)
|
||||
* // Ooops. An error occurred! You should handle this case.
|
||||
* // Now finished with all attributes in the inode.
|
||||
*/
|
||||
static inline int ntfs_attrs_walk(struct ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
|
||||
NULL, 0, ctx);
|
||||
}
|
||||
#endif /* _LINUX_NTFS_ATTRIB_H */
|
||||
|
||||
20
fs/ntfs/attrlist.h
Normal file
20
fs/ntfs/attrlist.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Exports for attribute list attribute handling.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_ATTRLIST_H
|
||||
#define _NTFS_ATTRLIST_H
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
int ntfs_attrlist_need(struct ntfs_inode *ni);
|
||||
int ntfs_attrlist_entry_add(struct ntfs_inode *ni, struct attr_record *attr);
|
||||
int ntfs_attrlist_entry_rm(struct ntfs_attr_search_ctx *ctx);
|
||||
int ntfs_attrlist_update(struct ntfs_inode *base_ni);
|
||||
|
||||
#endif /* defined _NTFS_ATTRLIST_H */
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* bitmap.h - Defines for NTFS kernel bitmap handling. Part of the Linux-NTFS
|
||||
* project.
|
||||
* Defines for NTFS kernel bitmap handling.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*/
|
||||
@@ -9,16 +8,15 @@
|
||||
#ifndef _LINUX_NTFS_BITMAP_H
|
||||
#define _LINUX_NTFS_BITMAP_H
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
|
||||
extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
|
||||
int ntfs_trim_fs(struct ntfs_volume *vol, struct fstrim_range *range);
|
||||
int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
|
||||
const s64 count, const u8 value, const bool is_rollback);
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
|
||||
* @vi: vfs inode describing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
@@ -37,7 +35,7 @@ static inline int ntfs_bitmap_set_bits_in_run(struct inode *vi,
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_bitmap_set_run - set a run of bits in a bitmap
|
||||
* @vi: vfs inode describing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
@@ -54,7 +52,7 @@ static inline int ntfs_bitmap_set_run(struct inode *vi, const s64 start_bit,
|
||||
return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_bitmap_clear_run - clear a run of bits in a bitmap
|
||||
* @vi: vfs inode describing the bitmap
|
||||
* @start_bit: first bit to clear
|
||||
@@ -71,7 +69,7 @@ static inline int ntfs_bitmap_clear_run(struct inode *vi, const s64 start_bit,
|
||||
return ntfs_bitmap_set_bits_in_run(vi, start_bit, count, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_bitmap_set_bit - set a bit in a bitmap
|
||||
* @vi: vfs inode describing the bitmap
|
||||
* @bit: bit to set
|
||||
@@ -85,7 +83,7 @@ static inline int ntfs_bitmap_set_bit(struct inode *vi, const s64 bit)
|
||||
return ntfs_bitmap_set_run(vi, bit, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_bitmap_clear_bit - clear a bit in a bitmap
|
||||
* @vi: vfs inode describing the bitmap
|
||||
* @bit: bit to clear
|
||||
@@ -99,6 +97,4 @@ static inline int ntfs_bitmap_clear_bit(struct inode *vi, const s64 bit)
|
||||
return ntfs_bitmap_clear_run(vi, bit, 1);
|
||||
}
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
#endif /* defined _LINUX_NTFS_BITMAP_H */
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* collate.h - Defines for NTFS kernel collation handling. Part of the
|
||||
* Linux-NTFS project.
|
||||
* Defines for NTFS kernel collation handling.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*
|
||||
* Part of this file is based on code from the NTFS-3G.
|
||||
* and is copyrighted by the respective authors below:
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_COLLATE_H
|
||||
#define _LINUX_NTFS_COLLATE_H
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
|
||||
static inline bool ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
|
||||
static inline bool ntfs_is_collation_rule_supported(__le32 cr)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* FIXME: At the moment we only support COLLATION_BINARY and
|
||||
* COLLATION_NTOFS_ULONG, so we return false for everything else for
|
||||
* now.
|
||||
*/
|
||||
if (unlikely(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG))
|
||||
if (unlikely(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG &&
|
||||
cr != COLLATION_FILE_NAME) && cr != COLLATION_NTOFS_ULONGS)
|
||||
return false;
|
||||
i = le32_to_cpu(cr);
|
||||
if (likely(((i >= 0) && (i <= 0x02)) ||
|
||||
@@ -29,8 +29,8 @@ static inline bool ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len);
|
||||
int ntfs_collate(struct ntfs_volume *vol, __le32 cr,
|
||||
const void *data1, const u32 data1_len,
|
||||
const void *data2, const u32 data2_len);
|
||||
|
||||
#endif /* _LINUX_NTFS_COLLATE_H */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* debug.h - NTFS kernel debug support. Part of the Linux-NTFS project.
|
||||
* NTFS kernel debug support.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
*/
|
||||
@@ -19,7 +19,7 @@ extern int debug_msgs;
|
||||
extern __printf(4, 5)
|
||||
void __ntfs_debug(const char *file, int line, const char *function,
|
||||
const char *format, ...);
|
||||
/**
|
||||
/*
|
||||
* ntfs_debug - write a debug level message to syslog
|
||||
* @f: a printf format string containing the message
|
||||
* @...: the variables to substitute into @f
|
||||
@@ -30,7 +30,7 @@ void __ntfs_debug(const char *file, int line, const char *function,
|
||||
#define ntfs_debug(f, a...) \
|
||||
__ntfs_debug(__FILE__, __LINE__, __func__, f, ##a)
|
||||
|
||||
extern void ntfs_debug_dump_runlist(const runlist_element *rl);
|
||||
void ntfs_debug_dump_runlist(const struct runlist_element *rl);
|
||||
|
||||
#else /* !DEBUG */
|
||||
|
||||
@@ -40,7 +40,11 @@ do { \
|
||||
no_printk(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ntfs_debug_dump_runlist(rl) do {} while (0)
|
||||
#define ntfs_debug_dump_runlist(rl) \
|
||||
do { \
|
||||
if (0) \
|
||||
(void)rl; \
|
||||
} while (0)
|
||||
|
||||
#endif /* !DEBUG */
|
||||
|
||||
@@ -50,8 +54,10 @@ void __ntfs_warning(const char *function, const struct super_block *sb,
|
||||
#define ntfs_warning(sb, f, a...) __ntfs_warning(__func__, sb, f, ##a)
|
||||
|
||||
extern __printf(3, 4)
|
||||
void __ntfs_error(const char *function, const struct super_block *sb,
|
||||
void __ntfs_error(const char *function, struct super_block *sb,
|
||||
const char *fmt, ...);
|
||||
#define ntfs_error(sb, f, a...) __ntfs_error(__func__, sb, f, ##a)
|
||||
|
||||
void ntfs_handle_error(struct super_block *sb);
|
||||
|
||||
#endif /* _LINUX_NTFS_DEBUG_H */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* dir.h - Defines for directory handling in NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project.
|
||||
* Defines for directory handling in NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
*/
|
||||
@@ -9,26 +8,25 @@
|
||||
#ifndef _LINUX_NTFS_DIR_H
|
||||
#define _LINUX_NTFS_DIR_H
|
||||
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* ntfs_name is used to return the file name to the caller of
|
||||
* ntfs_lookup_inode_by_name() in order for the caller (namei.c::ntfs_lookup())
|
||||
* to be able to deal with dcache aliasing issues.
|
||||
*/
|
||||
typedef struct {
|
||||
MFT_REF mref;
|
||||
FILE_NAME_TYPE_FLAGS type;
|
||||
struct ntfs_name {
|
||||
u64 mref;
|
||||
u8 type;
|
||||
u8 len;
|
||||
ntfschar name[0];
|
||||
} __attribute__ ((__packed__)) ntfs_name;
|
||||
__le16 name[];
|
||||
} __packed;
|
||||
|
||||
/* The little endian Unicode string $I30 as a global constant. */
|
||||
extern ntfschar I30[5];
|
||||
extern __le16 I30[5];
|
||||
|
||||
extern MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni,
|
||||
const ntfschar *uname, const int uname_len, ntfs_name **res);
|
||||
u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_ni,
|
||||
const __le16 *uname, const int uname_len, struct ntfs_name **res);
|
||||
int ntfs_check_empty_dir(struct ntfs_inode *ni, struct mft_record *ni_mrec);
|
||||
|
||||
#endif /* _LINUX_NTFS_FS_DIR_H */
|
||||
|
||||
30
fs/ntfs/ea.h
Normal file
30
fs/ntfs/ea.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef _LINUX_NTFS_EA_H
|
||||
#define _LINUX_NTFS_EA_H
|
||||
|
||||
#define NTFS_EA_UID BIT(1)
|
||||
#define NTFS_EA_GID BIT(2)
|
||||
#define NTFS_EA_MODE BIT(3)
|
||||
|
||||
extern const struct xattr_handler *const ntfs_xattr_handlers[];
|
||||
|
||||
int ntfs_ea_set_wsl_not_symlink(struct ntfs_inode *ni, mode_t mode, dev_t dev);
|
||||
int ntfs_ea_get_wsl_inode(struct inode *inode, dev_t *rdevp, unsigned int flags);
|
||||
int ntfs_ea_set_wsl_inode(struct inode *inode, dev_t rdev, __le16 *ea_size,
|
||||
unsigned int flags);
|
||||
ssize_t ntfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
|
||||
#ifdef CONFIG_NTFS_FS_POSIX_ACL
|
||||
struct posix_acl *ntfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
int type);
|
||||
int ntfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct posix_acl *acl, int type);
|
||||
int ntfs_init_acl(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct inode *dir);
|
||||
#else
|
||||
#define ntfs_get_acl NULL
|
||||
#define ntfs_set_acl NULL
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_NTFS_EA_H */
|
||||
@@ -1,79 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* endian.h - Defines for endianness handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_ENDIAN_H
|
||||
#define _LINUX_NTFS_ENDIAN_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include "types.h"
|
||||
|
||||
/*
|
||||
* Signed endianness conversion functions.
|
||||
*/
|
||||
|
||||
static inline s16 sle16_to_cpu(sle16 x)
|
||||
{
|
||||
return le16_to_cpu((__force le16)x);
|
||||
}
|
||||
|
||||
static inline s32 sle32_to_cpu(sle32 x)
|
||||
{
|
||||
return le32_to_cpu((__force le32)x);
|
||||
}
|
||||
|
||||
static inline s64 sle64_to_cpu(sle64 x)
|
||||
{
|
||||
return le64_to_cpu((__force le64)x);
|
||||
}
|
||||
|
||||
static inline s16 sle16_to_cpup(sle16 *x)
|
||||
{
|
||||
return le16_to_cpu(*(__force le16*)x);
|
||||
}
|
||||
|
||||
static inline s32 sle32_to_cpup(sle32 *x)
|
||||
{
|
||||
return le32_to_cpu(*(__force le32*)x);
|
||||
}
|
||||
|
||||
static inline s64 sle64_to_cpup(sle64 *x)
|
||||
{
|
||||
return le64_to_cpu(*(__force le64*)x);
|
||||
}
|
||||
|
||||
static inline sle16 cpu_to_sle16(s16 x)
|
||||
{
|
||||
return (__force sle16)cpu_to_le16(x);
|
||||
}
|
||||
|
||||
static inline sle32 cpu_to_sle32(s32 x)
|
||||
{
|
||||
return (__force sle32)cpu_to_le32(x);
|
||||
}
|
||||
|
||||
static inline sle64 cpu_to_sle64(s64 x)
|
||||
{
|
||||
return (__force sle64)cpu_to_le64(x);
|
||||
}
|
||||
|
||||
static inline sle16 cpu_to_sle16p(s16 *x)
|
||||
{
|
||||
return (__force sle16)cpu_to_le16(*x);
|
||||
}
|
||||
|
||||
static inline sle32 cpu_to_sle32p(s32 *x)
|
||||
{
|
||||
return (__force sle32)cpu_to_le32(*x);
|
||||
}
|
||||
|
||||
static inline sle64 cpu_to_sle64p(s64 *x)
|
||||
{
|
||||
return (__force sle64)cpu_to_le64(*x);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NTFS_ENDIAN_H */
|
||||
135
fs/ntfs/index.h
135
fs/ntfs/index.h
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* index.h - Defines for NTFS kernel index handling. Part of the Linux-NTFS
|
||||
* project.
|
||||
* Defines for NTFS kernel index handling.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*/
|
||||
@@ -11,24 +10,35 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "attrib.h"
|
||||
#include "mft.h"
|
||||
#include "aops.h"
|
||||
|
||||
/**
|
||||
#define VCN_INDEX_ROOT_PARENT ((s64)-2)
|
||||
|
||||
#define MAX_PARENT_VCN 32
|
||||
|
||||
/*
|
||||
* @idx_ni: index inode containing the @entry described by this context
|
||||
* @name: Unicode name of the indexed attribute
|
||||
* (usually $I30 for directories)
|
||||
* @name_len: length of @name in Unicode characters
|
||||
* @entry: index entry (points into @ir or @ia)
|
||||
* @cr: creation time of the entry (for sorting/validation)
|
||||
* @data: index entry data (points into @entry)
|
||||
* @data_len: length in bytes of @data
|
||||
* @is_in_root: 'true' if @entry is in @ir and 'false' if it is in @ia
|
||||
* @ir: index root if @is_in_root and NULL otherwise
|
||||
* @actx: attribute search context if @is_in_root and NULL otherwise
|
||||
* @base_ni: base inode if @is_in_root and NULL otherwise
|
||||
* @ia: index block if @is_in_root is 'false' and NULL otherwise
|
||||
* @page: page if @is_in_root is 'false' and NULL otherwise
|
||||
* @ib: index block header (valid when @is_in_root is 'false')
|
||||
* @ia_ni: index allocation inode (extent inode) for @ia
|
||||
* @parent_pos: array of parent entry positions in the B-tree nodes
|
||||
* @parent_vcn: VCNs of parent index blocks in the B-tree traversal
|
||||
* @pindex: current depth (number of parent nodes) in the traversal
|
||||
* (maximum is MAX_PARENT_VCN)
|
||||
* @ib_dirty: true if the current index block (@ia/@ib) was modified
|
||||
* @block_size: size of index blocks in bytes (from $INDEX_ROOT or $Boot)
|
||||
* @vcn_size_bits: log2(cluster size)
|
||||
* @sync_write: true if synchronous writeback is requested for this context
|
||||
*
|
||||
* @idx_ni is the index inode this context belongs to.
|
||||
*
|
||||
@@ -53,82 +63,49 @@
|
||||
* When finished with the @entry and its @data, call ntfs_index_ctx_put() to
|
||||
* free the context and other associated resources.
|
||||
*
|
||||
* If the index entry was modified, call flush_dcache_index_entry_page()
|
||||
* immediately after the modification and either ntfs_index_entry_mark_dirty()
|
||||
* If the index entry was modified, ntfs_index_entry_mark_dirty()
|
||||
* or ntfs_index_entry_write() before the call to ntfs_index_ctx_put() to
|
||||
* ensure that the changes are written to disk.
|
||||
*/
|
||||
typedef struct {
|
||||
ntfs_inode *idx_ni;
|
||||
INDEX_ENTRY *entry;
|
||||
struct ntfs_index_context {
|
||||
struct ntfs_inode *idx_ni;
|
||||
__le16 *name;
|
||||
u32 name_len;
|
||||
struct index_entry *entry;
|
||||
__le32 cr;
|
||||
void *data;
|
||||
u16 data_len;
|
||||
bool is_in_root;
|
||||
INDEX_ROOT *ir;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
ntfs_inode *base_ni;
|
||||
INDEX_ALLOCATION *ia;
|
||||
struct page *page;
|
||||
} ntfs_index_context;
|
||||
struct index_root *ir;
|
||||
struct ntfs_attr_search_ctx *actx;
|
||||
struct index_block *ib;
|
||||
struct ntfs_inode *ia_ni;
|
||||
int parent_pos[MAX_PARENT_VCN];
|
||||
s64 parent_vcn[MAX_PARENT_VCN];
|
||||
int pindex;
|
||||
bool ib_dirty;
|
||||
u32 block_size;
|
||||
u8 vcn_size_bits;
|
||||
bool sync_write;
|
||||
};
|
||||
|
||||
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni);
|
||||
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
||||
int ntfs_index_entry_inconsistent(struct ntfs_index_context *icx, struct ntfs_volume *vol,
|
||||
const struct index_entry *ie, __le32 collation_rule, u64 inum);
|
||||
struct ntfs_index_context *ntfs_index_ctx_get(struct ntfs_inode *ni, __le16 *name,
|
||||
u32 name_len);
|
||||
void ntfs_index_ctx_put(struct ntfs_index_context *ictx);
|
||||
int ntfs_index_lookup(const void *key, const u32 key_len,
|
||||
struct ntfs_index_context *ictx);
|
||||
|
||||
extern int ntfs_index_lookup(const void *key, const int key_len,
|
||||
ntfs_index_context *ictx);
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
/**
|
||||
* ntfs_index_entry_flush_dcache_page - flush_dcache_page() for index entries
|
||||
* @ictx: ntfs index context describing the index entry
|
||||
*
|
||||
* Call flush_dcache_page() for the page in which an index entry resides.
|
||||
*
|
||||
* This must be called every time an index entry is modified, just after the
|
||||
* modification.
|
||||
*
|
||||
* If the index entry is in the index root attribute, simply flush the page
|
||||
* containing the mft record containing the index root attribute.
|
||||
*
|
||||
* If the index entry is in an index block belonging to the index allocation
|
||||
* attribute, simply flush the page cache page containing the index block.
|
||||
*/
|
||||
static inline void ntfs_index_entry_flush_dcache_page(ntfs_index_context *ictx)
|
||||
{
|
||||
if (ictx->is_in_root)
|
||||
flush_dcache_mft_record_page(ictx->actx->ntfs_ino);
|
||||
else
|
||||
flush_dcache_page(ictx->page);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_index_entry_mark_dirty - mark an index entry dirty
|
||||
* @ictx: ntfs index context describing the index entry
|
||||
*
|
||||
* Mark the index entry described by the index entry context @ictx dirty.
|
||||
*
|
||||
* If the index entry is in the index root attribute, simply mark the mft
|
||||
* record containing the index root attribute dirty. This ensures the mft
|
||||
* record, and hence the index root attribute, will be written out to disk
|
||||
* later.
|
||||
*
|
||||
* If the index entry is in an index block belonging to the index allocation
|
||||
* attribute, mark the buffers belonging to the index record as well as the
|
||||
* page cache page the index block is in dirty. This automatically marks the
|
||||
* VFS inode of the ntfs index inode to which the index entry belongs dirty,
|
||||
* too (I_DIRTY_PAGES) and this in turn ensures the page buffers, and hence the
|
||||
* dirty index block, will be written out to disk later.
|
||||
*/
|
||||
static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
|
||||
{
|
||||
if (ictx->is_in_root)
|
||||
mark_mft_record_dirty(ictx->actx->ntfs_ino);
|
||||
else
|
||||
mark_ntfs_record_dirty(ictx->page,
|
||||
(u8*)ictx->ia - (u8*)page_address(ictx->page));
|
||||
}
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
void ntfs_index_entry_mark_dirty(struct ntfs_index_context *ictx);
|
||||
int ntfs_index_add_filename(struct ntfs_inode *ni, struct file_name_attr *fn, u64 mref);
|
||||
int ntfs_index_remove(struct ntfs_inode *ni, const void *key, const u32 keylen);
|
||||
struct ntfs_inode *ntfs_ia_open(struct ntfs_index_context *icx, struct ntfs_inode *ni);
|
||||
struct index_entry *ntfs_index_walk_down(struct index_entry *ie, struct ntfs_index_context *ictx);
|
||||
struct index_entry *ntfs_index_next(struct index_entry *ie, struct ntfs_index_context *ictx);
|
||||
int ntfs_index_rm(struct ntfs_index_context *icx);
|
||||
void ntfs_index_ctx_reinit(struct ntfs_index_context *icx);
|
||||
int ntfs_ie_add(struct ntfs_index_context *icx, struct index_entry *ie);
|
||||
int ntfs_icx_ib_sync_write(struct ntfs_index_context *icx);
|
||||
|
||||
#endif /* _LINUX_NTFS_INDEX_H */
|
||||
|
||||
451
fs/ntfs/inode.h
451
fs/ntfs/inode.h
@@ -1,159 +1,202 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project.
|
||||
* Defines for inode structures NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2007 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_INODE_H
|
||||
#define _LINUX_NTFS_INODE_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
#include "types.h"
|
||||
#include "runlist.h"
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct _ntfs_inode ntfs_inode;
|
||||
enum ntfs_inode_mutex_lock_class {
|
||||
NTFS_INODE_MUTEX_PARENT,
|
||||
NTFS_INODE_MUTEX_NORMAL,
|
||||
NTFS_INODE_MUTEX_NORMAL_CHILD,
|
||||
NTFS_INODE_MUTEX_PARENT_2,
|
||||
NTFS_INODE_MUTEX_NORMAL_2,
|
||||
NTFS_EXTEND_MUTEX_PARENT,
|
||||
NTFS_EA_MUTEX_NORMAL
|
||||
};
|
||||
|
||||
/*
|
||||
* The NTFS in-memory inode structure. It is just used as an extension to the
|
||||
* fields already provided in the VFS inode.
|
||||
* @size_lock: Lock serializing access to inode sizes.
|
||||
* @state: NTFS specific flags describing this inode.
|
||||
* @flags: Flags describing the file. (Copy from STANDARD_INFORMATION).
|
||||
* @mft_no: Number of the mft record / inode.
|
||||
* @seq_no: Sequence number of the mft record.
|
||||
* @count: Inode reference count for book keeping.
|
||||
* @vol: Pointer to the ntfs volume of this inode.
|
||||
*
|
||||
* If NInoAttr() is true, the below fields describe the attribute which
|
||||
* this fake inode belongs to. The actual inode of this attribute is
|
||||
* pointed to by base_ntfs_ino and nr_extents is always set to -1 (see
|
||||
* below). For real inodes, we also set the type (AT_DATA for files and
|
||||
* AT_INDEX_ALLOCATION for directories), with the name = NULL and
|
||||
* name_len = 0 for files and name = I30 (global constant) and
|
||||
* name_len = 4 for directories.
|
||||
* @type: Attribute type of this fake inode.
|
||||
* @name: Attribute name of this fake inode.
|
||||
* @name_len: Attribute name length of this fake inode.
|
||||
* @runlist: If state has the NI_NonResident bit set, the runlist of
|
||||
* the unnamed data attribute (if a file) or of the index allocation
|
||||
* attribute (directory) or of the attribute described by the fake inode
|
||||
* (if NInoAttr()). If runlist.rl is NULL, the runlist has not been read
|
||||
* in yet or has been unmapped. If NI_NonResident is clear, the attribute
|
||||
* is resident (file and fake inode) or there is no $I30 index allocation
|
||||
* attribute (small directory). In the latter case runlist.rl is always
|
||||
* NULL.
|
||||
* @data_size: Copy from the attribute record.
|
||||
* @initialized_size: Copy from the attribute record.
|
||||
* @allocated_size: Copy from the attribute record.
|
||||
* @i_crtime: File Creation time.
|
||||
* @mrec: MFT record
|
||||
* @mrec_lock: Lock for serializing access to the mft record belonging to
|
||||
* this inode.
|
||||
* @folio: The folio containing the mft record of the inode.
|
||||
* @folio_ofs: Offset into the folio at which the mft record begins.
|
||||
* @mft_lcn: Number containing the mft record.
|
||||
* @mft_lcn_count: Number of clusters per mft record.
|
||||
*
|
||||
* Attribute list support (only for use by the attribute lookup
|
||||
* functions). Setup during read_inode for all inodes with attribute
|
||||
* lists. Only valid if NI_AttrList is set in state.
|
||||
* @attr_list_size: Length of attribute list value in bytes.
|
||||
* @attr_list: Attribute list value itself.
|
||||
*
|
||||
* It is a directory, $MFT, or an index inode.
|
||||
* @block_size: Size of an index block.
|
||||
* @vcn_size: Size of a vcn in this index.
|
||||
* @collation_rule: The collation rule for the index.
|
||||
* @block_size_bits: Log2 of the above.
|
||||
* @vcn_size_bits: Log2 of the above.
|
||||
*
|
||||
* It is a compressed/sparse file/attribute inode.
|
||||
* @size: Copy of compressed_size from $DATA.
|
||||
* @block_size: Size of a compression block (cb).
|
||||
* @block_size_bits: Log2 of the size of a cb.
|
||||
* @block_clusters: Number of clusters per cb.
|
||||
* @extent_lock: Lock for accessing/modifying the below.
|
||||
* @nr_extents: For a base mft record, the number of attached extent inodes
|
||||
* (0 if none), for extent records and for fake inodes describing an
|
||||
* attribute this is -1.
|
||||
*
|
||||
* This union is only used if nr_extents != 0.
|
||||
* @extent_ntfs_inos: For nr_extents > 0, array of the ntfs inodes of
|
||||
* the extent mft records belonging to this base inode which have been
|
||||
* loaded.
|
||||
* @base_ntfs_ino: For nr_extents == -1, the ntfs inode of the base mft
|
||||
* record. For fake inodes, the real (base) inode to which the attribute
|
||||
* belongs.
|
||||
* @i_dealloc_clusters: delayed allocated clusters.
|
||||
* @target: symlink buffer.
|
||||
*/
|
||||
struct _ntfs_inode {
|
||||
rwlock_t size_lock; /* Lock serializing access to inode sizes. */
|
||||
s64 initialized_size; /* Copy from the attribute record. */
|
||||
s64 allocated_size; /* Copy from the attribute record. */
|
||||
unsigned long state; /* NTFS specific flags describing this inode.
|
||||
See ntfs_inode_state_bits below. */
|
||||
unsigned long mft_no; /* Number of the mft record / inode. */
|
||||
u16 seq_no; /* Sequence number of the mft record. */
|
||||
atomic_t count; /* Inode reference count for book keeping. */
|
||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||
/*
|
||||
* If NInoAttr() is true, the below fields describe the attribute which
|
||||
* this fake inode belongs to. The actual inode of this attribute is
|
||||
* pointed to by base_ntfs_ino and nr_extents is always set to -1 (see
|
||||
* below). For real inodes, we also set the type (AT_DATA for files and
|
||||
* AT_INDEX_ALLOCATION for directories), with the name = NULL and
|
||||
* name_len = 0 for files and name = I30 (global constant) and
|
||||
* name_len = 4 for directories.
|
||||
*/
|
||||
ATTR_TYPE type; /* Attribute type of this fake inode. */
|
||||
ntfschar *name; /* Attribute name of this fake inode. */
|
||||
u32 name_len; /* Attribute name length of this fake inode. */
|
||||
runlist runlist; /* If state has the NI_NonResident bit set,
|
||||
the runlist of the unnamed data attribute
|
||||
(if a file) or of the index allocation
|
||||
attribute (directory) or of the attribute
|
||||
described by the fake inode (if NInoAttr()).
|
||||
If runlist.rl is NULL, the runlist has not
|
||||
been read in yet or has been unmapped. If
|
||||
NI_NonResident is clear, the attribute is
|
||||
resident (file and fake inode) or there is
|
||||
no $I30 index allocation attribute
|
||||
(small directory). In the latter case
|
||||
runlist.rl is always NULL.*/
|
||||
/*
|
||||
* The following fields are only valid for real inodes and extent
|
||||
* inodes.
|
||||
*/
|
||||
struct mutex mrec_lock; /* Lock for serializing access to the
|
||||
mft record belonging to this inode. */
|
||||
struct page *page; /* The page containing the mft record of the
|
||||
inode. This should only be touched by the
|
||||
(un)map_mft_record*() functions. */
|
||||
int page_ofs; /* Offset into the page at which the mft record
|
||||
begins. This should only be touched by the
|
||||
(un)map_mft_record*() functions. */
|
||||
/*
|
||||
* Attribute list support (only for use by the attribute lookup
|
||||
* functions). Setup during read_inode for all inodes with attribute
|
||||
* lists. Only valid if NI_AttrList is set in state, and attr_list_rl is
|
||||
* further only valid if NI_AttrListNonResident is set.
|
||||
*/
|
||||
u32 attr_list_size; /* Length of attribute list value in bytes. */
|
||||
u8 *attr_list; /* Attribute list value itself. */
|
||||
runlist attr_list_rl; /* Run list for the attribute list value. */
|
||||
struct ntfs_inode {
|
||||
rwlock_t size_lock;
|
||||
unsigned long state;
|
||||
__le32 flags;
|
||||
unsigned long mft_no;
|
||||
u16 seq_no;
|
||||
atomic_t count;
|
||||
struct ntfs_volume *vol;
|
||||
__le32 type;
|
||||
__le16 *name;
|
||||
u32 name_len;
|
||||
struct runlist runlist;
|
||||
s64 data_size;
|
||||
s64 initialized_size;
|
||||
s64 allocated_size;
|
||||
struct timespec64 i_crtime;
|
||||
void *mrec;
|
||||
struct mutex mrec_lock;
|
||||
struct folio *folio;
|
||||
int folio_ofs;
|
||||
s64 mft_lcn[2];
|
||||
unsigned int mft_lcn_count;
|
||||
u32 attr_list_size;
|
||||
u8 *attr_list;
|
||||
union {
|
||||
struct { /* It is a directory, $MFT, or an index inode. */
|
||||
u32 block_size; /* Size of an index block. */
|
||||
u32 vcn_size; /* Size of a vcn in this
|
||||
index. */
|
||||
COLLATION_RULE collation_rule; /* The collation rule
|
||||
for the index. */
|
||||
u8 block_size_bits; /* Log2 of the above. */
|
||||
u8 vcn_size_bits; /* Log2 of the above. */
|
||||
struct {
|
||||
u32 block_size;
|
||||
u32 vcn_size;
|
||||
__le32 collation_rule;
|
||||
u8 block_size_bits;
|
||||
u8 vcn_size_bits;
|
||||
} index;
|
||||
struct { /* It is a compressed/sparse file/attribute inode. */
|
||||
s64 size; /* Copy of compressed_size from
|
||||
$DATA. */
|
||||
u32 block_size; /* Size of a compression block
|
||||
(cb). */
|
||||
u8 block_size_bits; /* Log2 of the size of a cb. */
|
||||
u8 block_clusters; /* Number of clusters per cb. */
|
||||
struct {
|
||||
s64 size;
|
||||
u32 block_size;
|
||||
u8 block_size_bits;
|
||||
u8 block_clusters;
|
||||
} compressed;
|
||||
} itype;
|
||||
struct mutex extent_lock; /* Lock for accessing/modifying the
|
||||
below . */
|
||||
s32 nr_extents; /* For a base mft record, the number of attached extent
|
||||
inodes (0 if none), for extent records and for fake
|
||||
inodes describing an attribute this is -1. */
|
||||
union { /* This union is only used if nr_extents != 0. */
|
||||
ntfs_inode **extent_ntfs_inos; /* For nr_extents > 0, array of
|
||||
the ntfs inodes of the extent
|
||||
mft records belonging to
|
||||
this base inode which have
|
||||
been loaded. */
|
||||
ntfs_inode *base_ntfs_ino; /* For nr_extents == -1, the
|
||||
ntfs inode of the base mft
|
||||
record. For fake inodes, the
|
||||
real (base) inode to which
|
||||
the attribute belongs. */
|
||||
struct mutex extent_lock;
|
||||
s32 nr_extents;
|
||||
union {
|
||||
struct ntfs_inode **extent_ntfs_inos;
|
||||
struct ntfs_inode *base_ntfs_ino;
|
||||
} ext;
|
||||
unsigned int i_dealloc_clusters;
|
||||
char *target;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defined bits for the state field in the ntfs_inode structure.
|
||||
* (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
|
||||
*
|
||||
* NI_Dirty Mft record needs to be written to disk.
|
||||
* NI_AttrListDirty Mft record contains an attribute list.
|
||||
* NI_AttrList Mft record contains an attribute list.
|
||||
* NI_AttrListNonResident Attribute list is non-resident. Implies
|
||||
* NI_AttrList is set.
|
||||
* NI_Attr 1: Fake inode for attribute i/o.
|
||||
* 0: Real inode or extent inode.
|
||||
* NI_MstProtected Attribute is protected by MST fixups.
|
||||
* NI_NonResident Unnamed data attr is non-resident (f)
|
||||
* Attribute is non-resident (a).
|
||||
* NI_IndexAllocPresent $I30 index alloc attr is present (d).
|
||||
* NI_Compressed Unnamed data attr is compressed (f).
|
||||
* Create compressed files by default (d).
|
||||
* Attribute is compressed (a).
|
||||
* NI_Encrypted Unnamed data attr is encrypted (f).
|
||||
* Create encrypted files by default (d).
|
||||
* Attribute is encrypted (a).
|
||||
* NI_Sparse Unnamed data attr is sparse (f).
|
||||
* Create sparse files by default (d).
|
||||
* Attribute is sparse (a).
|
||||
* NI_SparseDisabled May not create sparse regions.
|
||||
* NI_FullyMapped Runlist is fully mapped.
|
||||
* NI_FileNameDirty FILE_NAME attributes need to be updated.
|
||||
* NI_BeingDeleted ntfs inode is being delated.
|
||||
* NI_BeingCreated ntfs inode is being created.
|
||||
* NI_HasEA ntfs inode has EA attribute.
|
||||
* NI_RunlistDirty runlist need to be updated.
|
||||
*/
|
||||
typedef enum {
|
||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||
NI_AttrList, /* 1: Mft record contains an attribute list. */
|
||||
NI_AttrListNonResident, /* 1: Attribute list is non-resident. Implies
|
||||
NI_AttrList is set. */
|
||||
|
||||
NI_Attr, /* 1: Fake inode for attribute i/o.
|
||||
0: Real inode or extent inode. */
|
||||
|
||||
NI_MstProtected, /* 1: Attribute is protected by MST fixups.
|
||||
0: Attribute is not protected by fixups. */
|
||||
NI_NonResident, /* 1: Unnamed data attr is non-resident (f).
|
||||
1: Attribute is non-resident (a). */
|
||||
NI_IndexAllocPresent = NI_NonResident, /* 1: $I30 index alloc attr is
|
||||
present (d). */
|
||||
NI_Compressed, /* 1: Unnamed data attr is compressed (f).
|
||||
1: Create compressed files by default (d).
|
||||
1: Attribute is compressed (a). */
|
||||
NI_Encrypted, /* 1: Unnamed data attr is encrypted (f).
|
||||
1: Create encrypted files by default (d).
|
||||
1: Attribute is encrypted (a). */
|
||||
NI_Sparse, /* 1: Unnamed data attr is sparse (f).
|
||||
1: Create sparse files by default (d).
|
||||
1: Attribute is sparse (a). */
|
||||
NI_SparseDisabled, /* 1: May not create sparse regions. */
|
||||
NI_TruncateFailed, /* 1: Last ntfs_truncate() call failed. */
|
||||
} ntfs_inode_state_bits;
|
||||
enum {
|
||||
NI_Dirty,
|
||||
NI_AttrListDirty,
|
||||
NI_AttrList,
|
||||
NI_AttrListNonResident,
|
||||
NI_Attr,
|
||||
NI_MstProtected,
|
||||
NI_NonResident,
|
||||
NI_IndexAllocPresent,
|
||||
NI_Compressed,
|
||||
NI_Encrypted,
|
||||
NI_Sparse,
|
||||
NI_SparseDisabled,
|
||||
NI_FullyMapped,
|
||||
NI_FileNameDirty,
|
||||
NI_BeingDeleted,
|
||||
NI_BeingCreated,
|
||||
NI_HasEA,
|
||||
NI_RunlistDirty,
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: We should be adding dirty mft records to a list somewhere and they
|
||||
@@ -165,37 +208,38 @@ typedef enum {
|
||||
* Macro tricks to expand the NInoFoo(), NInoSetFoo(), and NInoClearFoo()
|
||||
* functions.
|
||||
*/
|
||||
#define NINO_FNS(flag) \
|
||||
static inline int NIno##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline void NInoSet##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
set_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline void NInoClear##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
clear_bit(NI_##flag, &(ni)->state); \
|
||||
#define NINO_FNS(flag) \
|
||||
static inline int NIno##flag(struct ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline void NInoSet##flag(struct ntfs_inode *ni) \
|
||||
{ \
|
||||
set_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline void NInoClear##flag(struct ntfs_inode *ni) \
|
||||
{ \
|
||||
clear_bit(NI_##flag, &(ni)->state); \
|
||||
}
|
||||
|
||||
/*
|
||||
* As above for NInoTestSetFoo() and NInoTestClearFoo().
|
||||
*/
|
||||
#define TAS_NINO_FNS(flag) \
|
||||
static inline int NInoTestSet##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_and_set_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline int NInoTestClear##flag(ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_and_clear_bit(NI_##flag, &(ni)->state); \
|
||||
#define TAS_NINO_FNS(flag) \
|
||||
static inline int NInoTestSet##flag(struct ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_and_set_bit(NI_##flag, &(ni)->state); \
|
||||
} \
|
||||
static inline int NInoTestClear##flag(struct ntfs_inode *ni) \
|
||||
{ \
|
||||
return test_and_clear_bit(NI_##flag, &(ni)->state); \
|
||||
}
|
||||
|
||||
/* Emit the ntfs inode bitops functions. */
|
||||
NINO_FNS(Dirty)
|
||||
TAS_NINO_FNS(Dirty)
|
||||
NINO_FNS(AttrList)
|
||||
NINO_FNS(AttrListDirty)
|
||||
NINO_FNS(AttrListNonResident)
|
||||
NINO_FNS(Attr)
|
||||
NINO_FNS(MstProtected)
|
||||
@@ -205,40 +249,41 @@ NINO_FNS(Compressed)
|
||||
NINO_FNS(Encrypted)
|
||||
NINO_FNS(Sparse)
|
||||
NINO_FNS(SparseDisabled)
|
||||
NINO_FNS(TruncateFailed)
|
||||
NINO_FNS(FullyMapped)
|
||||
NINO_FNS(FileNameDirty)
|
||||
TAS_NINO_FNS(FileNameDirty)
|
||||
NINO_FNS(BeingDeleted)
|
||||
NINO_FNS(HasEA)
|
||||
NINO_FNS(RunlistDirty)
|
||||
|
||||
/*
|
||||
* The full structure containing a ntfs_inode and a vfs struct inode. Used for
|
||||
* all real and fake inodes but not for extent inodes which lack the vfs struct
|
||||
* inode.
|
||||
*/
|
||||
typedef struct {
|
||||
ntfs_inode ntfs_inode;
|
||||
struct big_ntfs_inode {
|
||||
struct ntfs_inode ntfs_inode;
|
||||
struct inode vfs_inode; /* The vfs inode structure. */
|
||||
} big_ntfs_inode;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* NTFS_I - return the ntfs inode given a vfs inode
|
||||
* @inode: VFS inode
|
||||
*
|
||||
* NTFS_I() returns the ntfs inode associated with the VFS @inode.
|
||||
*/
|
||||
static inline ntfs_inode *NTFS_I(struct inode *inode)
|
||||
static inline struct ntfs_inode *NTFS_I(struct inode *inode)
|
||||
{
|
||||
return (ntfs_inode *)container_of(inode, big_ntfs_inode, vfs_inode);
|
||||
return &container_of(inode, struct big_ntfs_inode, vfs_inode)->ntfs_inode;
|
||||
}
|
||||
|
||||
static inline struct inode *VFS_I(ntfs_inode *ni)
|
||||
static inline struct inode *VFS_I(struct ntfs_inode *ni)
|
||||
{
|
||||
return &((big_ntfs_inode *)ni)->vfs_inode;
|
||||
return &container_of(ni, struct big_ntfs_inode, ntfs_inode)->vfs_inode;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_attr - ntfs in memory attribute structure
|
||||
* @mft_no: mft record number of the base mft record of this attribute
|
||||
* @name: Unicode name of the attribute (NULL if unnamed)
|
||||
* @name_len: length of @name in Unicode characters (0 if unnamed)
|
||||
* @type: attribute type (see layout.h)
|
||||
*
|
||||
* This structure exists only to provide a small structure for the
|
||||
* ntfs_{attr_}iget()/ntfs_test_inode()/ntfs_init_locked_inode() mechanism.
|
||||
@@ -246,65 +291,69 @@ static inline struct inode *VFS_I(ntfs_inode *ni)
|
||||
* NOTE: Elements are ordered by size to make the structure as compact as
|
||||
* possible on all architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
struct ntfs_attr {
|
||||
unsigned long mft_no;
|
||||
ntfschar *name;
|
||||
__le16 *name;
|
||||
u32 name_len;
|
||||
ATTR_TYPE type;
|
||||
} ntfs_attr;
|
||||
__le32 type;
|
||||
unsigned long state;
|
||||
};
|
||||
|
||||
extern int ntfs_test_inode(struct inode *vi, void *data);
|
||||
|
||||
extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
|
||||
extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name,
|
||||
int ntfs_test_inode(struct inode *vi, void *data);
|
||||
struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
|
||||
struct inode *ntfs_attr_iget(struct inode *base_vi, __le32 type,
|
||||
__le16 *name, u32 name_len);
|
||||
struct inode *ntfs_index_iget(struct inode *base_vi, __le16 *name,
|
||||
u32 name_len);
|
||||
|
||||
extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
|
||||
extern void ntfs_free_big_inode(struct inode *inode);
|
||||
extern void ntfs_evict_big_inode(struct inode *vi);
|
||||
|
||||
extern void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni);
|
||||
struct inode *ntfs_alloc_big_inode(struct super_block *sb);
|
||||
void ntfs_free_big_inode(struct inode *inode);
|
||||
int ntfs_drop_big_inode(struct inode *inode);
|
||||
void ntfs_evict_big_inode(struct inode *vi);
|
||||
void __ntfs_init_inode(struct super_block *sb, struct ntfs_inode *ni);
|
||||
|
||||
static inline void ntfs_init_big_inode(struct inode *vi)
|
||||
{
|
||||
ntfs_inode *ni = NTFS_I(vi);
|
||||
struct ntfs_inode *ni = NTFS_I(vi);
|
||||
|
||||
ntfs_debug("Entering.");
|
||||
__ntfs_init_inode(vi->i_sb, ni);
|
||||
ni->mft_no = vi->i_ino;
|
||||
}
|
||||
|
||||
extern ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
|
||||
struct ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
|
||||
unsigned long mft_no);
|
||||
extern void ntfs_clear_extent_inode(ntfs_inode *ni);
|
||||
void ntfs_clear_extent_inode(struct ntfs_inode *ni);
|
||||
int ntfs_read_inode_mount(struct inode *vi);
|
||||
int ntfs_show_options(struct seq_file *sf, struct dentry *root);
|
||||
int ntfs_truncate_vfs(struct inode *vi, loff_t new_size, loff_t i_size);
|
||||
|
||||
extern int ntfs_read_inode_mount(struct inode *vi);
|
||||
int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, unsigned int request_mask,
|
||||
unsigned int query_flags);
|
||||
|
||||
extern int ntfs_show_options(struct seq_file *sf, struct dentry *root);
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
extern int ntfs_truncate(struct inode *vi);
|
||||
extern void ntfs_truncate_vfs(struct inode *vi);
|
||||
|
||||
extern int ntfs_setattr(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct iattr *attr);
|
||||
|
||||
extern int __ntfs_write_inode(struct inode *vi, int sync);
|
||||
int ntfs_get_block_mft_record(struct ntfs_inode *mft_ni, struct ntfs_inode *ni);
|
||||
int __ntfs_write_inode(struct inode *vi, int sync);
|
||||
int ntfs_inode_attach_all_extents(struct ntfs_inode *ni);
|
||||
int ntfs_inode_add_attrlist(struct ntfs_inode *ni);
|
||||
void ntfs_destroy_ext_inode(struct ntfs_inode *ni);
|
||||
int ntfs_inode_free_space(struct ntfs_inode *ni, int size);
|
||||
s64 ntfs_inode_attr_pread(struct inode *vi, s64 pos, s64 count, u8 *buf);
|
||||
s64 ntfs_inode_attr_pwrite(struct inode *vi, s64 pos, s64 count, u8 *buf,
|
||||
bool sync);
|
||||
int ntfs_inode_close(struct ntfs_inode *ni);
|
||||
|
||||
static inline void ntfs_commit_inode(struct inode *vi)
|
||||
{
|
||||
if (!is_bad_inode(vi))
|
||||
__ntfs_write_inode(vi, 1);
|
||||
return;
|
||||
__ntfs_write_inode(vi, 1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void ntfs_truncate_vfs(struct inode *vi) {}
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
int ntfs_inode_sync_filename(struct ntfs_inode *ni);
|
||||
int ntfs_extend_initialized_size(struct inode *vi, const loff_t offset,
|
||||
const loff_t new_size, bool bsync);
|
||||
void ntfs_set_vfs_operations(struct inode *inode, mode_t mode, dev_t dev);
|
||||
struct folio *ntfs_get_locked_folio(struct address_space *mapping,
|
||||
pgoff_t index, pgoff_t end_index, struct file_ra_state *ra);
|
||||
|
||||
#endif /* _LINUX_NTFS_INODE_H */
|
||||
|
||||
23
fs/ntfs/iomap.h
Normal file
23
fs/ntfs/iomap.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_IOMAP_H
|
||||
#define _LINUX_NTFS_IOMAP_H
|
||||
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/iomap.h>
|
||||
|
||||
#include "volume.h"
|
||||
#include "inode.h"
|
||||
|
||||
extern const struct iomap_ops ntfs_write_iomap_ops;
|
||||
extern const struct iomap_ops ntfs_read_iomap_ops;
|
||||
extern const struct iomap_ops ntfs_seek_iomap_ops;
|
||||
extern const struct iomap_ops ntfs_page_mkwrite_iomap_ops;
|
||||
extern const struct iomap_ops ntfs_dio_iomap_ops;
|
||||
extern const struct iomap_writeback_ops ntfs_writeback_ops;
|
||||
extern const struct iomap_write_ops ntfs_iomap_folio_ops;
|
||||
extern int ntfs_dio_zero_range(struct inode *inode, loff_t offset, loff_t length);
|
||||
#endif /* _LINUX_NTFS_IOMAP_H */
|
||||
2911
fs/ntfs/layout.h
2911
fs/ntfs/layout.h
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the
|
||||
* Linux-NTFS project.
|
||||
* Exports for NTFS kernel cluster (de)allocation.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
*/
|
||||
@@ -9,32 +8,35 @@
|
||||
#ifndef _LINUX_NTFS_LCNALLOC_H
|
||||
#define _LINUX_NTFS_LCNALLOC_H
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched/mm.h>
|
||||
|
||||
#include "attrib.h"
|
||||
#include "types.h"
|
||||
#include "inode.h"
|
||||
#include "runlist.h"
|
||||
#include "volume.h"
|
||||
|
||||
typedef enum {
|
||||
FIRST_ZONE = 0, /* For sanity checking. */
|
||||
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
||||
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
||||
LAST_ZONE = 1, /* For sanity checking. */
|
||||
} NTFS_CLUSTER_ALLOCATION_ZONES;
|
||||
/*
|
||||
* enum zone_type - Zone identifiers for cluster allocation policy
|
||||
*
|
||||
* FIRST_ZONE For sanity checking.
|
||||
* MFT_ZONE Allocate from $MFT zone.
|
||||
* DATA_ZONE Allocate from $DATA zone.
|
||||
* LAST_ZONE For sanity checking.
|
||||
*/
|
||||
enum {
|
||||
FIRST_ZONE = 0,
|
||||
MFT_ZONE = 0,
|
||||
DATA_ZONE = 1,
|
||||
LAST_ZONE = 1,
|
||||
};
|
||||
|
||||
extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
|
||||
const VCN start_vcn, const s64 count, const LCN start_lcn,
|
||||
const NTFS_CLUSTER_ALLOCATION_ZONES zone,
|
||||
const bool is_extension);
|
||||
struct runlist_element *ntfs_cluster_alloc(struct ntfs_volume *vol,
|
||||
const s64 start_vcn, const s64 count, const s64 start_lcn,
|
||||
const int zone,
|
||||
const bool is_extension,
|
||||
const bool is_contig,
|
||||
const bool is_dealloc);
|
||||
s64 __ntfs_cluster_free(struct ntfs_inode *ni, const s64 start_vcn,
|
||||
s64 count, struct ntfs_attr_search_ctx *ctx, const bool is_rollback);
|
||||
|
||||
extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
|
||||
s64 count, ntfs_attr_search_ctx *ctx, const bool is_rollback);
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_cluster_free - free clusters on an ntfs volume
|
||||
* @ni: ntfs inode whose runlist describes the clusters to free
|
||||
* @start_vcn: vcn in the runlist of @ni at which to start freeing clusters
|
||||
@@ -90,16 +92,16 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
|
||||
* - If @ctx is not NULL, the base mft record must be mapped on entry
|
||||
* and it will be left mapped on return.
|
||||
*/
|
||||
static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
|
||||
s64 count, ntfs_attr_search_ctx *ctx)
|
||||
static inline s64 ntfs_cluster_free(struct ntfs_inode *ni, const s64 start_vcn,
|
||||
s64 count, struct ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
return __ntfs_cluster_free(ni, start_vcn, count, ctx, false);
|
||||
}
|
||||
|
||||
extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
|
||||
const runlist_element *rl);
|
||||
int ntfs_cluster_free_from_rl_nolock(struct ntfs_volume *vol,
|
||||
const struct runlist_element *rl);
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs_cluster_free_from_rl - free clusters from runlist
|
||||
* @vol: mounted ntfs volume on which to free the clusters
|
||||
* @rl: runlist describing the clusters to free
|
||||
@@ -115,17 +117,18 @@ extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
|
||||
* - The caller must have locked the runlist @rl for reading or
|
||||
* writing.
|
||||
*/
|
||||
static inline int ntfs_cluster_free_from_rl(ntfs_volume *vol,
|
||||
const runlist_element *rl)
|
||||
static inline int ntfs_cluster_free_from_rl(struct ntfs_volume *vol,
|
||||
const struct runlist_element *rl)
|
||||
{
|
||||
int ret;
|
||||
unsigned int memalloc_flags;
|
||||
|
||||
memalloc_flags = memalloc_nofs_save();
|
||||
down_write(&vol->lcnbmp_lock);
|
||||
ret = ntfs_cluster_free_from_rl_nolock(vol, rl);
|
||||
up_write(&vol->lcnbmp_lock);
|
||||
memalloc_nofs_restore(memalloc_flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
#endif /* defined _LINUX_NTFS_LCNALLOC_H */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* logfile.h - Defines for NTFS kernel journal ($LogFile) handling. Part of
|
||||
* the Linux-NTFS project.
|
||||
* Defines for NTFS kernel journal (LogFile) handling.
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
*/
|
||||
@@ -9,16 +8,10 @@
|
||||
#ifndef _LINUX_NTFS_LOGFILE_H
|
||||
#define _LINUX_NTFS_LOGFILE_H
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "endian.h"
|
||||
#include "layout.h"
|
||||
|
||||
/*
|
||||
* Journal ($LogFile) organization:
|
||||
* Journal (LogFile) organization:
|
||||
*
|
||||
* Two restart areas present in the first two pages (restart pages, one restart
|
||||
* area in each page). When the volume is dismounted they should be identical,
|
||||
@@ -42,48 +35,47 @@
|
||||
* reinitialize the logfile and start again with version 1.1.
|
||||
*/
|
||||
|
||||
/* Some $LogFile related constants. */
|
||||
/* Some LogFile related constants. */
|
||||
#define MaxLogFileSize 0x100000000ULL
|
||||
#define DefaultLogPageSize 4096
|
||||
#define MinLogRecordPages 48
|
||||
|
||||
/*
|
||||
* Log file restart page header (begins the restart area).
|
||||
*
|
||||
* @magic: The magic is "RSTR".
|
||||
* @usa_ofs: See ntfs_record struct definition in layout.h. When creating,
|
||||
* set this to be immediately after this header structure (without any
|
||||
* alignment).
|
||||
* @usa_count: See ntfs_record struct definition in layout.h.
|
||||
* @chkdsk_lsn: The last log file sequence number found by chkdsk. Only
|
||||
* used when the magic is changed to "CHKD". Otherwise this is zero.
|
||||
* @system_page_size: Byte size of system pages when the log file was
|
||||
* created, has to be >= 512 and a power of 2. Use this to calculate
|
||||
* the required size of the usa (usa_count) and add it to usa_ofs. Then
|
||||
* verify that the result is less than the value of
|
||||
* the restart_area_offset.
|
||||
* @log_page_size: Byte size of log file pages, has to be >= 512 and
|
||||
* a power of 2. The default is 4096 and is used when the system page
|
||||
* size is between 4096 and 8192. Otherwise this is set to the system
|
||||
* page size instead.
|
||||
* @restart_area_offset: Byte offset from the start of this header to
|
||||
* the RESTART_AREA. Value has to be aligned to 8-byte boundary. When
|
||||
* creating, set this to be after the usa.
|
||||
* @minor_ver: Log file minor version. Only check if major version is 1.
|
||||
* @major_ver: Log file major version. We only support version 1.1.
|
||||
*/
|
||||
typedef struct {
|
||||
/*Ofs*/
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
/* 0*/ NTFS_RECORD_TYPE magic; /* The magic is "RSTR". */
|
||||
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
When creating, set this to be immediately
|
||||
after this header structure (without any
|
||||
alignment). */
|
||||
/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by
|
||||
chkdsk. Only used when the magic is changed
|
||||
to "CHKD". Otherwise this is zero. */
|
||||
/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file
|
||||
was created, has to be >= 512 and a power of
|
||||
2. Use this to calculate the required size
|
||||
of the usa (usa_count) and add it to usa_ofs.
|
||||
Then verify that the result is less than the
|
||||
value of the restart_area_offset. */
|
||||
/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >=
|
||||
512 and a power of 2. The default is 4096
|
||||
and is used when the system page size is
|
||||
between 4096 and 8192. Otherwise this is
|
||||
set to the system page size instead. */
|
||||
/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to
|
||||
the RESTART_AREA. Value has to be aligned
|
||||
to 8-byte boundary. When creating, set this
|
||||
to be after the usa. */
|
||||
/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major
|
||||
version is 1. */
|
||||
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
||||
version 1.1. */
|
||||
/* sizeof() = 30 (0x1e) bytes */
|
||||
} __attribute__ ((__packed__)) RESTART_PAGE_HEADER;
|
||||
struct restart_page_header {
|
||||
__le32 magic;
|
||||
__le16 usa_ofs;
|
||||
__le16 usa_count;
|
||||
__le64 chkdsk_lsn;
|
||||
__le32 system_page_size;
|
||||
__le32 log_page_size;
|
||||
__le16 restart_area_offset;
|
||||
__le16 minor_ver;
|
||||
__le16 major_ver;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Constant for the log client indices meaning that there are no client records
|
||||
@@ -96,200 +88,158 @@ typedef struct {
|
||||
/*
|
||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||
* information about the log file in which they are present.
|
||||
* gcc: Force enum bit width to 16.
|
||||
*/
|
||||
enum {
|
||||
RESTART_VOLUME_IS_CLEAN = cpu_to_le16(0x0002),
|
||||
RESTART_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16. */
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef le16 RESTART_AREA_FLAGS;
|
||||
RESTART_SPACE_FILLER = cpu_to_le16(0xffff),
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Log file restart area record. The offset of this record is found by adding
|
||||
* the offset of the RESTART_PAGE_HEADER to the restart_area_offset value found
|
||||
* in it. See notes at restart_area_offset above.
|
||||
*
|
||||
* @current_lsn: The current, i.e. last LSN inside the log when
|
||||
* the restart area was last written. This happens often but what is
|
||||
* the interval? Is it just fixed time or is it every time a check point
|
||||
* is written or somethine else? On create set to 0.
|
||||
* @log_clients: Number of log client records in the array of log client
|
||||
* records which follows this restart area. Must be 1.
|
||||
* @client_free_list: The index of the first free log client record in
|
||||
* the array of log client records. LOGFILE_NO_CLIENT means that there
|
||||
* are no free log client records in the array. If != LOGFILE_NO_CLIENT,
|
||||
* check that log_clients > client_free_list. On Win2k and presumably
|
||||
* earlier, on a clean volume this is != LOGFILE_NO_CLIENT, and it should
|
||||
* be 0, i.e. the first (and only) client record is free and thus
|
||||
* the logfile is closed and hence clean. A dirty volume would have left
|
||||
* the logfile open and hence this would be LOGFILE_NO_CLIENT. On WinXP
|
||||
* and presumably later, the logfile is always open, even on clean
|
||||
* shutdown so this should always be LOGFILE_NO_CLIENT.
|
||||
* @client_in_use_list: The index of the first in-use log client record in
|
||||
* the array of log client records. LOGFILE_NO_CLIENT means that there
|
||||
* are no in-use log client records in the array.
|
||||
* If != LOGFILE_NO_CLIENT check that log_clients > client_in_use_list.
|
||||
* On Win2k and presumably earlier, on a clean volume this is
|
||||
* LOGFILE_NO_CLIENT, i.e. there are no client records in use and thus
|
||||
* the logfile is closed and hence clean. A dirty volume would have left
|
||||
* the logfile open and hence this would be != LOGFILE_NO_CLIENT, and it
|
||||
* should be 0, i.e. the first (and only) client record is in use. On
|
||||
* WinXP and presumably later, the logfile is always open, even on clean
|
||||
* shutdown so this should always be 0.
|
||||
* @flags: Flags modifying LFS behaviour. On Win2k and presumably earlier
|
||||
* this is always 0. On WinXP and presumably later, if the logfile was
|
||||
* shutdown cleanly, the second bit, RESTART_VOLUME_IS_CLEAN, is set.
|
||||
* This bit is cleared when the volume is mounted by WinXP and set when
|
||||
* the volume is dismounted, thus if the logfile is dirty, this bit is
|
||||
* clear. Thus we don't need to check the Windows version to determine
|
||||
* if the logfile is clean. Instead if the logfile is closed, we know
|
||||
* it must be clean. If it is open and this bit is set, we also know
|
||||
* it must be clean. If on the other hand the logfile is open and this
|
||||
* bit is clear, we can be almost certain that the logfile is dirty.
|
||||
* @seq_number_bits: How many bits to use for the sequence number. This
|
||||
* is calculated as 67 - the number of bits required to store the logfile
|
||||
* size in bytes and this can be used in with the specified file_size as
|
||||
* a consistency check.
|
||||
* @restart_area_length: Length of the restart area including the client
|
||||
* array. Following checks required if version matches. Otherwise,
|
||||
* skip them. restart_area_offset + restart_area_length has to be
|
||||
* <= system_page_size. Also, restart_area_length has to be >=
|
||||
* client_array_offset + (log_clients * sizeof(log client record)).
|
||||
* @client_array_offset: Offset from the start of this record to the first
|
||||
* log client record if versions are matched. When creating, set this
|
||||
* to be after this restart area structure, aligned to 8-bytes boundary.
|
||||
* If the versions do not match, this is ignored and the offset is
|
||||
* assumed to be (sizeof(RESTART_AREA) + 7) & ~7, i.e. rounded up to
|
||||
* first 8-byte boundary. Either way, client_array_offset has to be
|
||||
* aligned to an 8-byte boundary. Also, restart_area_offset +
|
||||
* client_array_offset has to be <= 510. Finally, client_array_offset +
|
||||
* (log_clients * sizeof(log client record)) has to be <= system_page_size.
|
||||
* On Win2k and presumably earlier, this is 0x30, i.e. immediately
|
||||
* following this record. On WinXP and presumably later, this is 0x40,
|
||||
* i.e. there are 16 extra bytes between this record and the client
|
||||
* array. This probably means that the RESTART_AREA record is actually
|
||||
* bigger in WinXP and later.
|
||||
* @file_size: Usable byte size of the log file.
|
||||
* If the restart_area_offset + the offset of the file_size are > 510
|
||||
* then corruption has occurred. This is the very first check when
|
||||
* starting with the restart_area as if it fails it means that some of
|
||||
* the above values will be corrupted by the multi sector transfer
|
||||
* protection. The file_size has to be rounded down to be a multiple
|
||||
* of the log_page_size in the RESTART_PAGE_HEADER and then it has to be
|
||||
* at least big enough to store the two restart pages and 48 (0x30) log
|
||||
* record pages.
|
||||
* @last_lsn_data_length: Length of data of last LSN, not including the log
|
||||
* record header. On create set to 0.
|
||||
* @log_record_header_length: Byte size of the log record header. If the
|
||||
* version matches then check that the value of log_record_header_length
|
||||
* is a multiple of 8, i.e. (log_record_header_length + 7) & ~7 ==
|
||||
* log_record_header_length. When creating set it to
|
||||
* sizeof(LOG_RECORD_HEADER), aligned to 8 bytes.
|
||||
* @log_page_data_offset: Offset to the start of data in a log record page.
|
||||
* Must be a multiple of 8. On create set it to immediately after
|
||||
* the update sequence array of the log record page.
|
||||
* @restart_log_open_count: A counter that gets incremented every time
|
||||
* the logfile is restarted which happens at mount time when the logfile
|
||||
* is opened. When creating set to a random value. Win2k sets it to
|
||||
* the low 32 bits of the current system time in NTFS format (see time.h).
|
||||
* @reserved: Reserved/alignment to 8-byte boundary.
|
||||
*/
|
||||
typedef struct {
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||
when the restart area was last written.
|
||||
This happens often but what is the interval?
|
||||
Is it just fixed time or is it every time a
|
||||
check point is written or somethine else?
|
||||
On create set to 0. */
|
||||
/* 8*/ le16 log_clients; /* Number of log client records in the array of
|
||||
log client records which follows this
|
||||
restart area. Must be 1. */
|
||||
/* 10*/ le16 client_free_list; /* The index of the first free log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means that there are no
|
||||
free log client records in the array.
|
||||
If != LOGFILE_NO_CLIENT, check that
|
||||
log_clients > client_free_list. On Win2k
|
||||
and presumably earlier, on a clean volume
|
||||
this is != LOGFILE_NO_CLIENT, and it should
|
||||
be 0, i.e. the first (and only) client
|
||||
record is free and thus the logfile is
|
||||
closed and hence clean. A dirty volume
|
||||
would have left the logfile open and hence
|
||||
this would be LOGFILE_NO_CLIENT. On WinXP
|
||||
and presumably later, the logfile is always
|
||||
open, even on clean shutdown so this should
|
||||
always be LOGFILE_NO_CLIENT. */
|
||||
/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client
|
||||
record in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means that there are no
|
||||
in-use log client records in the array. If
|
||||
!= LOGFILE_NO_CLIENT check that log_clients
|
||||
> client_in_use_list. On Win2k and
|
||||
presumably earlier, on a clean volume this
|
||||
is LOGFILE_NO_CLIENT, i.e. there are no
|
||||
client records in use and thus the logfile
|
||||
is closed and hence clean. A dirty volume
|
||||
would have left the logfile open and hence
|
||||
this would be != LOGFILE_NO_CLIENT, and it
|
||||
should be 0, i.e. the first (and only)
|
||||
client record is in use. On WinXP and
|
||||
presumably later, the logfile is always
|
||||
open, even on clean shutdown so this should
|
||||
always be 0. */
|
||||
/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
|
||||
and presumably earlier this is always 0. On
|
||||
WinXP and presumably later, if the logfile
|
||||
was shutdown cleanly, the second bit,
|
||||
RESTART_VOLUME_IS_CLEAN, is set. This bit
|
||||
is cleared when the volume is mounted by
|
||||
WinXP and set when the volume is dismounted,
|
||||
thus if the logfile is dirty, this bit is
|
||||
clear. Thus we don't need to check the
|
||||
Windows version to determine if the logfile
|
||||
is clean. Instead if the logfile is closed,
|
||||
we know it must be clean. If it is open and
|
||||
this bit is set, we also know it must be
|
||||
clean. If on the other hand the logfile is
|
||||
open and this bit is clear, we can be almost
|
||||
certain that the logfile is dirty. */
|
||||
/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence
|
||||
number. This is calculated as 67 - the
|
||||
number of bits required to store the logfile
|
||||
size in bytes and this can be used in with
|
||||
the specified file_size as a consistency
|
||||
check. */
|
||||
/* 20*/ le16 restart_area_length;/* Length of the restart area including the
|
||||
client array. Following checks required if
|
||||
version matches. Otherwise, skip them.
|
||||
restart_area_offset + restart_area_length
|
||||
has to be <= system_page_size. Also,
|
||||
restart_area_length has to be >=
|
||||
client_array_offset + (log_clients *
|
||||
sizeof(log client record)). */
|
||||
/* 22*/ le16 client_array_offset;/* Offset from the start of this record to
|
||||
the first log client record if versions are
|
||||
matched. When creating, set this to be
|
||||
after this restart area structure, aligned
|
||||
to 8-bytes boundary. If the versions do not
|
||||
match, this is ignored and the offset is
|
||||
assumed to be (sizeof(RESTART_AREA) + 7) &
|
||||
~7, i.e. rounded up to first 8-byte
|
||||
boundary. Either way, client_array_offset
|
||||
has to be aligned to an 8-byte boundary.
|
||||
Also, restart_area_offset +
|
||||
client_array_offset has to be <= 510.
|
||||
Finally, client_array_offset + (log_clients
|
||||
* sizeof(log client record)) has to be <=
|
||||
system_page_size. On Win2k and presumably
|
||||
earlier, this is 0x30, i.e. immediately
|
||||
following this record. On WinXP and
|
||||
presumably later, this is 0x40, i.e. there
|
||||
are 16 extra bytes between this record and
|
||||
the client array. This probably means that
|
||||
the RESTART_AREA record is actually bigger
|
||||
in WinXP and later. */
|
||||
/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the
|
||||
restart_area_offset + the offset of the
|
||||
file_size are > 510 then corruption has
|
||||
occurred. This is the very first check when
|
||||
starting with the restart_area as if it
|
||||
fails it means that some of the above values
|
||||
will be corrupted by the multi sector
|
||||
transfer protection. The file_size has to
|
||||
be rounded down to be a multiple of the
|
||||
log_page_size in the RESTART_PAGE_HEADER and
|
||||
then it has to be at least big enough to
|
||||
store the two restart pages and 48 (0x30)
|
||||
log record pages. */
|
||||
/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including
|
||||
the log record header. On create set to
|
||||
0. */
|
||||
/* 36*/ le16 log_record_header_length;/* Byte size of the log record header.
|
||||
If the version matches then check that the
|
||||
value of log_record_header_length is a
|
||||
multiple of 8, i.e.
|
||||
(log_record_header_length + 7) & ~7 ==
|
||||
log_record_header_length. When creating set
|
||||
it to sizeof(LOG_RECORD_HEADER), aligned to
|
||||
8 bytes. */
|
||||
/* 38*/ le16 log_page_data_offset;/* Offset to the start of data in a log record
|
||||
page. Must be a multiple of 8. On create
|
||||
set it to immediately after the update
|
||||
sequence array of the log record page. */
|
||||
/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every
|
||||
time the logfile is restarted which happens
|
||||
at mount time when the logfile is opened.
|
||||
When creating set to a random value. Win2k
|
||||
sets it to the low 32 bits of the current
|
||||
system time in NTFS format (see time.h). */
|
||||
/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */
|
||||
/* sizeof() = 48 (0x30) bytes */
|
||||
} __attribute__ ((__packed__)) RESTART_AREA;
|
||||
struct restart_area {
|
||||
__le64 current_lsn;
|
||||
__le16 log_clients;
|
||||
__le16 client_free_list;
|
||||
__le16 client_in_use_list;
|
||||
__le16 flags;
|
||||
__le32 seq_number_bits;
|
||||
__le16 restart_area_length;
|
||||
__le16 client_array_offset;
|
||||
__le64 file_size;
|
||||
__le32 last_lsn_data_length;
|
||||
__le16 log_record_header_length;
|
||||
__le16 log_page_data_offset;
|
||||
__le32 restart_log_open_count;
|
||||
__le32 reserved;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Log client record. The offset of this record is found by adding the offset
|
||||
* of the RESTART_AREA to the client_array_offset value found in it.
|
||||
*
|
||||
* @oldest_lsn: Oldest LSN needed by this client. On create set to 0.
|
||||
* @client_restart_lsn: LSN at which this client needs to restart
|
||||
* the volume, i.e. the current position within the log file.
|
||||
* At present, if clean this should = current_lsn in restart area but it
|
||||
* probably also = current_lsn when dirty most of the time.
|
||||
* At create set to 0.
|
||||
* @prev_client: The offset to the previous log client record in the array
|
||||
* of log client records. LOGFILE_NO_CLIENT means there is no previous
|
||||
* client record, i.e. this is the first one. This is always
|
||||
* LOGFILE_NO_CLIENT.
|
||||
* @next_client: The offset to the next log client record in the array of
|
||||
* log client records. LOGFILE_NO_CLIENT means there are no next client
|
||||
* records, i.e. this is the last one. This is always LOGFILE_NO_CLIENT.
|
||||
* @seq_number: On Win2k and presumably earlier, this is set to zero every
|
||||
* time the logfile is restarted and it is incremented when the logfile
|
||||
* is closed at dismount time. Thus it is 0 when dirty and 1 when clean.
|
||||
* On WinXP and presumably later, this is always 0.
|
||||
* @reserved[6]: Reserved/alignment.
|
||||
* @client_name_length: Length of client name in bytes. Should always be 8.
|
||||
* @client_name[64]: Name of the client in Unicode. Should always be "NTFS"
|
||||
* with the remaining bytes set to 0.
|
||||
*/
|
||||
typedef struct {
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
set to 0. */
|
||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||
the volume, i.e. the current position within
|
||||
the log file. At present, if clean this
|
||||
should = current_lsn in restart area but it
|
||||
probably also = current_lsn when dirty most
|
||||
of the time. At create set to 0. */
|
||||
/* 16*/ le16 prev_client; /* The offset to the previous log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there is no previous
|
||||
client record, i.e. this is the first one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 18*/ le16 next_client; /* The offset to the next log client record in
|
||||
the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there are no next
|
||||
client records, i.e. this is the last one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
|
||||
to zero every time the logfile is restarted
|
||||
and it is incremented when the logfile is
|
||||
closed at dismount time. Thus it is 0 when
|
||||
dirty and 1 when clean. On WinXP and
|
||||
presumably later, this is always 0. */
|
||||
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
|
||||
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
|
||||
always be 8. */
|
||||
/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should
|
||||
always be "NTFS" with the remaining bytes
|
||||
set to 0. */
|
||||
/* sizeof() = 160 (0xa0) bytes */
|
||||
} __attribute__ ((__packed__)) LOG_CLIENT_RECORD;
|
||||
|
||||
extern bool ntfs_check_logfile(struct inode *log_vi,
|
||||
RESTART_PAGE_HEADER **rp);
|
||||
|
||||
extern bool ntfs_is_logfile_clean(struct inode *log_vi,
|
||||
const RESTART_PAGE_HEADER *rp);
|
||||
|
||||
extern bool ntfs_empty_logfile(struct inode *log_vi);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
struct log_client_record {
|
||||
__le64 oldest_lsn;
|
||||
__le64 client_restart_lsn;
|
||||
__le16 prev_client;
|
||||
__le16 next_client;
|
||||
__le16 seq_number;
|
||||
u8 reserved[6];
|
||||
__le32 client_name_length;
|
||||
__le16 client_name[64];
|
||||
} __packed;
|
||||
|
||||
bool ntfs_check_logfile(struct inode *log_vi,
|
||||
struct restart_page_header **rp);
|
||||
bool ntfs_empty_logfile(struct inode *log_vi);
|
||||
#endif /* _LINUX_NTFS_LOGFILE_H */
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* mft.h - Defines for mft record handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
* Defines for mft record handling in NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
*/
|
||||
@@ -9,43 +8,24 @@
|
||||
#ifndef _LINUX_NTFS_MFT_H
|
||||
#define _LINUX_NTFS_MFT_H
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include "inode.h"
|
||||
|
||||
extern MFT_RECORD *map_mft_record(ntfs_inode *ni);
|
||||
extern void unmap_mft_record(ntfs_inode *ni);
|
||||
struct mft_record *map_mft_record(struct ntfs_inode *ni);
|
||||
void unmap_mft_record(struct ntfs_inode *ni);
|
||||
struct mft_record *map_extent_mft_record(struct ntfs_inode *base_ni, u64 mref,
|
||||
struct ntfs_inode **ntfs_ino);
|
||||
|
||||
extern MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
|
||||
ntfs_inode **ntfs_ino);
|
||||
|
||||
static inline void unmap_extent_mft_record(ntfs_inode *ni)
|
||||
static inline void unmap_extent_mft_record(struct ntfs_inode *ni)
|
||||
{
|
||||
unmap_mft_record(ni);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef NTFS_RW
|
||||
void __mark_mft_record_dirty(struct ntfs_inode *ni);
|
||||
|
||||
/**
|
||||
* flush_dcache_mft_record_page - flush_dcache_page() for mft records
|
||||
* @ni: ntfs inode structure of mft record
|
||||
*
|
||||
* Call flush_dcache_page() for the page in which an mft record resides.
|
||||
*
|
||||
* This must be called every time an mft record is modified, just after the
|
||||
* modification.
|
||||
*/
|
||||
static inline void flush_dcache_mft_record_page(ntfs_inode *ni)
|
||||
{
|
||||
flush_dcache_page(ni->page);
|
||||
}
|
||||
|
||||
extern void __mark_mft_record_dirty(ntfs_inode *ni);
|
||||
|
||||
/**
|
||||
/*
|
||||
* mark_mft_record_dirty - set the mft record and the page containing it dirty
|
||||
* @ni: ntfs inode describing the mapped mft record
|
||||
*
|
||||
@@ -56,18 +36,17 @@ extern void __mark_mft_record_dirty(ntfs_inode *ni);
|
||||
*
|
||||
* NOTE: Do not do anything if the mft record is already marked dirty.
|
||||
*/
|
||||
static inline void mark_mft_record_dirty(ntfs_inode *ni)
|
||||
static inline void mark_mft_record_dirty(struct ntfs_inode *ni)
|
||||
{
|
||||
if (!NInoTestSetDirty(ni))
|
||||
__mark_mft_record_dirty(ni);
|
||||
}
|
||||
|
||||
extern int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
|
||||
MFT_RECORD *m, int sync);
|
||||
int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const unsigned long mft_no,
|
||||
struct mft_record *m);
|
||||
int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int sync);
|
||||
|
||||
extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync);
|
||||
|
||||
/**
|
||||
/*
|
||||
* write_mft_record - write out a mapped (extent) mft record
|
||||
* @ni: ntfs inode describing the mapped (extent) mft record
|
||||
* @m: mapped (extent) mft record to write
|
||||
@@ -85,26 +64,31 @@ extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync);
|
||||
* On success, clean the mft record and return 0. On error, leave the mft
|
||||
* record dirty and return -errno.
|
||||
*/
|
||||
static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync)
|
||||
static inline int write_mft_record(struct ntfs_inode *ni, struct mft_record *m, int sync)
|
||||
{
|
||||
struct page *page = ni->page;
|
||||
struct folio *folio = ni->folio;
|
||||
int err;
|
||||
|
||||
BUG_ON(!page);
|
||||
lock_page(page);
|
||||
folio_lock(folio);
|
||||
err = write_mft_record_nolock(ni, m, sync);
|
||||
unlock_page(page);
|
||||
folio_unlock(folio);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
extern bool ntfs_may_write_mft_record(ntfs_volume *vol,
|
||||
const unsigned long mft_no, const MFT_RECORD *m,
|
||||
ntfs_inode **locked_ni);
|
||||
|
||||
extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
|
||||
ntfs_inode *base_ni, MFT_RECORD **mrec);
|
||||
extern int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
bool ntfs_may_write_mft_record(struct ntfs_volume *vol,
|
||||
const unsigned long mft_no, const struct mft_record *m,
|
||||
struct ntfs_inode **locked_ni, struct inode **ref_vi);
|
||||
int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
|
||||
struct ntfs_inode **ni, struct ntfs_inode *base_ni,
|
||||
struct mft_record **ni_mrec);
|
||||
int ntfs_mft_record_free(struct ntfs_volume *vol, struct ntfs_inode *ni);
|
||||
int ntfs_mft_records_write(const struct ntfs_volume *vol, const u64 mref,
|
||||
const s64 count, struct mft_record *b);
|
||||
int ntfs_mft_record_check(const struct ntfs_volume *vol, struct mft_record *m,
|
||||
unsigned long mft_no);
|
||||
int ntfs_mft_writepages(struct address_space *mapping,
|
||||
struct writeback_control *wbc);
|
||||
void ntfs_mft_mark_dirty(struct folio *folio);
|
||||
|
||||
#endif /* _LINUX_NTFS_MFT_H */
|
||||
|
||||
238
fs/ntfs/ntfs.h
238
fs/ntfs/ntfs.h
@@ -1,9 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* ntfs.h - Defines for NTFS Linux kernel driver.
|
||||
* Defines for NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc.
|
||||
* Copyright (C) 2002 Richard Russon
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_H
|
||||
@@ -11,26 +12,154 @@
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/uidgid.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
|
||||
typedef enum {
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/*
|
||||
* Default pre-allocation size is optimize runlist merge overhead
|
||||
* with small chunk size.
|
||||
*/
|
||||
#define NTFS_DEF_PREALLOC_SIZE 65536
|
||||
|
||||
/*
|
||||
* The log2 of the standard number of clusters per compression block.
|
||||
* A value of 4 corresponds to 16 clusters (1 << 4), which is the
|
||||
* default chunk size used by NTFS LZNT1 compression.
|
||||
*/
|
||||
#define STANDARD_COMPRESSION_UNIT 4
|
||||
|
||||
/*
|
||||
* The maximum cluster size (4KB) allowed for compression to be enabled.
|
||||
* By design, NTFS does not support compression on volumes where the
|
||||
* cluster size exceeds 4096 bytes.
|
||||
*/
|
||||
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
|
||||
|
||||
#define NTFS_B_TO_CLU(vol, b) ((b) >> (vol)->cluster_size_bits)
|
||||
#define NTFS_CLU_TO_B(vol, clu) ((u64)(clu) << (vol)->cluster_size_bits)
|
||||
#define NTFS_B_TO_CLU_OFS(vol, clu) ((u64)(clu) & (vol)->cluster_size_mask)
|
||||
|
||||
#define NTFS_MFT_NR_TO_CLU(vol, mft_no) (((u64)mft_no << (vol)->mft_record_size_bits) >> \
|
||||
(vol)->cluster_size_bits)
|
||||
#define NTFS_MFT_NR_TO_PIDX(vol, mft_no) (mft_no >> (PAGE_SHIFT - \
|
||||
(vol)->mft_record_size_bits))
|
||||
#define NTFS_MFT_NR_TO_POFS(vol, mft_no) (((u64)mft_no << (vol)->mft_record_size_bits) & \
|
||||
~PAGE_MASK)
|
||||
|
||||
#define NTFS_PIDX_TO_BLK(vol, idx) (((u64)idx << PAGE_SHIFT) >> \
|
||||
((vol)->sb)->s_blocksize_bits)
|
||||
#define NTFS_PIDX_TO_CLU(vol, idx) (((u64)idx << PAGE_SHIFT) >> \
|
||||
(vol)->cluster_size_bits)
|
||||
#define NTFS_CLU_TO_PIDX(vol, clu) (((u64)(clu) << (vol)->cluster_size_bits) >> \
|
||||
PAGE_SHIFT)
|
||||
#define NTFS_CLU_TO_POFS(vol, clu) (((u64)(clu) << (vol)->cluster_size_bits) & \
|
||||
~PAGE_MASK)
|
||||
|
||||
#define NTFS_B_TO_SECTOR(vol, b) ((b) >> ((vol)->sb)->s_blocksize_bits)
|
||||
|
||||
enum {
|
||||
NTFS_BLOCK_SIZE = 512,
|
||||
NTFS_BLOCK_SIZE_BITS = 9,
|
||||
NTFS_SB_MAGIC = 0x5346544e, /* 'NTFS' */
|
||||
NTFS_MAX_NAME_LEN = 255,
|
||||
NTFS_MAX_ATTR_NAME_LEN = 255,
|
||||
NTFS_MAX_CLUSTER_SIZE = 64 * 1024, /* 64kiB */
|
||||
NTFS_MAX_PAGES_PER_CLUSTER = NTFS_MAX_CLUSTER_SIZE / PAGE_SIZE,
|
||||
} NTFS_CONSTANTS;
|
||||
NTFS_MAX_LABEL_LEN = 128,
|
||||
};
|
||||
|
||||
enum {
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Conversion helpers for NTFS units.
|
||||
*/
|
||||
|
||||
/* Convert bytes to cluster count */
|
||||
static inline u64 ntfs_bytes_to_cluster(const struct ntfs_volume *vol,
|
||||
s64 bytes)
|
||||
{
|
||||
return bytes >> vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/* Convert cluster count to bytes */
|
||||
static inline u64 ntfs_cluster_to_bytes(const struct ntfs_volume *vol,
|
||||
u64 clusters)
|
||||
{
|
||||
return clusters << vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/* Get the byte offset within a cluster from a linear byte address */
|
||||
static inline u64 ntfs_bytes_to_cluster_off(const struct ntfs_volume *vol,
|
||||
u64 bytes)
|
||||
{
|
||||
return bytes & vol->cluster_size_mask;
|
||||
}
|
||||
|
||||
/* Calculate the physical cluster number containing a specific MFT record. */
|
||||
static inline u64 ntfs_mft_no_to_cluster(const struct ntfs_volume *vol,
|
||||
unsigned long mft_no)
|
||||
{
|
||||
return ((u64)mft_no << vol->mft_record_size_bits) >>
|
||||
vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/* Calculate the folio index where the MFT record resides. */
|
||||
static inline pgoff_t ntfs_mft_no_to_pidx(const struct ntfs_volume *vol,
|
||||
unsigned long mft_no)
|
||||
{
|
||||
return mft_no >> (PAGE_SHIFT - vol->mft_record_size_bits);
|
||||
}
|
||||
|
||||
/* Calculate the byte offset within a folio for an MFT record. */
|
||||
static inline u64 ntfs_mft_no_to_poff(const struct ntfs_volume *vol,
|
||||
unsigned long mft_no)
|
||||
{
|
||||
return ((u64)mft_no << vol->mft_record_size_bits) & ~PAGE_MASK;
|
||||
}
|
||||
|
||||
/* Convert folio index to cluster number. */
|
||||
static inline u64 ntfs_pidx_to_cluster(const struct ntfs_volume *vol,
|
||||
pgoff_t idx)
|
||||
{
|
||||
return ((u64)idx << PAGE_SHIFT) >> vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/* Convert cluster number to folio index. */
|
||||
static inline pgoff_t ntfs_cluster_to_pidx(const struct ntfs_volume *vol,
|
||||
u64 clu)
|
||||
{
|
||||
return (clu << vol->cluster_size_bits) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
/* Get the byte offset within a folio from a cluster number */
|
||||
static inline u64 ntfs_cluster_to_poff(const struct ntfs_volume *vol,
|
||||
u64 clu)
|
||||
{
|
||||
return (clu << vol->cluster_size_bits) & ~PAGE_MASK;
|
||||
}
|
||||
|
||||
/* Convert byte offset to sector (block) number. */
|
||||
static inline sector_t ntfs_bytes_to_sector(const struct ntfs_volume *vol,
|
||||
u64 bytes)
|
||||
{
|
||||
return bytes >> vol->sb->s_blocksize_bits;
|
||||
}
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
@@ -42,12 +171,13 @@ extern struct kmem_cache *ntfs_attr_ctx_cache;
|
||||
extern struct kmem_cache *ntfs_index_ctx_cache;
|
||||
|
||||
/* The various operations structs defined throughout the driver files. */
|
||||
extern const struct address_space_operations ntfs_normal_aops;
|
||||
extern const struct address_space_operations ntfs_compressed_aops;
|
||||
extern const struct address_space_operations ntfs_mst_aops;
|
||||
extern const struct address_space_operations ntfs_aops;
|
||||
extern const struct address_space_operations ntfs_mft_aops;
|
||||
|
||||
extern const struct file_operations ntfs_file_ops;
|
||||
extern const struct inode_operations ntfs_file_inode_ops;
|
||||
extern const struct inode_operations ntfs_symlink_inode_operations;
|
||||
extern const struct inode_operations ntfs_special_inode_operations;
|
||||
|
||||
extern const struct file_operations ntfs_dir_ops;
|
||||
extern const struct inode_operations ntfs_dir_inode_ops;
|
||||
@@ -57,13 +187,13 @@ extern const struct inode_operations ntfs_empty_inode_ops;
|
||||
|
||||
extern const struct export_operations ntfs_export_ops;
|
||||
|
||||
/**
|
||||
/*
|
||||
* NTFS_SB - return the ntfs volume given a vfs super block
|
||||
* @sb: VFS super block
|
||||
*
|
||||
* NTFS_SB() returns the ntfs volume associated with the VFS super block @sb.
|
||||
*/
|
||||
static inline ntfs_volume *NTFS_SB(struct super_block *sb)
|
||||
static inline struct ntfs_volume *NTFS_SB(struct super_block *sb)
|
||||
{
|
||||
return sb->s_fs_info;
|
||||
}
|
||||
@@ -71,52 +201,64 @@ static inline ntfs_volume *NTFS_SB(struct super_block *sb)
|
||||
/* Declarations of functions and global variables. */
|
||||
|
||||
/* From fs/ntfs/compress.c */
|
||||
extern int ntfs_read_compressed_block(struct page *page);
|
||||
extern int allocate_compression_buffers(void);
|
||||
extern void free_compression_buffers(void);
|
||||
int ntfs_read_compressed_block(struct folio *folio);
|
||||
int allocate_compression_buffers(void);
|
||||
void free_compression_buffers(void);
|
||||
int ntfs_compress_write(struct ntfs_inode *ni, loff_t pos, size_t count,
|
||||
struct iov_iter *from);
|
||||
|
||||
/* From fs/ntfs/super.c */
|
||||
#define default_upcase_len 0x10000
|
||||
extern struct mutex ntfs_lock;
|
||||
|
||||
typedef struct {
|
||||
struct option_t {
|
||||
int val;
|
||||
char *str;
|
||||
} option_t;
|
||||
extern const option_t on_errors_arr[];
|
||||
};
|
||||
extern const struct option_t on_errors_arr[];
|
||||
int ntfs_set_volume_flags(struct ntfs_volume *vol, __le16 flags);
|
||||
int ntfs_clear_volume_flags(struct ntfs_volume *vol, __le16 flags);
|
||||
int ntfs_write_volume_label(struct ntfs_volume *vol, char *label);
|
||||
|
||||
/* From fs/ntfs/mst.c */
|
||||
extern int post_read_mst_fixup(NTFS_RECORD *b, const u32 size);
|
||||
extern int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size);
|
||||
extern void post_write_mst_fixup(NTFS_RECORD *b);
|
||||
int post_read_mst_fixup(struct ntfs_record *b, const u32 size);
|
||||
int pre_write_mst_fixup(struct ntfs_record *b, const u32 size);
|
||||
void post_write_mst_fixup(struct ntfs_record *b);
|
||||
|
||||
/* From fs/ntfs/unistr.c */
|
||||
extern bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
|
||||
const ntfschar *s2, size_t s2_len,
|
||||
const IGNORE_CASE_BOOL ic,
|
||||
const ntfschar *upcase, const u32 upcase_size);
|
||||
extern int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
const int err_val, const IGNORE_CASE_BOOL ic,
|
||||
const ntfschar *upcase, const u32 upcase_len);
|
||||
extern int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n);
|
||||
extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
|
||||
const ntfschar *upcase, const u32 upcase_size);
|
||||
extern void ntfs_upcase_name(ntfschar *name, u32 name_len,
|
||||
const ntfschar *upcase, const u32 upcase_len);
|
||||
extern void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
|
||||
const ntfschar *upcase, const u32 upcase_len);
|
||||
extern int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
|
||||
FILE_NAME_ATTR *file_name_attr2,
|
||||
const int err_val, const IGNORE_CASE_BOOL ic,
|
||||
const ntfschar *upcase, const u32 upcase_len);
|
||||
extern int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
|
||||
const int ins_len, ntfschar **outs);
|
||||
extern int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
|
||||
bool ntfs_are_names_equal(const __le16 *s1, size_t s1_len,
|
||||
const __le16 *s2, size_t s2_len,
|
||||
const u32 ic,
|
||||
const __le16 *upcase, const u32 upcase_size);
|
||||
int ntfs_collate_names(const __le16 *name1, const u32 name1_len,
|
||||
const __le16 *name2, const u32 name2_len,
|
||||
const int err_val, const u32 ic,
|
||||
const __le16 *upcase, const u32 upcase_len);
|
||||
int ntfs_ucsncmp(const __le16 *s1, const __le16 *s2, size_t n);
|
||||
int ntfs_ucsncasecmp(const __le16 *s1, const __le16 *s2, size_t n,
|
||||
const __le16 *upcase, const u32 upcase_size);
|
||||
int ntfs_file_compare_values(const struct file_name_attr *file_name_attr1,
|
||||
const struct file_name_attr *file_name_attr2,
|
||||
const int err_val, const u32 ic,
|
||||
const __le16 *upcase, const u32 upcase_len);
|
||||
int ntfs_nlstoucs(const struct ntfs_volume *vol, const char *ins,
|
||||
const int ins_len, __le16 **outs, int max_name_len);
|
||||
int ntfs_ucstonls(const struct ntfs_volume *vol, const __le16 *ins,
|
||||
const int ins_len, unsigned char **outs, int outs_len);
|
||||
__le16 *ntfs_ucsndup(const __le16 *s, u32 maxlen);
|
||||
bool ntfs_names_are_equal(const __le16 *s1, size_t s1_len,
|
||||
const __le16 *s2, size_t s2_len,
|
||||
const u32 ic,
|
||||
const __le16 *upcase, const u32 upcase_size);
|
||||
int ntfs_force_shutdown(struct super_block *sb, u32 flags);
|
||||
long ntfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
||||
#ifdef CONFIG_COMPAT
|
||||
long ntfs_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
#endif
|
||||
|
||||
/* From fs/ntfs/upcase.c */
|
||||
extern ntfschar *generate_default_upcase(void);
|
||||
__le16 *generate_default_upcase(void);
|
||||
|
||||
static inline int ntfs_ffs(int x)
|
||||
{
|
||||
@@ -140,11 +282,13 @@ static inline int ntfs_ffs(int x)
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
if (!(x & 1))
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* From fs/ntfs/bdev-io.c */
|
||||
int ntfs_bdev_read(struct block_device *bdev, char *data, loff_t start, size_t size);
|
||||
int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size);
|
||||
|
||||
#endif /* _LINUX_NTFS_H */
|
||||
|
||||
14
fs/ntfs/object_id.h
Normal file
14
fs/ntfs/object_id.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2008-2021 Jean-Pierre Andre
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_OBJECT_ID_H
|
||||
#define _LINUX_NTFS_OBJECT_ID_H
|
||||
|
||||
extern __le16 objid_index_name[];
|
||||
|
||||
int ntfs_delete_object_id_index(struct ntfs_inode *ni);
|
||||
|
||||
#endif /* _LINUX_NTFS_OBJECT_ID_H */
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* quota.h - Defines for NTFS kernel quota ($Quota) handling. Part of the
|
||||
* Linux-NTFS project.
|
||||
* Defines for NTFS kernel quota ($Quota) handling.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*/
|
||||
@@ -9,13 +8,8 @@
|
||||
#ifndef _LINUX_NTFS_QUOTA_H
|
||||
#define _LINUX_NTFS_QUOTA_H
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
|
||||
extern bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
bool ntfs_mark_quotas_out_of_date(struct ntfs_volume *vol);
|
||||
|
||||
#endif /* _LINUX_NTFS_QUOTA_H */
|
||||
|
||||
20
fs/ntfs/reparse.h
Normal file
20
fs/ntfs/reparse.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2008-2021 Jean-Pierre Andre
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_REPARSE_H
|
||||
#define _LINUX_NTFS_REPARSE_H
|
||||
|
||||
extern __le16 reparse_index_name[];
|
||||
|
||||
unsigned int ntfs_make_symlink(struct ntfs_inode *ni);
|
||||
unsigned int ntfs_reparse_tag_dt_types(struct ntfs_volume *vol, unsigned long mref);
|
||||
int ntfs_reparse_set_wsl_symlink(struct ntfs_inode *ni,
|
||||
const __le16 *target, int target_len);
|
||||
int ntfs_reparse_set_wsl_not_symlink(struct ntfs_inode *ni, mode_t mode);
|
||||
int ntfs_delete_reparse_index(struct ntfs_inode *ni);
|
||||
int ntfs_remove_ntfs_reparse_data(struct ntfs_inode *ni);
|
||||
|
||||
#endif /* _LINUX_NTFS_REPARSE_H */
|
||||
@@ -1,20 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* runlist.h - Defines for runlist handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
* Defines for runlist handling in NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_RUNLIST_H
|
||||
#define _LINUX_NTFS_RUNLIST_H
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
|
||||
/**
|
||||
/*
|
||||
* runlist_element - in memory vcn to lcn mapping array element
|
||||
* @vcn: starting vcn of the current array element
|
||||
* @lcn: starting lcn of the current array element
|
||||
@@ -24,65 +22,76 @@
|
||||
*
|
||||
* When lcn == -1 this means that the count vcns starting at vcn are not
|
||||
* physically allocated (i.e. this is a hole / data is sparse).
|
||||
*
|
||||
* In memory vcn to lcn mapping structure element.
|
||||
* @vcn: vcn = Starting virtual cluster number.
|
||||
* @lcn: lcn = Starting logical cluster number.
|
||||
* @length: Run length in clusters.
|
||||
*/
|
||||
typedef struct { /* In memory vcn to lcn mapping structure element. */
|
||||
VCN vcn; /* vcn = Starting virtual cluster number. */
|
||||
LCN lcn; /* lcn = Starting logical cluster number. */
|
||||
s64 length; /* Run length in clusters. */
|
||||
} runlist_element;
|
||||
struct runlist_element {
|
||||
s64 vcn;
|
||||
s64 lcn;
|
||||
s64 length;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* runlist - in memory vcn to lcn mapping array including a read/write lock
|
||||
* @rl: pointer to an array of runlist elements
|
||||
* @lock: read/write spinlock for serializing access to @rl
|
||||
*
|
||||
* @rl_hint: hint/cache pointing to the last accessed runlist element
|
||||
*/
|
||||
typedef struct {
|
||||
runlist_element *rl;
|
||||
struct runlist {
|
||||
struct runlist_element *rl;
|
||||
struct rw_semaphore lock;
|
||||
} runlist;
|
||||
size_t count;
|
||||
int rl_hint;
|
||||
};
|
||||
|
||||
static inline void ntfs_init_runlist(runlist *rl)
|
||||
static inline void ntfs_init_runlist(struct runlist *rl)
|
||||
{
|
||||
rl->rl = NULL;
|
||||
init_rwsem(&rl->lock);
|
||||
rl->count = 0;
|
||||
rl->rl_hint = -1;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
LCN_ENOMEM = -4,
|
||||
LCN_EIO = -5,
|
||||
} LCN_SPECIAL_VALUES;
|
||||
|
||||
extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
|
||||
runlist_element *srl);
|
||||
|
||||
extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
|
||||
const ATTR_RECORD *attr, runlist_element *old_rl);
|
||||
|
||||
extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
extern runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl,
|
||||
const VCN vcn);
|
||||
|
||||
extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
const runlist_element *rl, const VCN first_vcn,
|
||||
const VCN last_vcn);
|
||||
|
||||
extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
|
||||
const int dst_len, const runlist_element *rl,
|
||||
const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn);
|
||||
|
||||
extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol,
|
||||
runlist *const runlist, const s64 new_length);
|
||||
|
||||
int ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist,
|
||||
const VCN start, const s64 length);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
enum {
|
||||
LCN_DELALLOC = -1,
|
||||
LCN_HOLE = -2,
|
||||
LCN_RL_NOT_MAPPED = -3,
|
||||
LCN_ENOENT = -4,
|
||||
LCN_ENOMEM = -5,
|
||||
LCN_EIO = -6,
|
||||
LCN_EINVAL = -7,
|
||||
};
|
||||
|
||||
struct runlist_element *ntfs_runlists_merge(struct runlist *d_runlist,
|
||||
struct runlist_element *srl, size_t s_rl_count,
|
||||
size_t *new_rl_count);
|
||||
struct runlist_element *ntfs_mapping_pairs_decompress(const struct ntfs_volume *vol,
|
||||
const struct attr_record *attr, struct runlist *old_runlist,
|
||||
size_t *new_rl_count);
|
||||
s64 ntfs_rl_vcn_to_lcn(const struct runlist_element *rl, const s64 vcn);
|
||||
struct runlist_element *ntfs_rl_find_vcn_nolock(struct runlist_element *rl, const s64 vcn);
|
||||
int ntfs_get_size_for_mapping_pairs(const struct ntfs_volume *vol,
|
||||
const struct runlist_element *rl, const s64 first_vcn,
|
||||
const s64 last_vcn, int max_mp_size);
|
||||
int ntfs_mapping_pairs_build(const struct ntfs_volume *vol, s8 *dst,
|
||||
const int dst_len, const struct runlist_element *rl,
|
||||
const s64 first_vcn, const s64 last_vcn, s64 *const stop_vcn,
|
||||
struct runlist_element **stop_rl, unsigned int *de_cluster_count);
|
||||
int ntfs_rl_truncate_nolock(const struct ntfs_volume *vol,
|
||||
struct runlist *const runlist, const s64 new_length);
|
||||
int ntfs_rl_sparse(struct runlist_element *rl);
|
||||
s64 ntfs_rl_get_compressed_size(struct ntfs_volume *vol, struct runlist_element *rl);
|
||||
struct runlist_element *ntfs_rl_insert_range(struct runlist_element *dst_rl, int dst_cnt,
|
||||
struct runlist_element *src_rl, int src_cnt, size_t *new_cnt);
|
||||
struct runlist_element *ntfs_rl_punch_hole(struct runlist_element *dst_rl, int dst_cnt,
|
||||
s64 start_vcn, s64 len, struct runlist_element **punch_rl,
|
||||
size_t *new_rl_cnt);
|
||||
struct runlist_element *ntfs_rl_collapse_range(struct runlist_element *dst_rl, int dst_cnt,
|
||||
s64 start_vcn, s64 len, struct runlist_element **punch_rl,
|
||||
size_t *new_rl_cnt);
|
||||
struct runlist_element *ntfs_rl_realloc(struct runlist_element *rl, int old_size,
|
||||
int new_size);
|
||||
#endif /* _LINUX_NTFS_RUNLIST_H */
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* sysctl.h - Defines for sysctl handling in NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project. Adapted from the old NTFS driver,
|
||||
* Copyright (C) 1997 Martin von Löwis, Régis Duchesne
|
||||
* Defines for sysctl handling in NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (C) 1997 Martin von Löwis, Régis Duchesne
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
*/
|
||||
|
||||
@@ -13,7 +12,7 @@
|
||||
|
||||
#if defined(DEBUG) && defined(CONFIG_SYSCTL)
|
||||
|
||||
extern int ntfs_sysctl(int add);
|
||||
int ntfs_sysctl(int add);
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* time.h - NTFS time conversion functions. Part of the Linux-NTFS project.
|
||||
* NTFS time conversion functions.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
*/
|
||||
@@ -8,14 +8,12 @@
|
||||
#ifndef _LINUX_NTFS_TIME_H
|
||||
#define _LINUX_NTFS_TIME_H
|
||||
|
||||
#include <linux/time.h> /* For current_kernel_time(). */
|
||||
#include <linux/time.h>
|
||||
#include <asm/div64.h> /* For do_div(). */
|
||||
|
||||
#include "endian.h"
|
||||
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600)
|
||||
|
||||
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
|
||||
|
||||
/**
|
||||
/*
|
||||
* utc2ntfs - convert Linux UTC time to NTFS time
|
||||
* @ts: Linux UTC time to convert to NTFS time
|
||||
*
|
||||
@@ -31,23 +29,23 @@
|
||||
* measured as the number of 100-nano-second intervals since 1st January 1601,
|
||||
* 00:00:00 UTC.
|
||||
*/
|
||||
static inline sle64 utc2ntfs(const struct timespec64 ts)
|
||||
static inline __le64 utc2ntfs(const struct timespec64 ts)
|
||||
{
|
||||
/*
|
||||
* Convert the seconds to 100ns intervals, add the nano-seconds
|
||||
* converted to 100ns intervals, and then add the NTFS time offset.
|
||||
*/
|
||||
return cpu_to_sle64((s64)ts.tv_sec * 10000000 + ts.tv_nsec / 100 +
|
||||
NTFS_TIME_OFFSET);
|
||||
return cpu_to_le64((u64)(ts.tv_sec + NTFS_TIME_OFFSET) * 10000000 +
|
||||
ts.tv_nsec / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* get_current_ntfs_time - get the current time in little endian NTFS format
|
||||
*
|
||||
* Get the current time from the Linux kernel, convert it to its corresponding
|
||||
* NTFS time and return that in little endian format.
|
||||
*/
|
||||
static inline sle64 get_current_ntfs_time(void)
|
||||
static inline __le64 get_current_ntfs_time(void)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
|
||||
@@ -55,7 +53,7 @@ static inline sle64 get_current_ntfs_time(void)
|
||||
return utc2ntfs(ts);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* ntfs2utc - convert NTFS time to Linux time
|
||||
* @time: NTFS time (little endian) to convert to Linux UTC
|
||||
*
|
||||
@@ -71,19 +69,19 @@ static inline sle64 get_current_ntfs_time(void)
|
||||
* measured as the number of 100 nano-second intervals since 1st January 1601,
|
||||
* 00:00:00 UTC.
|
||||
*/
|
||||
static inline struct timespec64 ntfs2utc(const sle64 time)
|
||||
static inline struct timespec64 ntfs2utc(const __le64 time)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
s32 t32;
|
||||
|
||||
/* Subtract the NTFS time offset. */
|
||||
u64 t = (u64)(sle64_to_cpu(time) - NTFS_TIME_OFFSET);
|
||||
s64 t = le64_to_cpu(time) - NTFS_TIME_OFFSET * 10000000;
|
||||
/*
|
||||
* Convert the time to 1-second intervals and the remainder to
|
||||
* 1-nano-second intervals.
|
||||
*/
|
||||
ts.tv_nsec = do_div(t, 10000000) * 100;
|
||||
ts.tv_sec = t;
|
||||
ts.tv_sec = div_s64_rem(t, 10000000, &t32);
|
||||
ts.tv_nsec = t32 * 100;
|
||||
return ts;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NTFS_TIME_H */
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* types.h - Defines for NTFS Linux kernel driver specific types.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_TYPES_H
|
||||
#define _LINUX_NTFS_TYPES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
typedef __le16 le16;
|
||||
typedef __le32 le32;
|
||||
typedef __le64 le64;
|
||||
typedef __u16 __bitwise sle16;
|
||||
typedef __u32 __bitwise sle32;
|
||||
typedef __u64 __bitwise sle64;
|
||||
|
||||
/* 2-byte Unicode character type. */
|
||||
typedef le16 ntfschar;
|
||||
#define UCHAR_T_SIZE_BITS 1
|
||||
|
||||
/*
|
||||
* Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN
|
||||
* and VCN, to allow for type checking and better code readability.
|
||||
*/
|
||||
typedef s64 VCN;
|
||||
typedef sle64 leVCN;
|
||||
typedef s64 LCN;
|
||||
typedef sle64 leLCN;
|
||||
|
||||
/*
|
||||
* The NTFS journal $LogFile uses log sequence numbers which are signed 64-bit
|
||||
* values. We define our own type LSN, to allow for type checking and better
|
||||
* code readability.
|
||||
*/
|
||||
typedef s64 LSN;
|
||||
typedef sle64 leLSN;
|
||||
|
||||
/*
|
||||
* The NTFS transaction log $UsnJrnl uses usn which are signed 64-bit values.
|
||||
* We define our own type USN, to allow for type checking and better code
|
||||
* readability.
|
||||
*/
|
||||
typedef s64 USN;
|
||||
typedef sle64 leUSN;
|
||||
|
||||
typedef enum {
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
} IGNORE_CASE_BOOL;
|
||||
|
||||
#endif /* _LINUX_NTFS_TYPES_H */
|
||||
380
fs/ntfs/volume.h
380
fs/ntfs/volume.h
@@ -1,155 +1,221 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
|
||||
* of the Linux-NTFS project.
|
||||
* Defines for volume structures in NTFS Linux kernel driver.
|
||||
*
|
||||
* Copyright (c) 2001-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2025 LG Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_NTFS_VOLUME_H
|
||||
#define _LINUX_NTFS_VOLUME_H
|
||||
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/errseq.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
|
||||
#define NTFS_VOL_UID BIT(1)
|
||||
#define NTFS_VOL_GID BIT(2)
|
||||
|
||||
/*
|
||||
* The NTFS in memory super block structure.
|
||||
*
|
||||
* @sb: Pointer back to the super_block.
|
||||
* @nr_blocks: Number of sb->s_blocksize bytes sized blocks on the device.
|
||||
* @flags: Miscellaneous flags, see below.
|
||||
* @uid: uid that files will be mounted as.
|
||||
* @gid: gid that files will be mounted as.
|
||||
* @fmask: The mask for file permissions.
|
||||
* @dmask: The mask for directory permissions.
|
||||
* @mft_zone_multiplier: Initial mft zone multiplier.
|
||||
* @on_errors: What to do on filesystem errors.
|
||||
* @wb_err: Writeback error tracking.
|
||||
* @sector_size: in bytes
|
||||
* @sector_size_bits: log2(sector_size)
|
||||
* @cluster_size: in bytes
|
||||
* @cluster_size_mask: cluster_size - 1
|
||||
* @cluster_size_bits: log2(cluster_size)
|
||||
* @mft_record_size: in bytes
|
||||
* @mft_record_size_mask: mft_record_size - 1
|
||||
* @mft_record_size_bits: log2(mft_record_size)
|
||||
* @index_record_size: in bytes
|
||||
* @index_record_size_mask: index_record_size - 1
|
||||
* @index_record_size_bits: log2(index_record_size)
|
||||
* @nr_clusters: Volume size in clusters == number of bits in lcn bitmap.
|
||||
* @mft_lcn: Cluster location of mft data.
|
||||
* @mftmirr_lcn: Cluster location of copy of mft.
|
||||
* @serial_no: The volume serial number.
|
||||
* @upcase_len: Number of entries in upcase[].
|
||||
* @upcase: The upcase table.
|
||||
* @attrdef_size: Size of the attribute definition table in bytes.
|
||||
* @attrdef: Table of attribute definitions. Obtained from FILE_AttrDef.
|
||||
* @mft_data_pos: Mft record number at which to allocate the next mft record.
|
||||
* @mft_zone_start: First cluster of the mft zone.
|
||||
* @mft_zone_end: First cluster beyond the mft zone.
|
||||
* @mft_zone_pos: Current position in the mft zone.
|
||||
* @data1_zone_pos: Current position in the first data zone.
|
||||
* @data2_zone_pos: Current position in the second data zone.
|
||||
* @mft_ino: The VFS inode of $MFT.
|
||||
* @mftbmp_ino: Attribute inode for $MFT/$BITMAP.
|
||||
* @mftbmp_lock: Lock for serializing accesses to the mft record bitmap.
|
||||
* @mftmirr_ino: The VFS inode of $MFTMirr.
|
||||
* @mftmirr_size: Size of mft mirror in mft records.
|
||||
* @logfile_ino: The VFS inode of LogFile.
|
||||
* @lcnbmp_ino: The VFS inode of $Bitmap.
|
||||
* @lcnbmp_lock: Lock for serializing accesses to the cluster bitmap
|
||||
* @vol_ino: The VFS inode of $Volume.
|
||||
* @vol_flags: Volume flags.
|
||||
* @major_ver: Ntfs major version of volume.
|
||||
* @minor_ver: Ntfs minor version of volume.
|
||||
* @volume_label: volume label.
|
||||
* @root_ino: The VFS inode of the root directory.
|
||||
* @secure_ino: The VFS inode of $Secure (NTFS3.0+ only, otherwise NULL).
|
||||
* @extend_ino: The VFS inode of $Extend (NTFS3.0+ only, otherwise NULL).
|
||||
* @quota_ino: The VFS inode of $Quota.
|
||||
* @quota_q_ino: Attribute inode for $Quota/$Q.
|
||||
* @nls_map: NLS (National Language Support) table.
|
||||
* @nls_utf8: NLS table for UTF-8.
|
||||
* @free_waitq: Wait queue for threads waiting for free clusters or MFT records.
|
||||
* @free_clusters: Track the number of free clusters.
|
||||
* @free_mft_records: Track the free mft records.
|
||||
* @dirty_clusters: Number of clusters that are dirty.
|
||||
* @sparse_compression_unit: Size of compression/sparse unit in clusters.
|
||||
* @lcn_empty_bits_per_page: Number of empty bits per page in the LCN bitmap.
|
||||
* @precalc_work: Work structure for background pre-calculation tasks.
|
||||
* @preallocated_size: reallocation size (in bytes).
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* FIXME: Reorder to have commonly used together element within the
|
||||
* same cache line, aiming at a cache line size of 32 bytes. Aim for
|
||||
* 64 bytes for less commonly used together elements. Put most commonly
|
||||
* used elements to front of structure. Obviously do this only when the
|
||||
* structure has stabilized... (AIA)
|
||||
*/
|
||||
/* Device specifics. */
|
||||
struct super_block *sb; /* Pointer back to the super_block. */
|
||||
LCN nr_blocks; /* Number of sb->s_blocksize bytes
|
||||
sized blocks on the device. */
|
||||
/* Configuration provided by user at mount time. */
|
||||
unsigned long flags; /* Miscellaneous flags, see below. */
|
||||
kuid_t uid; /* uid that files will be mounted as. */
|
||||
kgid_t gid; /* gid that files will be mounted as. */
|
||||
umode_t fmask; /* The mask for file permissions. */
|
||||
umode_t dmask; /* The mask for directory
|
||||
permissions. */
|
||||
u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
|
||||
u8 on_errors; /* What to do on filesystem errors. */
|
||||
/* NTFS bootsector provided information. */
|
||||
u16 sector_size; /* in bytes */
|
||||
u8 sector_size_bits; /* log2(sector_size) */
|
||||
u32 cluster_size; /* in bytes */
|
||||
u32 cluster_size_mask; /* cluster_size - 1 */
|
||||
u8 cluster_size_bits; /* log2(cluster_size) */
|
||||
u32 mft_record_size; /* in bytes */
|
||||
u32 mft_record_size_mask; /* mft_record_size - 1 */
|
||||
u8 mft_record_size_bits; /* log2(mft_record_size) */
|
||||
u32 index_record_size; /* in bytes */
|
||||
u32 index_record_size_mask; /* index_record_size - 1 */
|
||||
u8 index_record_size_bits; /* log2(index_record_size) */
|
||||
LCN nr_clusters; /* Volume size in clusters == number of
|
||||
bits in lcn bitmap. */
|
||||
LCN mft_lcn; /* Cluster location of mft data. */
|
||||
LCN mftmirr_lcn; /* Cluster location of copy of mft. */
|
||||
u64 serial_no; /* The volume serial number. */
|
||||
/* Mount specific NTFS information. */
|
||||
u32 upcase_len; /* Number of entries in upcase[]. */
|
||||
ntfschar *upcase; /* The upcase table. */
|
||||
|
||||
s32 attrdef_size; /* Size of the attribute definition
|
||||
table in bytes. */
|
||||
ATTR_DEF *attrdef; /* Table of attribute definitions.
|
||||
Obtained from FILE_AttrDef. */
|
||||
|
||||
#ifdef NTFS_RW
|
||||
/* Variables used by the cluster and mft allocators. */
|
||||
s64 mft_data_pos; /* Mft record number at which to
|
||||
allocate the next mft record. */
|
||||
LCN mft_zone_start; /* First cluster of the mft zone. */
|
||||
LCN mft_zone_end; /* First cluster beyond the mft zone. */
|
||||
LCN mft_zone_pos; /* Current position in the mft zone. */
|
||||
LCN data1_zone_pos; /* Current position in the first data
|
||||
zone. */
|
||||
LCN data2_zone_pos; /* Current position in the second data
|
||||
zone. */
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
struct inode *mft_ino; /* The VFS inode of $MFT. */
|
||||
|
||||
struct inode *mftbmp_ino; /* Attribute inode for $MFT/$BITMAP. */
|
||||
struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
|
||||
mft record bitmap ($MFT/$BITMAP). */
|
||||
#ifdef NTFS_RW
|
||||
struct inode *mftmirr_ino; /* The VFS inode of $MFTMirr. */
|
||||
int mftmirr_size; /* Size of mft mirror in mft records. */
|
||||
|
||||
struct inode *logfile_ino; /* The VFS inode of $LogFile. */
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
struct inode *lcnbmp_ino; /* The VFS inode of $Bitmap. */
|
||||
struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
|
||||
cluster bitmap ($Bitmap/$DATA). */
|
||||
|
||||
struct inode *vol_ino; /* The VFS inode of $Volume. */
|
||||
VOLUME_FLAGS vol_flags; /* Volume flags. */
|
||||
u8 major_ver; /* Ntfs major version of volume. */
|
||||
u8 minor_ver; /* Ntfs minor version of volume. */
|
||||
|
||||
struct inode *root_ino; /* The VFS inode of the root
|
||||
directory. */
|
||||
struct inode *secure_ino; /* The VFS inode of $Secure (NTFS3.0+
|
||||
only, otherwise NULL). */
|
||||
struct inode *extend_ino; /* The VFS inode of $Extend (NTFS3.0+
|
||||
only, otherwise NULL). */
|
||||
#ifdef NTFS_RW
|
||||
/* $Quota stuff is NTFS3.0+ specific. Unused/NULL otherwise. */
|
||||
struct inode *quota_ino; /* The VFS inode of $Quota. */
|
||||
struct inode *quota_q_ino; /* Attribute inode for $Quota/$Q. */
|
||||
/* $UsnJrnl stuff is NTFS3.0+ specific. Unused/NULL otherwise. */
|
||||
struct inode *usnjrnl_ino; /* The VFS inode of $UsnJrnl. */
|
||||
struct inode *usnjrnl_max_ino; /* Attribute inode for $UsnJrnl/$Max. */
|
||||
struct inode *usnjrnl_j_ino; /* Attribute inode for $UsnJrnl/$J. */
|
||||
#endif /* NTFS_RW */
|
||||
struct ntfs_volume {
|
||||
struct super_block *sb;
|
||||
s64 nr_blocks;
|
||||
unsigned long flags;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
umode_t fmask;
|
||||
umode_t dmask;
|
||||
u8 mft_zone_multiplier;
|
||||
u8 on_errors;
|
||||
errseq_t wb_err;
|
||||
u16 sector_size;
|
||||
u8 sector_size_bits;
|
||||
u32 cluster_size;
|
||||
u32 cluster_size_mask;
|
||||
u8 cluster_size_bits;
|
||||
u32 mft_record_size;
|
||||
u32 mft_record_size_mask;
|
||||
u8 mft_record_size_bits;
|
||||
u32 index_record_size;
|
||||
u32 index_record_size_mask;
|
||||
u8 index_record_size_bits;
|
||||
s64 nr_clusters;
|
||||
s64 mft_lcn;
|
||||
s64 mftmirr_lcn;
|
||||
u64 serial_no;
|
||||
u32 upcase_len;
|
||||
__le16 *upcase;
|
||||
s32 attrdef_size;
|
||||
struct attr_def *attrdef;
|
||||
s64 mft_data_pos;
|
||||
s64 mft_zone_start;
|
||||
s64 mft_zone_end;
|
||||
s64 mft_zone_pos;
|
||||
s64 data1_zone_pos;
|
||||
s64 data2_zone_pos;
|
||||
struct inode *mft_ino;
|
||||
struct inode *mftbmp_ino;
|
||||
struct rw_semaphore mftbmp_lock;
|
||||
struct inode *mftmirr_ino;
|
||||
int mftmirr_size;
|
||||
struct inode *logfile_ino;
|
||||
struct inode *lcnbmp_ino;
|
||||
struct rw_semaphore lcnbmp_lock;
|
||||
struct inode *vol_ino;
|
||||
__le16 vol_flags;
|
||||
u8 major_ver;
|
||||
u8 minor_ver;
|
||||
unsigned char *volume_label;
|
||||
struct inode *root_ino;
|
||||
struct inode *secure_ino;
|
||||
struct inode *extend_ino;
|
||||
struct inode *quota_ino;
|
||||
struct inode *quota_q_ino;
|
||||
struct nls_table *nls_map;
|
||||
} ntfs_volume;
|
||||
bool nls_utf8;
|
||||
wait_queue_head_t free_waitq;
|
||||
atomic64_t free_clusters;
|
||||
atomic64_t free_mft_records;
|
||||
atomic64_t dirty_clusters;
|
||||
u8 sparse_compression_unit;
|
||||
unsigned int *lcn_empty_bits_per_page;
|
||||
struct work_struct precalc_work;
|
||||
loff_t preallocated_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Defined bits for the flags field in the ntfs_volume structure.
|
||||
*
|
||||
* NV_Errors Volume has errors, prevent remount rw.
|
||||
* NV_ShowSystemFiles Return system files in ntfs_readdir().
|
||||
* NV_CaseSensitive Treat file names as case sensitive and
|
||||
* create filenames in the POSIX namespace.
|
||||
* Otherwise be case insensitive but still
|
||||
* create file names in POSIX namespace.
|
||||
* NV_LogFileEmpty LogFile journal is empty.
|
||||
* NV_QuotaOutOfDate Quota is out of date.
|
||||
* NV_UsnJrnlStamped UsnJrnl has been stamped.
|
||||
* NV_ReadOnly Volume is mounted read-only.
|
||||
* NV_Compression Volume supports compression.
|
||||
* NV_FreeClusterKnown Free cluster count is known and up-to-date.
|
||||
* NV_Shutdown Volume is in shutdown state
|
||||
* NV_SysImmutable Protect system files from deletion.
|
||||
* NV_ShowHiddenFiles Return hidden files in ntfs_readdir().
|
||||
* NV_HideDotFiles Hide names beginning with a dot (".").
|
||||
* NV_CheckWindowsNames Refuse creation/rename of files with
|
||||
* Windows-reserved names (CON, AUX, NUL, COM1,
|
||||
* LPT1, etc.) or invalid characters.
|
||||
*
|
||||
* NV_Discard Issue discard/TRIM commands for freed clusters.
|
||||
* NV_DisableSparse Disable creation of sparse regions.
|
||||
*/
|
||||
typedef enum {
|
||||
NV_Errors, /* 1: Volume has errors, prevent remount rw. */
|
||||
NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */
|
||||
NV_CaseSensitive, /* 1: Treat file names as case sensitive and
|
||||
create filenames in the POSIX namespace.
|
||||
Otherwise be case insensitive but still
|
||||
create file names in POSIX namespace. */
|
||||
NV_LogFileEmpty, /* 1: $LogFile journal is empty. */
|
||||
NV_QuotaOutOfDate, /* 1: $Quota is out of date. */
|
||||
NV_UsnJrnlStamped, /* 1: $UsnJrnl has been stamped. */
|
||||
NV_SparseEnabled, /* 1: May create sparse files. */
|
||||
} ntfs_volume_flags;
|
||||
enum {
|
||||
NV_Errors,
|
||||
NV_ShowSystemFiles,
|
||||
NV_CaseSensitive,
|
||||
NV_LogFileEmpty,
|
||||
NV_QuotaOutOfDate,
|
||||
NV_UsnJrnlStamped,
|
||||
NV_ReadOnly,
|
||||
NV_Compression,
|
||||
NV_FreeClusterKnown,
|
||||
NV_Shutdown,
|
||||
NV_SysImmutable,
|
||||
NV_ShowHiddenFiles,
|
||||
NV_HideDotFiles,
|
||||
NV_CheckWindowsNames,
|
||||
NV_Discard,
|
||||
NV_DisableSparse,
|
||||
};
|
||||
|
||||
/*
|
||||
* Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo()
|
||||
* functions.
|
||||
*/
|
||||
#define DEFINE_NVOL_BIT_OPS(flag) \
|
||||
static inline int NVol##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
return test_bit(NV_##flag, &(vol)->flags); \
|
||||
} \
|
||||
static inline void NVolSet##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
set_bit(NV_##flag, &(vol)->flags); \
|
||||
} \
|
||||
static inline void NVolClear##flag(ntfs_volume *vol) \
|
||||
{ \
|
||||
clear_bit(NV_##flag, &(vol)->flags); \
|
||||
static inline int NVol##flag(struct ntfs_volume *vol) \
|
||||
{ \
|
||||
return test_bit(NV_##flag, &(vol)->flags); \
|
||||
} \
|
||||
static inline void NVolSet##flag(struct ntfs_volume *vol) \
|
||||
{ \
|
||||
set_bit(NV_##flag, &(vol)->flags); \
|
||||
} \
|
||||
static inline void NVolClear##flag(struct ntfs_volume *vol) \
|
||||
{ \
|
||||
clear_bit(NV_##flag, &(vol)->flags); \
|
||||
}
|
||||
|
||||
/* Emit the ntfs volume bitops functions. */
|
||||
@@ -159,6 +225,72 @@ DEFINE_NVOL_BIT_OPS(CaseSensitive)
|
||||
DEFINE_NVOL_BIT_OPS(LogFileEmpty)
|
||||
DEFINE_NVOL_BIT_OPS(QuotaOutOfDate)
|
||||
DEFINE_NVOL_BIT_OPS(UsnJrnlStamped)
|
||||
DEFINE_NVOL_BIT_OPS(SparseEnabled)
|
||||
DEFINE_NVOL_BIT_OPS(ReadOnly)
|
||||
DEFINE_NVOL_BIT_OPS(Compression)
|
||||
DEFINE_NVOL_BIT_OPS(FreeClusterKnown)
|
||||
DEFINE_NVOL_BIT_OPS(Shutdown)
|
||||
DEFINE_NVOL_BIT_OPS(SysImmutable)
|
||||
DEFINE_NVOL_BIT_OPS(ShowHiddenFiles)
|
||||
DEFINE_NVOL_BIT_OPS(HideDotFiles)
|
||||
DEFINE_NVOL_BIT_OPS(CheckWindowsNames)
|
||||
DEFINE_NVOL_BIT_OPS(Discard)
|
||||
DEFINE_NVOL_BIT_OPS(DisableSparse)
|
||||
|
||||
static inline void ntfs_inc_free_clusters(struct ntfs_volume *vol, s64 nr)
|
||||
{
|
||||
if (!NVolFreeClusterKnown(vol))
|
||||
wait_event(vol->free_waitq, NVolFreeClusterKnown(vol));
|
||||
atomic64_add(nr, &vol->free_clusters);
|
||||
}
|
||||
|
||||
static inline void ntfs_dec_free_clusters(struct ntfs_volume *vol, s64 nr)
|
||||
{
|
||||
if (!NVolFreeClusterKnown(vol))
|
||||
wait_event(vol->free_waitq, NVolFreeClusterKnown(vol));
|
||||
atomic64_sub(nr, &vol->free_clusters);
|
||||
}
|
||||
|
||||
static inline void ntfs_inc_free_mft_records(struct ntfs_volume *vol, s64 nr)
|
||||
{
|
||||
if (!NVolFreeClusterKnown(vol))
|
||||
return;
|
||||
|
||||
atomic64_add(nr, &vol->free_mft_records);
|
||||
}
|
||||
|
||||
static inline void ntfs_dec_free_mft_records(struct ntfs_volume *vol, s64 nr)
|
||||
{
|
||||
if (!NVolFreeClusterKnown(vol))
|
||||
return;
|
||||
|
||||
atomic64_sub(nr, &vol->free_mft_records);
|
||||
}
|
||||
|
||||
static inline void ntfs_set_lcn_empty_bits(struct ntfs_volume *vol, unsigned long index,
|
||||
u8 val, unsigned int count)
|
||||
{
|
||||
if (!NVolFreeClusterKnown(vol))
|
||||
wait_event(vol->free_waitq, NVolFreeClusterKnown(vol));
|
||||
|
||||
if (val)
|
||||
vol->lcn_empty_bits_per_page[index] -= count;
|
||||
else
|
||||
vol->lcn_empty_bits_per_page[index] += count;
|
||||
}
|
||||
|
||||
static __always_inline void ntfs_hold_dirty_clusters(struct ntfs_volume *vol, s64 nr_clusters)
|
||||
{
|
||||
atomic64_add(nr_clusters, &vol->dirty_clusters);
|
||||
}
|
||||
|
||||
static __always_inline void ntfs_release_dirty_clusters(struct ntfs_volume *vol, s64 nr_clusters)
|
||||
{
|
||||
if (atomic64_read(&vol->dirty_clusters) < nr_clusters)
|
||||
atomic64_set(&vol->dirty_clusters, 0);
|
||||
else
|
||||
atomic64_sub(nr_clusters, &vol->dirty_clusters);
|
||||
}
|
||||
|
||||
s64 ntfs_available_clusters_count(struct ntfs_volume *vol, s64 nr_clusters);
|
||||
s64 get_nr_free_clusters(struct ntfs_volume *vol);
|
||||
#endif /* _LINUX_NTFS_VOLUME_H */
|
||||
|
||||
Reference in New Issue
Block a user