]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ntfs: update misc operations
authorNamjae Jeon <linkinjeon@kernel.org>
Fri, 13 Feb 2026 01:49:27 +0000 (10:49 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Thu, 19 Feb 2026 12:50:56 +0000 (21:50 +0900)
Updates various miscellaneous operations including collation,
debugging, logfile handling, unicode string processing, bdev io helpers,
object id system file handling.

Acked-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/bdev-io.c [new file with mode: 0644]
fs/ntfs/collate.c
fs/ntfs/debug.c
fs/ntfs/logfile.c
fs/ntfs/object_id.c [new file with mode: 0644]
fs/ntfs/quota.c
fs/ntfs/sysctl.c
fs/ntfs/unistr.c
fs/ntfs/upcase.c
fs/ntfs/usnjrnl.c [deleted file]
fs/ntfs/usnjrnl.h [deleted file]

diff --git a/fs/ntfs/bdev-io.c b/fs/ntfs/bdev-io.c
new file mode 100644 (file)
index 0000000..67e65c8
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * NTFS block device I/O.
+ *
+ * Copyright (c) 2026 LG Electronics Co., Ltd.
+ */
+
+#include <linux/blkdev.h>
+
+#include "ntfs.h"
+
+/*
+ * ntfs_bdev_read - Read data directly from block device using bio
+ * @bdev:      block device to read from
+ * @data:      destination buffer
+ * @start:     starting byte offset on the block device
+ * @size:      number of bytes to read
+ *
+ * Reads @size bytes starting from byte offset @start directly from the block
+ * device using one or more BIOs. This function bypasses the page cache
+ * completely and performs synchronous I/O with REQ_META | REQ_SYNC flags set.
+ *
+ * The @start offset must be sector-aligned (512 bytes). If it is not aligned,
+ * the function will return -EINVAL.
+ *
+ * If the destination buffer @data is not a vmalloc address, it falls back
+ * to the more efficient bdev_rw_virt() helper.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int ntfs_bdev_read(struct block_device *bdev, char *data, loff_t start, size_t size)
+{
+       unsigned int done = 0, added;
+       int error;
+       struct bio *bio;
+       enum req_op op;
+       sector_t sector = start >> SECTOR_SHIFT;
+
+       if (start & (SECTOR_SIZE - 1))
+               return -EINVAL;
+
+       op = REQ_OP_READ | REQ_META | REQ_SYNC;
+       if (!is_vmalloc_addr(data))
+               return bdev_rw_virt(bdev, sector, data, size, op);
+
+       bio = bio_alloc(bdev,
+                       bio_max_segs(DIV_ROUND_UP(size, PAGE_SIZE)),
+                       op, GFP_KERNEL);
+       bio->bi_iter.bi_sector = sector;
+
+       do {
+               added = bio_add_vmalloc_chunk(bio, data + done, size - done);
+               if (!added) {
+                       struct bio      *prev = bio;
+
+                       bio = bio_alloc(prev->bi_bdev,
+                                       bio_max_segs(DIV_ROUND_UP(size - done, PAGE_SIZE)),
+                                       prev->bi_opf, GFP_KERNEL);
+                       bio->bi_iter.bi_sector = bio_end_sector(prev);
+                       bio_chain(prev, bio);
+                       submit_bio(prev);
+               }
+               done += added;
+       } while (done < size);
+
+       error = submit_bio_wait(bio);
+       bio_put(bio);
+
+       if (op == REQ_OP_READ)
+               invalidate_kernel_vmap_range(data, size);
+       return error;
+}
+
+/*
+ * ntfs_bdev_write - Update block device contents via page cache
+ * @sb:                super block of the mounted NTFS filesystem
+ * @buf:       source buffer containing data to write
+ * @start:     starting byte offset on the block device
+ * @size:      number of bytes to write
+ *
+ * Writes @size bytes from @buf to the block device (sb->s_bdev) starting
+ * at byte offset @start. The write is performed entirely through the page
+ * cache of the block device's address space.
+ */
+int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size)
+{
+       pgoff_t idx, idx_end;
+       loff_t offset, end = start + size;
+       u32 from, to, buf_off = 0;
+       struct folio *folio;
+
+       idx = start >> PAGE_SHIFT;
+       idx_end = end >> PAGE_SHIFT;
+       from = start & ~PAGE_MASK;
+
+       if (idx == idx_end)
+               idx_end++;
+
+       for (; idx < idx_end; idx++, from = 0) {
+               folio = read_mapping_folio(sb->s_bdev->bd_mapping, idx, NULL);
+               if (IS_ERR(folio)) {
+                       ntfs_error(sb, "Unable to read %ld page", idx);
+                       return PTR_ERR(folio);
+               }
+
+               offset = (loff_t)idx << PAGE_SHIFT;
+               to = min_t(u32, end - offset, PAGE_SIZE);
+
+               memcpy_to_folio(folio, from, buf + buf_off, to);
+               buf_off += to;
+               folio_mark_uptodate(folio);
+               folio_mark_dirty(folio);
+               folio_put(folio);
+       }
+
+       return 0;
+}
index 3ab6ec96abfe2aa7ad4adef525c3e5e5a0b5f0b8..77e34038902d1375d19f88170d1a4f39b4b7df87 100644 (file)
@@ -1,21 +1,27 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * collate.c - NTFS kernel collation handling.  Part of the Linux-NTFS project.
+ * NTFS kernel collation handling.
  *
  * Copyright (c) 2004 Anton Altaparmakov
+ *
+ * Part of this file is based on code from the NTFS-3G.
+ * and is copyrighted by the respective authors below:
+ * Copyright (c) 2004 Anton Altaparmakov
+ * Copyright (c) 2005 Yura Pakhuchiy
  */
 
 #include "collate.h"
 #include "debug.h"
 #include "ntfs.h"
 
