[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251229112446.12164-3-linkinjeon@kernel.org>
Date: Mon, 29 Dec 2025 20:24:34 +0900
From: Namjae Jeon <linkinjeon@...nel.org>
To: viro@...iv.linux.org.uk,
brauner@...nel.org,
hch@...radead.org,
hch@....de,
tytso@....edu,
willy@...radead.org,
jack@...e.cz,
djwong@...nel.org,
josef@...icpanda.com,
sandeen@...deen.net,
rgoldwyn@...e.com,
xiang@...nel.org,
dsterba@...e.com,
pali@...nel.org,
ebiggers@...nel.org,
neil@...wn.name,
amir73il@...il.com
Cc: linux-fsdevel@...r.kernel.org,
linux-kernel@...r.kernel.org,
iamjoonsoo.kim@....com,
cheol.lee@....com,
jay.sim@....com,
gunho.lee@....com,
Namjae Jeon <linkinjeon@...nel.org>
Subject: [PATCH v3 RESEND 02/14] ntfs: update in-memory, on-disk structures and headers
This updates in-memory, on-disk structures, headers and documentation.
Signed-off-by: Namjae Jeon <linkinjeon@...nel.org>
---
Documentation/filesystems/index.rst | 1 +
Documentation/filesystems/ntfs.rst | 203 +++
fs/ntfs/aops.h | 84 +-
fs/ntfs/attrib.h | 181 +-
fs/ntfs/attrlist.h | 21 +
fs/ntfs/bitmap.h | 21 +-
fs/ntfs/collate.h | 23 +-
fs/ntfs/debug.h | 14 +-
fs/ntfs/dir.h | 23 +-
fs/ntfs/ea.h | 25 +
fs/ntfs/index.h | 97 +-
fs/ntfs/inode.h | 378 +++--
fs/ntfs/iomap.h | 22 +
fs/ntfs/layout.h | 2436 +++++++++++++--------------
fs/ntfs/lcnalloc.h | 48 +-
fs/ntfs/logfile.h | 461 ++---
fs/ntfs/malloc.h | 33 +-
fs/ntfs/mft.h | 74 +-
fs/ntfs/ntfs.h | 142 +-
fs/ntfs/quota.h | 11 +-
fs/ntfs/reparse.h | 15 +
fs/ntfs/runlist.h | 105 +-
fs/ntfs/sysctl.h | 8 +-
fs/ntfs/time.h | 16 +-
fs/ntfs/volume.h | 248 ++-
include/uapi/linux/ntfs.h | 23 +
26 files changed, 2539 insertions(+), 2174 deletions(-)
create mode 100644 Documentation/filesystems/ntfs.rst
create mode 100644 fs/ntfs/attrlist.h
create mode 100644 fs/ntfs/ea.h
create mode 100644 fs/ntfs/iomap.h
create mode 100644 fs/ntfs/reparse.h
create mode 100644 include/uapi/linux/ntfs.h
diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst
index f4873197587d..0d1f88185b73 100644
--- a/Documentation/filesystems/index.rst
+++ b/Documentation/filesystems/index.rst
@@ -98,6 +98,7 @@ Documentation for filesystem implementations.
isofs
nilfs2
nfs/index
+ ntfs
ntfs3
ocfs2
ocfs2-online-filecheck
diff --git a/Documentation/filesystems/ntfs.rst b/Documentation/filesystems/ntfs.rst
new file mode 100644
index 000000000000..1ae44772cd53
--- /dev/null
+++ b/Documentation/filesystems/ntfs.rst
@@ -0,0 +1,203 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================================
+The Linux NTFS filesystem driver
+=================================
+
+
+.. Table of contents
+
+ - Overview
+ - Features
+ - Utilities support
+ - Supported mount options
+
+
+Overview
+========
+
+The new ntfs is an implementation that supports write and the current
+trends(iomap, no buffer-head) based on read-only classic NTFS.
+The old read-only ntfs code is much cleaner, with extensive comments,
+offers readability that makes understanding NTFS easier.
+The target is to provide current trends(iomap, no buffer head, folio),
+enhanced performance, stable maintenance, utility support including fsck.
+
+Features
+========
+
+- Write support:
+ Implement write support on classic read-only NTFS. Additionally,
+ integrate delayed allocation to enhance write performance through
+ multi-cluster allocation and minimized fragmentation of cluster bitmap.
+
+- Switch to using iomap:
+ Use iomap for buffered IO writes, reads, direct IO, file extent mapping,
+ readpages, writepages operations.
+
+- Stop using the buffer head:
+ The use of buffer head in old ntfs and switched to use folio instead.
+ As a result, CONFIG_BUFFER_HEAD option enable is removed in Kconfig.
+
+- Performance Enhancements:
+ write, file list browsing, mount performance are improved with
+ the following.
+ - Use iomap aops.
+ - Delayed allocation support.
+ - Optimize zero out for newly allocated clusters.
+ - Optimize runlist merge overhead with small chunck size.
+ - pre-load mft(inode) blocks and index(dentry) blocks to improve
+ readdir + stat performance.
+ - Load lcn bitmap on background.
+
+- Stability improvement:
+ a. Pass more xfstests tests:
+ ntfs implement fallocate, idmapped mount and permission, etc,
+ resulting in a significantly high number(287) of xfstests pass.
+ b. Bonnie++ issue[3]:
+ The Bonnie++ benchmark fails on ntfs3 with a "Directory not empty"
+ error during file deletion. ntfs3 currently iterates directory
+ entries by reading index blocks one by one. When entries are deleted
+ concurrently, index block merging or entry relocation can cause
+ readdir() to skip some entries, leaving files undeleted in
+ workloads(bonnie++) that mix unlink and directory scans.
+ ntfs implement leaf chain traversal in readdir to avoid entry skip
+ on deletion.
+
+
+Utilities support
+=================
+
+While ntfs-3g includes ntfsprogs as a component, it notably lacks
+the fsck implementation. So we have launched a new ntfs utilitiies
+project called ntfsprogs-plus by forking from ntfs-3g after removing
+unnecessary ntfs fuse implementation. fsck.ntfs can be used for ntfs
+testing with xfstests as well as for recovering corrupted NTFS device.
+Download the following ntfsprogs-plus and can use mkfs.ntfs and fsck.ntfs.
+
+ https://github.com/ntfsprogs-plus/ntfsprogs-plus
+
+
+Supported mount options
+=======================
+
+The NTFS+ driver supports the following mount options:
+
+======================= ===================================================
+iocharset=name Character set to use for converting between
+ the encoding is used for user visible filename and
+ 16 bit Unicode characters.
+
+nls=name Deprecated option. Still supported but please use
+ iocharset=name in the future.
+
+uid=
+gid=
+umask= Provide default owner, group, and access mode mask.
+ These options work as documented in mount(8). By
+ default, the files/directories are owned by root
+ and he/she has read and write permissions, as well
+ as browse permission for directories. No one else
+ has any access permissions. I.e. the mode on all
+ files is by default rw------- and
+ for directories rwx------, a consequence of
+ the default fmask=0177 and dmask=0077.
+ Using a umask of zero will grant all permissions to
+ everyone, i.e. all files and directories will have
+ mode rwxrwxrwx.
+
+fmask=
+dmask= Instead of specifying umask which applies both to
+ files and directories, fmask applies only to files
+ and dmask only to directories.
+
+showmeta=<BOOL>
+show_sys_files=<BOOL> If show_sys_files is specified, show the system
+ files in directory listings. Otherwise the default
+ behaviour is to hide the system files.
+ Note that even when show_sys_files is specified,
+ "$MFT" will not be visible due to bugs/mis-features
+ in glibc. Further, note that irrespective of
+ show_sys_files, all files are accessible by name,
+ i.e. you can always do "ls -l \$UpCase" for example
+ to specifically show the system file containing
+ the Unicode upcase table.
+
+case_sensitive=<BOOL> If case_sensitive is specified, treat all filenames
+ as case sensitive and create file names in
+ the POSIX namespace (default behavior). Note,
+ the Linux NTFS driver will never create short
+ filenames and will remove them on rename/delete of
+ the corresponding long file name. Note that files
+ remain accessible via their short file name, if it
+ exists.
+
+nocase=<BOOL> If nocase is specified, treat filenames
+ case-insensitively.
+
+disable_sparse=<BOOL> If disable_sparse is specified, creation of sparse
+ regions, i.e. holes, inside files is disabled for
+ the volume (for the duration of this mount only).
+ By default, creation of sparse regions is enabled,
+ which is consistent with the behaviour of
+ traditional Unix filesystems.
+
+errors=opt Specify NTFS+ behavior on critical errors: panic,
+ remount the partition in read-only mode or
+ continue without doing anything (default behavior).
+
+mft_zone_multiplier= Set the MFT zone multiplier for the volume (this
+ setting is not persistent across mounts and can be
+ changed from mount to mount but cannot be changed
+ on remount). Values of 1 to 4 are allowed, 1 being
+ the default. The MFT zone multiplier determines
+ how much space is reserved for the MFT on the
+ volume. If all other space is used up, then the
+ MFT zone will be shrunk dynamically, so this has no
+ impact on the amount of free space. However, it
+ can have an impact on performance by affecting
+ fragmentation of the MFT. In general use the
+ default. If you have a lot of small files then use
+ a higher value. The values have the following
+ meaning:
+
+ ===== =================================
+ Value MFT zone size (% of volume size)
+ ===== =================================
+ 1 12.5%
+ 2 25%
+ 3 37.5%
+ 4 50%
+ ===== =================================
+
+ Note this option is irrelevant for read-only mount.
+
+preallocated_size= Set preallocated size to optimize runlist merge
+ overhead with small chunck size.(64KB size by
+ default)
+
+acl=<BOOL> Enable POSIX ACL support. When specified, POSIX
+ ACLs stored in extended attributes are enforced.
+ Default is off. Requires kernel config
+ NTFSPLUS_FS_POSIX_ACL enabled.
+
+sys_immutable=<BOOL> Make NTFS system files (e.g. $MFT, $LogFile,
+ $Bitmap, $UpCase, etc.) immutable to user initiated
+ modifications for extra safety. Default is off.
+
+nohidden=<BOOL> Hide files and directories marked with the Windows
+ "hidden" attribute. By default hidden items are
+ shown.
+
+hide_dot_files=<BOOL> Hide names beginning with a dot ("."). By default
+ dot files are shown. When enabled, files and
+ directories created with a leading '.' will be
+ hidden from directory listings.
+
+windows_names=<BOOL> Refuse creation/rename of files with characters or
+ reserved device names disallowed on Windows (e.g.
+ CON, NUL, AUX, COM1, LPT1, etc.). Default is off.
+discard=<BOOL> Issue block device discard for clusters freed on
+ file deletion/truncation to inform underlying
+ storage.
+======================= ==================================================
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
index 8d0958a149cb..43e4ef7722a5 100644
--- a/fs/ntfs/aops.h
+++ b/fs/ntfs/aops.h
@@ -1,88 +1,24 @@
/* 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.
+/**
+ * Defines for NTFS kernel address space operations and page cache
+ * handling.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
+ * Copyright (c) 2025 LG Electronics Co., Ltd.
*/
#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 <linux/iomap.h>
+#include "volume.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 */
-
+void mark_ntfs_record_dirty(struct folio *folio);
+int ntfs_dev_read(struct super_block *sb, void *buf, loff_t start, loff_t end);
+int ntfs_dev_write(struct super_block *sb, void *buf, loff_t start,
+ loff_t size, bool wait);
#endif /* _LINUX_NTFS_AOPS_H */
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h
index fe0890d3d072..e7991851dc9a 100644
--- a/fs/ntfs/attrib.h
+++ b/fs/ntfs/attrib.h
@@ -1,21 +1,20 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* 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
@@ -35,68 +34,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;
-
-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);
-
-extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
+ 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;
+};
+
+enum { /* ways of processing holes when expanding */
+ HOLES_NO,
+ HOLES_OK,
+};
+
+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);
-
-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)
+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);
+
+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 */
diff --git a/fs/ntfs/attrlist.h b/fs/ntfs/attrlist.h
new file mode 100644
index 000000000000..d0eadc5db1b0
--- /dev/null
+++ b/fs/ntfs/attrlist.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Exports for attribute list attribute handling.
+ * Originated from Linux-NTFS project.
+ *
+ * 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 */
diff --git a/fs/ntfs/bitmap.h b/fs/ntfs/bitmap.h
index 9dd2224ca9c4..d58b3ebe5944 100644
--- a/fs/ntfs/bitmap.h
+++ b/fs/ntfs/bitmap.h
@@ -1,7 +1,7 @@
/* 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. Part of the Linux-NTFS
+ * project.
*
* Copyright (c) 2004 Anton Altaparmakov
*/
@@ -9,13 +9,12 @@
#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 ntfsp_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);
/**
@@ -27,8 +26,6 @@ extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
*
* Set @count bits starting at bit @start_bit in the bitmap described by the
* vfs inode @vi to @value, where @value is either 0 or 1.
- *
- * Return 0 on success and -errno on error.
*/
static inline int ntfs_bitmap_set_bits_in_run(struct inode *vi,
const s64 start_bit, const s64 count, const u8 value)
@@ -62,8 +59,6 @@ static inline int ntfs_bitmap_set_run(struct inode *vi, const s64 start_bit,
*
* Clear @count bits starting at bit @start_bit in the bitmap described by the
* vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
*/
static inline int ntfs_bitmap_clear_run(struct inode *vi, const s64 start_bit,
const s64 count)
@@ -77,8 +72,6 @@ static inline int ntfs_bitmap_clear_run(struct inode *vi, const s64 start_bit,
* @bit: bit to set
*
* Set bit @bit in the bitmap described by the vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
*/
static inline int ntfs_bitmap_set_bit(struct inode *vi, const s64 bit)
{
@@ -91,14 +84,10 @@ static inline int ntfs_bitmap_set_bit(struct inode *vi, const s64 bit)
* @bit: bit to clear
*
* Clear bit @bit in the bitmap described by the vfs inode @vi.
- *
- * Return 0 on success and -errno on error.
*/
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 */
diff --git a/fs/ntfs/collate.h b/fs/ntfs/collate.h
index f2255619b4f4..cf04508340f0 100644
--- a/fs/ntfs/collate.h
+++ b/fs/ntfs/collate.h
@@ -1,26 +1,27 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* Copyright (c) 2004 Anton Altaparmakov
+ *
+ * Part of this file is based on code from the NTFS-3G project.
+ * 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,7 +30,7 @@ static inline bool ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
return false;
}
-extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
+int ntfs_collate(struct ntfs_volume *vol, __le32 cr,
const void *data1, const int data1_len,
const void *data2, const int data2_len);
diff --git a/fs/ntfs/debug.h b/fs/ntfs/debug.h
index 6fdef388f129..fc8ae7b5c28e 100644
--- a/fs/ntfs/debug.h
+++ b/fs/ntfs/debug.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. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
*/
@@ -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 */
diff --git a/fs/ntfs/dir.h b/fs/ntfs/dir.h
index 0e326753df40..5abe21c3d938 100644
--- a/fs/ntfs/dir.h
+++ b/fs/ntfs/dir.h
@@ -1,7 +1,7 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2004 Anton Altaparmakov
*/
@@ -9,26 +9,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 */
diff --git a/fs/ntfs/ea.h b/fs/ntfs/ea.h
new file mode 100644
index 000000000000..a4302f98d359
--- /dev/null
+++ b/fs/ntfs/ea.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#define NTFS_EA_UID BIT(1)
+#define NTFS_EA_GID BIT(2)
+#define NTFS_EA_MODE BIT(3)
+
+extern const struct xattr_handler *const ntfsp_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 ntfsp_listxattr(struct dentry *dentry, char *buffer, size_t size);
+
+#ifdef CONFIG_NTFS_FS_POSIX_ACL
+struct posix_acl *ntfsp_get_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ int type);
+int ntfsp_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct posix_acl *acl, int type);
+int ntfsp_init_acl(struct mnt_idmap *idmap, struct inode *inode,
+ struct inode *dir);
+#else
+#define ntfsp_get_acl NULL
+#define ntfsp_set_acl NULL
+#endif
diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
index bb3c3ae55138..b5c719910ab6 100644
--- a/fs/ntfs/index.h
+++ b/fs/ntfs/index.h
@@ -1,7 +1,7 @@
/* 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. Part of the Linux-NTFS
+ * project.
*
* Copyright (c) 2004 Anton Altaparmakov
*/
@@ -11,13 +11,14 @@
#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
* @entry: index entry (points into @ir or @ia)
@@ -58,26 +59,38 @@
* 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 index_root *ir;
+ struct ntfs_attr_search_ctx *actx;
+ struct index_block *ib;
+ struct ntfs_inode *base_ni;
+ struct index_block *ia;
struct page *page;
-} ntfs_index_context;
-
-extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni);
-extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
-
-extern int ntfs_index_lookup(const void *key, const int key_len,
- ntfs_index_context *ictx);
+ struct ntfs_inode *ia_ni;
+ int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */
+ s64 parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
+ int pindex; /* maximum it's the number of the parent nodes */
+ bool ib_dirty;
+ u32 block_size;
+ u8 vcn_size_bits;
+ bool sync_write;
+};
-#ifdef NTFS_RW
+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 int key_len,
+ struct ntfs_index_context *ictx);
/**
* ntfs_index_entry_flush_dcache_page - flush_dcache_page() for index entries
@@ -94,41 +107,21 @@ extern int ntfs_index_lookup(const void *key, const int key_len,
* 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)
+static inline void ntfs_index_entry_flush_dcache_page(struct ntfs_index_context *ictx)
{
- if (ictx->is_in_root)
- flush_dcache_mft_record_page(ictx->actx->ntfs_ino);
- else
+ if (!ictx->is_in_root)
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 int 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 */
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h
index 147ef4ddb691..a22798e1d756 100644
--- a/fs/ntfs/inode.h
+++ b/fs/ntfs/inode.h
@@ -1,45 +1,43 @@
/* 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. Part of
+ * the Linux-NTFS project.
*
* 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_PARENT_2,
+ NTFS_INODE_MUTEX_NORMAL_2,
+ NTFS_REPARSE_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.
*/
-struct _ntfs_inode {
+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 state; /*
+ * NTFS specific flags describing this inode.
+ * See ntfs_inode_state_bits below.
+ */
+ __le32 flags; /* Flags describing the file. (Copy from STANDARD_INFORMATION) */
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. */
+ struct 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
@@ -49,111 +47,153 @@ struct _ntfs_inode {
* 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. */
+ __le32 type; /* Attribute type of this fake inode. */
+ __le16 *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.*/
+ struct 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.
+ */
+ s64 lcn_seek_trunc;
+
+ s64 data_size; /* Copy from the attribute record. */
+ s64 initialized_size; /* Copy from the attribute record. */
+ s64 allocated_size; /* Copy from the attribute record. */
+
+ struct timespec64 i_crtime;
+
/*
* 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. */
+ void *mrec;
+ struct mutex mrec_lock; /*
+ * Lock for serializing access to the
+ * mft record belonging to this inode.
+ */
+ struct folio *folio; /*
+ * The folio containing the mft record of the
+ * inode. This should only be touched by the
+ * (un)map_mft_record*() functions.
+ */
+ int folio_ofs; /*
+ * Offset into the folio at which the mft record
+ * begins. This should only be touched by the
+ * (un)map_mft_record*() functions.
+ */
+ s64 mft_lcn[2]; /* s64 number containing the mft record */
+ unsigned int mft_lcn_count;
+
/*
* 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.
+ * lists. Only valid if NI_AttrList is set in state.
*/
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. */
+
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. */
+ u32 vcn_size; /* Size of a vcn in this index. */
+ __le32 collation_rule; /* The collation rule for the index. */
+ u8 block_size_bits; /* Log2 of the above. */
u8 vcn_size_bits; /* Log2 of the above. */
} 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). */
+ 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. */
} 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. */
+ 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 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.
+ */
+ struct 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.
+ */
} 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
*/
-typedef enum {
+enum {
NI_Dirty, /* 1: Mft record needs to be written to disk. */
+ NI_AttrListDirty, /* 1: Mft record contains an attribute list. */
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_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, /* 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;
+ 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 +205,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,17 +246,22 @@ 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
@@ -223,22 +269,18 @@ typedef struct {
*
* 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 (struct ntfs_inode *)container_of(inode, struct big_ntfs_inode, vfs_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 &((struct big_ntfs_inode *)ni)->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 +288,67 @@ 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;
-
-extern int ntfs_test_inode(struct inode *vi, void *data);
+ __le32 type;
+ unsigned long state;
+};
-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);
-
-extern int ntfs_read_inode_mount(struct inode *vi);
-
-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);
+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);
+
+int ntfsp_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct iattr *attr);
+int ntfsp_getattr(struct mnt_idmap *idmap, const struct path *path,
+ struct kstat *stat, unsigned int request_mask,
+ unsigned int query_flags);
+
+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);
+void ntfs_set_vfs_operations(struct inode *inode, mode_t mode, dev_t dev);
#endif /* _LINUX_NTFS_INODE_H */
diff --git a/fs/ntfs/iomap.h b/fs/ntfs/iomap.h
new file mode 100644
index 000000000000..c2602f3ff11a
--- /dev/null
+++ b/fs/ntfs/iomap.h
@@ -0,0 +1,22 @@
+/* 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_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_zero_range(struct inode *inode, loff_t offset, loff_t length, bool bdirect);
+#endif /* _LINUX_NTFS_IOMAP_H */
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
index 5d4bf7a3259f..a29ea10d9a37 100644
--- a/fs/ntfs/layout.h
+++ b/fs/ntfs/layout.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
- * project.
+ * All NTFS associated on-disk structures. Part of the Linux-NTFS
+ * project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
@@ -15,8 +15,6 @@
#include <linux/list.h>
#include <asm/byteorder.h>
-#include "types.h"
-
/* The NTFS oem_id "NTFS " */
#define magicNTFS cpu_to_le64(0x202020205346544eULL)
@@ -34,54 +32,60 @@
/*
* BIOS parameter block (bpb) structure.
*/
-typedef struct {
- le16 bytes_per_sector; /* Size of a sector in bytes. */
+struct bios_parameter_block {
+ __le16 bytes_per_sector; /* Size of a sector in bytes. */
u8 sectors_per_cluster; /* Size of a cluster in sectors. */
- le16 reserved_sectors; /* zero */
+ __le16 reserved_sectors; /* zero */
u8 fats; /* zero */
- le16 root_entries; /* zero */
- le16 sectors; /* zero */
+ __le16 root_entries; /* zero */
+ __le16 sectors; /* zero */
u8 media_type; /* 0xf8 = hard disk */
- le16 sectors_per_fat; /* zero */
- le16 sectors_per_track; /* irrelevant */
- le16 heads; /* irrelevant */
- le32 hidden_sectors; /* zero */
- le32 large_sectors; /* zero */
-} __attribute__ ((__packed__)) BIOS_PARAMETER_BLOCK;
+ __le16 sectors_per_fat; /* zero */
+ __le16 sectors_per_track; /* irrelevant */
+ __le16 heads; /* irrelevant */
+ __le32 hidden_sectors; /* zero */
+ __le32 large_sectors; /* zero */
+} __packed;
/*
* NTFS boot sector structure.
*/
-typedef struct {
+struct ntfs_boot_sector {
u8 jump[3]; /* Irrelevant (jump to boot up code).*/
- le64 oem_id; /* Magic "NTFS ". */
- BIOS_PARAMETER_BLOCK bpb; /* See BIOS_PARAMETER_BLOCK. */
- u8 unused[4]; /* zero, NTFS diskedit.exe states that
- this is actually:
- __u8 physical_drive; // 0x80
- __u8 current_head; // zero
- __u8 extended_boot_signature;
- // 0x80
- __u8 unused; // zero
+ __le64 oem_id; /* Magic "NTFS ". */
+ struct bios_parameter_block bpb; /* See BIOS_PARAMETER_BLOCK. */
+ u8 unused[4]; /*
+ * zero, NTFS diskedit.exe states that
+ * this is actually:
+ * __u8 physical_drive; // 0x80
+ * __u8 current_head; // zero
+ * __u8 extended_boot_signature;
+ * // 0x80
+ * __u8 unused; // zero
+ */
+ __le64 number_of_sectors; /*
+ * Number of sectors in volume. Gives
+ * maximum volume size of 2^63 sectors.
+ * Assuming standard sector size of 512
+ * bytes, the maximum byte size is
+ * approx. 4.7x10^21 bytes. (-;
*/
-/*0x28*/sle64 number_of_sectors; /* Number of sectors in volume. Gives
- maximum volume size of 2^63 sectors.
- Assuming standard sector size of 512
- bytes, the maximum byte size is
- approx. 4.7x10^21 bytes. (-; */
- sle64 mft_lcn; /* Cluster location of mft data. */
- sle64 mftmirr_lcn; /* Cluster location of copy of mft. */
+ __le64 mft_lcn; /* Cluster location of mft data. */
+ __le64 mftmirr_lcn; /* Cluster location of copy of mft. */
s8 clusters_per_mft_record; /* Mft record size in clusters. */
u8 reserved0[3]; /* zero */
s8 clusters_per_index_record; /* Index block size in clusters. */
u8 reserved1[3]; /* zero */
- le64 volume_serial_number; /* Irrelevant (serial number). */
- le32 checksum; /* Boot sector checksum. */
-/*0x54*/u8 bootstrap[426]; /* Irrelevant (boot up code). */
- le16 end_of_sector_marker; /* End of bootsector magic. Always is
- 0xaa55 in little endian. */
-/* sizeof() = 512 (0x200) bytes */
-} __attribute__ ((__packed__)) NTFS_BOOT_SECTOR;
+ __le64 volume_serial_number; /* Irrelevant (serial number). */
+ __le32 checksum; /* Boot sector checksum. */
+ u8 bootstrap[426]; /* Irrelevant (boot up code). */
+ __le16 end_of_sector_marker; /*
+ * End of bootsector magic. Always is
+ * 0xaa55 in little endian.
+ */
+} __packed;
+
+static_assert(sizeof(struct ntfs_boot_sector) == 512);
/*
* Magic identifiers present at the beginning of all ntfs record containing
@@ -93,37 +97,37 @@ enum {
magic_INDX = cpu_to_le32(0x58444e49), /* Index buffer. */
magic_HOLE = cpu_to_le32(0x454c4f48), /* ? (NTFS 3.0+?) */
- /* Found in $LogFile/$DATA. */
+ /* Found in LogFile/DATA. */
magic_RSTR = cpu_to_le32(0x52545352), /* Restart page. */
magic_RCRD = cpu_to_le32(0x44524352), /* Log record page. */
- /* Found in $LogFile/$DATA. (May be found in $MFT/$DATA, also?) */
+ /* Found in LogFile/DATA. (May be found in $MFT/$DATA, also?) */
magic_CHKD = cpu_to_le32(0x444b4843), /* Modified by chkdsk. */
/* Found in all ntfs record containing records. */
- magic_BAAD = cpu_to_le32(0x44414142), /* Failed multi sector
- transfer was detected. */
+ magic_BAAD = cpu_to_le32(0x44414142), /*
+ * Failed multi sector
+ * transfer was detected.
+ */
/*
- * Found in $LogFile/$DATA when a page is full of 0xff bytes and is
+ * Found in LogFile/DATA when a page is full of 0xff bytes and is
* thus not initialized. Page must be initialized before using it.
*/
magic_empty = cpu_to_le32(0xffffffff) /* Record is empty. */
};
-typedef le32 NTFS_RECORD_TYPE;
-
/*
* Generic magic comparison macros. Finally found a use for the ## preprocessor
* operator! (-8
*/
-static inline bool __ntfs_is_magic(le32 x, NTFS_RECORD_TYPE r)
+static inline bool __ntfs_is_magic(__le32 x, __le32 r)
{
return (x == r);
}
#define ntfs_is_magic(x, m) __ntfs_is_magic(x, magic_##m)
-static inline bool __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
+static inline bool __ntfs_is_magicp(__le32 *p, __le32 r)
{
return (*p == r);
}
@@ -132,31 +136,31 @@ static inline bool __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
/*
* Specialised magic comparison macros for the NTFS_RECORD_TYPEs defined above.
*/
-#define ntfs_is_file_record(x) ( ntfs_is_magic (x, FILE) )
-#define ntfs_is_file_recordp(p) ( ntfs_is_magicp(p, FILE) )
-#define ntfs_is_mft_record(x) ( ntfs_is_file_record (x) )
-#define ntfs_is_mft_recordp(p) ( ntfs_is_file_recordp(p) )
-#define ntfs_is_indx_record(x) ( ntfs_is_magic (x, INDX) )
-#define ntfs_is_indx_recordp(p) ( ntfs_is_magicp(p, INDX) )
-#define ntfs_is_hole_record(x) ( ntfs_is_magic (x, HOLE) )
-#define ntfs_is_hole_recordp(p) ( ntfs_is_magicp(p, HOLE) )
+#define ntfs_is_file_record(x) (ntfs_is_magic(x, FILE))
+#define ntfs_is_file_recordp(p) (ntfs_is_magicp(p, FILE))
+#define ntfs_is_mft_record(x) (ntfs_is_file_record(x))
+#define ntfs_is_mft_recordp(p) (ntfs_is_file_recordp(p))
+#define ntfs_is_indx_record(x) (ntfs_is_magic(x, INDX))
+#define ntfs_is_indx_recordp(p) (ntfs_is_magicp(p, INDX))
+#define ntfs_is_hole_record(x) (ntfs_is_magic(x, HOLE))
+#define ntfs_is_hole_recordp(p) (ntfs_is_magicp(p, HOLE))
-#define ntfs_is_rstr_record(x) ( ntfs_is_magic (x, RSTR) )
-#define ntfs_is_rstr_recordp(p) ( ntfs_is_magicp(p, RSTR) )
-#define ntfs_is_rcrd_record(x) ( ntfs_is_magic (x, RCRD) )
-#define ntfs_is_rcrd_recordp(p) ( ntfs_is_magicp(p, RCRD) )
+#define ntfs_is_rstr_record(x) (ntfs_is_magic(x, RSTR))
+#define ntfs_is_rstr_recordp(p) (ntfs_is_magicp(p, RSTR))
+#define ntfs_is_rcrd_record(x) (ntfs_is_magic(x, RCRD))
+#define ntfs_is_rcrd_recordp(p) (ntfs_is_magicp(p, RCRD))
-#define ntfs_is_chkd_record(x) ( ntfs_is_magic (x, CHKD) )
-#define ntfs_is_chkd_recordp(p) ( ntfs_is_magicp(p, CHKD) )
+#define ntfs_is_chkd_record(x) (ntfs_is_magic(x, CHKD))
+#define ntfs_is_chkd_recordp(p) (ntfs_is_magicp(p, CHKD))
-#define ntfs_is_baad_record(x) ( ntfs_is_magic (x, BAAD) )
-#define ntfs_is_baad_recordp(p) ( ntfs_is_magicp(p, BAAD) )
+#define ntfs_is_baad_record(x) (ntfs_is_magic(x, BAAD))
+#define ntfs_is_baad_recordp(p) (ntfs_is_magicp(p, BAAD))
-#define ntfs_is_empty_record(x) ( ntfs_is_magic (x, empty) )
-#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) )
+#define ntfs_is_empty_record(x) (ntfs_is_magic(x, empty))
+#define ntfs_is_empty_recordp(p) (ntfs_is_magicp(p, empty))
/*
- * The Update Sequence Array (usa) is an array of the le16 values which belong
+ * The Update Sequence Array (usa) is an array of the __le16 values which belong
* to the end of each sector protected by the update sequence record in which
* this array is contained. Note that the first entry is the Update Sequence
* Number (usn), a cyclic counter of how many times the protected record has
@@ -166,21 +170,27 @@ static inline bool __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
* transfer has occurred when the data was written.
* The maximum size for the update sequence array is fixed to:
* maximum size = usa_ofs + (usa_count * 2) = 510 bytes
- * The 510 bytes comes from the fact that the last le16 in the array has to
- * (obviously) finish before the last le16 of the first 512-byte sector.
+ * The 510 bytes comes from the fact that the last __le16 in the array has to
+ * (obviously) finish before the last __le16 of the first 512-byte sector.
* This formula can be used as a consistency check in that usa_ofs +
* (usa_count * 2) has to be less than or equal to 510.
*/
-typedef struct {
- NTFS_RECORD_TYPE magic; /* A four-byte magic identifying the record
- type and/or status. */
- le16 usa_ofs; /* Offset to the Update Sequence Array (usa)
- from the start of the ntfs record. */
- le16 usa_count; /* Number of le16 sized entries in the usa
- including the Update Sequence Number (usn),
- thus the number of fixups is the usa_count
- minus 1. */
-} __attribute__ ((__packed__)) NTFS_RECORD;
+struct ntfs_record {
+ __le32 magic; /*
+ * A four-byte magic identifying the record
+ * type and/or status.
+ */
+ __le16 usa_ofs; /*
+ * Offset to the Update Sequence Array (usa)
+ * from the start of the ntfs record.
+ */
+ __le16 usa_count; /*
+ * Number of __le16 sized entries in the usa
+ * including the Update Sequence Number (usn),
+ * thus the number of fixups is the usa_count
+ * minus 1.
+ */
+} __packed;
/*
* System files mft record numbers. All these files are always marked as used
@@ -189,55 +199,77 @@ typedef struct {
* of the system files is always equal to their mft record number and it is
* never modified.
*/
-typedef enum {
- FILE_MFT = 0, /* Master file table (mft). Data attribute
- contains the entries and bitmap attribute
- records which ones are in use (bit==1). */
+enum {
+ FILE_MFT = 0, /*
+ * Master file table (mft). Data attribute
+ * contains the entries and bitmap attribute
+ * records which ones are in use (bit==1).
+ */
FILE_MFTMirr = 1, /* Mft mirror: copy of first four mft records
- in data attribute. If cluster size > 4kiB,
- copy of first N mft records, with
- N = cluster_size / mft_record_size. */
+ * in data attribute. If cluster size > 4kiB,
+ * copy of first N mft records, with
+ * N = cluster_size / mft_record_size.
+ */
FILE_LogFile = 2, /* Journalling log in data attribute. */
- FILE_Volume = 3, /* Volume name attribute and volume information
- attribute (flags and ntfs version). Windows
- refers to this file as volume DASD (Direct
- Access Storage Device). */
- FILE_AttrDef = 4, /* Array of attribute definitions in data
- attribute. */
+ FILE_Volume = 3, /*
+ * Volume name attribute and volume information
+ * attribute (flags and ntfs version). Windows
+ * refers to this file as volume DASD (Direct
+ * Access Storage Device).
+ */
+ FILE_AttrDef = 4, /*
+ * Array of attribute definitions in data
+ * attribute.
+ */
FILE_root = 5, /* Root directory. */
- FILE_Bitmap = 6, /* Allocation bitmap of all clusters (lcns) in
- data attribute. */
- FILE_Boot = 7, /* Boot sector (always at cluster 0) in data
- attribute. */
- FILE_BadClus = 8, /* Contains all bad clusters in the non-resident
- data attribute. */
- FILE_Secure = 9, /* Shared security descriptors in data attribute
- and two indexes into the descriptors.
- Appeared in Windows 2000. Before that, this
- file was named $Quota but was unused. */
- FILE_UpCase = 10, /* Uppercase equivalents of all 65536 Unicode
- characters in data attribute. */
- FILE_Extend = 11, /* Directory containing other system files (eg.
- $ObjId, $Quota, $Reparse and $UsnJrnl). This
- is new to NTFS3.0. */
+ FILE_Bitmap = 6, /*
+ * Allocation bitmap of all clusters (lcns) in
+ * data attribute.
+ */
+ FILE_Boot = 7, /*
+ * Boot sector (always at cluster 0) in data
+ * attribute.
+ */
+ FILE_BadClus = 8, /*
+ * Contains all bad clusters in the non-resident
+ * data attribute.
+ */
+ FILE_Secure = 9, /*
+ * Shared security descriptors in data attribute
+ * and two indexes into the descriptors.
+ * Appeared in Windows 2000. Before that, this
+ * file was named $Quota but was unused.
+ */
+ FILE_UpCase = 10, /*
+ * Uppercase equivalents of all 65536 Unicode
+ * characters in data attribute.
+ */
+ FILE_Extend = 11, /*
+ * Directory containing other system files (eg.
+ * $ObjId, $Quota, $Reparse and $UsnJrnl). This
+ * is new to NTFS3.0.
+ */
FILE_reserved12 = 12, /* Reserved for future use (records 12-15). */
FILE_reserved13 = 13,
FILE_reserved14 = 14,
FILE_reserved15 = 15,
- FILE_first_user = 16, /* First user file, used as test limit for
- whether to allow opening a file or not. */
-} NTFS_SYSTEM_FILES;
+ FILE_first_user = 16, /*
+ * First user file, used as test limit for
+ * whether to allow opening a file or not.
+ */
+};
/*
* These are the so far known MFT_RECORD_* flags (16-bit) which contain
* information about the mft record in which they are present.
*/
enum {
- MFT_RECORD_IN_USE = cpu_to_le16(0x0001),
- MFT_RECORD_IS_DIRECTORY = cpu_to_le16(0x0002),
-} __attribute__ ((__packed__));
-
-typedef le16 MFT_RECORD_FLAGS;
+ MFT_RECORD_IN_USE = cpu_to_le16(0x0001),
+ MFT_RECORD_IS_DIRECTORY = cpu_to_le16(0x0002),
+ MFT_RECORD_IS_4 = cpu_to_le16(0x0004),
+ MFT_RECORD_IS_VIEW_INDEX = cpu_to_le16(0x0008),
+ MFT_REC_SPACE_FILLER = 0xffff, /*Just to make flags 16-bit.*/
+} __packed;
/*
* mft references (aka file references or file record segment references) are
@@ -251,34 +283,14 @@ typedef le16 MFT_RECORD_FLAGS;
* The sequence number is a circular counter (skipping 0) describing how many
* times the referenced mft record has been (re)used. This has to match the
* sequence number of the mft record being referenced, otherwise the reference
- * is considered stale and removed (FIXME: only ntfsck or the driver itself?).
+ * is considered stale and removed.
*
* If the sequence number is zero it is assumed that no sequence number
* consistency checking should be performed.
- *
- * FIXME: Since inodes are 32-bit as of now, the driver needs to always check
- * for high_part being 0 and if not either BUG(), cause a panic() or handle
- * the situation in some other way. This shouldn't be a problem as a volume has
- * to become HUGE in order to need more than 32-bits worth of mft records.
- * Assuming the standard mft record size of 1kb only the records (never mind
- * the non-resident attributes, etc.) would require 4Tb of space on their own
- * for the first 32 bits worth of records. This is only if some strange person
- * doesn't decide to foul play and make the mft sparse which would be a really
- * horrible thing to do as it would trash our current driver implementation. )-:
- * Do I hear screams "we want 64-bit inodes!" ?!? (-;
- *
- * FIXME: The mft zone is defined as the first 12% of the volume. This space is
- * reserved so that the mft can grow contiguously and hence doesn't become
- * fragmented. Volume free space includes the empty part of the mft zone and
- * when the volume's free 88% are used up, the mft zone is shrunk by a factor
- * of 2, thus making more space available for more files/data. This process is
- * repeated every time there is no more free space except for the mft zone until
- * there really is no more free space.
- */
-
-/*
- * Typedef the MFT_REF as a 64-bit value for easier handling.
- * Also define two unpacking macros to get to the reference (MREF) and
+ */
+
+/*
+ * Define two unpacking macros to get to the reference (MREF) and
* sequence number (MSEQNO) respectively.
* The _LE versions are to be applied on little endian MFT_REFs.
* Note: The _LE versions will return a CPU endian formatted value!
@@ -286,16 +298,14 @@ typedef le16 MFT_RECORD_FLAGS;
#define MFT_REF_MASK_CPU 0x0000ffffffffffffULL
#define MFT_REF_MASK_LE cpu_to_le64(MFT_REF_MASK_CPU)
-typedef u64 MFT_REF;
-typedef le64 leMFT_REF;
-
-#define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \
- ((MFT_REF)(m) & MFT_REF_MASK_CPU)))
+#define MK_MREF(m, s) ((u64)(((u64)(s) << 48) | \
+ ((u64)(m) & MFT_REF_MASK_CPU)))
#define MK_LE_MREF(m, s) cpu_to_le64(MK_MREF(m, s))
#define MREF(x) ((unsigned long)((x) & MFT_REF_MASK_CPU))
#define MSEQNO(x) ((u16)(((x) >> 48) & 0xffff))
#define MREF_LE(x) ((unsigned long)(le64_to_cpu(x) & MFT_REF_MASK_CPU))
+#define MREF_INO(x) ((unsigned long)MREF_LE(x))
#define MSEQNO_LE(x) ((u16)((le64_to_cpu(x) >> 48) & 0xffff))
#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? true : false)
@@ -309,63 +319,77 @@ typedef le64 leMFT_REF;
* in that it only consists of the attribute type code AT_END and none of the
* other members of the attribute structure are present.
*/
-typedef struct {
-/*Ofs*/
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPE magic; /* Usually the magic is "FILE". */
- le16 usa_ofs; /* See NTFS_RECORD definition above. */
- le16 usa_count; /* See NTFS_RECORD definition above. */
-
-/* 8*/ le64 lsn; /* $LogFile sequence number for this record.
- Changed every time the record is modified. */
-/* 16*/ le16 sequence_number; /* Number of times this mft record has been
- reused. (See description for MFT_REF
- above.) NOTE: The increment (skipping zero)
- is done when the file is deleted. NOTE: If
- this is zero it is left zero. */
-/* 18*/ le16 link_count; /* Number of hard links, i.e. the number of
- directory entries referencing this record.
- NOTE: Only used in mft base records.
- NOTE: When deleting a directory entry we
- check the link_count and if it is 1 we
- delete the file. Otherwise we delete the
- FILE_NAME_ATTR being referenced by the
- directory entry from the mft record and
- decrement the link_count.
- FIXME: Careful with Win32 + DOS names! */
-/* 20*/ le16 attrs_offset; /* Byte offset to the first attribute in this
- mft record from the start of the mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file
- is deleted, the MFT_RECORD_IN_USE flag is
- set to zero. */
-/* 24*/ le32 bytes_in_use; /* Number of bytes used in this mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 28*/ le32 bytes_allocated; /* Number of bytes allocated for this mft
- record. This should be equal to the mft
- record size. */
-/* 32*/ leMFT_REF base_mft_record;/* This is zero for base mft records.
- When it is not zero it is a mft reference
- pointing to the base mft record to which
- this record belongs (this is then used to
- locate the attribute list attribute present
- in the base record which describes this
- extension record and hence might need
- modification when the extension record
- itself is modified, also locating the
- attribute list also means finding the other
- potential extents, belonging to the non-base
- mft record). */
-/* 40*/ le16 next_attr_instance;/* The instance number that will be assigned to
- the next attribute added to this mft record.
- NOTE: Incremented each time after it is used.
- NOTE: Every time the mft record is reused
- this number is set to zero. NOTE: The first
- instance number is always 0. */
+struct mft_record {
+ __le32 magic; /* Usually the magic is "FILE". */
+ __le16 usa_ofs; /* See ntfs_record struct definition above. */
+ __le16 usa_count; /* See ntfs_record struct definition above. */
+
+ __le64 lsn; /*
+ * LogFile sequence number for this record.
+ * Changed every time the record is modified.
+ */
+ __le16 sequence_number; /*
+ * Number of times this mft record has been
+ * reused. (See description for MFT_REF
+ * above.) NOTE: The increment (skipping zero)
+ * is done when the file is deleted. NOTE: If
+ * this is zero it is left zero.
+ */
+ __le16 link_count; /*
+ * Number of hard links, i.e. the number of
+ * directory entries referencing this record.
+ * NOTE: Only used in mft base records.
+ * NOTE: When deleting a directory entry we
+ * check the link_count and if it is 1 we
+ * delete the file. Otherwise we delete the
+ * struct file_name_attr being referenced by the
+ * directory entry from the mft record and
+ * decrement the link_count.
+ */
+ __le16 attrs_offset; /*
+ * Byte offset to the first attribute in this
+ * mft record from the start of the mft record.
+ * NOTE: Must be aligned to 8-byte boundary.
+ */
+ __le16 flags; /*
+ * Bit array of MFT_RECORD_FLAGS. When a file
+ * is deleted, the MFT_RECORD_IN_USE flag is
+ * set to zero.
+ */
+ __le32 bytes_in_use; /*
+ * Number of bytes used in this mft record.
+ * NOTE: Must be aligned to 8-byte boundary.
+ */
+ __le32 bytes_allocated; /*
+ * Number of bytes allocated for this mft
+ * record. This should be equal to the mft
+ * record size.
+ */
+ __le64 base_mft_record; /*
+ * This is zero for base mft records.
+ * When it is not zero it is a mft reference
+ * pointing to the base mft record to which
+ * this record belongs (this is then used to
+ * locate the attribute list attribute present
+ * in the base record which describes this
+ * extension record and hence might need
+ * modification when the extension record
+ * itself is modified, also locating the
+ * attribute list also means finding the other
+ * potential extents, belonging to the non-base
+ * mft record).
+ */
+ __le16 next_attr_instance; /*
+ * The instance number that will be assigned to
+ * the next attribute added to this mft record.
+ * NOTE: Incremented each time after it is used.
+ * NOTE: Every time the mft record is reused
+ * this number is set to zero. NOTE: The first
+ * instance number is always 0.
+ */
/* The below fields are specific to NTFS 3.1+ (Windows XP and above): */
-/* 42*/ le16 reserved; /* Reserved/alignment. */
-/* 44*/ le32 mft_record_number; /* Number of this mft record. */
-/* sizeof() = 48 bytes */
+ __le16 reserved; /* Reserved/alignment. */
+ __le32 mft_record_number; /* Number of this mft record. */
/*
* When (re)using the mft record, we place the update sequence array at this
* offset, i.e. before we start with the attributes. This also makes sense,
@@ -375,63 +399,79 @@ typedef struct {
* by overwriting it since you then can't get it back...
* When reading we obviously use the data from the ntfs record header.
*/
-} __attribute__ ((__packed__)) MFT_RECORD;
+} __packed;
+
+static_assert(sizeof(struct mft_record) == 48);
/* This is the version without the NTFS 3.1+ specific fields. */
-typedef struct {
-/*Ofs*/
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPE magic; /* Usually the magic is "FILE". */
- le16 usa_ofs; /* See NTFS_RECORD definition above. */
- le16 usa_count; /* See NTFS_RECORD definition above. */
-
-/* 8*/ le64 lsn; /* $LogFile sequence number for this record.
- Changed every time the record is modified. */
-/* 16*/ le16 sequence_number; /* Number of times this mft record has been
- reused. (See description for MFT_REF
- above.) NOTE: The increment (skipping zero)
- is done when the file is deleted. NOTE: If
- this is zero it is left zero. */
-/* 18*/ le16 link_count; /* Number of hard links, i.e. the number of
- directory entries referencing this record.
- NOTE: Only used in mft base records.
- NOTE: When deleting a directory entry we
- check the link_count and if it is 1 we
- delete the file. Otherwise we delete the
- FILE_NAME_ATTR being referenced by the
- directory entry from the mft record and
- decrement the link_count.
- FIXME: Careful with Win32 + DOS names! */
-/* 20*/ le16 attrs_offset; /* Byte offset to the first attribute in this
- mft record from the start of the mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 22*/ MFT_RECORD_FLAGS flags; /* Bit array of MFT_RECORD_FLAGS. When a file
- is deleted, the MFT_RECORD_IN_USE flag is
- set to zero. */
-/* 24*/ le32 bytes_in_use; /* Number of bytes used in this mft record.
- NOTE: Must be aligned to 8-byte boundary. */
-/* 28*/ le32 bytes_allocated; /* Number of bytes allocated for this mft
- record. This should be equal to the mft
- record size. */
-/* 32*/ leMFT_REF base_mft_record;/* This is zero for base mft records.
- When it is not zero it is a mft reference
- pointing to the base mft record to which
- this record belongs (this is then used to
- locate the attribute list attribute present
- in the base record which describes this
- extension record and hence might need
- modification when the extension record
- itself is modified, also locating the
- attribute list also means finding the other
- potential extents, belonging to the non-base
- mft record). */
-/* 40*/ le16 next_attr_instance;/* The instance number that will be assigned to
- the next attribute added to this mft record.
- NOTE: Incremented each time after it is used.
- NOTE: Every time the mft record is reused
- this number is set to zero. NOTE: The first
- instance number is always 0. */
-/* sizeof() = 42 bytes */
+struct mft_record_old {
+ __le32 magic; /* Usually the magic is "FILE". */
+ __le16 usa_ofs; /* See ntfs_record struct definition above. */
+ __le16 usa_count; /* See ntfs_record struct definition above. */
+
+ __le64 lsn; /*
+ * LogFile sequence number for this record.
+ * Changed every time the record is modified.
+ */
+ __le16 sequence_number; /*
+ * Number of times this mft record has been
+ * reused. (See description for MFT_REF
+ * above.) NOTE: The increment (skipping zero)
+ * is done when the file is deleted. NOTE: If
+ * this is zero it is left zero.
+ */
+ __le16 link_count; /*
+ * Number of hard links, i.e. the number of
+ * directory entries referencing this record.
+ * NOTE: Only used in mft base records.
+ * NOTE: When deleting a directory entry we
+ * check the link_count and if it is 1 we
+ * delete the file. Otherwise we delete the
+ * struct file_name_attr being referenced by the
+ * directory entry from the mft record and
+ * decrement the link_count.
+ */
+ __le16 attrs_offset; /*
+ * Byte offset to the first attribute in this
+ * mft record from the start of the mft record.
+ * NOTE: Must be aligned to 8-byte boundary.
+ */
+ __le16 flags; /*
+ * Bit array of MFT_RECORD_FLAGS. When a file
+ * is deleted, the MFT_RECORD_IN_USE flag is
+ * set to zero.
+ */
+ __le32 bytes_in_use; /*
+ * Number of bytes used in this mft record.
+ * NOTE: Must be aligned to 8-byte boundary.
+ */
+ __le32 bytes_allocated; /*
+ * Number of bytes allocated for this mft
+ * record. This should be equal to the mft
+ * record size.
+ */
+ __le64 base_mft_record; /*
+ * This is zero for base mft records.
+ * When it is not zero it is a mft reference
+ * pointing to the base mft record to which
+ * this record belongs (this is then used to
+ * locate the attribute list attribute present
+ * in the base record which describes this
+ * extension record and hence might need
+ * modification when the extension record
+ * itself is modified, also locating the
+ * attribute list also means finding the other
+ * potential extents, belonging to the non-base
+ * mft record).
+ */
+ __le16 next_attr_instance; /*
+ * The instance number that will be assigned to
+ * the next attribute added to this mft record.
+ * NOTE: Incremented each time after it is used.
+ * NOTE: Every time the mft record is reused
+ * this number is set to zero. NOTE: The first
+ * instance number is always 0.
+ */
/*
* When (re)using the mft record, we place the update sequence array at this
* offset, i.e. before we start with the attributes. This also makes sense,
@@ -441,7 +481,9 @@ typedef struct {
* by overwriting it since you then can't get it back...
* When reading we obviously use the data from the ntfs record header.
*/
-} __attribute__ ((__packed__)) MFT_RECORD_OLD;
+} __packed;
+
+static_assert(sizeof(struct mft_record_old) == 42);
/*
* System defined attributes (32-bit). Each attribute type has a corresponding
@@ -452,29 +494,27 @@ typedef struct {
* a revealing choice of symbol I do not know what is... (-;
*/
enum {
- AT_UNUSED = cpu_to_le32( 0),
- AT_STANDARD_INFORMATION = cpu_to_le32( 0x10),
- AT_ATTRIBUTE_LIST = cpu_to_le32( 0x20),
- AT_FILE_NAME = cpu_to_le32( 0x30),
- AT_OBJECT_ID = cpu_to_le32( 0x40),
- AT_SECURITY_DESCRIPTOR = cpu_to_le32( 0x50),
- AT_VOLUME_NAME = cpu_to_le32( 0x60),
- AT_VOLUME_INFORMATION = cpu_to_le32( 0x70),
- AT_DATA = cpu_to_le32( 0x80),
- AT_INDEX_ROOT = cpu_to_le32( 0x90),
- AT_INDEX_ALLOCATION = cpu_to_le32( 0xa0),
- AT_BITMAP = cpu_to_le32( 0xb0),
- AT_REPARSE_POINT = cpu_to_le32( 0xc0),
- AT_EA_INFORMATION = cpu_to_le32( 0xd0),
- AT_EA = cpu_to_le32( 0xe0),
- AT_PROPERTY_SET = cpu_to_le32( 0xf0),
- AT_LOGGED_UTILITY_STREAM = cpu_to_le32( 0x100),
- AT_FIRST_USER_DEFINED_ATTRIBUTE = cpu_to_le32( 0x1000),
+ AT_UNUSED = cpu_to_le32(0),
+ AT_STANDARD_INFORMATION = cpu_to_le32(0x10),
+ AT_ATTRIBUTE_LIST = cpu_to_le32(0x20),
+ AT_FILE_NAME = cpu_to_le32(0x30),
+ AT_OBJECT_ID = cpu_to_le32(0x40),
+ AT_SECURITY_DESCRIPTOR = cpu_to_le32(0x50),
+ AT_VOLUME_NAME = cpu_to_le32(0x60),
+ AT_VOLUME_INFORMATION = cpu_to_le32(0x70),
+ AT_DATA = cpu_to_le32(0x80),
+ AT_INDEX_ROOT = cpu_to_le32(0x90),
+ AT_INDEX_ALLOCATION = cpu_to_le32(0xa0),
+ AT_BITMAP = cpu_to_le32(0xb0),
+ AT_REPARSE_POINT = cpu_to_le32(0xc0),
+ AT_EA_INFORMATION = cpu_to_le32(0xd0),
+ AT_EA = cpu_to_le32(0xe0),
+ AT_PROPERTY_SET = cpu_to_le32(0xf0),
+ AT_LOGGED_UTILITY_STREAM = cpu_to_le32(0x100),
+ AT_FIRST_USER_DEFINED_ATTRIBUTE = cpu_to_le32(0x1000),
AT_END = cpu_to_le32(0xffffffff)
};
-typedef le32 ATTR_TYPE;
-
/*
* The collation rules for sorting views/indexes/etc (32-bit).
*
@@ -490,7 +530,7 @@ typedef le32 ATTR_TYPE;
* unistr.c::ntfs_collate_names() and unistr.c::legal_ansi_char_array[]
* for what I mean but COLLATION_UNICODE_STRING would not give any special
* treatment to any characters at all, but this is speculation.
- * COLLATION_NTOFS_ULONG - Sorting is done according to ascending le32 key
+ * COLLATION_NTOFS_ULONG - Sorting is done according to ascending __le32 key
* values. E.g. used for $SII index in FILE_Secure, which sorts by
* security_id (le32).
* COLLATION_NTOFS_SID - Sorting is done according to ascending SID values.
@@ -499,19 +539,19 @@ typedef le32 ATTR_TYPE;
* values and second by ascending security_id values. E.g. used for $SDH
* index in FILE_Secure.
* COLLATION_NTOFS_ULONGS - Sorting is done according to a sequence of ascending
- * le32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which
+ * __le32 key values. E.g. used for $O index in FILE_Extend/$ObjId, which
* sorts by object_id (16-byte), by splitting up the object_id in four
- * le32 values and using them as individual keys. E.g. take the following
+ * __le32 values and using them as individual keys. E.g. take the following
* two security_ids, stored as follows on disk:
* 1st: a1 61 65 b7 65 7b d4 11 9e 3d 00 e0 81 10 42 59
* 2nd: 38 14 37 d2 d2 f3 d4 11 a5 21 c8 6b 79 b1 97 45
- * To compare them, they are split into four le32 values each, like so:
+ * To compare them, they are split into four __le32 values each, like so:
* 1st: 0xb76561a1 0x11d47b65 0xe0003d9e 0x59421081
* 2nd: 0xd2371438 0x11d4f3d2 0x6bc821a5 0x4597b179
* Now, it is apparent why the 2nd object_id collates after the 1st: the
- * first le32 value of the 1st object_id is less than the first le32 of
- * the 2nd object_id. If the first le32 values of both object_ids were
- * equal then the second le32 values would be compared, etc.
+ * first __le32 value of the 1st object_id is less than the first __le32 of
+ * the 2nd object_id. If the first __le32 values of both object_ids were
+ * equal then the second __le32 values would be compared, etc.
*/
enum {
COLLATION_BINARY = cpu_to_le32(0x00),
@@ -523,45 +563,45 @@ enum {
COLLATION_NTOFS_ULONGS = cpu_to_le32(0x13),
};
-typedef le32 COLLATION_RULE;
-
/*
* The flags (32-bit) describing attribute properties in the attribute
- * definition structure. FIXME: This information is based on Regis's
- * information and, according to him, it is not certain and probably
- * incomplete. The INDEXABLE flag is fairly certainly correct as only the file
+ * definition structure.
+ * The INDEXABLE flag is fairly certainly correct as only the file
* name attribute has this flag set and this is the only attribute indexed in
* NT4.
*/
enum {
- ATTR_DEF_INDEXABLE = cpu_to_le32(0x02), /* Attribute can be
- indexed. */
- ATTR_DEF_MULTIPLE = cpu_to_le32(0x04), /* Attribute type
- can be present multiple times in the
- mft records of an inode. */
- ATTR_DEF_NOT_ZERO = cpu_to_le32(0x08), /* Attribute value
- must contain at least one non-zero
- byte. */
- ATTR_DEF_INDEXED_UNIQUE = cpu_to_le32(0x10), /* Attribute must be
- indexed and the attribute value must be
- unique for the attribute type in all of
- the mft records of an inode. */
- ATTR_DEF_NAMED_UNIQUE = cpu_to_le32(0x20), /* Attribute must be
- named and the name must be unique for
- the attribute type in all of the mft
- records of an inode. */
- ATTR_DEF_RESIDENT = cpu_to_le32(0x40), /* Attribute must be
- resident. */
- ATTR_DEF_ALWAYS_LOG = cpu_to_le32(0x80), /* Always log
- modifications to this attribute,
- regardless of whether it is resident or
- non-resident. Without this, only log
- modifications if the attribute is
- resident. */
+ ATTR_DEF_INDEXABLE = cpu_to_le32(0x02), /* Attribute can be indexed. */
+ ATTR_DEF_MULTIPLE = cpu_to_le32(0x04), /*
+ * Attribute type can be present
+ * multiple times in the mft records
+ * of an inode.
+ */
+ ATTR_DEF_NOT_ZERO = cpu_to_le32(0x08), /*
+ * Attribute value must contain
+ * at least one non-zero byte.
+ */
+ ATTR_DEF_INDEXED_UNIQUE = cpu_to_le32(0x10), /*
+ * Attribute must be indexed and
+ * the attribute value must be unique
+ * for the attribute type in all of
+ * the mft records of an inode.
+ */
+ ATTR_DEF_NAMED_UNIQUE = cpu_to_le32(0x20), /*
+ * Attribute must be named and
+ * the name must be unique for
+ * the attribute type in all of the mft
+ * records of an inode.
+ */
+ ATTR_DEF_RESIDENT = cpu_to_le32(0x40), /* Attribute must be resident. */
+ ATTR_DEF_ALWAYS_LOG = cpu_to_le32(0x80), /*
+ * Always log modifications to this attribute,
+ * regardless of whether it is resident or
+ * non-resident. Without this, only log
+ * modifications if the attribute is resident.
+ */
};
-typedef le32 ATTR_DEF_FLAGS;
-
/*
* The data attribute of FILE_AttrDef contains a sequence of attribute
* definitions for the NTFS volume. With this, it is supposed to be safe for an
@@ -571,33 +611,30 @@ typedef le32 ATTR_DEF_FLAGS;
* attribute can be resident/non-resident and possibly other things, but the
* actual bits are unknown.
*/
-typedef struct {
-/*hex ofs*/
-/* 0*/ ntfschar name[0x40]; /* Unicode name of the attribute. Zero
- terminated. */
-/* 80*/ ATTR_TYPE type; /* Type of the attribute. */
-/* 84*/ le32 display_rule; /* Default display rule.
- FIXME: What does it mean? (AIA) */
-/* 88*/ COLLATION_RULE collation_rule; /* Default collation rule. */
-/* 8c*/ ATTR_DEF_FLAGS flags; /* Flags describing the attribute. */
-/* 90*/ sle64 min_size; /* Optional minimum attribute size. */
-/* 98*/ sle64 max_size; /* Maximum size of attribute. */
-/* sizeof() = 0xa0 or 160 bytes */
-} __attribute__ ((__packed__)) ATTR_DEF;
+struct attr_def {
+ __le16 name[0x40]; /* Unicode name of the attribute. Zero terminated. */
+ __le32 type; /* Type of the attribute. */
+ __le32 display_rule; /* Default display rule. */
+ __le32 collation_rule; /* Default collation rule. */
+ __le32 flags; /* Flags describing the attribute. */
+ __le64 min_size; /* Optional minimum attribute size. */
+ __le64 max_size; /* Maximum size of attribute. */
+} __packed;
+
+static_assert(sizeof(struct attr_def) == 160);
/*
* Attribute flags (16-bit).
*/
enum {
ATTR_IS_COMPRESSED = cpu_to_le16(0x0001),
- ATTR_COMPRESSION_MASK = cpu_to_le16(0x00ff), /* Compression method
- mask. Also, first
- illegal value. */
+ ATTR_COMPRESSION_MASK = cpu_to_le16(0x00ff), /*
+ * Compression method mask.
+ * Also, first illegal value.
+ */
ATTR_IS_ENCRYPTED = cpu_to_le16(0x4000),
ATTR_IS_SPARSE = cpu_to_le16(0x8000),
-} __attribute__ ((__packed__));
-
-typedef le16 ATTR_FLAGS;
+} __packed;
/*
* Attribute compression.
@@ -670,110 +707,133 @@ typedef le16 ATTR_FLAGS;
* Flags of resident attributes (8-bit).
*/
enum {
- RESIDENT_ATTR_IS_INDEXED = 0x01, /* Attribute is referenced in an index
- (has implications for deleting and
- modifying the attribute). */
-} __attribute__ ((__packed__));
-
-typedef u8 RESIDENT_ATTR_FLAGS;
+ RESIDENT_ATTR_IS_INDEXED = 0x01, /*
+ * Attribute is referenced in an index
+ * (has implications for deleting and
+ * modifying the attribute).
+ */
+} __packed;
/*
* Attribute record header. Always aligned to 8-byte boundary.
*/
-typedef struct {
-/*Ofs*/
-/* 0*/ ATTR_TYPE type; /* The (32-bit) type of the attribute. */
-/* 4*/ le32 length; /* Byte size of the resident part of the
- attribute (aligned to 8-byte boundary).
- Used to get to the next attribute. */
-/* 8*/ u8 non_resident; /* If 0, attribute is resident.
- If 1, attribute is non-resident. */
-/* 9*/ u8 name_length; /* Unicode character size of name of attribute.
- 0 if unnamed. */
-/* 10*/ le16 name_offset; /* If name_length != 0, the byte offset to the
- beginning of the name from the attribute
- record. Note that the name is stored as a
- Unicode string. When creating, place offset
- just at the end of the record header. Then,
- follow with attribute value or mapping pairs
- array, resident and non-resident attributes
- respectively, aligning to an 8-byte
- boundary. */
-/* 12*/ ATTR_FLAGS flags; /* Flags describing the attribute. */
-/* 14*/ le16 instance; /* The instance of this attribute record. This
- number is unique within this mft record (see
- MFT_RECORD/next_attribute_instance notes in
- mft.h for more details). */
-/* 16*/ union {
+struct attr_record {
+ __le32 type; /* The (32-bit) type of the attribute. */
+ __le32 length; /*
+ * Byte size of the resident part of the
+ * attribute (aligned to 8-byte boundary).
+ * Used to get to the next attribute.
+ */
+ u8 non_resident; /*
+ * If 0, attribute is resident.
+ * If 1, attribute is non-resident.
+ */
+ u8 name_length; /* Unicode character size of name of attribute. 0 if unnamed. */
+ __le16 name_offset; /*
+ * If name_length != 0, the byte offset to the
+ * beginning of the name from the attribute
+ * record. Note that the name is stored as a
+ * Unicode string. When creating, place offset
+ * just at the end of the record header. Then,
+ * follow with attribute value or mapping pairs
+ * array, resident and non-resident attributes
+ * respectively, aligning to an 8-byte
+ * boundary.
+ */
+ __le16 flags; /* Flags describing the attribute. */
+ __le16 instance; /*
+ * The instance of this attribute record. This
+ * number is unique within this mft record (see
+ * MFT_RECORD/next_attribute_instance notes in
+ * mft.h for more details).
+ */
+ union {
/* Resident attributes. */
struct {
-/* 16 */ le32 value_length;/* Byte size of attribute value. */
-/* 20 */ le16 value_offset;/* Byte offset of the attribute
- value from the start of the
- attribute record. When creating,
- align to 8-byte boundary if we
- have a name present as this might
- not have a length of a multiple
- of 8-bytes. */
-/* 22 */ RESIDENT_ATTR_FLAGS flags; /* See above. */
-/* 23 */ s8 reserved; /* Reserved/alignment to 8-byte
- boundary. */
- } __attribute__ ((__packed__)) resident;
+ __le32 value_length; /* Byte size of attribute value. */
+ __le16 value_offset; /*
+ * Byte offset of the attribute
+ * value from the start of the
+ * attribute record. When creating,
+ * align to 8-byte boundary if we
+ * have a name present as this might
+ * not have a length of a multiple
+ * of 8-bytes.
+ */
+ u8 flags; /* See above. */
+ s8 reserved; /* Reserved/alignment to 8-byte boundary. */
+ } __packed resident;
/* Non-resident attributes. */
struct {
-/* 16*/ leVCN lowest_vcn;/* Lowest valid virtual cluster number
- for this portion of the attribute value or
- 0 if this is the only extent (usually the
- case). - Only when an attribute list is used
- does lowest_vcn != 0 ever occur. */
-/* 24*/ leVCN highest_vcn;/* Highest valid vcn of this extent of
- the attribute value. - Usually there is only one
- portion, so this usually equals the attribute
- value size in clusters minus 1. Can be -1 for
- zero length files. Can be 0 for "single extent"
- attributes. */
-/* 32*/ le16 mapping_pairs_offset; /* Byte offset from the
- beginning of the structure to the mapping pairs
- array which contains the mappings between the
- vcns and the logical cluster numbers (lcns).
- When creating, place this at the end of this
- record header aligned to 8-byte boundary. */
-/* 34*/ u8 compression_unit; /* The compression unit expressed
- as the log to the base 2 of the number of
- clusters in a compression unit. 0 means not
- compressed. (This effectively limits the
- compression unit size to be a power of two
- clusters.) WinNT4 only uses a value of 4.
- Sparse files have this set to 0 on XPSP2. */
-/* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */
-/* The sizes below are only used when lowest_vcn is zero, as otherwise it would
- be difficult to keep them up-to-date.*/
-/* 40*/ sle64 allocated_size; /* Byte size of disk space
- allocated to hold the attribute value. Always
- is a multiple of the cluster size. When a file
- is compressed, this field is a multiple of the
- compression block size (2^compression_unit) and
- it represents the logically allocated space
- rather than the actual on disk usage. For this
- use the compressed_size (see below). */
-/* 48*/ sle64 data_size; /* Byte size of the attribute
- value. Can be larger than allocated_size if
- attribute value is compressed or sparse. */
-/* 56*/ sle64 initialized_size; /* Byte size of initialized
- portion of the attribute value. Usually equals
- data_size. */
-/* sizeof(uncompressed attr) = 64*/
-/* 64*/ sle64 compressed_size; /* Byte size of the attribute
- value after compression. Only present when
- compressed or sparse. Always is a multiple of
- the cluster size. Represents the actual amount
- of disk space being used on the disk. */
-/* sizeof(compressed attr) = 72*/
- } __attribute__ ((__packed__)) non_resident;
- } __attribute__ ((__packed__)) data;
-} __attribute__ ((__packed__)) ATTR_RECORD;
-
-typedef ATTR_RECORD ATTR_REC;
+ __le64 lowest_vcn; /*
+ * Lowest valid virtual cluster number
+ * for this portion of the attribute value or
+ * 0 if this is the only extent (usually the
+ * case). - Only when an attribute list is used
+ * does lowest_vcn != 0 ever occur.
+ */
+ __le64 highest_vcn; /*
+ * Highest valid vcn of this extent of
+ * the attribute value. - Usually there is only one
+ * portion, so this usually equals the attribute
+ * value size in clusters minus 1. Can be -1 for
+ * zero length files. Can be 0 for "single extent"
+ * attributes.
+ */
+ __le16 mapping_pairs_offset; /*
+ * Byte offset from the beginning of
+ * the structure to the mapping pairs
+ * array which contains the mappings
+ * between the vcns and the logical cluster
+ * numbers (lcns).
+ * When creating, place this at the end of
+ * this record header aligned to 8-byte
+ * boundary.
+ */
+ u8 compression_unit; /*
+ * The compression unit expressed as the log
+ * to the base 2 of the number of
+ * clusters in a compression unit. 0 means not
+ * compressed. (This effectively limits the
+ * compression unit size to be a power of two
+ * clusters.) WinNT4 only uses a value of 4.
+ * Sparse files have this set to 0 on XPSP2.
+ */
+ u8 reserved[5]; /* Align to 8-byte boundary. */
+/*
+ * The sizes below are only used when lowest_vcn is zero, as otherwise it would
+ * be difficult to keep them up-to-date.
+ */
+ __le64 allocated_size; /*
+ * Byte size of disk space allocated
+ * to hold the attribute value. Always
+ * is a multiple of the cluster size.
+ * When a file is compressed, this field
+ * is a multiple of the compression block
+ * size (2^compression_unit) and it represents
+ * the logically allocated space rather than
+ * the actual on disk usage. For this use
+ * the compressed_size (see below).
+ */
+ __le64 data_size; /*
+ * Byte size of the attribute value. Can be
+ * larger than allocated_size if attribute value
+ * is compressed or sparse.
+ */
+ __le64 initialized_size; /*
+ * Byte size of initialized portion of
+ * the attribute value. Usually equals data_size.
+ */
+ __le64 compressed_size; /*
+ * Byte size of the attribute value after
+ * compression. Only present when compressed
+ * or sparse. Always is a multiple of the cluster
+ * size. Represents the actual amount of disk
+ * space being used on the disk.
+ */
+ } __packed non_resident;
+ } __packed data;
+} __packed;
/*
* File attribute flags (32-bit) appearing in the file_attributes fields of the
@@ -792,8 +852,10 @@ enum {
/* Old DOS volid. Unused in NT. = cpu_to_le32(0x00000008), */
FILE_ATTR_DIRECTORY = cpu_to_le32(0x00000010),
- /* Note, FILE_ATTR_DIRECTORY is not considered valid in NT. It is
- reserved for the DOS SUBDIRECTORY flag. */
+ /*
+ * Note, FILE_ATTR_DIRECTORY is not considered valid in NT. It is
+ * reserved for the DOS SUBDIRECTORY flag.
+ */
FILE_ATTR_ARCHIVE = cpu_to_le32(0x00000020),
FILE_ATTR_DEVICE = cpu_to_le32(0x00000040),
FILE_ATTR_NORMAL = cpu_to_le32(0x00000080),
@@ -808,32 +870,40 @@ enum {
FILE_ATTR_ENCRYPTED = cpu_to_le32(0x00004000),
FILE_ATTR_VALID_FLAGS = cpu_to_le32(0x00007fb7),
- /* Note, FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the
- FILE_ATTR_DEVICE and preserves everything else. This mask is used
- to obtain all flags that are valid for reading. */
+ /*
+ * Note, FILE_ATTR_VALID_FLAGS masks out the old DOS VolId and the
+ * FILE_ATTR_DEVICE and preserves everything else. This mask is used
+ * to obtain all flags that are valid for reading.
+ */
FILE_ATTR_VALID_SET_FLAGS = cpu_to_le32(0x000031a7),
- /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
- F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
- F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
- is used to obtain all flags that are valid for setting. */
+ /*
+ * Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the
+ * F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT,
+ * F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
+ * is used to obtain all flags that are valid for setting.
+ */
+ /* Supposed to mean no data locally, possibly repurposed */
+ FILE_ATTRIBUTE_RECALL_ON_OPEN = cpu_to_le32(0x00040000),
/*
* The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all
* FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
* attribute of an mft record.
*/
FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = cpu_to_le32(0x10000000),
- /* Note, this is a copy of the corresponding bit from the mft record,
- telling us whether this is a directory or not, i.e. whether it has
- an index root attribute or not. */
+ /*
+ * Note, this is a copy of the corresponding bit from the mft record,
+ * telling us whether this is a directory or not, i.e. whether it has
+ * an index root attribute or not.
+ */
FILE_ATTR_DUP_VIEW_INDEX_PRESENT = cpu_to_le32(0x20000000),
- /* Note, this is a copy of the corresponding bit from the mft record,
- telling us whether this file has a view index present (eg. object id
- index, quota index, one of the security indexes or the encrypting
- filesystem related indexes). */
+ /*
+ * Note, this is a copy of the corresponding bit from the mft record,
+ * telling us whether this file has a view index present (eg. object id
+ * index, quota index, one of the security indexes or the encrypting
+ * filesystem related indexes).
+ */
};
-typedef le32 FILE_ATTR_FLAGS;
-
/*
* NOTE on times in NTFS: All times are in MS standard time format, i.e. they
* are the number of 100-nanosecond intervals since 1st January 1601, 00:00:00
@@ -851,30 +921,29 @@ typedef le32 FILE_ATTR_FLAGS;
* correct by practical experimentation on Windows NT4 SP6a and is hence
* assumed to be the one and only correct interpretation.
*/
-typedef struct {
-/*Ofs*/
-/* 0*/ sle64 creation_time; /* Time file was created. Updated when
- a filename is changed(?). */
-/* 8*/ sle64 last_data_change_time; /* Time the data attribute was last
- modified. */
-/* 16*/ sle64 last_mft_change_time; /* Time this mft record was last
- modified. */
-/* 24*/ sle64 last_access_time; /* Approximate time when the file was
- last accessed (obviously this is not
- updated on read-only volumes). In
- Windows this is only updated when
- accessed if some time delta has
- passed since the last update. Also,
- last access time updates can be
- disabled altogether for speed. */
-/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
-/* 36*/ union {
+struct standard_information {
+ __le64 creation_time; /*
+ * Time file was created. Updated when
+ * a filename is changed(?).
+ */
+ __le64 last_data_change_time; /* Time the data attribute was last modified. */
+ __le64 last_mft_change_time; /* Time this mft record was last modified. */
+ __le64 last_access_time; /*
+ * Approximate time when the file was
+ * last accessed (obviously this is not
+ * updated on read-only volumes). In
+ * Windows this is only updated when
+ * accessed if some time delta has
+ * passed since the last update. Also,
+ * last access time updates can be
+ * disabled altogether for speed.
+ */
+ __le32 file_attributes; /* Flags describing the file. */
+ union {
/* NTFS 1.2 */
struct {
- /* 36*/ u8 reserved12[12]; /* Reserved/alignment to 8-byte
- boundary. */
- } __attribute__ ((__packed__)) v1;
- /* sizeof() = 48 bytes */
+ u8 reserved12[12]; /* Reserved/alignment to 8-byte boundary. */
+ } __packed v1;
/* NTFS 3.x */
struct {
/*
@@ -883,7 +952,7 @@ typedef struct {
* Recognize the difference by comparing the length of the resident attribute
* value. If it is 48, then the following fields are missing. If it is 72 then
* the fields are present. Maybe just check like this:
- * if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) {
+ * if (resident.ValueLength < sizeof(struct standard_information)) {
* Assume NTFS 1.2- format.
* If (volume version is 3.x)
* Upgrade attribute to NTFS 3.x format.
@@ -896,32 +965,48 @@ typedef struct {
* views that as a corruption, assuming that it behaves like this for all
* attributes.
*/
- /* 36*/ le32 maximum_versions; /* Maximum allowed versions for
- file. Zero if version numbering is disabled. */
- /* 40*/ le32 version_number; /* This file's version (if any).
- Set to zero if maximum_versions is zero. */
- /* 44*/ le32 class_id; /* Class id from bidirectional
- class id index (?). */
- /* 48*/ le32 owner_id; /* Owner_id of the user owning
- the file. Translate via $Q index in FILE_Extend
- /$Quota to the quota control entry for the user
- owning the file. Zero if quotas are disabled. */
- /* 52*/ le32 security_id; /* Security_id for the file.
- Translate via $SII index and $SDS data stream
- in FILE_Secure to the security descriptor. */
- /* 56*/ le64 quota_charged; /* Byte size of the charge to
- the quota for all streams of the file. Note: Is
- zero if quotas are disabled. */
- /* 64*/ leUSN usn; /* Last update sequence number
- of the file. This is a direct index into the
- transaction log file ($UsnJrnl). It is zero if
- the usn journal is disabled or this file has
- not been subject to logging yet. See usnjrnl.h
- for details. */
- } __attribute__ ((__packed__)) v3;
- /* sizeof() = 72 bytes (NTFS 3.x) */
- } __attribute__ ((__packed__)) ver;
-} __attribute__ ((__packed__)) STANDARD_INFORMATION;
+ __le32 maximum_versions; /*
+ * Maximum allowed versions for
+ * file. Zero if version numbering
+ * is disabled.
+ */
+ __le32 version_number; /*
+ * This file's version (if any).
+ * Set to zero if maximum_versions
+ * is zero.
+ */
+ __le32 class_id; /*
+ * Class id from bidirectional
+ * class id index (?).
+ */
+ __le32 owner_id; /*
+ * Owner_id of the user owning
+ * the file. Translate via $Q index
+ * in FILE_Extend /$Quota to the quota
+ * control entry for the user owning
+ * the file. Zero if quotas are disabled.
+ */
+ __le32 security_id; /*
+ * Security_id for the file. Translate via
+ * $SII index and $SDS data stream in
+ * FILE_Secure to the security descriptor.
+ */
+ __le64 quota_charged; /*
+ * Byte size of the charge to the quota for
+ * all streams of the file. Note: Is zero
+ * if quotas are disabled.
+ */
+ __le64 usn; /*
+ * Last update sequence number of the file.
+ * This is a direct index into the transaction
+ * log file ($UsnJrnl). It is zero if the usn
+ * journal is disabled or this file has not been
+ * subject to logging yet. See usnjrnl.h
+ * for details.
+ */
+ } __packed v3;
+ } __packed ver;
+} __packed;
/*
* Attribute: Attribute list (0x20).
@@ -937,7 +1022,7 @@ typedef struct {
* itself. The list is sorted: first by attribute type, second by attribute
* name (if present), third by instance number. The extents of one
* non-resident attribute (if present) immediately follow after the initial
- * extent. They are ordered by lowest_vcn and have their instace set to zero.
+ * extent. They are ordered by lowest_vcn and have their instance set to zero.
* It is not allowed to have two attributes with all sorting keys equal.
* - Further restrictions:
* - If not resident, the vcn to lcn mapping array has to fit inside the
@@ -955,37 +1040,46 @@ typedef struct {
* NTFS 3.0 volumes).
* - There are many named streams.
*/
-typedef struct {
-/*Ofs*/
-/* 0*/ ATTR_TYPE type; /* Type of referenced attribute. */
-/* 4*/ le16 length; /* Byte size of this entry (8-byte aligned). */
-/* 6*/ u8 name_length; /* Size in Unicode chars of the name of the
- attribute or 0 if unnamed. */
-/* 7*/ u8 name_offset; /* Byte offset to beginning of attribute name
- (always set this to where the name would
- start even if unnamed). */
-/* 8*/ leVCN lowest_vcn; /* Lowest virtual cluster number of this portion
- of the attribute value. This is usually 0. It
- is non-zero for the case where one attribute
- does not fit into one mft record and thus
- several mft records are allocated to hold
- this attribute. In the latter case, each mft
- record holds one extent of the attribute and
- there is one attribute list entry for each
- extent. NOTE: This is DEFINITELY a signed
- value! The windows driver uses cmp, followed
- by jg when comparing this, thus it treats it
- as signed. */
-/* 16*/ leMFT_REF mft_reference;/* The reference of the mft record holding
- the ATTR_RECORD for this portion of the
- attribute value. */
-/* 24*/ le16 instance; /* If lowest_vcn = 0, the instance of the
- attribute being referenced; otherwise 0. */
-/* 26*/ ntfschar name[0]; /* Use when creating only. When reading use
- name_offset to determine the location of the
- name. */
-/* sizeof() = 26 + (attribute_name_length * 2) bytes */
-} __attribute__ ((__packed__)) ATTR_LIST_ENTRY;
+struct attr_list_entry {
+ __le32 type; /* Type of referenced attribute. */
+ __le16 length; /* Byte size of this entry (8-byte aligned). */
+ u8 name_length; /*
+ * Size in Unicode chars of the name of the
+ * attribute or 0 if unnamed.
+ */
+ u8 name_offset; /*
+ * Byte offset to beginning of attribute name
+ * (always set this to where the name would
+ * start even if unnamed).
+ */
+ __le64 lowest_vcn; /*
+ * Lowest virtual cluster number of this portion
+ * of the attribute value. This is usually 0. It
+ * is non-zero for the case where one attribute
+ * does not fit into one mft record and thus
+ * several mft records are allocated to hold
+ * this attribute. In the latter case, each mft
+ * record holds one extent of the attribute and
+ * there is one attribute list entry for each
+ * extent. NOTE: This is DEFINITELY a signed
+ * value! The windows driver uses cmp, followed
+ * by jg when comparing this, thus it treats it
+ * as signed.
+ */
+ __le64 mft_reference; /*
+ * The reference of the mft record holding
+ * the attr record for this portion of the
+ * attribute value.
+ */
+ __le16 instance; /*
+ * If lowest_vcn = 0, the instance of the
+ * attribute being referenced; otherwise 0.
+ */
+ __le16 name[]; /*
+ * Use when creating only. When reading use
+ * name_offset to determine the location of the name.
+ */
+} __packed;
/*
* The maximum allowed length for a file name.
@@ -997,33 +1091,39 @@ typedef struct {
*/
enum {
FILE_NAME_POSIX = 0x00,
- /* This is the largest namespace. It is case sensitive and allows all
- Unicode characters except for: '\0' and '/'. Beware that in
- WinNT/2k/2003 by default files which eg have the same name except
- for their case will not be distinguished by the standard utilities
- and thus a "del filename" will delete both "filename" and "fileName"
- without warning. However if for example Services For Unix (SFU) are
- installed and the case sensitive option was enabled at installation
- time, then you can create/access/delete such files.
- Note that even SFU places restrictions on the filenames beyond the
- '\0' and '/' and in particular the following set of characters is
- not allowed: '"', '/', '<', '>', '\'. All other characters,
- including the ones no allowed in WIN32 namespace are allowed.
- Tested with SFU 3.5 (this is now free) running on Windows XP. */
+ /*
+ * This is the largest namespace. It is case sensitive and allows all
+ * Unicode characters except for: '\0' and '/'. Beware that in
+ * WinNT/2k/2003 by default files which eg have the same name except
+ * for their case will not be distinguished by the standard utilities
+ * and thus a "del filename" will delete both "filename" and "fileName"
+ * without warning. However if for example Services For Unix (SFU) are
+ * installed and the case sensitive option was enabled at installation
+ * time, then you can create/access/delete such files.
+ * Note that even SFU places restrictions on the filenames beyond the
+ * '\0' and '/' and in particular the following set of characters is
+ * not allowed: '"', '/', '<', '>', '\'. All other characters,
+ * including the ones no allowed in WIN32 namespace are allowed.
+ * Tested with SFU 3.5 (this is now free) running on Windows XP.
+ */
FILE_NAME_WIN32 = 0x01,
- /* The standard WinNT/2k NTFS long filenames. Case insensitive. All
- Unicode chars except: '\0', '"', '*', '/', ':', '<', '>', '?', '\',
- and '|'. Further, names cannot end with a '.' or a space. */
+ /*
+ * The standard WinNT/2k NTFS long filenames. Case insensitive. All
+ * Unicode chars except: '\0', '"', '*', '/', ':', '<', '>', '?', '\',
+ * and '|'. Further, names cannot end with a '.' or a space.
+ */
FILE_NAME_DOS = 0x02,
- /* The standard DOS filenames (8.3 format). Uppercase only. All 8-bit
- characters greater space, except: '"', '*', '+', ',', '/', ':', ';',
- '<', '=', '>', '?', and '\'. */
+ /*
+ * The standard DOS filenames (8.3 format). Uppercase only. All 8-bit
+ * characters greater space, except: '"', '*', '+', ',', '/', ':', ';',
+ * '<', '=', '>', '?', and '\'.\
+ */
FILE_NAME_WIN32_AND_DOS = 0x03,
- /* 3 means that both the Win32 and the DOS filenames are identical and
- hence have been saved in this single filename record. */
-} __attribute__ ((__packed__));
-
-typedef u8 FILE_NAME_TYPE_FLAGS;
+ /*
+ * 3 means that both the Win32 and the DOS filenames are identical and
+ * hence have been saved in this single filename record.
+ */
+} __packed;
/*
* Attribute: Filename (0x30).
@@ -1038,53 +1138,54 @@ typedef u8 FILE_NAME_TYPE_FLAGS;
* correct by practical experimentation on Windows NT4 SP6a and is hence
* assumed to be the one and only correct interpretation.
*/
-typedef struct {
+struct file_name_attr {
/*hex ofs*/
-/* 0*/ leMFT_REF parent_directory; /* Directory this filename is
- referenced from. */
-/* 8*/ sle64 creation_time; /* Time file was created. */
-/* 10*/ sle64 last_data_change_time; /* Time the data attribute was last
- modified. */
-/* 18*/ sle64 last_mft_change_time; /* Time this mft record was last
- modified. */
-/* 20*/ sle64 last_access_time; /* Time this mft record was last
- accessed. */
-/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space
- for the unnamed data attribute. So
- for normal $DATA, this is the
- allocated_size from the unnamed
- $DATA attribute and for compressed
- and/or sparse $DATA, this is the
- compressed_size from the unnamed
- $DATA attribute. For a directory or
- other inode without an unnamed $DATA
- attribute, this is always 0. NOTE:
- This is a multiple of the cluster
- size. */
-/* 30*/ sle64 data_size; /* Byte size of actual data in unnamed
- data attribute. For a directory or
- other inode without an unnamed $DATA
- attribute, this is always 0. */
-/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
-/* 3c*/ union {
- /* 3c*/ struct {
- /* 3c*/ le16 packed_ea_size; /* Size of the buffer needed to
- pack the extended attributes
- (EAs), if such are present.*/
- /* 3e*/ le16 reserved; /* Reserved for alignment. */
- } __attribute__ ((__packed__)) ea;
- /* 3c*/ struct {
- /* 3c*/ le32 reparse_point_tag; /* Type of reparse point,
- present only in reparse
- points and only if there are
- no EAs. */
- } __attribute__ ((__packed__)) rp;
- } __attribute__ ((__packed__)) type;
-/* 40*/ u8 file_name_length; /* Length of file name in
- (Unicode) characters. */
-/* 41*/ FILE_NAME_TYPE_FLAGS file_name_type; /* Namespace of the file name.*/
-/* 42*/ ntfschar file_name[0]; /* File name in Unicode. */
-} __attribute__ ((__packed__)) FILE_NAME_ATTR;
+ __le64 parent_directory; /* Directory this filename is referenced from. */
+ __le64 creation_time; /* Time file was created. */
+ __le64 last_data_change_time; /* Time the data attribute was last modified. */
+ __le64 last_mft_change_time; /* Time this mft record was last modified. */
+ __le64 last_access_time; /* Time this mft record was last accessed. */
+ __le64 allocated_size; /*
+ * Byte size of on-disk allocated space
+ * for the unnamed data attribute. So for normal
+ * $DATA, this is the allocated_size from
+ * the unnamed $DATA attribute and for compressed
+ * and/or sparse $DATA, this is the
+ * compressed_size from the unnamed
+ * $DATA attribute. For a directory or
+ * other inode without an unnamed $DATA attribute,
+ * this is always 0. NOTE: This is a multiple of
+ * the cluster size.
+ */
+ __le64 data_size; /*
+ * Byte size of actual data in unnamed
+ * data attribute. For a directory or
+ * other inode without an unnamed $DATA
+ * attribute, this is always 0.
+ */
+ __le32 file_attributes; /* Flags describing the file. */
+ union {
+ struct {
+ __le16 packed_ea_size; /*
+ * Size of the buffer needed to
+ * pack the extended attributes
+ * (EAs), if such are present.
+ */
+ __le16 reserved; /* Reserved for alignment. */
+ } __packed ea;
+ struct {
+ __le32 reparse_point_tag; /*
+ * Type of reparse point,
+ * present only in reparse
+ * points and only if there are
+ * no EAs.
+ */
+ } __packed rp;
+ } __packed type;
+ u8 file_name_length; /* Length of file name in (Unicode) characters. */
+ u8 file_name_type; /* Namespace of the file name.*/
+ __le16 file_name[]; /* File name in Unicode. */
+} __packed;
/*
* GUID structures store globally unique identifiers (GUID). A GUID is a
@@ -1095,75 +1196,16 @@ typedef struct {
* Example of a GUID:
* 1F010768-5A73-BC91-0010A52216A7
*/
-typedef struct {
- le32 data1; /* The first eight hexadecimal digits of the GUID. */
- le16 data2; /* The first group of four hexadecimal digits. */
- le16 data3; /* The second group of four hexadecimal digits. */
- u8 data4[8]; /* The first two bytes are the third group of four
- hexadecimal digits. The remaining six bytes are the
- final 12 hexadecimal digits. */
-} __attribute__ ((__packed__)) GUID;
-
-/*
- * FILE_Extend/$ObjId contains an index named $O. This index contains all
- * object_ids present on the volume as the index keys and the corresponding
- * mft_record numbers as the index entry data parts. The data part (defined
- * below) also contains three other object_ids:
- * birth_volume_id - object_id of FILE_Volume on which the file was first
- * created. Optional (i.e. can be zero).
- * birth_object_id - object_id of file when it was first created. Usually
- * equals the object_id. Optional (i.e. can be zero).
- * domain_id - Reserved (always zero).
- */
-typedef struct {
- leMFT_REF mft_reference;/* Mft record containing the object_id in
- the index entry key. */
- union {
- struct {
- GUID birth_volume_id;
- GUID birth_object_id;
- GUID domain_id;
- } __attribute__ ((__packed__)) origin;
- u8 extended_info[48];
- } __attribute__ ((__packed__)) opt;
-} __attribute__ ((__packed__)) OBJ_ID_INDEX_DATA;
-
-/*
- * Attribute: Object id (NTFS 3.0+) (0x40).
- *
- * NOTE: Always resident.
- */
-typedef struct {
- GUID object_id; /* Unique id assigned to the
- file.*/
- /* The following fields are optional. The attribute value size is 16
- bytes, i.e. sizeof(GUID), if these are not present at all. Note,
- the entries can be present but one or more (or all) can be zero
- meaning that that particular value(s) is(are) not defined. */
- union {
- struct {
- GUID birth_volume_id; /* Unique id of volume on which
- the file was first created.*/
- GUID birth_object_id; /* Unique id of file when it was
- first created. */
- GUID domain_id; /* Reserved, zero. */
- } __attribute__ ((__packed__)) origin;
- u8 extended_info[48];
- } __attribute__ ((__packed__)) opt;
-} __attribute__ ((__packed__)) OBJECT_ID_ATTR;
-
-/*
- * The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
- * the SID structure (see below).
- */
-//typedef enum { /* SID string prefix. */
-// SECURITY_NULL_SID_AUTHORITY = {0, 0, 0, 0, 0, 0}, /* S-1-0 */
-// SECURITY_WORLD_SID_AUTHORITY = {0, 0, 0, 0, 0, 1}, /* S-1-1 */
-// SECURITY_LOCAL_SID_AUTHORITY = {0, 0, 0, 0, 0, 2}, /* S-1-2 */
-// SECURITY_CREATOR_SID_AUTHORITY = {0, 0, 0, 0, 0, 3}, /* S-1-3 */
-// SECURITY_NON_UNIQUE_AUTHORITY = {0, 0, 0, 0, 0, 4}, /* S-1-4 */
-// SECURITY_NT_SID_AUTHORITY = {0, 0, 0, 0, 0, 5}, /* S-1-5 */
-//} IDENTIFIER_AUTHORITIES;
+struct guid {
+ __le32 data1; /* The first eight hexadecimal digits of the GUID. */
+ __le16 data2; /* The first group of four hexadecimal digits. */
+ __le16 data3; /* The second group of four hexadecimal digits. */
+ u8 data4[8]; /*
+ * The first two bytes are the third group of four
+ * hexadecimal digits. The remaining six bytes are the
+ * final 12 hexadecimal digits.
+ */
+} __packed;
/*
* These relative identifiers (RIDs) are used with the above identifier
@@ -1175,75 +1217,75 @@ typedef struct {
* made up of the identifier authority SECURITY_CREATOR_SID_AUTHORITY (3) and
* the relative identifier SECURITY_CREATOR_OWNER_RID (0).
*/
-typedef enum { /* Identifier authority. */
- SECURITY_NULL_RID = 0, /* S-1-0 */
- SECURITY_WORLD_RID = 0, /* S-1-1 */
- SECURITY_LOCAL_RID = 0, /* S-1-2 */
+enum { /* Identifier authority. */
+ SECURITY_NULL_RID = 0, /* S-1-0 */
+ SECURITY_WORLD_RID = 0, /* S-1-1 */
+ SECURITY_LOCAL_RID = 0, /* S-1-2 */
- SECURITY_CREATOR_OWNER_RID = 0, /* S-1-3 */
- SECURITY_CREATOR_GROUP_RID = 1, /* S-1-3 */
+ SECURITY_CREATOR_OWNER_RID = 0, /* S-1-3 */
+ SECURITY_CREATOR_GROUP_RID = 1, /* S-1-3 */
- SECURITY_CREATOR_OWNER_SERVER_RID = 2, /* S-1-3 */
- SECURITY_CREATOR_GROUP_SERVER_RID = 3, /* S-1-3 */
+ SECURITY_CREATOR_OWNER_SERVER_RID = 2, /* S-1-3 */
+ SECURITY_CREATOR_GROUP_SERVER_RID = 3, /* S-1-3 */
- SECURITY_DIALUP_RID = 1,
- SECURITY_NETWORK_RID = 2,
- SECURITY_BATCH_RID = 3,
- SECURITY_INTERACTIVE_RID = 4,
- SECURITY_SERVICE_RID = 6,
- SECURITY_ANONYMOUS_LOGON_RID = 7,
- SECURITY_PROXY_RID = 8,
- SECURITY_ENTERPRISE_CONTROLLERS_RID=9,
- SECURITY_SERVER_LOGON_RID = 9,
- SECURITY_PRINCIPAL_SELF_RID = 0xa,
- SECURITY_AUTHENTICATED_USER_RID = 0xb,
- SECURITY_RESTRICTED_CODE_RID = 0xc,
- SECURITY_TERMINAL_SERVER_RID = 0xd,
+ SECURITY_DIALUP_RID = 1,
+ SECURITY_NETWORK_RID = 2,
+ SECURITY_BATCH_RID = 3,
+ SECURITY_INTERACTIVE_RID = 4,
+ SECURITY_SERVICE_RID = 6,
+ SECURITY_ANONYMOUS_LOGON_RID = 7,
+ SECURITY_PROXY_RID = 8,
+ SECURITY_ENTERPRISE_CONTROLLERS_RID = 9,
+ SECURITY_SERVER_LOGON_RID = 9,
+ SECURITY_PRINCIPAL_SELF_RID = 0xa,
+ SECURITY_AUTHENTICATED_USER_RID = 0xb,
+ SECURITY_RESTRICTED_CODE_RID = 0xc,
+ SECURITY_TERMINAL_SERVER_RID = 0xd,
- SECURITY_LOGON_IDS_RID = 5,
- SECURITY_LOGON_IDS_RID_COUNT = 3,
+ SECURITY_LOGON_IDS_RID = 5,
+ SECURITY_LOGON_IDS_RID_COUNT = 3,
- SECURITY_LOCAL_SYSTEM_RID = 0x12,
+ SECURITY_LOCAL_SYSTEM_RID = 0x12,
- SECURITY_NT_NON_UNIQUE = 0x15,
+ SECURITY_NT_NON_UNIQUE = 0x15,
- SECURITY_BUILTIN_DOMAIN_RID = 0x20,
+ SECURITY_BUILTIN_DOMAIN_RID = 0x20,
/*
* Well-known domain relative sub-authority values (RIDs).
*/
/* Users. */
- DOMAIN_USER_RID_ADMIN = 0x1f4,
- DOMAIN_USER_RID_GUEST = 0x1f5,
- DOMAIN_USER_RID_KRBTGT = 0x1f6,
+ DOMAIN_USER_RID_ADMIN = 0x1f4,
+ DOMAIN_USER_RID_GUEST = 0x1f5,
+ DOMAIN_USER_RID_KRBTGT = 0x1f6,
/* Groups. */
- DOMAIN_GROUP_RID_ADMINS = 0x200,
- DOMAIN_GROUP_RID_USERS = 0x201,
- DOMAIN_GROUP_RID_GUESTS = 0x202,
- DOMAIN_GROUP_RID_COMPUTERS = 0x203,
- DOMAIN_GROUP_RID_CONTROLLERS = 0x204,
- DOMAIN_GROUP_RID_CERT_ADMINS = 0x205,
- DOMAIN_GROUP_RID_SCHEMA_ADMINS = 0x206,
- DOMAIN_GROUP_RID_ENTERPRISE_ADMINS= 0x207,
- DOMAIN_GROUP_RID_POLICY_ADMINS = 0x208,
+ DOMAIN_GROUP_RID_ADMINS = 0x200,
+ DOMAIN_GROUP_RID_USERS = 0x201,
+ DOMAIN_GROUP_RID_GUESTS = 0x202,
+ DOMAIN_GROUP_RID_COMPUTERS = 0x203,
+ DOMAIN_GROUP_RID_CONTROLLERS = 0x204,
+ DOMAIN_GROUP_RID_CERT_ADMINS = 0x205,
+ DOMAIN_GROUP_RID_SCHEMA_ADMINS = 0x206,
+ DOMAIN_GROUP_RID_ENTERPRISE_ADMINS = 0x207,
+ DOMAIN_GROUP_RID_POLICY_ADMINS = 0x208,
/* Aliases. */
- DOMAIN_ALIAS_RID_ADMINS = 0x220,
- DOMAIN_ALIAS_RID_USERS = 0x221,
- DOMAIN_ALIAS_RID_GUESTS = 0x222,
- DOMAIN_ALIAS_RID_POWER_USERS = 0x223,
-
- DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224,
- DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225,
- DOMAIN_ALIAS_RID_PRINT_OPS = 0x226,
- DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227,
-
- DOMAIN_ALIAS_RID_REPLICATOR = 0x228,
- DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229,
- DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a,
-} RELATIVE_IDENTIFIERS;
+ DOMAIN_ALIAS_RID_ADMINS = 0x220,
+ DOMAIN_ALIAS_RID_USERS = 0x221,
+ DOMAIN_ALIAS_RID_GUESTS = 0x222,
+ DOMAIN_ALIAS_RID_POWER_USERS = 0x223,
+
+ DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224,
+ DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225,
+ DOMAIN_ALIAS_RID_PRINT_OPS = 0x226,
+ DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227,
+
+ DOMAIN_ALIAS_RID_REPLICATOR = 0x228,
+ DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229,
+ DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a,
+};
/*
* The universal well-known SIDs:
@@ -1282,20 +1324,6 @@ typedef enum { /* Identifier authority. */
* (Built-in domain) S-1-5-0x20
*/
-/*
- * The SID_IDENTIFIER_AUTHORITY is a 48-bit value used in the SID structure.
- *
- * NOTE: This is stored as a big endian number, hence the high_part comes
- * before the low_part.
- */
-typedef union {
- struct {
- u16 high_part; /* High 16-bits. */
- u32 low_part; /* Low 32-bits. */
- } __attribute__ ((__packed__)) parts;
- u8 value[6]; /* Value as individual bytes. */
-} __attribute__ ((__packed__)) SID_IDENTIFIER_AUTHORITY;
-
/*
* The SID structure is a variable-length structure used to uniquely identify
* users or groups. SID stands for security identifier.
@@ -1320,52 +1348,46 @@ typedef union {
* sub_authority[0] = 32, // SECURITY_BUILTIN_DOMAIN_RID
* sub_authority[1] = 544 // DOMAIN_ALIAS_RID_ADMINS
*/
-typedef struct {
+struct ntfs_sid {
u8 revision;
u8 sub_authority_count;
- SID_IDENTIFIER_AUTHORITY identifier_authority;
- le32 sub_authority[1]; /* At least one sub_authority. */
-} __attribute__ ((__packed__)) SID;
-
-/*
- * Current constants for SIDs.
- */
-typedef enum {
- SID_REVISION = 1, /* Current revision level. */
- SID_MAX_SUB_AUTHORITIES = 15, /* Maximum number of those. */
- SID_RECOMMENDED_SUB_AUTHORITIES = 1, /* Will change to around 6 in
- a future revision. */
-} SID_CONSTANTS;
+ union {
+ struct {
+ u16 high_part; /* High 16-bits. */
+ u32 low_part; /* Low 32-bits. */
+ } __packed parts;
+ u8 value[6]; /* Value as individual bytes. */
+ } identifier_authority;
+ __le32 sub_authority[]; /* At least one sub_authority. */
+} __packed;
/*
* The predefined ACE types (8-bit, see below).
*/
enum {
- ACCESS_MIN_MS_ACE_TYPE = 0,
- ACCESS_ALLOWED_ACE_TYPE = 0,
- ACCESS_DENIED_ACE_TYPE = 1,
- SYSTEM_AUDIT_ACE_TYPE = 2,
- SYSTEM_ALARM_ACE_TYPE = 3, /* Not implemented as of Win2k. */
- ACCESS_MAX_MS_V2_ACE_TYPE = 3,
+ ACCESS_MIN_MS_ACE_TYPE = 0,
+ ACCESS_ALLOWED_ACE_TYPE = 0,
+ ACCESS_DENIED_ACE_TYPE = 1,
+ SYSTEM_AUDIT_ACE_TYPE = 2,
+ SYSTEM_ALARM_ACE_TYPE = 3, /* Not implemented as of Win2k. */
+ ACCESS_MAX_MS_V2_ACE_TYPE = 3,
- ACCESS_ALLOWED_COMPOUND_ACE_TYPE= 4,
- ACCESS_MAX_MS_V3_ACE_TYPE = 4,
+ ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 4,
+ ACCESS_MAX_MS_V3_ACE_TYPE = 4,
/* The following are Win2k only. */
- ACCESS_MIN_MS_OBJECT_ACE_TYPE = 5,
- ACCESS_ALLOWED_OBJECT_ACE_TYPE = 5,
- ACCESS_DENIED_OBJECT_ACE_TYPE = 6,
- SYSTEM_AUDIT_OBJECT_ACE_TYPE = 7,
- SYSTEM_ALARM_OBJECT_ACE_TYPE = 8,
- ACCESS_MAX_MS_OBJECT_ACE_TYPE = 8,
+ ACCESS_MIN_MS_OBJECT_ACE_TYPE = 5,
+ ACCESS_ALLOWED_OBJECT_ACE_TYPE = 5,
+ ACCESS_DENIED_OBJECT_ACE_TYPE = 6,
+ SYSTEM_AUDIT_OBJECT_ACE_TYPE = 7,
+ SYSTEM_ALARM_OBJECT_ACE_TYPE = 8,
+ ACCESS_MAX_MS_OBJECT_ACE_TYPE = 8,
- ACCESS_MAX_MS_V4_ACE_TYPE = 8,
+ ACCESS_MAX_MS_V4_ACE_TYPE = 8,
/* This one is for WinNT/2k. */
- ACCESS_MAX_MS_ACE_TYPE = 8,
-} __attribute__ ((__packed__));
-
-typedef u8 ACE_TYPES;
+ ACCESS_MAX_MS_ACE_TYPE = 8,
+} __packed;
/*
* The ACE flags (8-bit) for audit and inheritance (see below).
@@ -1389,27 +1411,7 @@ enum {
/* The audit flags. */
SUCCESSFUL_ACCESS_ACE_FLAG = 0x40,
FAILED_ACCESS_ACE_FLAG = 0x80,
-} __attribute__ ((__packed__));
-
-typedef u8 ACE_FLAGS;
-
-/*
- * An ACE is an access-control entry in an access-control list (ACL).
- * An ACE defines access to an object for a specific user or group or defines
- * the types of access that generate system-administration messages or alarms
- * for a specific user or group. The user or group is identified by a security
- * identifier (SID).
- *
- * Each ACE starts with an ACE_HEADER structure (aligned on 4-byte boundary),
- * which specifies the type and size of the ACE. The format of the subsequent
- * data depends on the ACE type.
- */
-typedef struct {
-/*Ofs*/
-/* 0*/ ACE_TYPES type; /* Type of the ACE. */
-/* 1*/ ACE_FLAGS flags; /* Flags describing the ACE. */
-/* 2*/ le16 size; /* Size in bytes of the ACE. */
-} __attribute__ ((__packed__)) ACE_HEADER;
+} __packed;
/*
* The access mask (32-bit). Defines the access rights.
@@ -1542,38 +1544,17 @@ enum {
GENERIC_READ = cpu_to_le32(0x80000000),
};
-typedef le32 ACCESS_MASK;
-
-/*
- * The generic mapping array. Used to denote the mapping of each generic
- * access right to a specific access mask.
- *
- * FIXME: What exactly is this and what is it for? (AIA)
- */
-typedef struct {
- ACCESS_MASK generic_read;
- ACCESS_MASK generic_write;
- ACCESS_MASK generic_execute;
- ACCESS_MASK generic_all;
-} __attribute__ ((__packed__)) GENERIC_MAPPING;
-
/*
* The predefined ACE type structures are as defined below.
*/
-/*
- * ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
- */
-typedef struct {
-/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
- ACE_TYPES type; /* Type of the ACE. */
- ACE_FLAGS flags; /* Flags describing the ACE. */
- le16 size; /* Size in bytes of the ACE. */
-/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */
-
-/* 8*/ SID sid; /* The SID associated with the ACE. */
-} __attribute__ ((__packed__)) ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE,
- SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE;
+struct ntfs_ace {
+ u8 type; /* Type of the ACE. */
+ u8 flags; /* Flags describing the ACE. */
+ __le16 size; /* Size in bytes of the ACE. */
+ __le32 mask; /* Access mask associated with the ACE. */
+ struct ntfs_sid sid; /* The SID associated with the ACE. */
+} __packed;
/*
* The object ACE flags (32-bit).
@@ -1583,25 +1564,6 @@ enum {
ACE_INHERITED_OBJECT_TYPE_PRESENT = cpu_to_le32(2),
};
-typedef le32 OBJECT_ACE_FLAGS;
-
-typedef struct {
-/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
- ACE_TYPES type; /* Type of the ACE. */
- ACE_FLAGS flags; /* Flags describing the ACE. */
- le16 size; /* Size in bytes of the ACE. */
-/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */
-
-/* 8*/ OBJECT_ACE_FLAGS object_flags; /* Flags describing the object ACE. */
-/* 12*/ GUID object_type;
-/* 28*/ GUID inherited_object_type;
-
-/* 44*/ SID sid; /* The SID associated with the ACE. */
-} __attribute__ ((__packed__)) ACCESS_ALLOWED_OBJECT_ACE,
- ACCESS_DENIED_OBJECT_ACE,
- SYSTEM_AUDIT_OBJECT_ACE,
- SYSTEM_ALARM_OBJECT_ACE;
-
/*
* An ACL is an access-control list (ACL).
* An ACL starts with an ACL header structure, which specifies the size of
@@ -1609,32 +1571,18 @@ typedef struct {
* zero or more access control entries (ACEs). The ACL as well as each ACE
* are aligned on 4-byte boundaries.
*/
-typedef struct {
+struct ntfs_acl {
u8 revision; /* Revision of this ACL. */
u8 alignment1;
- le16 size; /* Allocated space in bytes for ACL. Includes this
- header, the ACEs and the remaining free space. */
- le16 ace_count; /* Number of ACEs in the ACL. */
- le16 alignment2;
-/* sizeof() = 8 bytes */
-} __attribute__ ((__packed__)) ACL;
+ __le16 size; /*
+ * Allocated space in bytes for ACL. Includes this
+ * header, the ACEs and the remaining free space.
+ */
+ __le16 ace_count; /* Number of ACEs in the ACL. */
+ __le16 alignment2;
+} __packed;
-/*
- * Current constants for ACLs.
- */
-typedef enum {
- /* Current revision. */
- ACL_REVISION = 2,
- ACL_REVISION_DS = 4,
-
- /* History of revisions. */
- ACL_REVISION1 = 1,
- MIN_ACL_REVISION = 2,
- ACL_REVISION2 = 2,
- ACL_REVISION3 = 3,
- ACL_REVISION4 = 4,
- MAX_ACL_REVISION = 4,
-} ACL_CONSTANTS;
+static_assert(sizeof(struct ntfs_acl) == 8);
/*
* The security descriptor control flags (16-bit).
@@ -1698,87 +1646,44 @@ enum {
SE_SACL_PROTECTED = cpu_to_le16(0x2000),
SE_RM_CONTROL_VALID = cpu_to_le16(0x4000),
SE_SELF_RELATIVE = cpu_to_le16(0x8000)
-} __attribute__ ((__packed__));
-
-typedef le16 SECURITY_DESCRIPTOR_CONTROL;
+} __packed;
/*
* Self-relative security descriptor. Contains the owner and group SIDs as well
* as the sacl and dacl ACLs inside the security descriptor itself.
*/
-typedef struct {
- u8 revision; /* Revision level of the security descriptor. */
- u8 alignment;
- SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
- the descriptor as well as the following fields. */
- le32 owner; /* Byte offset to a SID representing an object's
- owner. If this is NULL, no owner SID is present in
- the descriptor. */
- le32 group; /* Byte offset to a SID representing an object's
- primary group. If this is NULL, no primary group
- SID is present in the descriptor. */
- le32 sacl; /* Byte offset to a system ACL. Only valid, if
- SE_SACL_PRESENT is set in the control field. If
- SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
- is specified. */
- le32 dacl; /* Byte offset to a discretionary ACL. Only valid, if
- SE_DACL_PRESENT is set in the control field. If
- SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
- (unconditionally granting access) is specified. */
-/* sizeof() = 0x14 bytes */
-} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR_RELATIVE;
-
-/*
- * Absolute security descriptor. Does not contain the owner and group SIDs, nor
- * the sacl and dacl ACLs inside the security descriptor. Instead, it contains
- * pointers to these structures in memory. Obviously, absolute security
- * descriptors are only useful for in memory representations of security
- * descriptors. On disk, a self-relative security descriptor is used.
- */
-typedef struct {
+struct security_descriptor_relative {
u8 revision; /* Revision level of the security descriptor. */
u8 alignment;
- SECURITY_DESCRIPTOR_CONTROL control; /* Flags qualifying the type of
- the descriptor as well as the following fields. */
- SID *owner; /* Points to a SID representing an object's owner. If
- this is NULL, no owner SID is present in the
- descriptor. */
- SID *group; /* Points to a SID representing an object's primary
- group. If this is NULL, no primary group SID is
- present in the descriptor. */
- ACL *sacl; /* Points to a system ACL. Only valid, if
- SE_SACL_PRESENT is set in the control field. If
- SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
- is specified. */
- ACL *dacl; /* Points to a discretionary ACL. Only valid, if
- SE_DACL_PRESENT is set in the control field. If
- SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
- (unconditionally granting access) is specified. */
-} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR;
-
-/*
- * Current constants for security descriptors.
- */
-typedef enum {
- /* Current revision. */
- SECURITY_DESCRIPTOR_REVISION = 1,
- SECURITY_DESCRIPTOR_REVISION1 = 1,
-
- /* The sizes of both the absolute and relative security descriptors is
- the same as pointers, at least on ia32 architecture are 32-bit. */
- SECURITY_DESCRIPTOR_MIN_LENGTH = sizeof(SECURITY_DESCRIPTOR),
-} SECURITY_DESCRIPTOR_CONSTANTS;
-
-/*
- * Attribute: Security descriptor (0x50). A standard self-relative security
- * descriptor.
- *
- * NOTE: Can be resident or non-resident.
- * NOTE: Not used in NTFS 3.0+, as security descriptors are stored centrally
- * in FILE_Secure and the correct descriptor is found using the security_id
- * from the standard information attribute.
- */
-typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR;
+ __le16 control; /*
+ * Flags qualifying the type of * the descriptor as well as
+ * the following fields.
+ */
+ __le32 owner; /*
+ * Byte offset to a SID representing an object's
+ * owner. If this is NULL, no owner SID is present in
+ * the descriptor.
+ */
+ __le32 group; /*
+ * Byte offset to a SID representing an object's
+ * primary group. If this is NULL, no primary group
+ * SID is present in the descriptor.
+ */
+ __le32 sacl; /*
+ * Byte offset to a system ACL. Only valid, if
+ * SE_SACL_PRESENT is set in the control field. If
+ * SE_SACL_PRESENT is set but sacl is NULL, a NULL ACL
+ * is specified.
+ */
+ __le32 dacl; /*
+ * Byte offset to a discretionary ACL. Only valid, if
+ * SE_DACL_PRESENT is set in the control field. If
+ * SE_DACL_PRESENT is set but dacl is NULL, a NULL ACL
+ * (unconditionally granting access) is specified.
+ */
+} __packed;
+
+static_assert(sizeof(struct security_descriptor_relative) == 20);
/*
* On NTFS 3.0+, all security descriptors are stored in FILE_Secure. Only one
@@ -1819,67 +1724,23 @@ typedef SECURITY_DESCRIPTOR_RELATIVE SECURITY_DESCRIPTOR_ATTR;
* references an entry any more.
*/
-/*
- * This header precedes each security descriptor in the $SDS data stream.
- * This is also the index entry data part of both the $SII and $SDH indexes.
- */
-typedef struct {
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
- le64 offset; /* Byte offset of this entry in the $SDS stream. */
- le32 length; /* Size in bytes of this entry in $SDS stream. */
-} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR_HEADER;
-
-/*
- * The $SDS data stream contains the security descriptors, aligned on 16-byte
- * boundaries, sorted by security_id in a B+ tree. Security descriptors cannot
- * cross 256kib boundaries (this restriction is imposed by the Windows cache
- * manager). Each security descriptor is contained in a SDS_ENTRY structure.
- * Also, each security descriptor is stored twice in the $SDS stream with a
- * fixed offset of 0x40000 bytes (256kib, the Windows cache manager's max size)
- * between them; i.e. if a SDS_ENTRY specifies an offset of 0x51d0, then the
- * first copy of the security descriptor will be at offset 0x51d0 in the
- * $SDS data stream and the second copy will be at offset 0x451d0.
- */
-typedef struct {
-/*Ofs*/
-/* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
- unnamed structs. */
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
- le64 offset; /* Byte offset of this entry in the $SDS stream. */
- le32 length; /* Size in bytes of this entry in $SDS stream. */
-/* 20*/ SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security
- descriptor. */
-} __attribute__ ((__packed__)) SDS_ENTRY;
-
/*
* The index entry key used in the $SII index. The collation type is
* COLLATION_NTOFS_ULONG.
*/
-typedef struct {
- le32 security_id; /* The security_id assigned to the descriptor. */
-} __attribute__ ((__packed__)) SII_INDEX_KEY;
+struct sii_index_key {
+ __le32 security_id; /* The security_id assigned to the descriptor. */
+} __packed;
/*
* The index entry key used in the $SDH index. The keys are sorted first by
* hash and then by security_id. The collation rule is
* COLLATION_NTOFS_SECURITY_HASH.
*/
-typedef struct {
- le32 hash; /* Hash of the security descriptor. */
- le32 security_id; /* The security_id assigned to the descriptor. */
-} __attribute__ ((__packed__)) SDH_INDEX_KEY;
-
-/*
- * Attribute: Volume name (0x60).
- *
- * NOTE: Always resident.
- * NOTE: Present only in FILE_Volume.
- */
-typedef struct {
- ntfschar name[0]; /* The name of the volume in Unicode. */
-} __attribute__ ((__packed__)) VOLUME_NAME;
+struct sdh_index_key {
+ __le32 hash; /* Hash of the security descriptor. */
+ __le32 security_id; /* The security_id assigned to the descriptor. */
+} __packed;
/*
* Possible flags for the volume (16-bit).
@@ -1900,9 +1761,7 @@ enum {
/* To make our life easier when checking if we must mount read-only. */
VOLUME_MUST_MOUNT_RO_MASK = cpu_to_le16(0xc027),
-} __attribute__ ((__packed__));
-
-typedef le16 VOLUME_FLAGS;
+} __packed;
/*
* Attribute: Volume information (0x70).
@@ -1912,23 +1771,12 @@ typedef le16 VOLUME_FLAGS;
* NOTE: Windows 2000 uses NTFS 3.0 while Windows NT4 service pack 6a uses
* NTFS 1.2. I haven't personally seen other values yet.
*/
-typedef struct {
- le64 reserved; /* Not used (yet?). */
+struct volume_information {
+ __le64 reserved; /* Not used (yet?). */
u8 major_ver; /* Major version of the ntfs format. */
u8 minor_ver; /* Minor version of the ntfs format. */
- VOLUME_FLAGS flags; /* Bit array of VOLUME_* flags. */
-} __attribute__ ((__packed__)) VOLUME_INFORMATION;
-
-/*
- * Attribute: Data attribute (0x80).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Data contents of a file (i.e. the unnamed stream) or of a named stream.
- */
-typedef struct {
- u8 data[0]; /* The file's data contents. */
-} __attribute__ ((__packed__)) DATA_ATTR;
+ __le16 flags; /* Bit array of VOLUME_* flags. */
+} __packed;
/*
* Index header flags (8-bit).
@@ -1937,52 +1785,66 @@ enum {
/*
* When index header is in an index root attribute:
*/
- SMALL_INDEX = 0, /* The index is small enough to fit inside the index
- root attribute and there is no index allocation
- attribute present. */
- LARGE_INDEX = 1, /* The index is too large to fit in the index root
- attribute and/or an index allocation attribute is
- present. */
+ SMALL_INDEX = 0, /*
+ * The index is small enough to fit inside the index
+ * root attribute and there is no index allocation
+ * attribute present.
+ */
+ LARGE_INDEX = 1, /*
+ * The index is too large to fit in the index root
+ * attribute and/or an index allocation attribute is
+ * present.
+ */
/*
* When index header is in an index block, i.e. is part of index
* allocation attribute:
*/
- LEAF_NODE = 0, /* This is a leaf node, i.e. there are no more nodes
- branching off it. */
- INDEX_NODE = 1, /* This node indexes other nodes, i.e. it is not a leaf
- node. */
+ LEAF_NODE = 0, /*
+ * This is a leaf node, i.e. there are no more nodes
+ * branching off it.
+ */
+ INDEX_NODE = 1, /*
+ * This node indexes other nodes, i.e. it is not a leaf
+ * node.
+ */
NODE_MASK = 1, /* Mask for accessing the *_NODE bits. */
-} __attribute__ ((__packed__));
-
-typedef u8 INDEX_HEADER_FLAGS;
+} __packed;
/*
* This is the header for indexes, describing the INDEX_ENTRY records, which
- * follow the INDEX_HEADER. Together the index header and the index entries
+ * follow the index_header. Together the index header and the index entries
* make up a complete index.
*
* IMPORTANT NOTE: The offset, length and size structure members are counted
* relative to the start of the index header structure and not relative to the
* start of the index root or index allocation structures themselves.
*/
-typedef struct {
- le32 entries_offset; /* Byte offset to first INDEX_ENTRY
- aligned to 8-byte boundary. */
- le32 index_length; /* Data size of the index in bytes,
- i.e. bytes used from allocated
- size, aligned to 8-byte boundary. */
- le32 allocated_size; /* Byte size of this index (block),
- multiple of 8 bytes. */
- /* NOTE: For the index root attribute, the above two numbers are always
- equal, as the attribute is resident and it is resized as needed. In
- the case of the index allocation attribute the attribute is not
- resident and hence the allocated_size is a fixed value and must
- equal the index_block_size specified by the INDEX_ROOT attribute
- corresponding to the INDEX_ALLOCATION attribute this INDEX_BLOCK
- belongs to. */
- INDEX_HEADER_FLAGS flags; /* Bit field of INDEX_HEADER_FLAGS. */
+struct index_header {
+ __le32 entries_offset; /*
+ * Byte offset to first INDEX_ENTRY
+ * aligned to 8-byte boundary.
+ */
+ __le32 index_length; /*
+ * Data size of the index in bytes,
+ * i.e. bytes used from allocated
+ * size, aligned to 8-byte boundary.
+ */
+ __le32 allocated_size; /*
+ * Byte size of this index (block),
+ * multiple of 8 bytes.
+ */
+ /*
+ * NOTE: For the index root attribute, the above two numbers are always
+ * equal, as the attribute is resident and it is resized as needed. In
+ * the case of the index allocation attribute the attribute is not
+ * resident and hence the allocated_size is a fixed value and must
+ * equal the index_block_size specified by the INDEX_ROOT attribute
+ * corresponding to the INDEX_ALLOCATION attribute this INDEX_BLOCK
+ * belongs to.
+ */
+ u8 flags; /* Bit field of INDEX_HEADER_FLAGS. */
u8 reserved[3]; /* Reserved/align to 8-byte boundary. */
-} __attribute__ ((__packed__)) INDEX_HEADER;
+} __packed;
/*
* Attribute: Index root (0x90).
@@ -2003,28 +1865,35 @@ typedef struct {
* NOTE: The root directory (FILE_root) contains an entry for itself. Other
* directories do not contain entries for themselves, though.
*/
-typedef struct {
- ATTR_TYPE type; /* Type of the indexed attribute. Is
- $FILE_NAME for directories, zero
- for view indexes. No other values
- allowed. */
- COLLATION_RULE collation_rule; /* Collation rule used to sort the
- index entries. If type is $FILE_NAME,
- this must be COLLATION_FILE_NAME. */
- le32 index_block_size; /* Size of each index block in bytes (in
- the index allocation attribute). */
- u8 clusters_per_index_block; /* Cluster size of each index block (in
- the index allocation attribute), when
- an index block is >= than a cluster,
- otherwise this will be the log of
- the size (like how the encoding of
- the mft record size and the index
- record size found in the boot sector
- work). Has to be a power of 2. */
+struct index_root {
+ __le32 type; /*
+ * Type of the indexed attribute. Is
+ * $FILE_NAME for directories, zero
+ * for view indexes. No other values
+ * allowed.
+ */
+ __le32 collation_rule; /*
+ * Collation rule used to sort the index
+ * entries. If type is $FILE_NAME, this
+ * must be COLLATION_FILE_NAME.
+ */
+ __le32 index_block_size; /*
+ * Size of each index block in bytes (in
+ * the index allocation attribute).
+ */
+ u8 clusters_per_index_block; /*
+ * Cluster size of each index block (in
+ * the index allocation attribute), when
+ * an index block is >= than a cluster,
+ * otherwise this will be the log of
+ * the size (like how the encoding of
+ * the mft record size and the index
+ * record size found in the boot sector
+ * work). Has to be a power of 2.
+ */
u8 reserved[3]; /* Reserved/align to 8-byte boundary. */
- INDEX_HEADER index; /* Index header describing the
- following index entries. */
-} __attribute__ ((__packed__)) INDEX_ROOT;
+ struct index_header index; /* Index header describing the following index entries. */
+} __packed;
/*
* Attribute: Index allocation (0xa0).
@@ -2032,24 +1901,26 @@ typedef struct {
* NOTE: Always non-resident (doesn't make sense to be resident anyway!).
*
* This is an array of index blocks. Each index block starts with an
- * INDEX_BLOCK structure containing an index header, followed by a sequence of
- * index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
- */
-typedef struct {
-/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
- NTFS_RECORD_TYPE magic; /* Magic is "INDX". */
- le16 usa_ofs; /* See NTFS_RECORD definition. */
- le16 usa_count; /* See NTFS_RECORD definition. */
-
-/* 8*/ sle64 lsn; /* $LogFile sequence number of the last
- modification of this index block. */
-/* 16*/ leVCN index_block_vcn; /* Virtual cluster number of the index block.
- If the cluster_size on the volume is <= the
- index_block_size of the directory,
- index_block_vcn counts in units of clusters,
- and in units of sectors otherwise. */
-/* 24*/ INDEX_HEADER index; /* Describes the following index entries. */
-/* sizeof()= 40 (0x28) bytes */
+ * index_block structure containing an index header, followed by a sequence of
+ * index entries (INDEX_ENTRY structures), as described by the struct index_header.
+ */
+struct index_block {
+ __le32 magic; /* Magic is "INDX". */
+ __le16 usa_ofs; /* See ntfs_record struct definition. */
+ __le16 usa_count; /* See ntfs_record struct definition. */
+
+ __le64 lsn; /*
+ * LogFile sequence number of the last
+ * modification of this index block.
+ */
+ __le64 index_block_vcn; /*
+ * Virtual cluster number of the index block.
+ * If the cluster_size on the volume is <= the
+ * index_block_size of the directory,
+ * index_block_vcn counts in units of clusters,
+ * and in units of sectors otherwise.
+ */
+ struct index_header index; /* Describes the following index entries. */
/*
* When creating the index block, we place the update sequence array at this
* offset, i.e. before we start with the index entries. This also makes sense,
@@ -2059,9 +1930,9 @@ typedef struct {
* by overwriting it since you then can't get it back...
* When reading use the data from the ntfs record header.
*/
-} __attribute__ ((__packed__)) INDEX_BLOCK;
+} __packed;
-typedef INDEX_BLOCK INDEX_ALLOCATION;
+static_assert(sizeof(struct index_block) == 40);
/*
* The system file FILE_Extend/$Reparse contains an index named $R listing
@@ -2069,14 +1940,15 @@ typedef INDEX_BLOCK INDEX_ALLOCATION;
* below. Note, that there is no index data associated with the index entries.
*
* The index entries are sorted by the index key file_id. The collation rule is
- * COLLATION_NTOFS_ULONGS. FIXME: Verify whether the reparse_tag is not the
- * primary key / is not a key at all. (AIA)
+ * COLLATION_NTOFS_ULONGS.
*/
-typedef struct {
- le32 reparse_tag; /* Reparse point type (inc. flags). */
- leMFT_REF file_id; /* Mft record of the file containing the
- reparse point attribute. */
-} __attribute__ ((__packed__)) REPARSE_INDEX_KEY;
+struct reparse_index_key {
+ __le32 reparse_tag; /* Reparse point type (inc. flags). */
+ __le64 file_id; /*
+ * Mft record of the file containing
+ * the reparse point attribute.
+ */
+} __packed;
/*
* Quota flags (32-bit).
@@ -2106,8 +1978,6 @@ enum {
QUOTA_FLAG_PENDING_DELETES = cpu_to_le32(0x00000800),
};
-typedef le32 QUOTA_FLAGS;
-
/*
* The system file FILE_Extend/$Quota contains two indexes $O and $Q. Quotas
* are on a per volume and per user basis.
@@ -2129,19 +1999,21 @@ typedef le32 QUOTA_FLAGS;
*
* The $Q index entry data is the quota control entry and is defined below.
*/
-typedef struct {
- le32 version; /* Currently equals 2. */
- QUOTA_FLAGS flags; /* Flags describing this quota entry. */
- le64 bytes_used; /* How many bytes of the quota are in use. */
- sle64 change_time; /* Last time this quota entry was changed. */
- sle64 threshold; /* Soft quota (-1 if not limited). */
- sle64 limit; /* Hard quota (-1 if not limited). */
- sle64 exceeded_time; /* How long the soft quota has been exceeded. */
- SID sid; /* The SID of the user/object associated with
- this quota entry. Equals zero for the quota
- defaults entry (and in fact on a WinXP
- volume, it is not present at all). */
-} __attribute__ ((__packed__)) QUOTA_CONTROL_ENTRY;
+struct quota_control_entry {
+ __le32 version; /* Currently equals 2. */
+ __le32 flags; /* Flags describing this quota entry. */
+ __le64 bytes_used; /* How many bytes of the quota are in use. */
+ __le64 change_time; /* Last time this quota entry was changed. */
+ __le64 threshold; /* Soft quota (-1 if not limited). */
+ __le64 limit; /* Hard quota (-1 if not limited). */
+ __le64 exceeded_time; /* How long the soft quota has been exceeded. */
+ struct ntfs_sid sid; /*
+ * The SID of the user/object associated with
+ * this quota entry. Equals zero for the quota
+ * defaults entry (and in fact on a WinXP
+ * volume, it is not present at all).
+ */
+} __packed;
/*
* Predefined owner_id values (32-bit).
@@ -2155,138 +2027,141 @@ enum {
/*
* Current constants for quota control entries.
*/
-typedef enum {
+enum {
/* Current version. */
QUOTA_VERSION = 2,
-} QUOTA_CONTROL_ENTRY_CONSTANTS;
+};
/*
* Index entry flags (16-bit).
*/
enum {
- INDEX_ENTRY_NODE = cpu_to_le16(1), /* This entry contains a
- sub-node, i.e. a reference to an index block in form of
- a virtual cluster number (see below). */
- INDEX_ENTRY_END = cpu_to_le16(2), /* This signifies the last
- entry in an index block. The index entry does not
- represent a file but it can point to a sub-node. */
-
- INDEX_ENTRY_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force
- enum bit width to 16-bit. */
-} __attribute__ ((__packed__));
-
-typedef le16 INDEX_ENTRY_FLAGS;
+ INDEX_ENTRY_NODE = cpu_to_le16(1), /*
+ * This entry contains a sub-node,
+ * i.e. a reference to an index block
+ * in form of a virtual cluster number
+ * (see below).
+ */
+ INDEX_ENTRY_END = cpu_to_le16(2), /*
+ * This signifies the last entry in an
+ * index block. The index entry does not
+ * represent a file but it can point
+ * to a sub-node.
+ */
+
+ INDEX_ENTRY_SPACE_FILLER = cpu_to_le16(0xffff), /* gcc: Force enum bit width to 16-bit. */
+} __packed;
/*
* This the index entry header (see below).
*/
-typedef struct {
+struct index_entry_header {
/* 0*/ union {
struct { /* Only valid when INDEX_ENTRY_END is not set. */
- leMFT_REF indexed_file; /* The mft reference of the file
- described by this index
- entry. Used for directory
- indexes. */
- } __attribute__ ((__packed__)) dir;
- struct { /* Used for views/indexes to find the entry's data. */
- le16 data_offset; /* Data byte offset from this
- INDEX_ENTRY. Follows the
- index key. */
- le16 data_length; /* Data length in bytes. */
- le32 reservedV; /* Reserved (zero). */
- } __attribute__ ((__packed__)) vi;
- } __attribute__ ((__packed__)) data;
-/* 8*/ le16 length; /* Byte size of this index entry, multiple of
- 8-bytes. */
-/* 10*/ le16 key_length; /* Byte size of the key value, which is in the
- index entry. It follows field reserved. Not
- multiple of 8-bytes. */
-/* 12*/ INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
-/* 14*/ le16 reserved; /* Reserved/align to 8-byte boundary. */
-/* sizeof() = 16 bytes */
-} __attribute__ ((__packed__)) INDEX_ENTRY_HEADER;
-
-/*
- * This is an index entry. A sequence of such entries follows each INDEX_HEADER
+ __le64 indexed_file; /*
+ * The mft reference of the file
+ * described by this index entry.
+ * Used for directory indexes.
+ */
+ } __packed dir;
+ struct {
+ /* Used for views/indexes to find the entry's data. */
+ __le16 data_offset; /*
+ * Data byte offset from this
+ * INDEX_ENTRY. Follows the index key.
+ */
+ __le16 data_length; /* Data length in bytes. */
+ __le32 reservedV; /* Reserved (zero). */
+ } __packed vi;
+ } __packed data;
+ __le16 length; /* Byte size of this index entry, multiple of 8-bytes. */
+ __le16 key_length; /*
+ * Byte size of the key value, which is in the index entry.
+ * It follows field reserved. Not multiple of 8-bytes.
+ */
+ __le16 flags; /* Bit field of INDEX_ENTRY_* flags. */
+ __le16 reserved; /* Reserved/align to 8-byte boundary. */
+} __packed;
+
+static_assert(sizeof(struct index_entry_header) == 16);
+
+/*
+ * This is an index entry. A sequence of such entries follows each index_header
* structure. Together they make up a complete index. The index follows either
* an index root attribute or an index allocation attribute.
*
* NOTE: Before NTFS 3.0 only filename attributes were indexed.
*/
-typedef struct {
-/*Ofs*/
-/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
+struct index_entry {
union {
struct { /* Only valid when INDEX_ENTRY_END is not set. */
- leMFT_REF indexed_file; /* The mft reference of the file
- described by this index
- entry. Used for directory
- indexes. */
- } __attribute__ ((__packed__)) dir;
+ __le64 indexed_file; /*
+ * The mft reference of the file
+ * described by this index entry.
+ * Used for directory indexes.
+ */
+ } __packed dir;
struct { /* Used for views/indexes to find the entry's data. */
- le16 data_offset; /* Data byte offset from this
- INDEX_ENTRY. Follows the
- index key. */
- le16 data_length; /* Data length in bytes. */
- le32 reservedV; /* Reserved (zero). */
- } __attribute__ ((__packed__)) vi;
- } __attribute__ ((__packed__)) data;
- le16 length; /* Byte size of this index entry, multiple of
- 8-bytes. */
- le16 key_length; /* Byte size of the key value, which is in the
- index entry. It follows field reserved. Not
- multiple of 8-bytes. */
- INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
- le16 reserved; /* Reserved/align to 8-byte boundary. */
-
-/* 16*/ union { /* The key of the indexed attribute. NOTE: Only present
- if INDEX_ENTRY_END bit in flags is not set. NOTE: On
- NTFS versions before 3.0 the only valid key is the
- FILE_NAME_ATTR. On NTFS 3.0+ the following
- additional index keys are defined: */
- FILE_NAME_ATTR file_name;/* $I30 index in directories. */
- SII_INDEX_KEY sii; /* $SII index in $Secure. */
- SDH_INDEX_KEY sdh; /* $SDH index in $Secure. */
- GUID object_id; /* $O index in FILE_Extend/$ObjId: The
- object_id of the mft record found in
- the data part of the index. */
- REPARSE_INDEX_KEY reparse; /* $R index in
- FILE_Extend/$Reparse. */
- SID sid; /* $O index in FILE_Extend/$Quota:
- SID of the owner of the user_id. */
- le32 owner_id; /* $Q index in FILE_Extend/$Quota:
- user_id of the owner of the quota
- control entry in the data part of
- the index. */
- } __attribute__ ((__packed__)) key;
- /* The (optional) index data is inserted here when creating. */
- // leVCN vcn; /* If INDEX_ENTRY_NODE bit in flags is set, the last
- // eight bytes of this index entry contain the virtual
- // cluster number of the index block that holds the
- // entries immediately preceding the current entry (the
- // vcn references the corresponding cluster in the data
- // of the non-resident index allocation attribute). If
- // the key_length is zero, then the vcn immediately
- // follows the INDEX_ENTRY_HEADER. Regardless of
- // key_length, the address of the 8-byte boundary
- // aligned vcn of INDEX_ENTRY{_HEADER} *ie is given by
- // (char*)ie + le16_to_cpu(ie*)->length) - sizeof(VCN),
- // where sizeof(VCN) can be hardcoded as 8 if wanted. */
-} __attribute__ ((__packed__)) INDEX_ENTRY;
-
-/*
- * Attribute: Bitmap (0xb0).
- *
- * Contains an array of bits (aka a bitfield).
- *
- * When used in conjunction with the index allocation attribute, each bit
- * corresponds to one index block within the index allocation attribute. Thus
- * the number of bits in the bitmap * index block size / cluster size is the
- * number of clusters in the index allocation attribute.
- */
-typedef struct {
- u8 bitmap[0]; /* Array of bits. */
-} __attribute__ ((__packed__)) BITMAP_ATTR;
+ __le16 data_offset; /*
+ * Data byte offset from this INDEX_ENTRY.
+ * Follows the index key.
+ */
+ __le16 data_length; /* Data length in bytes. */
+ __le32 reservedV; /* Reserved (zero). */
+ } __packed vi;
+ } __packed data;
+ __le16 length; /* Byte size of this index entry, multiple of 8-bytes. */
+ __le16 key_length; /*
+ * Byte size of the key value, which is in the index entry.
+ * It follows field reserved. Not multiple of 8-bytes.
+ */
+ __le16 flags; /* Bit field of INDEX_ENTRY_* flags. */
+ __le16 reserved; /* Reserved/align to 8-byte boundary. */
+
+ union {
+ /*
+ * The key of the indexed attribute. NOTE: Only present
+ * if INDEX_ENTRY_END bit in flags is not set. NOTE: On
+ * NTFS versions before 3.0 the only valid key is the
+ * struct file_name_attr. On NTFS 3.0+ the following
+ * additional index keys are defined:
+ */
+ struct file_name_attr file_name; /* $I30 index in directories. */
+ struct sii_index_key sii; /* $SII index in $Secure. */
+ struct sdh_index_key sdh; /* $SDH index in $Secure. */
+ struct guid object_id; /*
+ * $O index in FILE_Extend/$ObjId: The object_id
+ * of the mft record found in the data part of
+ * the index.
+ */
+ struct reparse_index_key reparse; /* $R index in FILE_Extend/$Reparse. */
+ struct ntfs_sid sid; /*
+ * $O index in FILE_Extend/$Quota:
+ * SID of the owner of the user_id.
+ */
+ __le32 owner_id; /*
+ * $Q index in FILE_Extend/$Quota:
+ * user_id of the owner of the quota
+ * control entry in the data part of
+ * the index.
+ */
+ } __packed key;
+ /*
+ * The (optional) index data is inserted here when creating.
+ * __le64 vcn; If INDEX_ENTRY_NODE bit in flags is set, the last
+ * eight bytes of this index entry contain the virtual
+ * cluster number of the index block that holds the
+ * entries immediately preceding the current entry (the
+ * vcn references the corresponding cluster in the data
+ * of the non-resident index allocation attribute). If
+ * the key_length is zero, then the vcn immediately
+ * follows the INDEX_ENTRY_HEADER. Regardless of
+ * key_length, the address of the 8-byte boundary
+ * aligned vcn of INDEX_ENTRY{_HEADER} *ie is given by
+ * (char*)ie + le16_to_cpu(ie*)->length) - sizeof(VCN),
+ * where sizeof(VCN) can be hardcoded as 8 if wanted.
+ */
+} __packed;
/*
* The reparse point tag defines the type of the reparse point. It also
@@ -2294,21 +2169,25 @@ typedef struct {
*
* The reparse point tag is an unsigned 32-bit value divided in three parts:
*
- * 1. The least significant 16 bits (i.e. bits 0 to 15) specifiy the type of
+ * 1. The least significant 16 bits (i.e. bits 0 to 15) specify the type of
* the reparse point.
- * 2. The 13 bits after this (i.e. bits 16 to 28) are reserved for future use.
- * 3. The most significant three bits are flags describing the reparse point.
+ * 2. The 12 bits after this (i.e. bits 16 to 27) are reserved for future use.
+ * 3. The most significant four bits are flags describing the reparse point.
* They are defined as follows:
+ * bit 28: Directory bit. If set, the directory is not a surrogate
+ * and can be used the usual way.
* bit 29: Name surrogate bit. If set, the filename is an alias for
* another object in the system.
* bit 30: High-latency bit. If set, accessing the first byte of data will
* be slow. (E.g. the data is stored on a tape drive.)
* bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
* defined tags have to use zero here.
- *
- * These are the predefined reparse point tags:
+ * 4. Moreover, on Windows 10 :
+ * Some flags may be used in bits 12 to 15 to further describe the
+ * reparse point.
*/
enum {
+ IO_REPARSE_TAG_DIRECTORY = cpu_to_le32(0x10000000),
IO_REPARSE_TAG_IS_ALIAS = cpu_to_le32(0x20000000),
IO_REPARSE_TAG_IS_HIGH_LATENCY = cpu_to_le32(0x40000000),
IO_REPARSE_TAG_IS_MICROSOFT = cpu_to_le32(0x80000000),
@@ -2317,18 +2196,31 @@ enum {
IO_REPARSE_TAG_RESERVED_ONE = cpu_to_le32(0x00000001),
IO_REPARSE_TAG_RESERVED_RANGE = cpu_to_le32(0x00000001),
- IO_REPARSE_TAG_NSS = cpu_to_le32(0x68000005),
- IO_REPARSE_TAG_NSS_RECOVER = cpu_to_le32(0x68000006),
- IO_REPARSE_TAG_SIS = cpu_to_le32(0x68000007),
- IO_REPARSE_TAG_DFS = cpu_to_le32(0x68000008),
-
- IO_REPARSE_TAG_MOUNT_POINT = cpu_to_le32(0x88000003),
-
- IO_REPARSE_TAG_HSM = cpu_to_le32(0xa8000004),
-
- IO_REPARSE_TAG_SYMBOLIC_LINK = cpu_to_le32(0xe8000000),
-
- IO_REPARSE_TAG_VALID_VALUES = cpu_to_le32(0xe000ffff),
+ IO_REPARSE_TAG_CSV = cpu_to_le32(0x80000009),
+ IO_REPARSE_TAG_DEDUP = cpu_to_le32(0x80000013),
+ IO_REPARSE_TAG_DFS = cpu_to_le32(0x8000000A),
+ IO_REPARSE_TAG_DFSR = cpu_to_le32(0x80000012),
+ IO_REPARSE_TAG_HSM = cpu_to_le32(0xC0000004),
+ IO_REPARSE_TAG_HSM2 = cpu_to_le32(0x80000006),
+ IO_REPARSE_TAG_MOUNT_POINT = cpu_to_le32(0xA0000003),
+ IO_REPARSE_TAG_NFS = cpu_to_le32(0x80000014),
+ IO_REPARSE_TAG_SIS = cpu_to_le32(0x80000007),
+ IO_REPARSE_TAG_SYMLINK = cpu_to_le32(0xA000000C),
+ IO_REPARSE_TAG_WIM = cpu_to_le32(0x80000008),
+ IO_REPARSE_TAG_DFM = cpu_to_le32(0x80000016),
+ IO_REPARSE_TAG_WOF = cpu_to_le32(0x80000017),
+ IO_REPARSE_TAG_WCI = cpu_to_le32(0x80000018),
+ IO_REPARSE_TAG_CLOUD = cpu_to_le32(0x9000001A),
+ IO_REPARSE_TAG_APPEXECLINK = cpu_to_le32(0x8000001B),
+ IO_REPARSE_TAG_GVFS = cpu_to_le32(0x9000001C),
+ IO_REPARSE_TAG_LX_SYMLINK = cpu_to_le32(0xA000001D),
+ IO_REPARSE_TAG_AF_UNIX = cpu_to_le32(0x80000023),
+ IO_REPARSE_TAG_LX_FIFO = cpu_to_le32(0x80000024),
+ IO_REPARSE_TAG_LX_CHR = cpu_to_le32(0x80000025),
+ IO_REPARSE_TAG_LX_BLK = cpu_to_le32(0x80000026),
+
+ IO_REPARSE_TAG_VALID_VALUES = cpu_to_le32(0xf000ffff),
+ IO_REPARSE_PLUGIN_SELECT = cpu_to_le32(0xffff0fff),
};
/*
@@ -2336,40 +2228,42 @@ enum {
*
* NOTE: Can be resident or non-resident.
*/
-typedef struct {
- le32 reparse_tag; /* Reparse point type (inc. flags). */
- le16 reparse_data_length; /* Byte size of reparse data. */
- le16 reserved; /* Align to 8-byte boundary. */
+struct reparse_point {
+ __le32 reparse_tag; /* Reparse point type (inc. flags). */
+ __le16 reparse_data_length; /* Byte size of reparse data. */
+ __le16 reserved; /* Align to 8-byte boundary. */
u8 reparse_data[0]; /* Meaning depends on reparse_tag. */
-} __attribute__ ((__packed__)) REPARSE_POINT;
+} __packed;
/*
* Attribute: Extended attribute (EA) information (0xd0).
*
* NOTE: Always resident. (Is this true???)
*/
-typedef struct {
- le16 ea_length; /* Byte size of the packed extended
- attributes. */
- le16 need_ea_count; /* The number of extended attributes which have
- the NEED_EA bit set. */
- le32 ea_query_length; /* Byte size of the buffer required to query
- the extended attributes when calling
- ZwQueryEaFile() in Windows NT/2k. I.e. the
- byte size of the unpacked extended
- attributes. */
-} __attribute__ ((__packed__)) EA_INFORMATION;
+struct ea_information {
+ __le16 ea_length; /* Byte size of the packed extended attributes. */
+ __le16 need_ea_count; /*
+ * The number of extended attributes which have
+ * the NEED_EA bit set.
+ */
+ __le32 ea_query_length; /*
+ * Byte size of the buffer required to query
+ * the extended attributes when calling
+ * ZwQueryEaFile() in Windows NT/2k. I.e.
+ * the byte size of the unpacked extended attributes.
+ */
+} __packed;
/*
* Extended attribute flags (8-bit).
*/
enum {
- NEED_EA = 0x80 /* If set the file to which the EA belongs
- cannot be interpreted without understanding
- the associates extended attributes. */
-} __attribute__ ((__packed__));
-
-typedef u8 EA_FLAGS;
+ NEED_EA = 0x80 /*
+ * If set the file to which the EA belongs
+ * cannot be interpreted without understanding
+ * the associates extended attributes.
+ */
+} __packed;
/*
* Attribute: Extended attribute (EA) (0xe0).
@@ -2379,43 +2273,19 @@ typedef u8 EA_FLAGS;
* Like the attribute list and the index buffer list, the EA attribute value is
* a sequence of EA_ATTR variable length records.
*/
-typedef struct {
- le32 next_entry_offset; /* Offset to the next EA_ATTR. */
- EA_FLAGS flags; /* Flags describing the EA. */
- u8 ea_name_length; /* Length of the name of the EA in bytes
- excluding the '\0' byte terminator. */
- le16 ea_value_length; /* Byte size of the EA's value. */
- u8 ea_name[0]; /* Name of the EA. Note this is ASCII, not
- Unicode and it is zero terminated. */
- u8 ea_value[0]; /* The value of the EA. Immediately follows
- the name. */
-} __attribute__ ((__packed__)) EA_ATTR;
-
-/*
- * Attribute: Property set (0xf0).
- *
- * Intended to support Native Structure Storage (NSS) - a feature removed from
- * NTFS 3.0 during beta testing.
- */
-typedef struct {
- /* Irrelevant as feature unused. */
-} __attribute__ ((__packed__)) PROPERTY_SET;
-
-/*
- * Attribute: Logged utility stream (0x100).
- *
- * NOTE: Can be resident or non-resident.
- *
- * Operations on this attribute are logged to the journal ($LogFile) like
- * normal metadata changes.
- *
- * Used by the Encrypting File System (EFS). All encrypted files have this
- * attribute with the name $EFS.
- */
-typedef struct {
- /* Can be anything the creator chooses. */
- /* EFS uses it as follows: */
- // FIXME: Type this info, verifying it along the way. (AIA)
-} __attribute__ ((__packed__)) LOGGED_UTILITY_STREAM, EFS_ATTR;
+struct ea_attr {
+ __le32 next_entry_offset; /* Offset to the next EA_ATTR. */
+ u8 flags; /* Flags describing the EA. */
+ u8 ea_name_length; /*
+ * Length of the name of the EA in bytes
+ * excluding the '\0' byte terminator.
+ */
+ __le16 ea_value_length; /* Byte size of the EA's value. */
+ u8 ea_name[]; /*
+ * Name of the EA. Note this is ASCII, not
+ * Unicode and it is zero terminated.
+ */
+ /* u8 ea_value[]; */ /* The value of the EA. Immediately follows the name. */
+} __packed;
#endif /* _LINUX_NTFS_LAYOUT_H */
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
index 1589a6d8434b..a1c66b8b73ac 100644
--- a/fs/ntfs/lcnalloc.h
+++ b/fs/ntfs/lcnalloc.h
@@ -1,7 +1,7 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* Copyright (c) 2004-2005 Anton Altaparmakov
*/
@@ -9,30 +9,25 @@
#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 {
+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;
-
-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);
+};
-extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
- s64 count, ntfs_attr_search_ctx *ctx, const bool is_rollback);
+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);
/**
* ntfs_cluster_free - free clusters on an ntfs volume
@@ -90,14 +85,14 @@ 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
@@ -115,17 +110,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 */
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h
index 429d4909cc72..3c7e42425503 100644
--- a/fs/ntfs/logfile.h
+++ b/fs/ntfs/logfile.h
@@ -1,7 +1,7 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2005 Anton Altaparmakov
*/
@@ -9,16 +9,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,7 +36,7 @@
* 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
@@ -50,40 +44,42 @@
/*
* Log file restart page header (begins the restart area).
*/
-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. */
+struct restart_page_header {
+ __le32 magic; /* The magic is "RSTR". */
+ __le16 usa_ofs; /*
+ * See ntfs_record struct definition in layout.h.
+ * When creating, set this to be immediately after
+ * this header structure (without any alignment).
+ */
+ __le16 usa_count; /* See ntfs_record struct 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. */
+ __le64 chkdsk_lsn; /*
+ * The last log file sequence number found by chkdsk.
+ * Only used when the magic is changed to "CHKD".
+ * Otherwise this is zero.
+ */
+ __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.
+ */
+ __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.
+ */
+ __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.
+ */
+ __le16 minor_ver; /* Log file minor version. Only check if major version is 1. */
+ __le16 major_ver; /* Log file major version. We only support version 1.1. */
/* sizeof() = 30 (0x1e) bytes */
-} __attribute__ ((__packed__)) RESTART_PAGE_HEADER;
+} __packed;
/*
* Constant for the log client indices meaning that there are no client records
@@ -100,196 +96,221 @@ typedef struct {
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;
+} __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.
*/
-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. */
+struct restart_area {
+ __le64 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.
+ */
+ __le16 log_clients; /*
+ * Number of log client records in the array of
+ * log client records which follows this
+ * restart area. Must be 1.
+ */
+ __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.
+ */
+ __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.
+ */
+ __le16 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.
+ */
+ __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.
+ */
+ __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)).
+ */
+ __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.
+ */
+ __le64 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.
+ */
+ __le32 last_lsn_data_length; /*
+ * Length of data of last LSN, not including
+ * the log record header. On create set to 0.
+ */
+ __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.
+ */
+ __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.
+ */
+ __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).
+ */
+ __le32 reserved; /* Reserved/alignment to 8-byte boundary. */
/* sizeof() = 48 (0x30) bytes */
-} __attribute__ ((__packed__)) RESTART_AREA;
+} __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.
*/
-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. */
+struct log_client_record {
+ __le64 oldest_lsn; /*
+ * Oldest LSN needed by this client. On create
+ * set to 0.
+ */
+ __le64 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.
+ */
+ __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.
+ */
+ __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.
+ */
+ __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.
+ */
+ u8 reserved[6]; /* Reserved/alignment. */
+ __le32 client_name_length; /* Length of client name in bytes. Should always be 8. */
+ __le16 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 */
+} __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 */
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h
index 7068425735f1..52afe4e1ffcc 100644
--- a/fs/ntfs/malloc.h
+++ b/fs/ntfs/malloc.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project.
+ * NTFS kernel memory handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
*/
@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/highmem.h>
+#include <linux/version.h>
/**
* __ntfs_malloc - allocate memory in multiples of pages
@@ -28,9 +29,10 @@
static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask)
{
if (likely(size <= PAGE_SIZE)) {
- BUG_ON(!size);
+ if (!size)
+ return NULL;
/* kmalloc() has per-CPU caches so is faster for now. */
- return kmalloc(PAGE_SIZE, gfp_mask & ~__GFP_HIGHMEM);
+ return kmalloc(PAGE_SIZE, gfp_mask);
/* return (void *)__get_free_page(gfp_mask); */
}
if (likely((size >> PAGE_SHIFT) < totalram_pages()))
@@ -49,7 +51,7 @@ static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask)
*/
static inline void *ntfs_malloc_nofs(unsigned long size)
{
- return __ntfs_malloc(size, GFP_NOFS | __GFP_HIGHMEM);
+ return __ntfs_malloc(size, GFP_NOFS | __GFP_ZERO);
}
/**
@@ -66,7 +68,7 @@ static inline void *ntfs_malloc_nofs(unsigned long size)
*/
static inline void *ntfs_malloc_nofs_nofail(unsigned long size)
{
- return __ntfs_malloc(size, GFP_NOFS | __GFP_HIGHMEM | __GFP_NOFAIL);
+ return __ntfs_malloc(size, GFP_NOFS | __GFP_NOFAIL);
}
static inline void ntfs_free(void *addr)
@@ -74,4 +76,25 @@ static inline void ntfs_free(void *addr)
kvfree(addr);
}
+static inline void *ntfs_realloc_nofs(void *addr, unsigned long new_size,
+ unsigned long cpy_size)
+{
+ void *pnew_addr;
+
+ if (new_size == 0) {
+ ntfs_free(addr);
+ return NULL;
+ }
+
+ pnew_addr = ntfs_malloc_nofs(new_size);
+ if (pnew_addr == NULL)
+ return NULL;
+ if (addr) {
+ cpy_size = min(cpy_size, new_size);
+ if (cpy_size)
+ memcpy(pnew_addr, addr, cpy_size);
+ ntfs_free(addr);
+ }
+ return pnew_addr;
+}
#endif /* _LINUX_NTFS_MALLOC_H */
diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
index 49c001af16ed..cce944242f89 100644
--- a/fs/ntfs/mft.h
+++ b/fs/ntfs/mft.h
@@ -1,7 +1,7 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
*/
@@ -9,41 +9,22 @@
#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
-
-/**
- * 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);
+void __mark_mft_record_dirty(struct ntfs_inode *ni);
/**
* mark_mft_record_dirty - set the mft record and the page containing it dirty
@@ -56,16 +37,15 @@ 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);
-
-extern int write_mft_record_nolock(ntfs_inode *ni, 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);
/**
* write_mft_record - write out a mapped (extent) mft record
@@ -85,26 +65,28 @@ 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);
+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);
#endif /* _LINUX_NTFS_MFT_H */
diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
index e81376ea9152..00720645fae9 100644
--- a/fs/ntfs/ntfs.h
+++ b/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
@@ -17,20 +18,59 @@
#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
+
+#define NTFS_DEF_PREALLOC_SIZE (64*1024*1024)
+
+#define STANDARD_COMPRESSION_UNIT 4
+#define MAX_COMPRESSION_CLUSTER_SIZE 4096
+
+#define UCHAR_T_SIZE_BITS 1
+
+#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,
+};
/* Global variables. */
@@ -42,12 +82,12 @@ 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 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 ntfsp_special_inode_operations;
extern const struct file_operations ntfs_dir_ops;
extern const struct inode_operations ntfs_dir_inode_ops;
@@ -63,7 +103,7 @@ extern const struct export_operations ntfs_export_ops;
*
* 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 +111,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 ntfsp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long ntfsp_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,10 +192,8 @@ static inline int ntfs_ffs(int x)
x >>= 2;
r += 2;
}
- if (!(x & 1)) {
- x >>= 1;
+ if (!(x & 1))
r += 1;
- }
return r;
}
diff --git a/fs/ntfs/quota.h b/fs/ntfs/quota.h
index fe3132a3d6d2..7d70a0f5aa0e 100644
--- a/fs/ntfs/quota.h
+++ b/fs/ntfs/quota.h
@@ -1,7 +1,7 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* Copyright (c) 2004 Anton Altaparmakov
*/
@@ -9,13 +9,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 */
diff --git a/fs/ntfs/reparse.h b/fs/ntfs/reparse.h
new file mode 100644
index 000000000000..a1f3829a89da
--- /dev/null
+++ b/fs/ntfs/reparse.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/**
+ * Copyright (c) 2008-2021 Jean-Pierre Andre
+ * Copyright (c) 2025 LG Electronics Co., Ltd.
+ */
+
+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);
diff --git a/fs/ntfs/runlist.h b/fs/ntfs/runlist.h
index 38de0a375f59..cac8b5a26a79 100644
--- a/fs/ntfs/runlist.h
+++ b/fs/ntfs/runlist.h
@@ -1,17 +1,16 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* 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"
/**
@@ -25,64 +24,70 @@
* 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).
*/
-typedef struct { /* In memory vcn to lcn mapping structure element. */
- VCN vcn; /* vcn = Starting virtual cluster number. */
- LCN lcn; /* lcn = Starting logical cluster number. */
+struct runlist_element { /* In memory vcn to lcn mapping structure element. */
+ s64 vcn; /* vcn = Starting virtual cluster number. */
+ s64 lcn; /* lcn = Starting logical cluster number. */
s64 length; /* Run length in clusters. */
-} runlist_element;
+};
/**
* 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 */
diff --git a/fs/ntfs/sysctl.h b/fs/ntfs/sysctl.h
index 96bb2299d2d5..50fa1095ad7f 100644
--- a/fs/ntfs/sysctl.h
+++ b/fs/ntfs/sysctl.h
@@ -1,9 +1,9 @@
/* 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. Part of
+ * the Linux-NTFS project. Adapted from the old NTFS driver.
*
+ * Copyright (C) 1997 Martin von Löwis, Régis Duchesne
* Copyright (c) 2002-2004 Anton Altaparmakov
*/
@@ -13,7 +13,7 @@
#if defined(DEBUG) && defined(CONFIG_SYSCTL)
-extern int ntfs_sysctl(int add);
+int ntfs_sysctl(int add);
#else
diff --git a/fs/ntfs/time.h b/fs/ntfs/time.h
index 6b63261300cc..0d56ae5dc0c5 100644
--- a/fs/ntfs/time.h
+++ b/fs/ntfs/time.h
@@ -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. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
*/
@@ -8,11 +8,9 @@
#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 * 10000000)
/**
@@ -31,13 +29,13 @@
* 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 +
+ return cpu_to_le64((s64)ts.tv_sec * 10000000 + ts.tv_nsec / 100 +
NTFS_TIME_OFFSET);
}
@@ -47,7 +45,7 @@ static inline sle64 utc2ntfs(const struct timespec64 ts)
* 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;
@@ -71,12 +69,12 @@ 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;
/* Subtract the NTFS time offset. */
- u64 t = (u64)(sle64_to_cpu(time) - NTFS_TIME_OFFSET);
+ u64 t = (u64)(le64_to_cpu(time) - NTFS_TIME_OFFSET);
/*
* Convert the time to 1-second intervals and the remainder to
* 1-nano-second intervals.
diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h
index 930a9ae8a053..b934c88e5e11 100644
--- a/fs/ntfs/volume.h
+++ b/fs/ntfs/volume.h
@@ -1,45 +1,47 @@
/* 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.
+ * Part of the Linux-NTFS project.
*
* 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.
*/
-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)
- */
+struct ntfs_volume {
/* 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. */
+ s64 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. */
+ 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. */
+ errseq_t wb_err;
/* NTFS bootsector provided information. */
u16 sector_size; /* in bytes */
u8 sector_size_bits; /* log2(sector_size) */
@@ -52,104 +54,126 @@ typedef struct {
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. */
+ s64 nr_clusters; /*
+ * Volume size in clusters == number of
+ * bits in lcn bitmap.
+ */
+ s64 mft_lcn; /* Cluster location of mft data. */
+ s64 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. */
+ __le16 *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. */
+ s32 attrdef_size; /* Size of the attribute definition table in bytes. */
+ struct 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 */
+ s64 mft_data_pos; /*
+ * Mft record number at which to
+ * allocate the next mft record.
+ */
+ s64 mft_zone_start; /* First cluster of the mft zone. */
+ s64 mft_zone_end; /* First cluster beyond the mft zone. */
+ s64 mft_zone_pos; /* Current position in the mft zone. */
+ s64 data1_zone_pos; /* Current position in the first data zone. */
+ s64 data2_zone_pos; /* Current position in the second data zone. */
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 rw_semaphore mftbmp_lock; /*
+ * Lock for serializing accesses to the
+ * mft record bitmap ($MFT/$BITMAP).
+ */
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 *logfile_ino; /* The VFS inode of LogFile. */
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 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. */
+ __le16 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
+ unsigned char *volume_label;
+
+ 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).
+ */
/* $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 nls_table *nls_map;
-} ntfs_volume;
+ bool nls_utf8;
+ wait_queue_head_t free_waitq;
+
+ atomic64_t free_clusters; /* Track the number of free clusters */
+ atomic64_t free_mft_records; /* Track the 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.
*/
-typedef enum {
+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;
+ 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_ReadOnly,
+ NV_Compression,
+ NV_FreeClusterKnown,
+ NV_Shutdown,
+ NV_SysImmutable, /* 1: Protect system files from deletion. */
+ NV_ShowHiddenFiles, /* 1: Return hidden files in ntfs_readdir(). */
+ 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 +183,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 */
diff --git a/include/uapi/linux/ntfs.h b/include/uapi/linux/ntfs.h
new file mode 100644
index 000000000000..e76957285280
--- /dev/null
+++ b/include/uapi/linux/ntfs.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2025 LG Electronics Co., Ltd.
+ */
+
+#ifndef _UAPI_LINUX_NTFS_H
+#define _UAPI_LINUX_NTFS_H
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/*
+ * ntfs-specific ioctl commands
+ */
+#define NTFS_IOC_SHUTDOWN _IOR('X', 125, __u32)
+
+/*
+ * Flags used by NTFS_IOC_SHUTDOWN
+ */
+#define NTFS_GOING_DOWN_DEFAULT 0x0 /* default with full sync */
+#define NTFS_GOING_DOWN_FULLSYNC 0x1 /* going down with full sync*/
+#define NTFS_GOING_DOWN_NOSYNC 0x2 /* going down */
+
+#endif /* _UAPI_LINUX_NTFS_H */
--
2.25.1
Powered by blists - more mailing lists