-static int ntfs_collate_binary(ntfs_volume *vol,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len)
+#include <linux/sort.h>
+
+static int ntfs_collate_binary(struct ntfs_volume *vol,
+               const void *data1, const u32 data1_len,
+               const void *data2, const u32 data2_len)
 {
        int rc;
 
-       ntfs_debug("Entering.");
        rc = memcmp(data1, data2, min(data1_len, data2_len));
        if (!rc && (data1_len != data2_len)) {
                if (data1_len < data2_len)
@@ -23,23 +29,19 @@ static int ntfs_collate_binary(ntfs_volume *vol,
                else
                        rc = 1;
        }
-       ntfs_debug("Done, returning %i", rc);
        return rc;
 }
 
-static int ntfs_collate_ntofs_ulong(ntfs_volume *vol,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len)
+static int ntfs_collate_ntofs_ulong(struct ntfs_volume *vol,
+               const void *data1, const u32 data1_len,
+               const void *data2, const u32 data2_len)
 {
        int rc;
-       u32 d1, d2;
+       u32 d1 = le32_to_cpup(data1), d2 = le32_to_cpup(data2);
+
+       if (data1_len != data2_len || data1_len != 4)
+               return -EINVAL;
 
-       ntfs_debug("Entering.");
-       // FIXME:  We don't really want to bug here.
-       BUG_ON(data1_len != data2_len);
-       BUG_ON(data1_len != 4);
-       d1 = le32_to_cpup(data1);
-       d2 = le32_to_cpup(data2);
        if (d1 < d2)
                rc = -1;
        else {
@@ -48,27 +50,65 @@ static int ntfs_collate_ntofs_ulong(ntfs_volume *vol,
                else
                        rc = 1;
        }
-       ntfs_debug("Done, returning %i", rc);
        return rc;
 }
 
-typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, const int,
-               const void *, const int);
+/*
+ * ntfs_collate_ntofs_ulongs - Which of two le32 arrays should be listed first
+ * @vol: ntfs volume
+ * @data1: first ulong array to collate
+ * @data1_len: length in bytes of @data1
+ * @data2: second ulong array to collate
+ * @data2_len: length in bytes of @data2
+ *
+ * Returns: -1, 0 or 1 depending of how the arrays compare
+ */
+static int ntfs_collate_ntofs_ulongs(struct ntfs_volume *vol,
+               const void *data1, const u32 data1_len,
+               const void *data2, const u32 data2_len)
+{
+       int len;
+       const __le32 *p1 = data1, *p2 = data2;
+       u32 d1, d2;
 
-static ntfs_collate_func_t ntfs_do_collate0x0[3] = {
-       ntfs_collate_binary,
-       NULL/*ntfs_collate_file_name*/,
-       NULL/*ntfs_collate_unicode_string*/,
-};
+       if (data1_len != data2_len || data1_len & 3) {
+               ntfs_error(vol->sb, "data1_len or data2_len not valid\n");
+               return -1;
+       }
 
-static ntfs_collate_func_t ntfs_do_collate0x1[4] = {
-       ntfs_collate_ntofs_ulong,
-       NULL/*ntfs_collate_ntofs_sid*/,
-       NULL/*ntfs_collate_ntofs_security_hash*/,
-       NULL/*ntfs_collate_ntofs_ulongs*/,
-};
+       len = data1_len;
+       do {
+               d1 = le32_to_cpup(p1);
+               p1++;
+               d2 = le32_to_cpup(p2);
+               p2++;
+       } while (d1 == d2 && (len -= 4) > 0);
+       return cmp_int(d1, d2);
+}
 
-/**
+/*
+ * ntfs_collate_file_name - Which of two filenames should be listed first
+ * @vol: ntfs volume
+ * @data1: first filename to collate
+ * @data1_len: length in bytes of @data1(unused)
+ * @data2: second filename to collate
+ * @data2_len: length in bytes of @data2(unused)
+ */
+static int ntfs_collate_file_name(struct ntfs_volume *vol,
+               const void *data1, const u32 data1_len,
+               const void *data2, const u32 data2_len)
+{
+       int rc;
+
+       rc = ntfs_file_compare_values(data1, data2, -EINVAL,
+                       IGNORE_CASE, vol->upcase, vol->upcase_len);
+       if (!rc)
+               rc = ntfs_file_compare_values(data1, data2,
+                       -EINVAL, CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+       return rc;
+}
+
+/*
  * ntfs_collate - collate two data items using a specified collation rule
  * @vol:       ntfs volume to which the data items belong
  * @cr:                collation rule to use when comparing the items
@@ -79,32 +119,28 @@ static ntfs_collate_func_t ntfs_do_collate0x1[4] = {
  *
  * Collate the two data items @data1 and @data2 using the collation rule @cr
  * and return -1, 0, ir 1 if @data1 is found, respectively, to collate before,
- * to match, or to collate after @data2.
- *
- * For speed we use the collation rule @cr as an index into two tables of
- * function pointers to call the appropriate collation function.
+ * to match, or to collate after @data2. return -EINVAL if an error occurred.
  */
-int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
-               const void *data1, const int data1_len,
-               const void *data2, const int data2_len) {
-       int i;
-
-       ntfs_debug("Entering.");
-       /*
-        * FIXME:  At the moment we only support COLLATION_BINARY and
-        * COLLATION_NTOFS_ULONG, so we BUG() for everything else for now.
-        */
-       BUG_ON(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG);
-       i = le32_to_cpu(cr);
-       BUG_ON(i < 0);
-       if (i <= 0x02)
-               return ntfs_do_collate0x0[i](vol, data1, data1_len,
-                               data2, data2_len);
-       BUG_ON(i < 0x10);
-       i -= 0x10;
-       if (likely(i <= 3))
-               return ntfs_do_collate0x1[i](vol, data1, data1_len,
-                               data2, data2_len);
-       BUG();
-       return 0;
+int ntfs_collate(struct ntfs_volume *vol, __le32 cr,
+               const void *data1, const u32 data1_len,
+               const void *data2, const u32 data2_len)
+{
+       switch (le32_to_cpu(cr)) {
+       case le32_to_cpu(COLLATION_BINARY):
+               return ntfs_collate_binary(vol, data1, data1_len,
+                                          data2, data2_len);
+       case le32_to_cpu(COLLATION_FILE_NAME):
+               return ntfs_collate_file_name(vol, data1, data1_len,
+                                             data2, data2_len);
+       case le32_to_cpu(COLLATION_NTOFS_ULONG):
+               return ntfs_collate_ntofs_ulong(vol, data1, data1_len,
+                                               data2, data2_len);
+       case le32_to_cpu(COLLATION_NTOFS_ULONGS):
+               return ntfs_collate_ntofs_ulongs(vol, data1, data1_len,
+                                                data2, data2_len);
+       default:
+               ntfs_error(vol->sb, "Unknown collation rule 0x%x",
+                          le32_to_cpu(cr));
+               return -EINVAL;
+       }
 }
index a3c1c5656f8f6988e473d6fd5b983a6e4d78479b..f241ebc97d374b0fb2e47bdb5bb0f53d9f0508ab 100644 (file)
@@ -1,13 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * debug.c - NTFS kernel debug support. Part of the Linux-NTFS project.
+ * NTFS kernel debug support.
  *
  * Copyright (c) 2001-2004 Anton Altaparmakov
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include "debug.h"
 
-/**
+/*
  * __ntfs_warning - output a warning to the syslog
  * @function:  name of function outputting the warning
  * @sb:                super block of mounted ntfs filesystem
@@ -33,24 +33,28 @@ void __ntfs_warning(const char *function, const struct super_block *sb,
        va_list args;
        int flen = 0;
 
-#ifndef DEBUG
-       if (!printk_ratelimit())
-               return;
-#endif
        if (function)
                flen = strlen(function);
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
+#ifdef DEBUG
        if (sb)
                pr_warn("(device %s): %s(): %pV\n",
                        sb->s_id, flen ? function : "", &vaf);
        else
                pr_warn("%s(): %pV\n", flen ? function : "", &vaf);
+#else
+       if (sb)
+               pr_warn_ratelimited("(device %s): %s(): %pV\n",
+                       sb->s_id, flen ? function : "", &vaf);
+       else
+               pr_warn_ratelimited("%s(): %pV\n", flen ? function : "", &vaf);
+#endif
        va_end(args);
 }
 
-/**
+/*
  * __ntfs_error - output an error to the syslog
  * @function:  name of function outputting the error
  * @sb:                super block of mounted ntfs filesystem
@@ -69,34 +73,41 @@ void __ntfs_warning(const char *function, const struct super_block *sb,
  * Note, you should be using debug.h::ntfs_error(@sb, @fmt, @...) instead
  * as this provides the @function parameter automatically.
  */
-void __ntfs_error(const char *function, const struct super_block *sb,
+void __ntfs_error(const char *function, struct super_block *sb,
                const char *fmt, ...)
 {
        struct va_format vaf;
        va_list args;
        int flen = 0;
 
-#ifndef DEBUG
-       if (!printk_ratelimit())
-               return;
-#endif
        if (function)
                flen = strlen(function);
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
+#ifdef DEBUG
        if (sb)
                pr_err("(device %s): %s(): %pV\n",
                       sb->s_id, flen ? function : "", &vaf);
        else
                pr_err("%s(): %pV\n", flen ? function : "", &vaf);
+#else
+       if (sb)
+               pr_err_ratelimited("(device %s): %s(): %pV\n",
+                      sb->s_id, flen ? function : "", &vaf);
+       else
+               pr_err_ratelimited("%s(): %pV\n", flen ? function : "", &vaf);
+#endif
        va_end(args);
+
+       if (sb)
+               ntfs_handle_error(sb);
 }
 
 #ifdef DEBUG
 
 /* If 1, output debug messages, and if 0, don't. */
-int debug_msgs = 0;
+int debug_msgs;
 
 void __ntfs_debug(const char *file, int line, const char *function,
                const char *fmt, ...)
@@ -117,11 +128,12 @@ void __ntfs_debug(const char *file, int line, const char *function,
 }
 
 /* Dump a runlist. Caller has to provide synchronisation for @rl. */
-void ntfs_debug_dump_runlist(const runlist_element *rl)
+void ntfs_debug_dump_runlist(const struct runlist_element *rl)
 {
        int i;
-       const char *lcn_str[5] = { "LCN_HOLE         ", "LCN_RL_NOT_MAPPED",
-                                  "LCN_ENOENT       ", "LCN_unknown      " };
+       const char *lcn_str[5] = { "LCN_DELALLOC     ", "LCN_HOLE         ",
+                                  "LCN_RL_NOT_MAPPED", "LCN_ENOENT       ",
+                                  "LCN_unknown      " };
 
        if (!debug_msgs)
                return;
@@ -132,9 +144,9 @@ void ntfs_debug_dump_runlist(const runlist_element *rl)
        }
        pr_debug("VCN              LCN               Run length\n");
        for (i = 0; ; i++) {
-               LCN lcn = (rl + i)->lcn;
+               s64 lcn = (rl + i)->lcn;
 
-               if (lcn < (LCN)0) {
+               if (lcn < 0) {
                        int index = -lcn - 1;
 
                        if (index > -LCN_ENOENT - 1)
index 6ce60ffc6ac0497304f1dd2bcb8b1589d252bcb8..3f8d1640f1d501d4ac7407feeab0826ad0cd56e0 100644 (file)
@@ -1,31 +1,19 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
+ * NTFS kernel journal handling.
  *
  * Copyright (c) 2002-2007 Anton Altaparmakov
  */
 
-#ifdef NTFS_RW
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/highmem.h>
-#include <linux/buffer_head.h>
-#include <linux/bitops.h>
-#include <linux/log2.h>
-#include <linux/bio.h>
+#include <linux/blkdev.h>
 
 #include "attrib.h"
-#include "aops.h"
-#include "debug.h"
 #include "logfile.h"
-#include "malloc.h"
-#include "volume.h"
 #include "ntfs.h"
 
-/**
+/*
  * ntfs_check_restart_page_header - check the page header for consistency
- * @vi:                $LogFile inode to which the restart page header belongs
+ * @vi:                LogFile inode to which the restart page header belongs
  * @rp:                restart page header to check
  * @pos:       position in @vi at which the restart page header resides
  *
@@ -36,7 +24,7 @@
  * require the full restart page.
  */
 static bool ntfs_check_restart_page_header(struct inode *vi,
-               RESTART_PAGE_HEADER *rp, s64 pos)
+               struct restart_page_header *rp, s64 pos)
 {
        u32 logfile_system_page_size, logfile_log_page_size;
        u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
@@ -54,7 +42,7 @@ static bool ntfs_check_restart_page_header(struct inode *vi,
                        logfile_system_page_size &
                        (logfile_system_page_size - 1) ||
                        !is_power_of_2(logfile_log_page_size)) {
-               ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
+               ntfs_error(vi->i_sb, "LogFile uses unsupported page size.");
                return false;
        }
        /*
@@ -62,17 +50,16 @@ static bool ntfs_check_restart_page_header(struct inode *vi,
         * size (2nd restart page).
         */
        if (pos && pos != logfile_system_page_size) {
-               ntfs_error(vi->i_sb, "Found restart area in incorrect "
-                               "position in $LogFile.");
+               ntfs_error(vi->i_sb, "Found restart area in incorrect position in LogFile.");
                return false;
        }
        /* We only know how to handle version 1.1. */
-       if (sle16_to_cpu(rp->major_ver) != 1 ||
-                       sle16_to_cpu(rp->minor_ver) != 1) {
-               ntfs_error(vi->i_sb, "$LogFile version %i.%i is not "
-                               "supported.  (This driver supports version "
-                               "1.1 only.)", (int)sle16_to_cpu(rp->major_ver),
-                               (int)sle16_to_cpu(rp->minor_ver));
+       if (le16_to_cpu(rp->major_ver) != 1 ||
+           le16_to_cpu(rp->minor_ver) != 1) {
+               ntfs_error(vi->i_sb,
+                       "LogFile version %i.%i is not supported.  (This driver supports version 1.1 only.)",
+                       (int)le16_to_cpu(rp->major_ver),
+                       (int)le16_to_cpu(rp->minor_ver));
                return false;
        }
        /*
@@ -86,17 +73,17 @@ static bool ntfs_check_restart_page_header(struct inode *vi,
        /* Verify the size of the update sequence array. */
        usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
        if (usa_count != le16_to_cpu(rp->usa_count)) {
-               ntfs_error(vi->i_sb, "$LogFile restart page specifies "
-                               "inconsistent update sequence array count.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart page specifies inconsistent update sequence array count.");
                return false;
        }
        /* Verify the position of the update sequence array. */
        usa_ofs = le16_to_cpu(rp->usa_ofs);
        usa_end = usa_ofs + usa_count * sizeof(u16);
-       if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
+       if (usa_ofs < sizeof(struct restart_page_header) ||
                        usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
-               ntfs_error(vi->i_sb, "$LogFile restart page specifies "
-                               "inconsistent update sequence array offset.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart page specifies inconsistent update sequence array offset.");
                return false;
        }
 skip_usa_checks:
@@ -108,28 +95,28 @@ skip_usa_checks:
         */
        ra_ofs = le16_to_cpu(rp->restart_area_offset);
        if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
-                       ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
+                       ra_ofs < sizeof(struct restart_page_header)) ||
                        ra_ofs > logfile_system_page_size) {
-               ntfs_error(vi->i_sb, "$LogFile restart page specifies "
-                               "inconsistent restart area offset.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart page specifies inconsistent restart area offset.");
                return false;
        }
        /*
         * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
         * set.
         */
-       if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
-               ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
-                               "by chkdsk but a chkdsk LSN is specified.");
+       if (!ntfs_is_chkd_record(rp->magic) && le64_to_cpu(rp->chkdsk_lsn)) {
+               ntfs_error(vi->i_sb,
+                       "LogFile restart page is not modified by chkdsk but a chkdsk LSN is specified.");
                return false;
        }
        ntfs_debug("Done.");
        return true;
 }
 
-/**
+/*
  * ntfs_check_restart_area - check the restart area for consistency
- * @vi:                $LogFile inode to which the restart page belongs
+ * @vi:                LogFile inode to which the restart page belongs
  * @rp:                restart page whose restart area to check
  *
  * Check the restart area of the restart page @rp for consistency and return
@@ -141,25 +128,25 @@ skip_usa_checks:
  * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
  * require the full restart page.
  */
-static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
+static bool ntfs_check_restart_area(struct inode *vi, struct restart_page_header *rp)
 {
        u64 file_size;
-       RESTART_AREA *ra;
+       struct restart_area *ra;
        u16 ra_ofs, ra_len, ca_ofs;
        u8 fs_bits;
 
        ntfs_debug("Entering.");
        ra_ofs = le16_to_cpu(rp->restart_area_offset);
-       ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
+       ra = (struct restart_area *)((u8 *)rp + ra_ofs);
        /*
         * Everything before ra->file_size must be before the first word
         * protected by an update sequence number.  This ensures that it is
         * safe to access ra->client_array_offset.
         */
-       if (ra_ofs + offsetof(RESTART_AREA, file_size) >
+       if (ra_ofs + offsetof(struct restart_area, file_size) >
                        NTFS_BLOCK_SIZE - sizeof(u16)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent file offset.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area specifies inconsistent file offset.");
                return false;
        }
        /*
@@ -172,8 +159,8 @@ static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
        ca_ofs = le16_to_cpu(ra->client_array_offset);
        if (((ca_ofs + 7) & ~7) != ca_ofs ||
                        ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent client array offset.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area specifies inconsistent client array offset.");
                return false;
        }
        /*
@@ -182,15 +169,13 @@ static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
         * Also, the calculated length must not exceed the specified length.
         */
        ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
-                       sizeof(LOG_CLIENT_RECORD);
+                       sizeof(struct log_client_record);
        if (ra_ofs + ra_len > le32_to_cpu(rp->system_page_size) ||
                        ra_ofs + le16_to_cpu(ra->restart_area_length) >
                        le32_to_cpu(rp->system_page_size) ||
                        ra_len > le16_to_cpu(ra->restart_area_length)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area is out of bounds "
-                               "of the system page size specified by the "
-                               "restart page header and/or the specified "
-                               "restart area length is inconsistent.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area is out of bounds of the system page size specified by the restart page header and/or the specified restart area length is inconsistent.");
                return false;
        }
        /*
@@ -204,46 +189,46 @@ static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
                        (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
                        le16_to_cpu(ra->client_in_use_list) >=
                        le16_to_cpu(ra->log_clients))) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "overflowing client free and/or in use lists.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area specifies overflowing client free and/or in use lists.");
                return false;
        }
        /*
         * Check ra->seq_number_bits against ra->file_size for consistency.
         * We cannot just use ffs() because the file size is not a power of 2.
         */
-       file_size = (u64)sle64_to_cpu(ra->file_size);
+       file_size = le64_to_cpu(ra->file_size);
        fs_bits = 0;
        while (file_size) {
                file_size >>= 1;
                fs_bits++;
        }
        if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent sequence number bits.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area specifies inconsistent sequence number bits.");
                return false;
        }
        /* The log record header length must be a multiple of 8. */
        if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
                        le16_to_cpu(ra->log_record_header_length)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent log record header length.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area specifies inconsistent log record header length.");
                return false;
        }
        /* Dito for the log page data offset. */
        if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
                        le16_to_cpu(ra->log_page_data_offset)) {
-               ntfs_error(vi->i_sb, "$LogFile restart area specifies "
-                               "inconsistent log page data offset.");
+               ntfs_error(vi->i_sb,
+                       "LogFile restart area specifies inconsistent log page data offset.");
                return false;
        }
        ntfs_debug("Done.");
        return true;
 }
 
-/**
+/*
  * ntfs_check_log_client_array - check the log client array for consistency
- * @vi:                $LogFile inode to which the restart page belongs
+ * @vi:                LogFile inode to which the restart page belongs
  * @rp:                restart page whose log client array to check
  *
  * Check the log client array of the restart page @rp for consistency and
@@ -257,16 +242,16 @@ static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
  * restart page and the page must be multi sector transfer deprotected.
  */
 static bool ntfs_check_log_client_array(struct inode *vi,
-               RESTART_PAGE_HEADER *rp)
+               struct restart_page_header *rp)
 {
-       RESTART_AREA *ra;
-       LOG_CLIENT_RECORD *ca, *cr;
+       struct restart_area *ra;
+       struct log_client_record *ca, *cr;
        u16 nr_clients, idx;
        bool in_free_list, idx_is_first;
 
        ntfs_debug("Entering.");
-       ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
-       ca = (LOG_CLIENT_RECORD*)((u8*)ra +
+       ra = (struct restart_area *)((u8 *)rp + le16_to_cpu(rp->restart_area_offset));
+       ca = (struct log_client_record *)((u8 *)ra +
                        le16_to_cpu(ra->client_array_offset));
        /*
         * Check the ra->client_free_list first and then check the
@@ -302,13 +287,13 @@ check_list:
        ntfs_debug("Done.");
        return true;
 err_out:
-       ntfs_error(vi->i_sb, "$LogFile log client array is corrupt.");
+       ntfs_error(vi->i_sb, "LogFile log client array is corrupt.");
        return false;
 }
 
-/**
+/*
  * ntfs_check_and_load_restart_page - check the restart page for consistency
- * @vi:                $LogFile inode to which the restart page belongs
+ * @vi:                LogFile inode to which the restart page belongs
  * @rp:                restart page to check
  * @pos:       position in @vi at which the restart page resides
  * @wrp:       [OUT] copy of the multi sector transfer deprotected restart page
@@ -331,14 +316,14 @@ err_out:
  * The following error codes are defined:
  *     -EINVAL - The restart page is inconsistent.
  *     -ENOMEM - Not enough memory to load the restart page.
- *     -EIO    - Failed to reading from $LogFile.
+ *     -EIO    - Failed to reading from LogFile.
  */
 static int ntfs_check_and_load_restart_page(struct inode *vi,
-               RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
-               LSN *lsn)
+               struct restart_page_header *rp, s64 pos, struct restart_page_header **wrp,
+               s64 *lsn)
 {
-       RESTART_AREA *ra;
-       RESTART_PAGE_HEADER *trp;
+       struct restart_area *ra;
+       struct restart_page_header *trp;
        int size, err;
 
        ntfs_debug("Entering.");
@@ -352,15 +337,14 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
                /* Error output already done inside the function. */
                return -EINVAL;
        }
-       ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
+       ra = (struct restart_area *)((u8 *)rp + le16_to_cpu(rp->restart_area_offset));
        /*
         * Allocate a buffer to store the whole restart page so we can multi
         * sector transfer deprotect it.
         */
-       trp = ntfs_malloc_nofs(le32_to_cpu(rp->system_page_size));
+       trp = kvzalloc(le32_to_cpu(rp->system_page_size), GFP_NOFS);
        if (!trp) {
-               ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile "
-                               "restart page buffer.");
+               ntfs_error(vi->i_sb, "Failed to allocate memory for LogFile restart page buffer.");
                return -ENOMEM;
        }
        /*
@@ -373,7 +357,7 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
                memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
        } else {
                pgoff_t idx;
-               struct page *page;
+               struct folio *folio;
                int have_read, to_read;
 
                /* First copy what we already have in @rp. */
@@ -382,20 +366,19 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
                have_read = size;
                to_read = le32_to_cpu(rp->system_page_size) - size;
                idx = (pos + size) >> PAGE_SHIFT;
-               BUG_ON((pos + size) & ~PAGE_MASK);
                do {
-                       page = ntfs_map_page(vi->i_mapping, idx);
-                       if (IS_ERR(page)) {
-                               ntfs_error(vi->i_sb, "Error mapping $LogFile "
-                                               "page (index %lu).", idx);
-                               err = PTR_ERR(page);
+                       folio = read_mapping_folio(vi->i_mapping, idx, NULL);
+                       if (IS_ERR(folio)) {
+                               ntfs_error(vi->i_sb, "Error mapping LogFile page (index %lu).",
+                                               idx);
+                               err = PTR_ERR(folio);
                                if (err != -EIO && err != -ENOMEM)
                                        err = -EIO;
                                goto err_out;
                        }
                        size = min_t(int, to_read, PAGE_SIZE);
-                       memcpy((u8*)trp + have_read, page_address(page), size);
-                       ntfs_unmap_page(page);
+                       memcpy((u8 *)trp + have_read, folio_address(folio), size);
+                       folio_put(folio);
                        have_read += size;
                        to_read -= size;
                        idx++;
@@ -405,19 +388,18 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
         * Perform the multi sector transfer deprotection on the buffer if the
         * restart page is protected.
         */
-       if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
-                       && post_read_mst_fixup((NTFS_RECORD*)trp,
-                       le32_to_cpu(rp->system_page_size))) {
+       if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) &&
+           post_read_mst_fixup((struct ntfs_record *)trp, le32_to_cpu(rp->system_page_size))) {
                /*
-                * A multi sector tranfer error was detected.  We only need to
+                * A multi sector transfer error was detected.  We only need to
                 * abort if the restart page contents exceed the multi sector
                 * transfer fixup of the first sector.
                 */
                if (le16_to_cpu(rp->restart_area_offset) +
                                le16_to_cpu(ra->restart_area_length) >
                                NTFS_BLOCK_SIZE - sizeof(u16)) {
-                       ntfs_error(vi->i_sb, "Multi sector transfer error "
-                                       "detected in $LogFile restart page.");
+                       ntfs_error(vi->i_sb,
+                               "Multi sector transfer error detected in LogFile restart page.");
                        err = -EINVAL;
                        goto err_out;
                }
@@ -437,53 +419,53 @@ static int ntfs_check_and_load_restart_page(struct inode *vi,
        }
        if (lsn) {
                if (ntfs_is_rstr_record(rp->magic))
-                       *lsn = sle64_to_cpu(ra->current_lsn);
+                       *lsn = le64_to_cpu(ra->current_lsn);
                else /* if (ntfs_is_chkd_record(rp->magic)) */
-                       *lsn = sle64_to_cpu(rp->chkdsk_lsn);
+                       *lsn = le64_to_cpu(rp->chkdsk_lsn);
        }
        ntfs_debug("Done.");
        if (wrp)
                *wrp = trp;
        else {
 err_out:
-               ntfs_free(trp);
+               kvfree(trp);
        }
        return err;
 }
 
-/**
+/*
  * ntfs_check_logfile - check the journal for consistency
- * @log_vi:    struct inode of loaded journal $LogFile to check
+ * @log_vi:    struct inode of loaded journal LogFile to check
  * @rp:                [OUT] on success this is a copy of the current restart page
  *
- * Check the $LogFile journal for consistency and return 'true' if it is
+ * Check the LogFile journal for consistency and return 'true' if it is
  * consistent and 'false' if not.  On success, the current restart page is
- * returned in *@rp.  Caller must call ntfs_free(*@rp) when finished with it.
+ * returned in *@rp.  Caller must call kvfree(*@rp) when finished with it.
  *
  * At present we only check the two restart pages and ignore the log record
  * pages.
  *
- * Note that the MstProtected flag is not set on the $LogFile inode and hence
+ * Note that the MstProtected flag is not set on the LogFile inode and hence
  * when reading pages they are not deprotected.  This is because we do not know
- * if the $LogFile was created on a system with a different page size to ours
+ * if the LogFile was created on a system with a different page size to ours
  * yet and mst deprotection would fail if our page size is smaller.
  */
-bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
+bool ntfs_check_logfile(struct inode *log_vi, struct restart_page_header **rp)
 {
        s64 size, pos;
-       LSN rstr1_lsn, rstr2_lsn;
-       ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+       s64 rstr1_lsn, rstr2_lsn;
+       struct ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
        struct address_space *mapping = log_vi->i_mapping;
-       struct page *page = NULL;
+       struct folio *folio = NULL;
        u8 *kaddr = NULL;
-       RESTART_PAGE_HEADER *rstr1_ph = NULL;
-       RESTART_PAGE_HEADER *rstr2_ph = NULL;
+       struct restart_page_header *rstr1_ph = NULL;
+       struct restart_page_header *rstr2_ph = NULL;
        int log_page_size, err;
        bool logfile_is_empty = true;
        u8 log_page_bits;
 
        ntfs_debug("Entering.");
-       /* An empty $LogFile must have been clean before it got emptied. */
+       /* An empty LogFile must have been clean before it got emptied. */
        if (NVolLogFileEmpty(vol))
                goto is_empty;
        size = i_size_read(log_vi);
@@ -496,8 +478,8 @@ bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
         * log page size if the page cache size is between the default log page
         * size and twice that.
         */
-       if (PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <=
-                       DefaultLogPageSize * 2)
+       if (DefaultLogPageSize <= PAGE_SIZE &&
+           DefaultLogPageSize * 2 <= PAGE_SIZE)
                log_page_size = DefaultLogPageSize;
        else
                log_page_size = PAGE_SIZE;
@@ -513,7 +495,7 @@ bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
         */
        if (size < log_page_size * 2 || (size - log_page_size * 2) >>
                        log_page_bits < MinLogRecordPages) {
-               ntfs_error(vol->sb, "$LogFile is too small.");
+               ntfs_error(vol->sb, "LogFile is too small.");
                return false;
        }
        /*
@@ -526,23 +508,26 @@ bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
         */
        for (pos = 0; pos < size; pos <<= 1) {
                pgoff_t idx = pos >> PAGE_SHIFT;
-               if (!page || page->index != idx) {
-                       if (page)
-                               ntfs_unmap_page(page);
-                       page = ntfs_map_page(mapping, idx);
-                       if (IS_ERR(page)) {
-                               ntfs_error(vol->sb, "Error mapping $LogFile "
-                                               "page (index %lu).", idx);
+
+               if (!folio || folio->index != idx) {
+                       if (folio) {
+                               kunmap_local(kaddr);
+                               folio_put(folio);
+                       }
+                       folio = read_mapping_folio(mapping, idx, NULL);
+                       if (IS_ERR(folio)) {
+                               ntfs_error(vol->sb, "Error mapping LogFile page (index %lu).",
+                                               idx);
                                goto err_out;
                        }
                }
-               kaddr = (u8*)page_address(page) + (pos & ~PAGE_MASK);
+               kaddr = (u8 *)kmap_local_folio(folio, 0) + (pos & ~PAGE_MASK);
                /*
                 * A non-empty block means the logfile is not empty while an
                 * empty block after a non-empty block has been encountered
                 * means we are done.
                 */
-               if (!ntfs_is_empty_recordp((le32*)kaddr))
+               if (!ntfs_is_empty_recordp((__le32 *)kaddr))
                        logfile_is_empty = false;
                else if (!logfile_is_empty)
                        break;
@@ -550,11 +535,11 @@ bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
                 * A log record page means there cannot be a restart page after
                 * this so no need to continue searching.
                 */
-               if (ntfs_is_rcrd_recordp((le32*)kaddr))
+               if (ntfs_is_rcrd_recordp((__le32 *)kaddr))
                        break;
                /* If not a (modified by chkdsk) restart page, continue. */
-               if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
-                               !ntfs_is_chkd_recordp((le32*)kaddr)) {
+               if (!ntfs_is_rstr_recordp((__le32 *)kaddr) &&
+                               !ntfs_is_chkd_recordp((__le32 *)kaddr)) {
                        if (!pos)
                                pos = NTFS_BLOCK_SIZE >> 1;
                        continue;
@@ -565,7 +550,7 @@ bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
                 * deprotected restart page.
                 */
                err = ntfs_check_and_load_restart_page(log_vi,
-                               (RESTART_PAGE_HEADER*)kaddr, pos,
+                               (struct restart_page_header *)kaddr, pos,
                                !rstr1_ph ? &rstr1_ph : &rstr2_ph,
                                !rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
                if (!err) {
@@ -589,25 +574,27 @@ bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
                 * find a valid one further in the file.
                 */
                if (err != -EINVAL) {
-                       ntfs_unmap_page(page);
+                       kunmap_local(kaddr);
+                       folio_put(folio);
                        goto err_out;
                }
                /* Continue looking. */
                if (!pos)
                        pos = NTFS_BLOCK_SIZE >> 1;
        }
-       if (page)
-               ntfs_unmap_page(page);
+       if (folio) {
+               kunmap_local(kaddr);
+               folio_put(folio);
+       }
        if (logfile_is_empty) {
                NVolSetLogFileEmpty(vol);
 is_empty:
-               ntfs_debug("Done.  ($LogFile is empty.)");
+               ntfs_debug("Done.  (LogFile is empty.)");
                return true;
        }
        if (!rstr1_ph) {
-               BUG_ON(rstr2_ph);
-               ntfs_error(vol->sb, "Did not find any restart pages in "
-                               "$LogFile and it was not empty.");
+               ntfs_error(vol->sb,
+                       "Did not find any restart pages in LogFile and it was not empty.");
                return false;
        }
        /* If both restart pages were found, use the more recent one. */
@@ -617,15 +604,13 @@ is_empty:
                 * Otherwise just throw it away.
                 */
                if (rstr2_lsn > rstr1_lsn) {
-                       ntfs_debug("Using second restart page as it is more "
-                                       "recent.");
-                       ntfs_free(rstr1_ph);
+                       ntfs_debug("Using second restart page as it is more recent.");
+                       kvfree(rstr1_ph);
                        rstr1_ph = rstr2_ph;
                        /* rstr1_lsn = rstr2_lsn; */
                } else {
-                       ntfs_debug("Using first restart page as it is more "
-                                       "recent.");
-                       ntfs_free(rstr2_ph);
+                       ntfs_debug("Using first restart page as it is more recent.");
+                       kvfree(rstr2_ph);
                }
                rstr2_ph = NULL;
        }
@@ -633,108 +618,52 @@ is_empty:
        if (rp)
                *rp = rstr1_ph;
        else
-               ntfs_free(rstr1_ph);
+               kvfree(rstr1_ph);
        ntfs_debug("Done.");
        return true;
 err_out:
        if (rstr1_ph)
-               ntfs_free(rstr1_ph);
+               kvfree(rstr1_ph);
        return false;
 }
 
-/**
- * ntfs_is_logfile_clean - check in the journal if the volume is clean
- * @log_vi:    struct inode of loaded journal $LogFile to check
- * @rp:                copy of the current restart page
- *
- * Analyze the $LogFile journal and return 'true' if it indicates the volume was
- * shutdown cleanly and 'false' if not.
- *
- * At present we only look at the two restart pages and ignore the log record
- * pages.  This is a little bit crude in that there will be a very small number
- * of cases where we think that a volume is dirty when in fact it is clean.
- * This should only affect volumes that have not been shutdown cleanly but did
- * not have any pending, non-check-pointed i/o, i.e. they were completely idle
- * at least for the five seconds preceding the unclean shutdown.
- *
- * This function assumes that the $LogFile journal has already been consistency
- * checked by a call to ntfs_check_logfile() and in particular if the $LogFile
- * is empty this function requires that NVolLogFileEmpty() is true otherwise an
- * empty volume will be reported as dirty.
- */
-bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
-{
-       ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
-       RESTART_AREA *ra;
-
-       ntfs_debug("Entering.");
-       /* An empty $LogFile must have been clean before it got emptied. */
-       if (NVolLogFileEmpty(vol)) {
-               ntfs_debug("Done.  ($LogFile is empty.)");
-               return true;
-       }
-       BUG_ON(!rp);
-       if (!ntfs_is_rstr_record(rp->magic) &&
-                       !ntfs_is_chkd_record(rp->magic)) {
-               ntfs_error(vol->sb, "Restart page buffer is invalid.  This is "
-                               "probably a bug in that the $LogFile should "
-                               "have been consistency checked before calling "
-                               "this function.");
-               return false;
-       }
-       ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
-       /*
-        * If the $LogFile has active clients, i.e. it is open, and we do not
-        * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
-        * we assume there was an unclean shutdown.
-        */
-       if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
-                       !(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
-               ntfs_debug("Done.  $LogFile indicates a dirty shutdown.");
-               return false;
-       }
-       /* $LogFile indicates a clean shutdown. */
-       ntfs_debug("Done.  $LogFile indicates a clean shutdown.");
-       return true;
-}
-
-/**
- * ntfs_empty_logfile - empty the contents of the $LogFile journal
- * @log_vi:    struct inode of loaded journal $LogFile to empty
+/*
+ * ntfs_empty_logfile - empty the contents of the LogFile journal
+ * @log_vi:    struct inode of loaded journal LogFile to empty
  *
- * Empty the contents of the $LogFile journal @log_vi and return 'true' on
+ * Empty the contents of the LogFile journal @log_vi and return 'true' on
  * success and 'false' on error.
  *
- * This function assumes that the $LogFile journal has already been consistency
+ * This function assumes that the LogFile journal has already been consistency
  * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
- * has been used to ensure that the $LogFile is clean.
+ * has been used to ensure that the LogFile is clean.
  */
 bool ntfs_empty_logfile(struct inode *log_vi)
 {
-       VCN vcn, end_vcn;
-       ntfs_inode *log_ni = NTFS_I(log_vi);
-       ntfs_volume *vol = log_ni->vol;
+       s64 vcn, end_vcn;
+       struct ntfs_inode *log_ni = NTFS_I(log_vi);
+       struct ntfs_volume *vol = log_ni->vol;
        struct super_block *sb = vol->sb;
-       runlist_element *rl;
+       struct runlist_element *rl;
        unsigned long flags;
-       unsigned block_size, block_size_bits;
        int err;
        bool should_wait = true;
+       char *empty_buf = NULL;
+       struct file_ra_state *ra = NULL;
 
        ntfs_debug("Entering.");
        if (NVolLogFileEmpty(vol)) {
                ntfs_debug("Done.");
                return true;
        }
+
        /*
         * We cannot use ntfs_attr_set() because we may be still in the middle
         * of a mount operation.  Thus we do the emptying by hand by first
-        * zapping the page cache pages for the $LogFile/$DATA attribute and
+        * zapping the page cache pages for the LogFile/DATA attribute and
         * then emptying each of the buffers in each of the clusters specified
         * by the runlist by hand.
         */
-       block_size = sb->s_blocksize;
-       block_size_bits = sb->s_blocksize_bits;
        vcn = 0;
        read_lock_irqsave(&log_ni->size_lock, flags);
        end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
@@ -747,19 +676,30 @@ bool ntfs_empty_logfile(struct inode *log_vi)
 map_vcn:
                err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
                if (err) {
-                       ntfs_error(sb, "Failed to map runlist fragment (error "
-                                       "%d).", -err);
+                       ntfs_error(sb, "Failed to map runlist fragment (error %d).", -err);
                        goto err;
                }
                rl = log_ni->runlist.rl;
-               BUG_ON(!rl || vcn < rl->vcn || !rl->length);
        }
        /* Seek to the runlist element containing @vcn. */
        while (rl->length && vcn >= rl[1].vcn)
                rl++;
+
+       err = -ENOMEM;
+       empty_buf = kvzalloc(vol->cluster_size, GFP_NOFS);
+       if (!empty_buf)
+               goto err;
+
+       memset(empty_buf, 0xff, vol->cluster_size);
+
+       ra = kzalloc(sizeof(*ra), GFP_NOFS);
+       if (!ra)
+               goto err;
+
+       file_ra_state_init(ra, sb->s_bdev->bd_mapping);
        do {
-               LCN lcn;
-               sector_t block, end_block;
+               s64 lcn;
+               loff_t start, end;
                s64 len;
 
                /*
@@ -769,6 +709,7 @@ map_vcn:
                lcn = rl->lcn;
                if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
                        vcn = rl->vcn;
+                       kvfree(empty_buf);
                        goto map_vcn;
                }
                /* If this run is not valid abort with an error. */
@@ -777,29 +718,23 @@ map_vcn:
                /* Skip holes. */
                if (lcn == LCN_HOLE)
                        continue;
-               block = lcn << vol->cluster_size_bits >> block_size_bits;
+               start = NTFS_CLU_TO_B(vol, lcn);
                len = rl->length;
                if (rl[1].vcn > end_vcn)
                        len = end_vcn - rl->vcn;
-               end_block = (lcn + len) << vol->cluster_size_bits >>
-                               block_size_bits;
-               /* Iterate over the blocks in the run and empty them. */
+               end = NTFS_CLU_TO_B(vol, lcn + len);
+
+               page_cache_sync_readahead(sb->s_bdev->bd_mapping, ra, NULL,
+                       start >> PAGE_SHIFT, (end - start) >> PAGE_SHIFT);
+
                do {
-                       struct buffer_head *bh;
+                       err = ntfs_bdev_write(sb, empty_buf, start,
+                                                 vol->cluster_size);
+                       if (err) {
+                               ntfs_error(sb, "ntfs_dev_write failed, err : %d\n", err);
+                               goto io_err;
+                       }
 
-                       /* Obtain the buffer, possibly not uptodate. */
-                       bh = sb_getblk(sb, block);
-                       BUG_ON(!bh);
-                       /* Setup buffer i/o submission. */
-                       lock_buffer(bh);
-                       bh->b_end_io = end_buffer_write_sync;
-                       get_bh(bh);
-                       /* Set the entire contents of the buffer to 0xff. */
-                       memset(bh->b_data, -1, block_size);
-                       if (!buffer_uptodate(bh))
-                               set_buffer_uptodate(bh);
-                       if (buffer_dirty(bh))
-                               clear_buffer_dirty(bh);
                        /*
                         * Submit the buffer and wait for i/o to complete but
                         * only for the first buffer so we do not miss really
@@ -807,25 +742,19 @@ map_vcn:
                         * completed ignore errors afterwards as we can assume
                         * that if one buffer worked all of them will work.
                         */
-                       submit_bh(REQ_OP_WRITE, bh);
                        if (should_wait) {
                                should_wait = false;
-                               wait_on_buffer(bh);
-                               if (unlikely(!buffer_uptodate(bh)))
+                               err = filemap_write_and_wait_range(sb->s_bdev->bd_mapping,
+                                               start, start + vol->cluster_size);
+                               if (err)
                                        goto io_err;
                        }
-                       brelse(bh);
-               } while (++block < end_block);
+                       start += vol->cluster_size;
+               } while (start < end);
        } while ((++rl)->vcn < end_vcn);
        up_write(&log_ni->runlist.lock);
-       /*
-        * Zap the pages again just in case any got instantiated whilst we were
-        * emptying the blocks by hand.  FIXME: We may not have completed
-        * writing to all the buffer heads yet so this may happen too early.
-        * We really should use a kernel thread to do the emptying
-        * asynchronously and then we can also set the volume dirty and output
-        * an error message if emptying should fail.
-        */
+       kfree(empty_buf);
+       kfree(ra);
        truncate_inode_pages(log_vi->i_mapping, 0);
        /* Set the flag so we do not have to do it again on remount. */
        NVolSetLogFileEmpty(vol);
@@ -840,10 +769,10 @@ dirty_err:
        NVolSetErrors(vol);
        err = -EIO;
 err:
+       kvfree(empty_buf);
+       kfree(ra);
        up_write(&log_ni->runlist.lock);
-       ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
+       ntfs_error(sb, "Failed to fill LogFile with 0xff bytes (error %d).",
                        -err);
        return false;
 }
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/object_id.c b/fs/ntfs/object_id.c
new file mode 100644 (file)
index 0000000..89002c3
--- /dev/null
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pocessing of object ids
+ *
+ * Part of this file is based on code from the NTFS-3G.
+ *
+ * Copyright (c) 2009-2019 Jean-Pierre Andre
+ * Copyright (c) 2026 LG Electronics Co., Ltd.
+ */
+
+#include "ntfs.h"
+#include "index.h"
+#include "object_id.h"
+
+struct object_id_index_key {
+       union {
+               u32 alignment;
+               struct guid guid;
+       } object_id;
+} __packed;
+
+struct object_id_index_data {
+       __le64 file_id;
+       struct guid birth_volume_id;
+       struct guid birth_object_id;
+       struct guid domain_id;
+} __packed;
+
+/* Index entry in $Extend/$ObjId */
+struct object_id_index {
+       struct index_entry_header header;
+       struct object_id_index_key key;
+       struct object_id_index_data data;
+} __packed;
+
+__le16 objid_index_name[] = {cpu_to_le16('$'), cpu_to_le16('O'), 0};
+
+/*
+ * open_object_id_index - Open the $Extend/$ObjId file and its index
+ * @vol: NTFS volume structure
+ *
+ * Opens the $ObjId system file and retrieves its index context.
+ *
+ * Return: The index context if opened successfully, or NULL if an error
+ *        occurred.
+ */
+static struct ntfs_index_context *open_object_id_index(struct ntfs_volume *vol)
+{
+       struct inode *dir_vi, *vi;
+       struct ntfs_inode *dir_ni;
+       struct ntfs_index_context *xo = NULL;
+       struct ntfs_name *name = NULL;
+       u64 mref;
+       int uname_len;
+       __le16 *uname;
+
+       uname_len = ntfs_nlstoucs(vol, "$ObjId", 6, &uname,
+                       NTFS_MAX_NAME_LEN);
+       if (uname_len < 0)
+               return NULL;
+
+       /* do not use path_name_to inode - could reopen root */
+       dir_vi = ntfs_iget(vol->sb, FILE_Extend);
+       if (IS_ERR(dir_vi)) {
+               kmem_cache_free(ntfs_name_cache, uname);
+               return NULL;
+       }
+       dir_ni = NTFS_I(dir_vi);
+
+       mutex_lock_nested(&dir_ni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT);
+       mref = ntfs_lookup_inode_by_name(dir_ni, uname, uname_len, &name);
+       mutex_unlock(&dir_ni->mrec_lock);
+       kfree(name);
+       kmem_cache_free(ntfs_name_cache, uname);
+       if (IS_ERR_MREF(mref))
+               goto put_dir_vi;
+
+       vi = ntfs_iget(vol->sb, MREF(mref));
+       if (IS_ERR(vi))
+               goto put_dir_vi;
+
+       xo = ntfs_index_ctx_get(NTFS_I(vi), objid_index_name, 2);
+       if (!xo)
+               iput(vi);
+put_dir_vi:
+       iput(dir_vi);
+       return xo;
+}
+
+
+/*
+ * remove_object_id_index - Remove an object id index entry if attribute present
+ * @ni: NTFS inode structure containing the attribute
+ * @xo:        Index context for the object id index
+ *
+ * Reads the existing object ID attribute and removes it from the index.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int remove_object_id_index(struct ntfs_inode *ni, struct ntfs_index_context *xo)
+{
+       struct object_id_index_key key = {0};
+       s64 size;
+
+       if (ni->data_size == 0)
+               return -ENODATA;
+
+       /* read the existing object id attribute */
+       size = ntfs_inode_attr_pread(VFS_I(ni), 0, sizeof(struct guid),
+                                    (char *)&key);
+       if (size != sizeof(struct guid))
+               return -ENODATA;
+
+       if (!ntfs_index_lookup(&key, sizeof(struct object_id_index_key), xo))
+               return ntfs_index_rm(xo);
+
+       return 0;
+}
+
+/*
+ * ntfs_delete_object_id_index - Delete an object_id index entry
+ * @ni:        NTFS inode structure
+ *
+ * Opens the object ID index and removes the entry corresponding to the inode.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int ntfs_delete_object_id_index(struct ntfs_inode *ni)
+{
+       struct ntfs_index_context *xo;
+       struct ntfs_inode *xoni;
+       struct inode *attr_vi;
+       int ret = 0;
+
+       attr_vi = ntfs_attr_iget(VFS_I(ni), AT_OBJECT_ID, AT_UNNAMED, 0);
+       if (IS_ERR(attr_vi))
+               return PTR_ERR(attr_vi);
+
+       /*
+        * read the existing object id and un-index it
+        */
+       xo = open_object_id_index(ni->vol);
+       if (xo) {
+               xoni = xo->idx_ni;
+               mutex_lock_nested(&xoni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT);
+               ret = remove_object_id_index(NTFS_I(attr_vi), xo);
+               if (!ret) {
+                       ntfs_index_entry_mark_dirty(xo);
+                       mark_mft_record_dirty(xoni);
+               }
+               ntfs_index_ctx_put(xo);
+               mutex_unlock(&xoni->mrec_lock);
+               iput(VFS_I(xoni));
+       }
+
+       iput(attr_vi);
+       return ret;
+}
index 9160480222fd72f493e4260f30a8630bf378c537..b443243b58fbf71e9d28d0eb92e8b64ba9fe367c 100644 (file)
@@ -1,30 +1,27 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * quota.c - NTFS kernel quota ($Quota) handling.  Part of the Linux-NTFS
- *          project.
+ * NTFS kernel quota ($Quota) handling.
  *
  * Copyright (c) 2004 Anton Altaparmakov
  */
 
-#ifdef NTFS_RW
-
 #include "index.h"
 #include "quota.h"
 #include "debug.h"
 #include "ntfs.h"
 
-/**
+/*
  * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume
  * @vol:       ntfs volume on which to mark the quotas out of date
  *
  * Mark the quotas out of date on the ntfs volume @vol and return 'true' on
  * success and 'false' on error.
  */
-bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
+bool ntfs_mark_quotas_out_of_date(struct ntfs_volume *vol)
 {
-       ntfs_index_context *ictx;
-       QUOTA_CONTROL_ENTRY *qce;
-       const le32 qid = QUOTA_DEFAULTS_ID;
+       struct ntfs_index_context *ictx;
+       struct quota_control_entry *qce;
+       const __le32 qid = QUOTA_DEFAULTS_ID;
        int err;
 
        ntfs_debug("Entering.");
@@ -35,7 +32,7 @@ bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
                return false;
        }
        inode_lock(vol->quota_q_ino);
-       ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino));
+       ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino), I30, 4);
        if (!ictx) {
                ntfs_error(vol->sb, "Failed to get index context.");
                goto err_out;
@@ -43,22 +40,20 @@ bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
        err = ntfs_index_lookup(&qid, sizeof(qid), ictx);
        if (err) {
                if (err == -ENOENT)
-                       ntfs_error(vol->sb, "Quota defaults entry is not "
-                                       "present.");
+                       ntfs_error(vol->sb, "Quota defaults entry is not present.");
                else
-                       ntfs_error(vol->sb, "Lookup of quota defaults entry "
-                                       "failed.");
+                       ntfs_error(vol->sb, "Lookup of quota defaults entry failed.");
                goto err_out;
        }
-       if (ictx->data_len < offsetof(QUOTA_CONTROL_ENTRY, sid)) {
-               ntfs_error(vol->sb, "Quota defaults entry size is invalid.  "
-                               "Run chkdsk.");
+       if (ictx->data_len < offsetof(struct quota_control_entry, sid)) {
+               ntfs_error(vol->sb, "Quota defaults entry size is invalid.  Run chkdsk.");
                goto err_out;
        }
-       qce = (QUOTA_CONTROL_ENTRY*)ictx->data;
+       qce = (struct quota_control_entry *)ictx->data;
        if (le32_to_cpu(qce->version) != QUOTA_VERSION) {
-               ntfs_error(vol->sb, "Quota defaults entry version 0x%x is not "
-                               "supported.", le32_to_cpu(qce->version));
+               ntfs_error(vol->sb,
+                       "Quota defaults entry version 0x%x is not supported.",
+                       le32_to_cpu(qce->version));
                goto err_out;
        }
        ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags));
@@ -80,7 +75,6 @@ bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
         */
        qce->flags |= QUOTA_FLAG_OUT_OF_DATE;
        /* Ensure the modified flags are written to disk. */
-       ntfs_index_entry_flush_dcache_page(ictx);
        ntfs_index_entry_mark_dirty(ictx);
 set_done:
        ntfs_index_ctx_put(ictx);
@@ -99,5 +93,3 @@ err_out:
        inode_unlock(vol->quota_q_ino);
        return false;
 }
-
-#endif /* NTFS_RW */
index 4e980170d86a40ebbc4f1d96d95f6c4c1b7ba599..aa4a821a117b94ee30ed5585912ff7fd52a7f235 100644 (file)
@@ -1,9 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * sysctl.c - Code 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
+ * Code for sysctl handling in NTFS Linux kernel driver.
  *
+ * Copyright (C) 1997 Martin von Löwis, Régis Duchesne
  * Copyright (c) 2002-2005 Anton Altaparmakov
  */
 
@@ -20,7 +19,7 @@
 #include "debug.h"
 
 /* Definition of the ntfs sysctl. */
-static struct ctl_table ntfs_sysctls[] = {
+static const struct ctl_table ntfs_sysctls[] = {
        {
                .procname       = "ntfs-debug",
                .data           = &debug_msgs,          /* Data pointer and size. */
@@ -28,12 +27,13 @@ static struct ctl_table ntfs_sysctls[] = {
                .mode           = 0644,                 /* Mode, proc handler. */
                .proc_handler   = proc_dointvec
        },
+       {}
 };
 
 /* Storage for the sysctls header. */
 static struct ctl_table_header *sysctls_root_table;
 
-/**
+/*
  * ntfs_sysctl - add or remove the debug sysctl
  * @add:       add (1) or remove (0) the sysctl
  *
@@ -42,17 +42,14 @@ static struct ctl_table_header *sysctls_root_table;
 int ntfs_sysctl(int add)
 {
        if (add) {
-               BUG_ON(sysctls_root_table);
                sysctls_root_table = register_sysctl("fs", ntfs_sysctls);
                if (!sysctls_root_table)
                        return -ENOMEM;
        } else {
-               BUG_ON(!sysctls_root_table);
                unregister_sysctl_table(sysctls_root_table);
                sysctls_root_table = NULL;
        }
        return 0;
 }
-
 #endif /* CONFIG_SYSCTL */
 #endif /* DEBUG */
index a6b6c64f14a93158e409e38127edb3948ac6902a..7f11a2825527fe6600cf5c4d62d8fe8ee61f61d0 100644 (file)
@@ -1,14 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
+ * NTFS Unicode string handling.
  *
  * Copyright (c) 2001-2006 Anton Altaparmakov
  */
 
-#include <linux/slab.h>
-
-#include "types.h"
-#include "debug.h"
 #include "ntfs.h"
 
 /*
@@ -37,7 +33,7 @@ static const u8 legal_ansi_char_array[0x40] = {
        0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
 };
 
-/**
+/*
  * ntfs_are_names_equal - compare two Unicode names for equality
  * @s1:                        name to compare to @s2
  * @s1_len:            length in Unicode characters of @s1
@@ -51,9 +47,9 @@ static const u8 legal_ansi_char_array[0x40] = {
  * identical, or 'false' (0) if they are not identical. If @ic is IGNORE_CASE,
  * the @upcase table is used to performa a case insensitive comparison.
  */
-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)
+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)
 {
        if (s1_len != s2_len)
                return false;
@@ -62,10 +58,12 @@ bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
        return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
 }
 
-/**
+/*
  * ntfs_collate_names - collate two Unicode names
  * @name1:     first Unicode name to compare
+ * @name1_len: first Unicode name length
  * @name2:     second Unicode name to compare
+ * @name2_len: second Unicode name length
  * @err_val:   if @name1 contains an invalid character return this value
  * @ic:                either CASE_SENSITIVE or IGNORE_CASE
  * @upcase:    upcase table (ignored if @ic is CASE_SENSITIVE)
@@ -80,10 +78,10 @@ bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
  *
  * The following characters are considered invalid: '"', '*', '<', '>' and '?'.
  */
-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)
+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)
 {
        u32 cnt, min_len;
        u16 c1, c2;
@@ -118,7 +116,7 @@ int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
        return 1;
 }
 
-/**
+/*
  * ntfs_ucsncmp - compare two little endian Unicode strings
  * @s1:                first string
  * @s2:                second string
@@ -132,7 +130,7 @@ int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
  * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
  * to be less than, to match, or be greater than @s2.
  */
-int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
+int ntfs_ucsncmp(const __le16 *s1, const __le16 *s2, size_t n)
 {
        u16 c1, c2;
        size_t i;
@@ -150,7 +148,7 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
        return 0;
 }
 
-/**
+/*
  * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
  * @s1:                        first string
  * @s2:                        second string
@@ -168,16 +166,18 @@ int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
  * if @s1 (or the first @n Unicode characters thereof) is found, respectively,
  * to be less than, to match, or be greater than @s2.
  */
-int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
-               const ntfschar *upcase, const u32 upcase_size)
+int ntfs_ucsncasecmp(const __le16 *s1, const __le16 *s2, size_t n,
+               const __le16 *upcase, const u32 upcase_size)
 {
        size_t i;
        u16 c1, c2;
 
        for (i = 0; i < n; ++i) {
-               if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
+               c1 = le16_to_cpu(s1[i]);
+               if (c1 < upcase_size)
                        c1 = le16_to_cpu(upcase[c1]);
-               if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
+               c2 = le16_to_cpu(s2[i]);
+               if (c2 < upcase_size)
                        c2 = le16_to_cpu(upcase[c2]);
                if (c1 < c2)
                        return -1;
@@ -189,42 +189,25 @@ int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
        return 0;
 }
 
-void ntfs_upcase_name(ntfschar *name, u32 name_len, const ntfschar *upcase,
-               const u32 upcase_len)
+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)
 {
-       u32 i;
-       u16 u;
-
-       for (i = 0; i < name_len; i++)
-               if ((u = le16_to_cpu(name[i])) < upcase_len)
-                       name[i] = upcase[u];
-}
-
-void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
-               const ntfschar *upcase, const u32 upcase_len)
-{
-       ntfs_upcase_name((ntfschar*)&file_name_attr->file_name,
-                       file_name_attr->file_name_length, upcase, upcase_len);
-}
-
-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)
-{
-       return ntfs_collate_names((ntfschar*)&file_name_attr1->file_name,
+       return ntfs_collate_names((__le16 *)&file_name_attr1->file_name,
                        file_name_attr1->file_name_length,
-                       (ntfschar*)&file_name_attr2->file_name,
+                       (__le16 *)&file_name_attr2->file_name,
                        file_name_attr2->file_name_length,
                        err_val, ic, upcase, upcase_len);
 }
 
-/**
+/*
  * ntfs_nlstoucs - convert NLS string to little endian Unicode string
  * @vol:       ntfs volume which we are working with
  * @ins:       input NLS string buffer
  * @ins_len:   length of input string in bytes
  * @outs:      on return contains the allocated output Unicode string buffer
+ * @max_name_len: maximum number of Unicode characters allowed for the output name
  *
  * Convert the input string @ins, which is in whatever format the loaded NLS
  * map dictates, into a little endian, 2-byte Unicode string.
@@ -242,59 +225,74 @@ int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
  *
  * This might look a bit odd due to fast path optimization...
  */
-int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
-               const int ins_len, ntfschar **outs)
+int ntfs_nlstoucs(const struct ntfs_volume *vol, const char *ins,
+               const int ins_len, __le16 **outs, int max_name_len)
 {
        struct nls_table *nls = vol->nls_map;
-       ntfschar *ucs;
+       __le16 *ucs;
        wchar_t wc;
        int i, o, wc_len;
 
        /* We do not trust outside sources. */
        if (likely(ins)) {
-               ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS);
+               if (max_name_len > NTFS_MAX_NAME_LEN)
+                       ucs = kvmalloc((max_name_len + 2) * sizeof(__le16),
+                                      GFP_NOFS | __GFP_ZERO);
+               else
+                       ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS);
                if (likely(ucs)) {
-                       for (i = o = 0; i < ins_len; i += wc_len) {
-                               wc_len = nls->char2uni(ins + i, ins_len - i,
-                                               &wc);
-                               if (likely(wc_len >= 0 &&
-                                               o < NTFS_MAX_NAME_LEN)) {
-                                       if (likely(wc)) {
-                                               ucs[o++] = cpu_to_le16(wc);
-                                               continue;
-                                       } /* else if (!wc) */
-                                       break;
-                               } /* else if (wc_len < 0 ||
-                                               o >= NTFS_MAX_NAME_LEN) */
-                               goto name_err;
+                       if (vol->nls_utf8) {
+                               o = utf8s_to_utf16s(ins, ins_len,
+                                                   UTF16_LITTLE_ENDIAN,
+                                                   (wchar_t *)ucs,
+                                                   max_name_len + 2);
+                               if (o < 0 || o > max_name_len) {
+                                       wc_len = o;
+                                       goto name_err;
+                               }
+                       } else {
+                               for (i = o = 0; i < ins_len; i += wc_len) {
+                                       wc_len = nls->char2uni(ins + i, ins_len - i,
+                                                       &wc);
+                                       if (likely(wc_len >= 0 &&
+                                           o < max_name_len)) {
+                                               if (likely(wc)) {
+                                                       ucs[o++] = cpu_to_le16(wc);
+                                                       continue;
+                                               } /* else if (!wc) */
+                                               break;
+                                       }
+
+                                       goto name_err;
+                               }
                        }
                        ucs[o] = 0;
                        *outs = ucs;
                        return o;
                } /* else if (!ucs) */
-               ntfs_error(vol->sb, "Failed to allocate buffer for converted "
-                               "name from ntfs_name_cache.");
+               ntfs_debug("Failed to allocate buffer for converted name from ntfs_name_cache.");
                return -ENOMEM;
        } /* else if (!ins) */
        ntfs_error(vol->sb, "Received NULL pointer.");
        return -EINVAL;
 name_err:
-       kmem_cache_free(ntfs_name_cache, ucs);
+       if (max_name_len > NTFS_MAX_NAME_LEN)
+               kvfree(ucs);
+       else
+               kmem_cache_free(ntfs_name_cache, ucs);
        if (wc_len < 0) {
-               ntfs_error(vol->sb, "Name using character set %s contains "
-                               "characters that cannot be converted to "
-                               "Unicode.", nls->charset);
+               ntfs_debug("Name using character set %s contains characters that cannot be converted to Unicode.",
+                               nls->charset);
                i = -EILSEQ;
-       } else /* if (o >= NTFS_MAX_NAME_LEN) */ {
-               ntfs_error(vol->sb, "Name is too long (maximum length for a "
-                               "name on NTFS is %d Unicode characters.",
-                               NTFS_MAX_NAME_LEN);
+       } else {
+               ntfs_debug("Name is too long (maximum length for a name on NTFS is %d Unicode characters.",
+                               max_name_len);
                i = -ENAMETOOLONG;
        }
        return i;
 }
 
-/**
+/*
  * ntfs_ucstonls - convert little endian Unicode string to NLS string
  * @vol:       ntfs volume which we are working with
  * @ins:       input Unicode string buffer
@@ -319,7 +317,7 @@ name_err:
  *
  * This might look a bit odd due to fast path optimization...
  */
-int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
+int ntfs_ucstonls(const struct ntfs_volume *vol, const __le16 *ins,
                const int ins_len, unsigned char **outs, int outs_len)
 {
        struct nls_table *nls = vol->nls_map;
@@ -340,8 +338,20 @@ int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
                        if (!ns)
                                goto mem_err_out;
                }
+
+               if (vol->nls_utf8) {
+                       o = utf16s_to_utf8s((const wchar_t *)ins, ins_len,
+                                       UTF16_LITTLE_ENDIAN, ns, ns_len);
+                       if (o >= ns_len) {
+                               wc = -ENAMETOOLONG;
+                               goto conversion_err;
+                       }
+                       goto done;
+               }
+
                for (i = o = 0; i < ins_len; i++) {
-retry:                 wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
+retry:
+                       wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
                                        ns_len - o);
                        if (wc > 0) {
                                o += wc;
@@ -363,6 +373,7 @@ retry:                      wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
                        } /* wc < 0, real error. */
                        goto conversion_err;
                }
+done:
                ns[o] = 0;
                *outs = ns;
                return o;
@@ -370,9 +381,9 @@ retry:                      wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
        ntfs_error(vol->sb, "Received NULL pointer.");
        return -EINVAL;
 conversion_err:
-       ntfs_error(vol->sb, "Unicode name contains characters that cannot be "
-                       "converted to character set %s.  You might want to "
-                       "try to use the mount option nls=utf8.", nls->charset);
+       ntfs_error(vol->sb,
+               "Unicode name contains characters that cannot be converted to character set %s.  You might want to try to use the mount option nls=utf8.",
+               nls->charset);
        if (ns != *outs)
                kfree(ns);
        if (wc != -ENAMETOOLONG)
@@ -382,3 +393,85 @@ mem_err_out:
        ntfs_error(vol->sb, "Failed to allocate name!");
        return -ENOMEM;
 }
+
+/*
+ * ntfs_ucsnlen - determine the length of a little endian Unicode string
+ * @s:         pointer to Unicode string
+ * @maxlen:    maximum length of string @s
+ *
+ * Return the number of Unicode characters in the little endian Unicode
+ * string @s up to a maximum of maxlen Unicode characters, not including
+ * the terminating (__le16)'\0'. If there is no (__le16)'\0' between @s
+ * and @s + @maxlen, @maxlen is returned.
+ *
+ * This function never looks beyond @s + @maxlen.
+ */
+static u32 ntfs_ucsnlen(const __le16 *s, u32 maxlen)
+{
+       u32 i;
+
+       for (i = 0; i < maxlen; i++) {
+               if (!le16_to_cpu(s[i]))
+                       break;
+       }
+       return i;
+}
+
+/*
+ * ntfs_ucsndup - duplicate little endian Unicode string
+ * @s:         pointer to Unicode string
+ * @maxlen:    maximum length of string @s
+ *
+ * Return a pointer to a new little endian Unicode string which is a duplicate
+ * of the string s.  Memory for the new string is obtained with kmalloc,
+ * and can be freed with kfree.
+ *
+ * A maximum of @maxlen Unicode characters are copied and a terminating
+ * (__le16)'\0' little endian Unicode character is added.
+ *
+ * This function never looks beyond @s + @maxlen.
+ *
+ * Return a pointer to the new little endian Unicode string on success and NULL
+ * on failure with errno set to the error code.
+ */
+__le16 *ntfs_ucsndup(const __le16 *s, u32 maxlen)
+{
+       __le16 *dst;
+       u32 len;
+
+       len = ntfs_ucsnlen(s, maxlen);
+       dst = kmalloc((len + 1) * sizeof(__le16), GFP_NOFS);
+       if (dst) {
+               memcpy(dst, s, len * sizeof(__le16));
+               dst[len] = cpu_to_le16(L'\0');
+       }
+       return dst;
+}
+
+/*
+ * ntfs_names_are_equal - compare two Unicode names for equality
+ * @s1:                 name to compare to @s2
+ * @s1_len:             length in Unicode characters of @s1
+ * @s2:                 name to compare to @s1
+ * @s2_len:             length in Unicode characters of @s2
+ * @ic:                 ignore case bool
+ * @upcase:             upcase table (only if @ic == IGNORE_CASE)
+ * @upcase_size:        length in Unicode characters of @upcase (if present)
+ *
+ * Compare the names @s1 and @s2 and return TRUE (1) if the names are
+ * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
+ * the @upcase table is used to perform a case insensitive comparison.
+ */
+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)
+{
+       if (s1_len != s2_len)
+               return false;
+       if (!s1_len)
+               return true;
+       if (ic == CASE_SENSITIVE)
+               return ntfs_ucsncmp(s1, s2, s1_len) ? false : true;
+       return ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? false : true;
+}
index 4ebe84a78dea581a09f6fe1ba2766481a6c65895..4b954470883f9d8da89f4442db62b1a4afc329e6 100644 (file)
@@ -1,16 +1,14 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * upcase.c - Generate the full NTFS Unicode upcase table in little endian.
- *           Part of the Linux-NTFS project.
+ * Generate the full NTFS Unicode upcase table in little endian.
  *
  * Copyright (c) 2001 Richard Russon <ntfs@flatcap.org>
  * Copyright (c) 2001-2006 Anton Altaparmakov
  */
 
-#include "malloc.h"
 #include "ntfs.h"
 
-ntfschar *generate_default_upcase(void)
+__le16 *generate_default_upcase(void)
 {
        static const int uc_run_table[][3] = { /* Start, End, Add */
        {0x0061, 0x007B,  -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72,  74},
@@ -52,12 +50,11 @@ ntfschar *generate_default_upcase(void)
        };
 
        int i, r;
-       ntfschar *uc;
+       __le16 *uc;
 
-       uc = ntfs_malloc_nofs(default_upcase_len * sizeof(ntfschar));
+       uc = kvcalloc(default_upcase_len, sizeof(__le16), GFP_NOFS);
        if (!uc)
                return uc;
-       memset(uc, 0, default_upcase_len * sizeof(ntfschar));
        /* Generate the little endian Unicode upcase table used by ntfs. */
        for (i = 0; i < default_upcase_len; i++)
                uc[i] = cpu_to_le16(i);
diff --git a/fs/ntfs/usnjrnl.c b/fs/ntfs/usnjrnl.c
deleted file mode 100644 (file)
index 9097a0b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * usnjrnl.h - NTFS kernel transaction log ($UsnJrnl) handling.  Part of the
- *            Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- */
-
-#ifdef NTFS_RW
-
-#include <linux/fs.h>
-#include <linux/highmem.h>
-#include <linux/mm.h>
-
-#include "aops.h"
-#include "debug.h"
-#include "endian.h"
-#include "time.h"
-#include "types.h"
-#include "usnjrnl.h"
-#include "volume.h"
-
-/**
- * ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume
- * @vol:       ntfs volume on which to stamp the transaction log
- *
- * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
- * 'true' on success and 'false' on error.
- *
- * This function assumes that the transaction log has already been loaded and
- * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
- */
-bool ntfs_stamp_usnjrnl(ntfs_volume *vol)
-{
-       ntfs_debug("Entering.");
-       if (likely(!NVolUsnJrnlStamped(vol))) {
-               sle64 stamp;
-               struct page *page;
-               USN_HEADER *uh;
-
-               page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
-               if (IS_ERR(page)) {
-                       ntfs_error(vol->sb, "Failed to read from "
-                                       "$UsnJrnl/$DATA/$Max attribute.");
-                       return false;
-               }
-               uh = (USN_HEADER*)page_address(page);
-               stamp = get_current_ntfs_time();
-               ntfs_debug("Stamping transaction log ($UsnJrnl): old "
-                               "journal_id 0x%llx, old lowest_valid_usn "
-                               "0x%llx, new journal_id 0x%llx, new "
-                               "lowest_valid_usn 0x%llx.",
-                               (long long)sle64_to_cpu(uh->journal_id),
-                               (long long)sle64_to_cpu(uh->lowest_valid_usn),
-                               (long long)sle64_to_cpu(stamp),
-                               i_size_read(vol->usnjrnl_j_ino));
-               uh->lowest_valid_usn =
-                               cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino));
-               uh->journal_id = stamp;
-               flush_dcache_page(page);
-               set_page_dirty(page);
-               ntfs_unmap_page(page);
-               /* Set the flag so we do not have to do it again on remount. */
-               NVolSetUsnJrnlStamped(vol);
-       }
-       ntfs_debug("Done.");
-       return true;
-}
-
-#endif /* NTFS_RW */
diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h
deleted file mode 100644 (file)
index 85f531b..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * usnjrnl.h - Defines for NTFS kernel transaction log ($UsnJrnl) handling.
- *            Part of the Linux-NTFS project.
- *
- * Copyright (c) 2005 Anton Altaparmakov
- */
-
-#ifndef _LINUX_NTFS_USNJRNL_H
-#define _LINUX_NTFS_USNJRNL_H
-
-#ifdef NTFS_RW
-
-#include "types.h"
-#include "endian.h"
-#include "layout.h"
-#include "volume.h"
-
-/*
- * Transaction log ($UsnJrnl) organization:
- *
- * The transaction log records whenever a file is modified in any way.  So for
- * example it will record that file "blah" was written to at a particular time
- * but not what was written.  If will record that a file was deleted or
- * created, that a file was truncated, etc.  See below for all the reason
- * codes used.
- *
- * The transaction log is in the $Extend directory which is in the root
- * directory of each volume.  If it is not present it means transaction
- * logging is disabled.  If it is present it means transaction logging is
- * either enabled or in the process of being disabled in which case we can
- * ignore it as it will go away as soon as Windows gets its hands on it.
- *
- * To determine whether the transaction logging is enabled or in the process
- * of being disabled, need to check the volume flags in the
- * $VOLUME_INFORMATION attribute in the $Volume system file (which is present
- * in the root directory and has a fixed mft record number, see layout.h).
- * If the flag VOLUME_DELETE_USN_UNDERWAY is set it means the transaction log
- * is in the process of being disabled and if this flag is clear it means the
- * transaction log is enabled.
- *
- * The transaction log consists of two parts; the $DATA/$Max attribute as well
- * as the $DATA/$J attribute.  $Max is a header describing the transaction
- * log whilst $J is the transaction log data itself as a sequence of variable
- * sized USN_RECORDs (see below for all the structures).
- *
- * We do not care about transaction logging at this point in time but we still
- * need to let windows know that the transaction log is out of date.  To do
- * this we need to stamp the transaction log.  This involves setting the
- * lowest_valid_usn field in the $DATA/$Max attribute to the usn to be used
- * for the next added USN_RECORD to the $DATA/$J attribute as well as
- * generating a new journal_id in $DATA/$Max.
- *
- * The journal_id is as of the current version (2.0) of the transaction log
- * simply the 64-bit timestamp of when the journal was either created or last
- * stamped.
- *
- * To determine the next usn there are two ways.  The first is to parse
- * $DATA/$J and to find the last USN_RECORD in it and to add its record_length
- * to its usn (which is the byte offset in the $DATA/$J attribute).  The
- * second is simply to take the data size of the attribute.  Since the usns
- * are simply byte offsets into $DATA/$J, this is exactly the next usn.  For
- * obvious reasons we use the second method as it is much simpler and faster.
- *
- * As an aside, note that to actually disable the transaction log, one would
- * need to set the VOLUME_DELETE_USN_UNDERWAY flag (see above), then go
- * through all the mft records on the volume and set the usn field in their
- * $STANDARD_INFORMATION attribute to zero.  Once that is done, one would need
- * to delete the transaction log file, i.e. \$Extent\$UsnJrnl, and finally,
- * one would need to clear the VOLUME_DELETE_USN_UNDERWAY flag.
- *
- * Note that if a volume is unmounted whilst the transaction log is being
- * disabled, the process will continue the next time the volume is mounted.
- * This is why we can safely mount read-write when we see a transaction log
- * in the process of being deleted.
- */
-
-/* Some $UsnJrnl related constants. */
-#define UsnJrnlMajorVer                2
-#define UsnJrnlMinorVer                0
-
-/*
- * $DATA/$Max attribute.  This is (always?) resident and has a fixed size of
- * 32 bytes.  It contains the header describing the transaction log.
- */
-typedef struct {
-/*Ofs*/
-/*   0*/sle64 maximum_size;    /* The maximum on-disk size of the $DATA/$J
-                                  attribute. */
-/*   8*/sle64 allocation_delta;        /* Number of bytes by which to increase the
-                                  size of the $DATA/$J attribute. */
-/*0x10*/sle64 journal_id;      /* Current id of the transaction log. */
-/*0x18*/leUSN lowest_valid_usn;        /* Lowest valid usn in $DATA/$J for the
-                                  current journal_id. */
-/* sizeof() = 32 (0x20) bytes */
-} __attribute__ ((__packed__)) USN_HEADER;
-
-/*
- * Reason flags (32-bit).  Cumulative flags describing the change(s) to the
- * file since it was last opened.  I think the names speak for themselves but
- * if you disagree check out the descriptions in the Linux NTFS project NTFS
- * documentation: http://www.linux-ntfs.org/
- */
-enum {
-       USN_REASON_DATA_OVERWRITE       = cpu_to_le32(0x00000001),
-       USN_REASON_DATA_EXTEND          = cpu_to_le32(0x00000002),
-       USN_REASON_DATA_TRUNCATION      = cpu_to_le32(0x00000004),
-       USN_REASON_NAMED_DATA_OVERWRITE = cpu_to_le32(0x00000010),
-       USN_REASON_NAMED_DATA_EXTEND    = cpu_to_le32(0x00000020),
-       USN_REASON_NAMED_DATA_TRUNCATION= cpu_to_le32(0x00000040),
-       USN_REASON_FILE_CREATE          = cpu_to_le32(0x00000100),
-       USN_REASON_FILE_DELETE          = cpu_to_le32(0x00000200),
-       USN_REASON_EA_CHANGE            = cpu_to_le32(0x00000400),
-       USN_REASON_SECURITY_CHANGE      = cpu_to_le32(0x00000800),
-       USN_REASON_RENAME_OLD_NAME      = cpu_to_le32(0x00001000),
-       USN_REASON_RENAME_NEW_NAME      = cpu_to_le32(0x00002000),
-       USN_REASON_INDEXABLE_CHANGE     = cpu_to_le32(0x00004000),
-       USN_REASON_BASIC_INFO_CHANGE    = cpu_to_le32(0x00008000),
-       USN_REASON_HARD_LINK_CHANGE     = cpu_to_le32(0x00010000),
-       USN_REASON_COMPRESSION_CHANGE   = cpu_to_le32(0x00020000),
-       USN_REASON_ENCRYPTION_CHANGE    = cpu_to_le32(0x00040000),
-       USN_REASON_OBJECT_ID_CHANGE     = cpu_to_le32(0x00080000),
-       USN_REASON_REPARSE_POINT_CHANGE = cpu_to_le32(0x00100000),
-       USN_REASON_STREAM_CHANGE        = cpu_to_le32(0x00200000),
-       USN_REASON_CLOSE                = cpu_to_le32(0x80000000),
-};
-
-typedef le32 USN_REASON_FLAGS;
-
-/*
- * Source info flags (32-bit).  Information about the source of the change(s)
- * to the file.  For detailed descriptions of what these mean, see the Linux
- * NTFS project NTFS documentation:
- *     http://www.linux-ntfs.org/
- */
-enum {
-       USN_SOURCE_DATA_MANAGEMENT        = cpu_to_le32(0x00000001),
-       USN_SOURCE_AUXILIARY_DATA         = cpu_to_le32(0x00000002),
-       USN_SOURCE_REPLICATION_MANAGEMENT = cpu_to_le32(0x00000004),
-};
-
-typedef le32 USN_SOURCE_INFO_FLAGS;
-
-/*
- * $DATA/$J attribute.  This is always non-resident, is marked as sparse, and
- * is of variabled size.  It consists of a sequence of variable size
- * USN_RECORDS.  The minimum allocated_size is allocation_delta as
- * specified in $DATA/$Max.  When the maximum_size specified in $DATA/$Max is
- * exceeded by more than allocation_delta bytes, allocation_delta bytes are
- * allocated and appended to the $DATA/$J attribute and an equal number of
- * bytes at the beginning of the attribute are freed and made sparse.  Note the
- * making sparse only happens at volume checkpoints and hence the actual
- * $DATA/$J size can exceed maximum_size + allocation_delta temporarily.
- */
-typedef struct {
-/*Ofs*/
-/*   0*/le32 length;           /* Byte size of this record (8-byte
-                                  aligned). */
-/*   4*/le16 major_ver;                /* Major version of the transaction log used
-                                  for this record. */
-/*   6*/le16 minor_ver;                /* Minor version of the transaction log used
-                                  for this record. */
-/*   8*/leMFT_REF mft_reference;/* The mft reference of the file (or
-                                  directory) described by this record. */
-/*0x10*/leMFT_REF parent_directory;/* The mft reference of the parent
-                                  directory of the file described by this
-                                  record. */
-/*0x18*/leUSN usn;             /* The usn of this record.  Equals the offset
-                                  within the $DATA/$J attribute. */
-/*0x20*/sle64 time;            /* Time when this record was created. */
-/*0x28*/USN_REASON_FLAGS reason;/* Reason flags (see above). */
-/*0x2c*/USN_SOURCE_INFO_FLAGS source_info;/* Source info flags (see above). */
-/*0x30*/le32 security_id;      /* File security_id copied from
-                                  $STANDARD_INFORMATION. */
-/*0x34*/FILE_ATTR_FLAGS file_attributes;       /* File attributes copied from
-                                  $STANDARD_INFORMATION or $FILE_NAME (not
-                                  sure which). */
-/*0x38*/le16 file_name_size;   /* Size of the file name in bytes. */
-/*0x3a*/le16 file_name_offset; /* Offset to the file name in bytes from the
-                                  start of this record. */
-/*0x3c*/ntfschar file_name[0]; /* Use when creating only.  When reading use
-                                  file_name_offset to determine the location
-                                  of the name. */
-/* sizeof() = 60 (0x3c) bytes */
-} __attribute__ ((__packed__)) USN_RECORD;
-
-extern bool ntfs_stamp_usnjrnl(ntfs_volume *vol);
-
-#endif /* NTFS_RW */
-
-#endif /* _LINUX_NTFS_USNJRNL_H */