Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ntfs: update misc operations

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>

+776 -706
+117
fs/ntfs/bdev-io.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * NTFS block device I/O. 4 + * 5 + * Copyright (c) 2026 LG Electronics Co., Ltd. 6 + */ 7 + 8 + #include <linux/blkdev.h> 9 + 10 + #include "ntfs.h" 11 + 12 + /* 13 + * ntfs_bdev_read - Read data directly from block device using bio 14 + * @bdev: block device to read from 15 + * @data: destination buffer 16 + * @start: starting byte offset on the block device 17 + * @size: number of bytes to read 18 + * 19 + * Reads @size bytes starting from byte offset @start directly from the block 20 + * device using one or more BIOs. This function bypasses the page cache 21 + * completely and performs synchronous I/O with REQ_META | REQ_SYNC flags set. 22 + * 23 + * The @start offset must be sector-aligned (512 bytes). If it is not aligned, 24 + * the function will return -EINVAL. 25 + * 26 + * If the destination buffer @data is not a vmalloc address, it falls back 27 + * to the more efficient bdev_rw_virt() helper. 28 + * 29 + * Return: 0 on success, negative error code on failure. 30 + */ 31 + int ntfs_bdev_read(struct block_device *bdev, char *data, loff_t start, size_t size) 32 + { 33 + unsigned int done = 0, added; 34 + int error; 35 + struct bio *bio; 36 + enum req_op op; 37 + sector_t sector = start >> SECTOR_SHIFT; 38 + 39 + if (start & (SECTOR_SIZE - 1)) 40 + return -EINVAL; 41 + 42 + op = REQ_OP_READ | REQ_META | REQ_SYNC; 43 + if (!is_vmalloc_addr(data)) 44 + return bdev_rw_virt(bdev, sector, data, size, op); 45 + 46 + bio = bio_alloc(bdev, 47 + bio_max_segs(DIV_ROUND_UP(size, PAGE_SIZE)), 48 + op, GFP_KERNEL); 49 + bio->bi_iter.bi_sector = sector; 50 + 51 + do { 52 + added = bio_add_vmalloc_chunk(bio, data + done, size - done); 53 + if (!added) { 54 + struct bio *prev = bio; 55 + 56 + bio = bio_alloc(prev->bi_bdev, 57 + bio_max_segs(DIV_ROUND_UP(size - done, PAGE_SIZE)), 58 + prev->bi_opf, GFP_KERNEL); 59 + bio->bi_iter.bi_sector = bio_end_sector(prev); 60 + bio_chain(prev, bio); 61 + submit_bio(prev); 62 + } 63 + done += added; 64 + } while (done < size); 65 + 66 + error = submit_bio_wait(bio); 67 + bio_put(bio); 68 + 69 + if (op == REQ_OP_READ) 70 + invalidate_kernel_vmap_range(data, size); 71 + return error; 72 + } 73 + 74 + /* 75 + * ntfs_bdev_write - Update block device contents via page cache 76 + * @sb: super block of the mounted NTFS filesystem 77 + * @buf: source buffer containing data to write 78 + * @start: starting byte offset on the block device 79 + * @size: number of bytes to write 80 + * 81 + * Writes @size bytes from @buf to the block device (sb->s_bdev) starting 82 + * at byte offset @start. The write is performed entirely through the page 83 + * cache of the block device's address space. 84 + */ 85 + int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size) 86 + { 87 + pgoff_t idx, idx_end; 88 + loff_t offset, end = start + size; 89 + u32 from, to, buf_off = 0; 90 + struct folio *folio; 91 + 92 + idx = start >> PAGE_SHIFT; 93 + idx_end = end >> PAGE_SHIFT; 94 + from = start & ~PAGE_MASK; 95 + 96 + if (idx == idx_end) 97 + idx_end++; 98 + 99 + for (; idx < idx_end; idx++, from = 0) { 100 + folio = read_mapping_folio(sb->s_bdev->bd_mapping, idx, NULL); 101 + if (IS_ERR(folio)) { 102 + ntfs_error(sb, "Unable to read %ld page", idx); 103 + return PTR_ERR(folio); 104 + } 105 + 106 + offset = (loff_t)idx << PAGE_SHIFT; 107 + to = min_t(u32, end - offset, PAGE_SIZE); 108 + 109 + memcpy_to_folio(folio, from, buf + buf_off, to); 110 + buf_off += to; 111 + folio_mark_uptodate(folio); 112 + folio_mark_dirty(folio); 113 + folio_put(folio); 114 + } 115 + 116 + return 0; 117 + }
+94 -58
fs/ntfs/collate.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * collate.c - NTFS kernel collation handling. Part of the Linux-NTFS project. 3 + * NTFS kernel collation handling. 4 4 * 5 5 * Copyright (c) 2004 Anton Altaparmakov 6 + * 7 + * Part of this file is based on code from the NTFS-3G. 8 + * and is copyrighted by the respective authors below: 9 + * Copyright (c) 2004 Anton Altaparmakov 10 + * Copyright (c) 2005 Yura Pakhuchiy 6 11 */ 7 12 8 13 #include "collate.h" 9 14 #include "debug.h" 10 15 #include "ntfs.h" 11 16 12 - static int ntfs_collate_binary(ntfs_volume *vol, 13 - const void *data1, const int data1_len, 14 - const void *data2, const int data2_len) 17 + #include <linux/sort.h> 18 + 19 + static int ntfs_collate_binary(struct ntfs_volume *vol, 20 + const void *data1, const u32 data1_len, 21 + const void *data2, const u32 data2_len) 15 22 { 16 23 int rc; 17 24 18 - ntfs_debug("Entering."); 19 25 rc = memcmp(data1, data2, min(data1_len, data2_len)); 20 26 if (!rc && (data1_len != data2_len)) { 21 27 if (data1_len < data2_len) ··· 29 23 else 30 24 rc = 1; 31 25 } 32 - ntfs_debug("Done, returning %i", rc); 33 26 return rc; 34 27 } 35 28 36 - static int ntfs_collate_ntofs_ulong(ntfs_volume *vol, 37 - const void *data1, const int data1_len, 38 - const void *data2, const int data2_len) 29 + static int ntfs_collate_ntofs_ulong(struct ntfs_volume *vol, 30 + const void *data1, const u32 data1_len, 31 + const void *data2, const u32 data2_len) 39 32 { 40 33 int rc; 41 - u32 d1, d2; 34 + u32 d1 = le32_to_cpup(data1), d2 = le32_to_cpup(data2); 42 35 43 - ntfs_debug("Entering."); 44 - // FIXME: We don't really want to bug here. 45 - BUG_ON(data1_len != data2_len); 46 - BUG_ON(data1_len != 4); 47 - d1 = le32_to_cpup(data1); 48 - d2 = le32_to_cpup(data2); 36 + if (data1_len != data2_len || data1_len != 4) 37 + return -EINVAL; 38 + 49 39 if (d1 < d2) 50 40 rc = -1; 51 41 else { ··· 50 48 else 51 49 rc = 1; 52 50 } 53 - ntfs_debug("Done, returning %i", rc); 54 51 return rc; 55 52 } 56 53 57 - typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, const int, 58 - const void *, const int); 54 + /* 55 + * ntfs_collate_ntofs_ulongs - Which of two le32 arrays should be listed first 56 + * @vol: ntfs volume 57 + * @data1: first ulong array to collate 58 + * @data1_len: length in bytes of @data1 59 + * @data2: second ulong array to collate 60 + * @data2_len: length in bytes of @data2 61 + * 62 + * Returns: -1, 0 or 1 depending of how the arrays compare 63 + */ 64 + static int ntfs_collate_ntofs_ulongs(struct ntfs_volume *vol, 65 + const void *data1, const u32 data1_len, 66 + const void *data2, const u32 data2_len) 67 + { 68 + int len; 69 + const __le32 *p1 = data1, *p2 = data2; 70 + u32 d1, d2; 59 71 60 - static ntfs_collate_func_t ntfs_do_collate0x0[3] = { 61 - ntfs_collate_binary, 62 - NULL/*ntfs_collate_file_name*/, 63 - NULL/*ntfs_collate_unicode_string*/, 64 - }; 72 + if (data1_len != data2_len || data1_len & 3) { 73 + ntfs_error(vol->sb, "data1_len or data2_len not valid\n"); 74 + return -1; 75 + } 65 76 66 - static ntfs_collate_func_t ntfs_do_collate0x1[4] = { 67 - ntfs_collate_ntofs_ulong, 68 - NULL/*ntfs_collate_ntofs_sid*/, 69 - NULL/*ntfs_collate_ntofs_security_hash*/, 70 - NULL/*ntfs_collate_ntofs_ulongs*/, 71 - }; 77 + len = data1_len; 78 + do { 79 + d1 = le32_to_cpup(p1); 80 + p1++; 81 + d2 = le32_to_cpup(p2); 82 + p2++; 83 + } while (d1 == d2 && (len -= 4) > 0); 84 + return cmp_int(d1, d2); 85 + } 72 86 73 - /** 87 + /* 88 + * ntfs_collate_file_name - Which of two filenames should be listed first 89 + * @vol: ntfs volume 90 + * @data1: first filename to collate 91 + * @data1_len: length in bytes of @data1(unused) 92 + * @data2: second filename to collate 93 + * @data2_len: length in bytes of @data2(unused) 94 + */ 95 + static int ntfs_collate_file_name(struct ntfs_volume *vol, 96 + const void *data1, const u32 data1_len, 97 + const void *data2, const u32 data2_len) 98 + { 99 + int rc; 100 + 101 + rc = ntfs_file_compare_values(data1, data2, -EINVAL, 102 + IGNORE_CASE, vol->upcase, vol->upcase_len); 103 + if (!rc) 104 + rc = ntfs_file_compare_values(data1, data2, 105 + -EINVAL, CASE_SENSITIVE, vol->upcase, vol->upcase_len); 106 + return rc; 107 + } 108 + 109 + /* 74 110 * ntfs_collate - collate two data items using a specified collation rule 75 111 * @vol: ntfs volume to which the data items belong 76 112 * @cr: collation rule to use when comparing the items ··· 119 79 * 120 80 * Collate the two data items @data1 and @data2 using the collation rule @cr 121 81 * and return -1, 0, ir 1 if @data1 is found, respectively, to collate before, 122 - * to match, or to collate after @data2. 123 - * 124 - * For speed we use the collation rule @cr as an index into two tables of 125 - * function pointers to call the appropriate collation function. 82 + * to match, or to collate after @data2. return -EINVAL if an error occurred. 126 83 */ 127 - int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr, 128 - const void *data1, const int data1_len, 129 - const void *data2, const int data2_len) { 130 - int i; 131 - 132 - ntfs_debug("Entering."); 133 - /* 134 - * FIXME: At the moment we only support COLLATION_BINARY and 135 - * COLLATION_NTOFS_ULONG, so we BUG() for everything else for now. 136 - */ 137 - BUG_ON(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG); 138 - i = le32_to_cpu(cr); 139 - BUG_ON(i < 0); 140 - if (i <= 0x02) 141 - return ntfs_do_collate0x0[i](vol, data1, data1_len, 142 - data2, data2_len); 143 - BUG_ON(i < 0x10); 144 - i -= 0x10; 145 - if (likely(i <= 3)) 146 - return ntfs_do_collate0x1[i](vol, data1, data1_len, 147 - data2, data2_len); 148 - BUG(); 149 - return 0; 84 + int ntfs_collate(struct ntfs_volume *vol, __le32 cr, 85 + const void *data1, const u32 data1_len, 86 + const void *data2, const u32 data2_len) 87 + { 88 + switch (le32_to_cpu(cr)) { 89 + case le32_to_cpu(COLLATION_BINARY): 90 + return ntfs_collate_binary(vol, data1, data1_len, 91 + data2, data2_len); 92 + case le32_to_cpu(COLLATION_FILE_NAME): 93 + return ntfs_collate_file_name(vol, data1, data1_len, 94 + data2, data2_len); 95 + case le32_to_cpu(COLLATION_NTOFS_ULONG): 96 + return ntfs_collate_ntofs_ulong(vol, data1, data1_len, 97 + data2, data2_len); 98 + case le32_to_cpu(COLLATION_NTOFS_ULONGS): 99 + return ntfs_collate_ntofs_ulongs(vol, data1, data1_len, 100 + data2, data2_len); 101 + default: 102 + ntfs_error(vol->sb, "Unknown collation rule 0x%x", 103 + le32_to_cpu(cr)); 104 + return -EINVAL; 105 + } 150 106 }
+30 -18
fs/ntfs/debug.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * debug.c - NTFS kernel debug support. Part of the Linux-NTFS project. 3 + * NTFS kernel debug support. 4 4 * 5 5 * Copyright (c) 2001-2004 Anton Altaparmakov 6 6 */ 7 7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 8 #include "debug.h" 9 9 10 - /** 10 + /* 11 11 * __ntfs_warning - output a warning to the syslog 12 12 * @function: name of function outputting the warning 13 13 * @sb: super block of mounted ntfs filesystem ··· 33 33 va_list args; 34 34 int flen = 0; 35 35 36 - #ifndef DEBUG 37 - if (!printk_ratelimit()) 38 - return; 39 - #endif 40 36 if (function) 41 37 flen = strlen(function); 42 38 va_start(args, fmt); 43 39 vaf.fmt = fmt; 44 40 vaf.va = &args; 41 + #ifdef DEBUG 45 42 if (sb) 46 43 pr_warn("(device %s): %s(): %pV\n", 47 44 sb->s_id, flen ? function : "", &vaf); 48 45 else 49 46 pr_warn("%s(): %pV\n", flen ? function : "", &vaf); 47 + #else 48 + if (sb) 49 + pr_warn_ratelimited("(device %s): %s(): %pV\n", 50 + sb->s_id, flen ? function : "", &vaf); 51 + else 52 + pr_warn_ratelimited("%s(): %pV\n", flen ? function : "", &vaf); 53 + #endif 50 54 va_end(args); 51 55 } 52 56 53 - /** 57 + /* 54 58 * __ntfs_error - output an error to the syslog 55 59 * @function: name of function outputting the error 56 60 * @sb: super block of mounted ntfs filesystem ··· 73 69 * Note, you should be using debug.h::ntfs_error(@sb, @fmt, @...) instead 74 70 * as this provides the @function parameter automatically. 75 71 */ 76 - void __ntfs_error(const char *function, const struct super_block *sb, 72 + void __ntfs_error(const char *function, struct super_block *sb, 77 73 const char *fmt, ...) 78 74 { 79 75 struct va_format vaf; 80 76 va_list args; 81 77 int flen = 0; 82 78 83 - #ifndef DEBUG 84 - if (!printk_ratelimit()) 85 - return; 86 - #endif 87 79 if (function) 88 80 flen = strlen(function); 89 81 va_start(args, fmt); 90 82 vaf.fmt = fmt; 91 83 vaf.va = &args; 84 + #ifdef DEBUG 92 85 if (sb) 93 86 pr_err("(device %s): %s(): %pV\n", 94 87 sb->s_id, flen ? function : "", &vaf); 95 88 else 96 89 pr_err("%s(): %pV\n", flen ? function : "", &vaf); 90 + #else 91 + if (sb) 92 + pr_err_ratelimited("(device %s): %s(): %pV\n", 93 + sb->s_id, flen ? function : "", &vaf); 94 + else 95 + pr_err_ratelimited("%s(): %pV\n", flen ? function : "", &vaf); 96 + #endif 97 97 va_end(args); 98 + 99 + if (sb) 100 + ntfs_handle_error(sb); 98 101 } 99 102 100 103 #ifdef DEBUG 101 104 102 105 /* If 1, output debug messages, and if 0, don't. */ 103 - int debug_msgs = 0; 106 + int debug_msgs; 104 107 105 108 void __ntfs_debug(const char *file, int line, const char *function, 106 109 const char *fmt, ...) ··· 128 117 } 129 118 130 119 /* Dump a runlist. Caller has to provide synchronisation for @rl. */ 131 - void ntfs_debug_dump_runlist(const runlist_element *rl) 120 + void ntfs_debug_dump_runlist(const struct runlist_element *rl) 132 121 { 133 122 int i; 134 - const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED", 135 - "LCN_ENOENT ", "LCN_unknown " }; 123 + const char *lcn_str[5] = { "LCN_DELALLOC ", "LCN_HOLE ", 124 + "LCN_RL_NOT_MAPPED", "LCN_ENOENT ", 125 + "LCN_unknown " }; 136 126 137 127 if (!debug_msgs) 138 128 return; ··· 144 132 } 145 133 pr_debug("VCN LCN Run length\n"); 146 134 for (i = 0; ; i++) { 147 - LCN lcn = (rl + i)->lcn; 135 + s64 lcn = (rl + i)->lcn; 148 136 149 - if (lcn < (LCN)0) { 137 + if (lcn < 0) { 150 138 int index = -lcn - 1; 151 139 152 140 if (index > -LCN_ENOENT - 1)
+181 -252
fs/ntfs/logfile.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project. 3 + * NTFS kernel journal handling. 4 4 * 5 5 * Copyright (c) 2002-2007 Anton Altaparmakov 6 6 */ 7 7 8 - #ifdef NTFS_RW 9 - 10 - #include <linux/types.h> 11 - #include <linux/fs.h> 12 - #include <linux/highmem.h> 13 - #include <linux/buffer_head.h> 14 - #include <linux/bitops.h> 15 - #include <linux/log2.h> 16 - #include <linux/bio.h> 8 + #include <linux/blkdev.h> 17 9 18 10 #include "attrib.h" 19 - #include "aops.h" 20 - #include "debug.h" 21 11 #include "logfile.h" 22 - #include "malloc.h" 23 - #include "volume.h" 24 12 #include "ntfs.h" 25 13 26 - /** 14 + /* 27 15 * ntfs_check_restart_page_header - check the page header for consistency 28 - * @vi: $LogFile inode to which the restart page header belongs 16 + * @vi: LogFile inode to which the restart page header belongs 29 17 * @rp: restart page header to check 30 18 * @pos: position in @vi at which the restart page header resides 31 19 * ··· 24 36 * require the full restart page. 25 37 */ 26 38 static bool ntfs_check_restart_page_header(struct inode *vi, 27 - RESTART_PAGE_HEADER *rp, s64 pos) 39 + struct restart_page_header *rp, s64 pos) 28 40 { 29 41 u32 logfile_system_page_size, logfile_log_page_size; 30 42 u16 ra_ofs, usa_count, usa_ofs, usa_end = 0; ··· 42 54 logfile_system_page_size & 43 55 (logfile_system_page_size - 1) || 44 56 !is_power_of_2(logfile_log_page_size)) { 45 - ntfs_error(vi->i_sb, "$LogFile uses unsupported page size."); 57 + ntfs_error(vi->i_sb, "LogFile uses unsupported page size."); 46 58 return false; 47 59 } 48 60 /* ··· 50 62 * size (2nd restart page). 51 63 */ 52 64 if (pos && pos != logfile_system_page_size) { 53 - ntfs_error(vi->i_sb, "Found restart area in incorrect " 54 - "position in $LogFile."); 65 + ntfs_error(vi->i_sb, "Found restart area in incorrect position in LogFile."); 55 66 return false; 56 67 } 57 68 /* We only know how to handle version 1.1. */ 58 - if (sle16_to_cpu(rp->major_ver) != 1 || 59 - sle16_to_cpu(rp->minor_ver) != 1) { 60 - ntfs_error(vi->i_sb, "$LogFile version %i.%i is not " 61 - "supported. (This driver supports version " 62 - "1.1 only.)", (int)sle16_to_cpu(rp->major_ver), 63 - (int)sle16_to_cpu(rp->minor_ver)); 69 + if (le16_to_cpu(rp->major_ver) != 1 || 70 + le16_to_cpu(rp->minor_ver) != 1) { 71 + ntfs_error(vi->i_sb, 72 + "LogFile version %i.%i is not supported. (This driver supports version 1.1 only.)", 73 + (int)le16_to_cpu(rp->major_ver), 74 + (int)le16_to_cpu(rp->minor_ver)); 64 75 return false; 65 76 } 66 77 /* ··· 73 86 /* Verify the size of the update sequence array. */ 74 87 usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS); 75 88 if (usa_count != le16_to_cpu(rp->usa_count)) { 76 - ntfs_error(vi->i_sb, "$LogFile restart page specifies " 77 - "inconsistent update sequence array count."); 89 + ntfs_error(vi->i_sb, 90 + "LogFile restart page specifies inconsistent update sequence array count."); 78 91 return false; 79 92 } 80 93 /* Verify the position of the update sequence array. */ 81 94 usa_ofs = le16_to_cpu(rp->usa_ofs); 82 95 usa_end = usa_ofs + usa_count * sizeof(u16); 83 - if (usa_ofs < sizeof(RESTART_PAGE_HEADER) || 96 + if (usa_ofs < sizeof(struct restart_page_header) || 84 97 usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) { 85 - ntfs_error(vi->i_sb, "$LogFile restart page specifies " 86 - "inconsistent update sequence array offset."); 98 + ntfs_error(vi->i_sb, 99 + "LogFile restart page specifies inconsistent update sequence array offset."); 87 100 return false; 88 101 } 89 102 skip_usa_checks: ··· 95 108 */ 96 109 ra_ofs = le16_to_cpu(rp->restart_area_offset); 97 110 if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end : 98 - ra_ofs < sizeof(RESTART_PAGE_HEADER)) || 111 + ra_ofs < sizeof(struct restart_page_header)) || 99 112 ra_ofs > logfile_system_page_size) { 100 - ntfs_error(vi->i_sb, "$LogFile restart page specifies " 101 - "inconsistent restart area offset."); 113 + ntfs_error(vi->i_sb, 114 + "LogFile restart page specifies inconsistent restart area offset."); 102 115 return false; 103 116 } 104 117 /* 105 118 * Only restart pages modified by chkdsk are allowed to have chkdsk_lsn 106 119 * set. 107 120 */ 108 - if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) { 109 - ntfs_error(vi->i_sb, "$LogFile restart page is not modified " 110 - "by chkdsk but a chkdsk LSN is specified."); 121 + if (!ntfs_is_chkd_record(rp->magic) && le64_to_cpu(rp->chkdsk_lsn)) { 122 + ntfs_error(vi->i_sb, 123 + "LogFile restart page is not modified by chkdsk but a chkdsk LSN is specified."); 111 124 return false; 112 125 } 113 126 ntfs_debug("Done."); 114 127 return true; 115 128 } 116 129 117 - /** 130 + /* 118 131 * ntfs_check_restart_area - check the restart area for consistency 119 - * @vi: $LogFile inode to which the restart page belongs 132 + * @vi: LogFile inode to which the restart page belongs 120 133 * @rp: restart page whose restart area to check 121 134 * 122 135 * Check the restart area of the restart page @rp for consistency and return ··· 128 141 * This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not 129 142 * require the full restart page. 130 143 */ 131 - static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp) 144 + static bool ntfs_check_restart_area(struct inode *vi, struct restart_page_header *rp) 132 145 { 133 146 u64 file_size; 134 - RESTART_AREA *ra; 147 + struct restart_area *ra; 135 148 u16 ra_ofs, ra_len, ca_ofs; 136 149 u8 fs_bits; 137 150 138 151 ntfs_debug("Entering."); 139 152 ra_ofs = le16_to_cpu(rp->restart_area_offset); 140 - ra = (RESTART_AREA*)((u8*)rp + ra_ofs); 153 + ra = (struct restart_area *)((u8 *)rp + ra_ofs); 141 154 /* 142 155 * Everything before ra->file_size must be before the first word 143 156 * protected by an update sequence number. This ensures that it is 144 157 * safe to access ra->client_array_offset. 145 158 */ 146 - if (ra_ofs + offsetof(RESTART_AREA, file_size) > 159 + if (ra_ofs + offsetof(struct restart_area, file_size) > 147 160 NTFS_BLOCK_SIZE - sizeof(u16)) { 148 - ntfs_error(vi->i_sb, "$LogFile restart area specifies " 149 - "inconsistent file offset."); 161 + ntfs_error(vi->i_sb, 162 + "LogFile restart area specifies inconsistent file offset."); 150 163 return false; 151 164 } 152 165 /* ··· 159 172 ca_ofs = le16_to_cpu(ra->client_array_offset); 160 173 if (((ca_ofs + 7) & ~7) != ca_ofs || 161 174 ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) { 162 - ntfs_error(vi->i_sb, "$LogFile restart area specifies " 163 - "inconsistent client array offset."); 175 + ntfs_error(vi->i_sb, 176 + "LogFile restart area specifies inconsistent client array offset."); 164 177 return false; 165 178 } 166 179 /* ··· 169 182 * Also, the calculated length must not exceed the specified length. 170 183 */ 171 184 ra_len = ca_ofs + le16_to_cpu(ra->log_clients) * 172 - sizeof(LOG_CLIENT_RECORD); 185 + sizeof(struct log_client_record); 173 186 if (ra_ofs + ra_len > le32_to_cpu(rp->system_page_size) || 174 187 ra_ofs + le16_to_cpu(ra->restart_area_length) > 175 188 le32_to_cpu(rp->system_page_size) || 176 189 ra_len > le16_to_cpu(ra->restart_area_length)) { 177 - ntfs_error(vi->i_sb, "$LogFile restart area is out of bounds " 178 - "of the system page size specified by the " 179 - "restart page header and/or the specified " 180 - "restart area length is inconsistent."); 190 + ntfs_error(vi->i_sb, 191 + "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."); 181 192 return false; 182 193 } 183 194 /* ··· 189 204 (ra->client_in_use_list != LOGFILE_NO_CLIENT && 190 205 le16_to_cpu(ra->client_in_use_list) >= 191 206 le16_to_cpu(ra->log_clients))) { 192 - ntfs_error(vi->i_sb, "$LogFile restart area specifies " 193 - "overflowing client free and/or in use lists."); 207 + ntfs_error(vi->i_sb, 208 + "LogFile restart area specifies overflowing client free and/or in use lists."); 194 209 return false; 195 210 } 196 211 /* 197 212 * Check ra->seq_number_bits against ra->file_size for consistency. 198 213 * We cannot just use ffs() because the file size is not a power of 2. 199 214 */ 200 - file_size = (u64)sle64_to_cpu(ra->file_size); 215 + file_size = le64_to_cpu(ra->file_size); 201 216 fs_bits = 0; 202 217 while (file_size) { 203 218 file_size >>= 1; 204 219 fs_bits++; 205 220 } 206 221 if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) { 207 - ntfs_error(vi->i_sb, "$LogFile restart area specifies " 208 - "inconsistent sequence number bits."); 222 + ntfs_error(vi->i_sb, 223 + "LogFile restart area specifies inconsistent sequence number bits."); 209 224 return false; 210 225 } 211 226 /* The log record header length must be a multiple of 8. */ 212 227 if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) != 213 228 le16_to_cpu(ra->log_record_header_length)) { 214 - ntfs_error(vi->i_sb, "$LogFile restart area specifies " 215 - "inconsistent log record header length."); 229 + ntfs_error(vi->i_sb, 230 + "LogFile restart area specifies inconsistent log record header length."); 216 231 return false; 217 232 } 218 233 /* Dito for the log page data offset. */ 219 234 if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) != 220 235 le16_to_cpu(ra->log_page_data_offset)) { 221 - ntfs_error(vi->i_sb, "$LogFile restart area specifies " 222 - "inconsistent log page data offset."); 236 + ntfs_error(vi->i_sb, 237 + "LogFile restart area specifies inconsistent log page data offset."); 223 238 return false; 224 239 } 225 240 ntfs_debug("Done."); 226 241 return true; 227 242 } 228 243 229 - /** 244 + /* 230 245 * ntfs_check_log_client_array - check the log client array for consistency 231 - * @vi: $LogFile inode to which the restart page belongs 246 + * @vi: LogFile inode to which the restart page belongs 232 247 * @rp: restart page whose log client array to check 233 248 * 234 249 * Check the log client array of the restart page @rp for consistency and ··· 242 257 * restart page and the page must be multi sector transfer deprotected. 243 258 */ 244 259 static bool ntfs_check_log_client_array(struct inode *vi, 245 - RESTART_PAGE_HEADER *rp) 260 + struct restart_page_header *rp) 246 261 { 247 - RESTART_AREA *ra; 248 - LOG_CLIENT_RECORD *ca, *cr; 262 + struct restart_area *ra; 263 + struct log_client_record *ca, *cr; 249 264 u16 nr_clients, idx; 250 265 bool in_free_list, idx_is_first; 251 266 252 267 ntfs_debug("Entering."); 253 - ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); 254 - ca = (LOG_CLIENT_RECORD*)((u8*)ra + 268 + ra = (struct restart_area *)((u8 *)rp + le16_to_cpu(rp->restart_area_offset)); 269 + ca = (struct log_client_record *)((u8 *)ra + 255 270 le16_to_cpu(ra->client_array_offset)); 256 271 /* 257 272 * Check the ra->client_free_list first and then check the ··· 287 302 ntfs_debug("Done."); 288 303 return true; 289 304 err_out: 290 - ntfs_error(vi->i_sb, "$LogFile log client array is corrupt."); 305 + ntfs_error(vi->i_sb, "LogFile log client array is corrupt."); 291 306 return false; 292 307 } 293 308 294 - /** 309 + /* 295 310 * ntfs_check_and_load_restart_page - check the restart page for consistency 296 - * @vi: $LogFile inode to which the restart page belongs 311 + * @vi: LogFile inode to which the restart page belongs 297 312 * @rp: restart page to check 298 313 * @pos: position in @vi at which the restart page resides 299 314 * @wrp: [OUT] copy of the multi sector transfer deprotected restart page ··· 316 331 * The following error codes are defined: 317 332 * -EINVAL - The restart page is inconsistent. 318 333 * -ENOMEM - Not enough memory to load the restart page. 319 - * -EIO - Failed to reading from $LogFile. 334 + * -EIO - Failed to reading from LogFile. 320 335 */ 321 336 static int ntfs_check_and_load_restart_page(struct inode *vi, 322 - RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp, 323 - LSN *lsn) 337 + struct restart_page_header *rp, s64 pos, struct restart_page_header **wrp, 338 + s64 *lsn) 324 339 { 325 - RESTART_AREA *ra; 326 - RESTART_PAGE_HEADER *trp; 340 + struct restart_area *ra; 341 + struct restart_page_header *trp; 327 342 int size, err; 328 343 329 344 ntfs_debug("Entering."); ··· 337 352 /* Error output already done inside the function. */ 338 353 return -EINVAL; 339 354 } 340 - ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); 355 + ra = (struct restart_area *)((u8 *)rp + le16_to_cpu(rp->restart_area_offset)); 341 356 /* 342 357 * Allocate a buffer to store the whole restart page so we can multi 343 358 * sector transfer deprotect it. 344 359 */ 345 - trp = ntfs_malloc_nofs(le32_to_cpu(rp->system_page_size)); 360 + trp = kvzalloc(le32_to_cpu(rp->system_page_size), GFP_NOFS); 346 361 if (!trp) { 347 - ntfs_error(vi->i_sb, "Failed to allocate memory for $LogFile " 348 - "restart page buffer."); 362 + ntfs_error(vi->i_sb, "Failed to allocate memory for LogFile restart page buffer."); 349 363 return -ENOMEM; 350 364 } 351 365 /* ··· 357 373 memcpy(trp, rp, le32_to_cpu(rp->system_page_size)); 358 374 } else { 359 375 pgoff_t idx; 360 - struct page *page; 376 + struct folio *folio; 361 377 int have_read, to_read; 362 378 363 379 /* First copy what we already have in @rp. */ ··· 366 382 have_read = size; 367 383 to_read = le32_to_cpu(rp->system_page_size) - size; 368 384 idx = (pos + size) >> PAGE_SHIFT; 369 - BUG_ON((pos + size) & ~PAGE_MASK); 370 385 do { 371 - page = ntfs_map_page(vi->i_mapping, idx); 372 - if (IS_ERR(page)) { 373 - ntfs_error(vi->i_sb, "Error mapping $LogFile " 374 - "page (index %lu).", idx); 375 - err = PTR_ERR(page); 386 + folio = read_mapping_folio(vi->i_mapping, idx, NULL); 387 + if (IS_ERR(folio)) { 388 + ntfs_error(vi->i_sb, "Error mapping LogFile page (index %lu).", 389 + idx); 390 + err = PTR_ERR(folio); 376 391 if (err != -EIO && err != -ENOMEM) 377 392 err = -EIO; 378 393 goto err_out; 379 394 } 380 395 size = min_t(int, to_read, PAGE_SIZE); 381 - memcpy((u8*)trp + have_read, page_address(page), size); 382 - ntfs_unmap_page(page); 396 + memcpy((u8 *)trp + have_read, folio_address(folio), size); 397 + folio_put(folio); 383 398 have_read += size; 384 399 to_read -= size; 385 400 idx++; ··· 388 405 * Perform the multi sector transfer deprotection on the buffer if the 389 406 * restart page is protected. 390 407 */ 391 - if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) 392 - && post_read_mst_fixup((NTFS_RECORD*)trp, 393 - le32_to_cpu(rp->system_page_size))) { 408 + if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count)) && 409 + post_read_mst_fixup((struct ntfs_record *)trp, le32_to_cpu(rp->system_page_size))) { 394 410 /* 395 - * A multi sector tranfer error was detected. We only need to 411 + * A multi sector transfer error was detected. We only need to 396 412 * abort if the restart page contents exceed the multi sector 397 413 * transfer fixup of the first sector. 398 414 */ 399 415 if (le16_to_cpu(rp->restart_area_offset) + 400 416 le16_to_cpu(ra->restart_area_length) > 401 417 NTFS_BLOCK_SIZE - sizeof(u16)) { 402 - ntfs_error(vi->i_sb, "Multi sector transfer error " 403 - "detected in $LogFile restart page."); 418 + ntfs_error(vi->i_sb, 419 + "Multi sector transfer error detected in LogFile restart page."); 404 420 err = -EINVAL; 405 421 goto err_out; 406 422 } ··· 419 437 } 420 438 if (lsn) { 421 439 if (ntfs_is_rstr_record(rp->magic)) 422 - *lsn = sle64_to_cpu(ra->current_lsn); 440 + *lsn = le64_to_cpu(ra->current_lsn); 423 441 else /* if (ntfs_is_chkd_record(rp->magic)) */ 424 - *lsn = sle64_to_cpu(rp->chkdsk_lsn); 442 + *lsn = le64_to_cpu(rp->chkdsk_lsn); 425 443 } 426 444 ntfs_debug("Done."); 427 445 if (wrp) 428 446 *wrp = trp; 429 447 else { 430 448 err_out: 431 - ntfs_free(trp); 449 + kvfree(trp); 432 450 } 433 451 return err; 434 452 } 435 453 436 - /** 454 + /* 437 455 * ntfs_check_logfile - check the journal for consistency 438 - * @log_vi: struct inode of loaded journal $LogFile to check 456 + * @log_vi: struct inode of loaded journal LogFile to check 439 457 * @rp: [OUT] on success this is a copy of the current restart page 440 458 * 441 - * Check the $LogFile journal for consistency and return 'true' if it is 459 + * Check the LogFile journal for consistency and return 'true' if it is 442 460 * consistent and 'false' if not. On success, the current restart page is 443 - * returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it. 461 + * returned in *@rp. Caller must call kvfree(*@rp) when finished with it. 444 462 * 445 463 * At present we only check the two restart pages and ignore the log record 446 464 * pages. 447 465 * 448 - * Note that the MstProtected flag is not set on the $LogFile inode and hence 466 + * Note that the MstProtected flag is not set on the LogFile inode and hence 449 467 * when reading pages they are not deprotected. This is because we do not know 450 - * if the $LogFile was created on a system with a different page size to ours 468 + * if the LogFile was created on a system with a different page size to ours 451 469 * yet and mst deprotection would fail if our page size is smaller. 452 470 */ 453 - bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp) 471 + bool ntfs_check_logfile(struct inode *log_vi, struct restart_page_header **rp) 454 472 { 455 473 s64 size, pos; 456 - LSN rstr1_lsn, rstr2_lsn; 457 - ntfs_volume *vol = NTFS_SB(log_vi->i_sb); 474 + s64 rstr1_lsn, rstr2_lsn; 475 + struct ntfs_volume *vol = NTFS_SB(log_vi->i_sb); 458 476 struct address_space *mapping = log_vi->i_mapping; 459 - struct page *page = NULL; 477 + struct folio *folio = NULL; 460 478 u8 *kaddr = NULL; 461 - RESTART_PAGE_HEADER *rstr1_ph = NULL; 462 - RESTART_PAGE_HEADER *rstr2_ph = NULL; 479 + struct restart_page_header *rstr1_ph = NULL; 480 + struct restart_page_header *rstr2_ph = NULL; 463 481 int log_page_size, err; 464 482 bool logfile_is_empty = true; 465 483 u8 log_page_bits; 466 484 467 485 ntfs_debug("Entering."); 468 - /* An empty $LogFile must have been clean before it got emptied. */ 486 + /* An empty LogFile must have been clean before it got emptied. */ 469 487 if (NVolLogFileEmpty(vol)) 470 488 goto is_empty; 471 489 size = i_size_read(log_vi); ··· 478 496 * log page size if the page cache size is between the default log page 479 497 * size and twice that. 480 498 */ 481 - if (PAGE_SIZE >= DefaultLogPageSize && PAGE_SIZE <= 482 - DefaultLogPageSize * 2) 499 + if (DefaultLogPageSize <= PAGE_SIZE && 500 + DefaultLogPageSize * 2 <= PAGE_SIZE) 483 501 log_page_size = DefaultLogPageSize; 484 502 else 485 503 log_page_size = PAGE_SIZE; ··· 495 513 */ 496 514 if (size < log_page_size * 2 || (size - log_page_size * 2) >> 497 515 log_page_bits < MinLogRecordPages) { 498 - ntfs_error(vol->sb, "$LogFile is too small."); 516 + ntfs_error(vol->sb, "LogFile is too small."); 499 517 return false; 500 518 } 501 519 /* ··· 508 526 */ 509 527 for (pos = 0; pos < size; pos <<= 1) { 510 528 pgoff_t idx = pos >> PAGE_SHIFT; 511 - if (!page || page->index != idx) { 512 - if (page) 513 - ntfs_unmap_page(page); 514 - page = ntfs_map_page(mapping, idx); 515 - if (IS_ERR(page)) { 516 - ntfs_error(vol->sb, "Error mapping $LogFile " 517 - "page (index %lu).", idx); 529 + 530 + if (!folio || folio->index != idx) { 531 + if (folio) { 532 + kunmap_local(kaddr); 533 + folio_put(folio); 534 + } 535 + folio = read_mapping_folio(mapping, idx, NULL); 536 + if (IS_ERR(folio)) { 537 + ntfs_error(vol->sb, "Error mapping LogFile page (index %lu).", 538 + idx); 518 539 goto err_out; 519 540 } 520 541 } 521 - kaddr = (u8*)page_address(page) + (pos & ~PAGE_MASK); 542 + kaddr = (u8 *)kmap_local_folio(folio, 0) + (pos & ~PAGE_MASK); 522 543 /* 523 544 * A non-empty block means the logfile is not empty while an 524 545 * empty block after a non-empty block has been encountered 525 546 * means we are done. 526 547 */ 527 - if (!ntfs_is_empty_recordp((le32*)kaddr)) 548 + if (!ntfs_is_empty_recordp((__le32 *)kaddr)) 528 549 logfile_is_empty = false; 529 550 else if (!logfile_is_empty) 530 551 break; ··· 535 550 * A log record page means there cannot be a restart page after 536 551 * this so no need to continue searching. 537 552 */ 538 - if (ntfs_is_rcrd_recordp((le32*)kaddr)) 553 + if (ntfs_is_rcrd_recordp((__le32 *)kaddr)) 539 554 break; 540 555 /* If not a (modified by chkdsk) restart page, continue. */ 541 - if (!ntfs_is_rstr_recordp((le32*)kaddr) && 542 - !ntfs_is_chkd_recordp((le32*)kaddr)) { 556 + if (!ntfs_is_rstr_recordp((__le32 *)kaddr) && 557 + !ntfs_is_chkd_recordp((__le32 *)kaddr)) { 543 558 if (!pos) 544 559 pos = NTFS_BLOCK_SIZE >> 1; 545 560 continue; ··· 550 565 * deprotected restart page. 551 566 */ 552 567 err = ntfs_check_and_load_restart_page(log_vi, 553 - (RESTART_PAGE_HEADER*)kaddr, pos, 568 + (struct restart_page_header *)kaddr, pos, 554 569 !rstr1_ph ? &rstr1_ph : &rstr2_ph, 555 570 !rstr1_ph ? &rstr1_lsn : &rstr2_lsn); 556 571 if (!err) { ··· 574 589 * find a valid one further in the file. 575 590 */ 576 591 if (err != -EINVAL) { 577 - ntfs_unmap_page(page); 592 + kunmap_local(kaddr); 593 + folio_put(folio); 578 594 goto err_out; 579 595 } 580 596 /* Continue looking. */ 581 597 if (!pos) 582 598 pos = NTFS_BLOCK_SIZE >> 1; 583 599 } 584 - if (page) 585 - ntfs_unmap_page(page); 600 + if (folio) { 601 + kunmap_local(kaddr); 602 + folio_put(folio); 603 + } 586 604 if (logfile_is_empty) { 587 605 NVolSetLogFileEmpty(vol); 588 606 is_empty: 589 - ntfs_debug("Done. ($LogFile is empty.)"); 607 + ntfs_debug("Done. (LogFile is empty.)"); 590 608 return true; 591 609 } 592 610 if (!rstr1_ph) { 593 - BUG_ON(rstr2_ph); 594 - ntfs_error(vol->sb, "Did not find any restart pages in " 595 - "$LogFile and it was not empty."); 611 + ntfs_error(vol->sb, 612 + "Did not find any restart pages in LogFile and it was not empty."); 596 613 return false; 597 614 } 598 615 /* If both restart pages were found, use the more recent one. */ ··· 604 617 * Otherwise just throw it away. 605 618 */ 606 619 if (rstr2_lsn > rstr1_lsn) { 607 - ntfs_debug("Using second restart page as it is more " 608 - "recent."); 609 - ntfs_free(rstr1_ph); 620 + ntfs_debug("Using second restart page as it is more recent."); 621 + kvfree(rstr1_ph); 610 622 rstr1_ph = rstr2_ph; 611 623 /* rstr1_lsn = rstr2_lsn; */ 612 624 } else { 613 - ntfs_debug("Using first restart page as it is more " 614 - "recent."); 615 - ntfs_free(rstr2_ph); 625 + ntfs_debug("Using first restart page as it is more recent."); 626 + kvfree(rstr2_ph); 616 627 } 617 628 rstr2_ph = NULL; 618 629 } ··· 618 633 if (rp) 619 634 *rp = rstr1_ph; 620 635 else 621 - ntfs_free(rstr1_ph); 636 + kvfree(rstr1_ph); 622 637 ntfs_debug("Done."); 623 638 return true; 624 639 err_out: 625 640 if (rstr1_ph) 626 - ntfs_free(rstr1_ph); 641 + kvfree(rstr1_ph); 627 642 return false; 628 643 } 629 644 630 - /** 631 - * ntfs_is_logfile_clean - check in the journal if the volume is clean 632 - * @log_vi: struct inode of loaded journal $LogFile to check 633 - * @rp: copy of the current restart page 645 + /* 646 + * ntfs_empty_logfile - empty the contents of the LogFile journal 647 + * @log_vi: struct inode of loaded journal LogFile to empty 634 648 * 635 - * Analyze the $LogFile journal and return 'true' if it indicates the volume was 636 - * shutdown cleanly and 'false' if not. 637 - * 638 - * At present we only look at the two restart pages and ignore the log record 639 - * pages. This is a little bit crude in that there will be a very small number 640 - * of cases where we think that a volume is dirty when in fact it is clean. 641 - * This should only affect volumes that have not been shutdown cleanly but did 642 - * not have any pending, non-check-pointed i/o, i.e. they were completely idle 643 - * at least for the five seconds preceding the unclean shutdown. 644 - * 645 - * This function assumes that the $LogFile journal has already been consistency 646 - * checked by a call to ntfs_check_logfile() and in particular if the $LogFile 647 - * is empty this function requires that NVolLogFileEmpty() is true otherwise an 648 - * empty volume will be reported as dirty. 649 - */ 650 - bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp) 651 - { 652 - ntfs_volume *vol = NTFS_SB(log_vi->i_sb); 653 - RESTART_AREA *ra; 654 - 655 - ntfs_debug("Entering."); 656 - /* An empty $LogFile must have been clean before it got emptied. */ 657 - if (NVolLogFileEmpty(vol)) { 658 - ntfs_debug("Done. ($LogFile is empty.)"); 659 - return true; 660 - } 661 - BUG_ON(!rp); 662 - if (!ntfs_is_rstr_record(rp->magic) && 663 - !ntfs_is_chkd_record(rp->magic)) { 664 - ntfs_error(vol->sb, "Restart page buffer is invalid. This is " 665 - "probably a bug in that the $LogFile should " 666 - "have been consistency checked before calling " 667 - "this function."); 668 - return false; 669 - } 670 - ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); 671 - /* 672 - * If the $LogFile has active clients, i.e. it is open, and we do not 673 - * have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags, 674 - * we assume there was an unclean shutdown. 675 - */ 676 - if (ra->client_in_use_list != LOGFILE_NO_CLIENT && 677 - !(ra->flags & RESTART_VOLUME_IS_CLEAN)) { 678 - ntfs_debug("Done. $LogFile indicates a dirty shutdown."); 679 - return false; 680 - } 681 - /* $LogFile indicates a clean shutdown. */ 682 - ntfs_debug("Done. $LogFile indicates a clean shutdown."); 683 - return true; 684 - } 685 - 686 - /** 687 - * ntfs_empty_logfile - empty the contents of the $LogFile journal 688 - * @log_vi: struct inode of loaded journal $LogFile to empty 689 - * 690 - * Empty the contents of the $LogFile journal @log_vi and return 'true' on 649 + * Empty the contents of the LogFile journal @log_vi and return 'true' on 691 650 * success and 'false' on error. 692 651 * 693 - * This function assumes that the $LogFile journal has already been consistency 652 + * This function assumes that the LogFile journal has already been consistency 694 653 * checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean() 695 - * has been used to ensure that the $LogFile is clean. 654 + * has been used to ensure that the LogFile is clean. 696 655 */ 697 656 bool ntfs_empty_logfile(struct inode *log_vi) 698 657 { 699 - VCN vcn, end_vcn; 700 - ntfs_inode *log_ni = NTFS_I(log_vi); 701 - ntfs_volume *vol = log_ni->vol; 658 + s64 vcn, end_vcn; 659 + struct ntfs_inode *log_ni = NTFS_I(log_vi); 660 + struct ntfs_volume *vol = log_ni->vol; 702 661 struct super_block *sb = vol->sb; 703 - runlist_element *rl; 662 + struct runlist_element *rl; 704 663 unsigned long flags; 705 - unsigned block_size, block_size_bits; 706 664 int err; 707 665 bool should_wait = true; 666 + char *empty_buf = NULL; 667 + struct file_ra_state *ra = NULL; 708 668 709 669 ntfs_debug("Entering."); 710 670 if (NVolLogFileEmpty(vol)) { 711 671 ntfs_debug("Done."); 712 672 return true; 713 673 } 674 + 714 675 /* 715 676 * We cannot use ntfs_attr_set() because we may be still in the middle 716 677 * of a mount operation. Thus we do the emptying by hand by first 717 - * zapping the page cache pages for the $LogFile/$DATA attribute and 678 + * zapping the page cache pages for the LogFile/DATA attribute and 718 679 * then emptying each of the buffers in each of the clusters specified 719 680 * by the runlist by hand. 720 681 */ 721 - block_size = sb->s_blocksize; 722 - block_size_bits = sb->s_blocksize_bits; 723 682 vcn = 0; 724 683 read_lock_irqsave(&log_ni->size_lock, flags); 725 684 end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >> ··· 676 747 map_vcn: 677 748 err = ntfs_map_runlist_nolock(log_ni, vcn, NULL); 678 749 if (err) { 679 - ntfs_error(sb, "Failed to map runlist fragment (error " 680 - "%d).", -err); 750 + ntfs_error(sb, "Failed to map runlist fragment (error %d).", -err); 681 751 goto err; 682 752 } 683 753 rl = log_ni->runlist.rl; 684 - BUG_ON(!rl || vcn < rl->vcn || !rl->length); 685 754 } 686 755 /* Seek to the runlist element containing @vcn. */ 687 756 while (rl->length && vcn >= rl[1].vcn) 688 757 rl++; 758 + 759 + err = -ENOMEM; 760 + empty_buf = kvzalloc(vol->cluster_size, GFP_NOFS); 761 + if (!empty_buf) 762 + goto err; 763 + 764 + memset(empty_buf, 0xff, vol->cluster_size); 765 + 766 + ra = kzalloc(sizeof(*ra), GFP_NOFS); 767 + if (!ra) 768 + goto err; 769 + 770 + file_ra_state_init(ra, sb->s_bdev->bd_mapping); 689 771 do { 690 - LCN lcn; 691 - sector_t block, end_block; 772 + s64 lcn; 773 + loff_t start, end; 692 774 s64 len; 693 775 694 776 /* ··· 709 769 lcn = rl->lcn; 710 770 if (unlikely(lcn == LCN_RL_NOT_MAPPED)) { 711 771 vcn = rl->vcn; 772 + kvfree(empty_buf); 712 773 goto map_vcn; 713 774 } 714 775 /* If this run is not valid abort with an error. */ ··· 718 777 /* Skip holes. */ 719 778 if (lcn == LCN_HOLE) 720 779 continue; 721 - block = lcn << vol->cluster_size_bits >> block_size_bits; 780 + start = NTFS_CLU_TO_B(vol, lcn); 722 781 len = rl->length; 723 782 if (rl[1].vcn > end_vcn) 724 783 len = end_vcn - rl->vcn; 725 - end_block = (lcn + len) << vol->cluster_size_bits >> 726 - block_size_bits; 727 - /* Iterate over the blocks in the run and empty them. */ 728 - do { 729 - struct buffer_head *bh; 784 + end = NTFS_CLU_TO_B(vol, lcn + len); 730 785 731 - /* Obtain the buffer, possibly not uptodate. */ 732 - bh = sb_getblk(sb, block); 733 - BUG_ON(!bh); 734 - /* Setup buffer i/o submission. */ 735 - lock_buffer(bh); 736 - bh->b_end_io = end_buffer_write_sync; 737 - get_bh(bh); 738 - /* Set the entire contents of the buffer to 0xff. */ 739 - memset(bh->b_data, -1, block_size); 740 - if (!buffer_uptodate(bh)) 741 - set_buffer_uptodate(bh); 742 - if (buffer_dirty(bh)) 743 - clear_buffer_dirty(bh); 786 + page_cache_sync_readahead(sb->s_bdev->bd_mapping, ra, NULL, 787 + start >> PAGE_SHIFT, (end - start) >> PAGE_SHIFT); 788 + 789 + do { 790 + err = ntfs_bdev_write(sb, empty_buf, start, 791 + vol->cluster_size); 792 + if (err) { 793 + ntfs_error(sb, "ntfs_dev_write failed, err : %d\n", err); 794 + goto io_err; 795 + } 796 + 744 797 /* 745 798 * Submit the buffer and wait for i/o to complete but 746 799 * only for the first buffer so we do not miss really ··· 742 807 * completed ignore errors afterwards as we can assume 743 808 * that if one buffer worked all of them will work. 744 809 */ 745 - submit_bh(REQ_OP_WRITE, bh); 746 810 if (should_wait) { 747 811 should_wait = false; 748 - wait_on_buffer(bh); 749 - if (unlikely(!buffer_uptodate(bh))) 812 + err = filemap_write_and_wait_range(sb->s_bdev->bd_mapping, 813 + start, start + vol->cluster_size); 814 + if (err) 750 815 goto io_err; 751 816 } 752 - brelse(bh); 753 - } while (++block < end_block); 817 + start += vol->cluster_size; 818 + } while (start < end); 754 819 } while ((++rl)->vcn < end_vcn); 755 820 up_write(&log_ni->runlist.lock); 756 - /* 757 - * Zap the pages again just in case any got instantiated whilst we were 758 - * emptying the blocks by hand. FIXME: We may not have completed 759 - * writing to all the buffer heads yet so this may happen too early. 760 - * We really should use a kernel thread to do the emptying 761 - * asynchronously and then we can also set the volume dirty and output 762 - * an error message if emptying should fail. 763 - */ 821 + kfree(empty_buf); 822 + kfree(ra); 764 823 truncate_inode_pages(log_vi->i_mapping, 0); 765 824 /* Set the flag so we do not have to do it again on remount. */ 766 825 NVolSetLogFileEmpty(vol); ··· 769 840 NVolSetErrors(vol); 770 841 err = -EIO; 771 842 err: 843 + kvfree(empty_buf); 844 + kfree(ra); 772 845 up_write(&log_ni->runlist.lock); 773 - ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).", 846 + ntfs_error(sb, "Failed to fill LogFile with 0xff bytes (error %d).", 774 847 -err); 775 848 return false; 776 849 } 777 - 778 - #endif /* NTFS_RW */
+158
fs/ntfs/object_id.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Pocessing of object ids 4 + * 5 + * Part of this file is based on code from the NTFS-3G. 6 + * 7 + * Copyright (c) 2009-2019 Jean-Pierre Andre 8 + * Copyright (c) 2026 LG Electronics Co., Ltd. 9 + */ 10 + 11 + #include "ntfs.h" 12 + #include "index.h" 13 + #include "object_id.h" 14 + 15 + struct object_id_index_key { 16 + union { 17 + u32 alignment; 18 + struct guid guid; 19 + } object_id; 20 + } __packed; 21 + 22 + struct object_id_index_data { 23 + __le64 file_id; 24 + struct guid birth_volume_id; 25 + struct guid birth_object_id; 26 + struct guid domain_id; 27 + } __packed; 28 + 29 + /* Index entry in $Extend/$ObjId */ 30 + struct object_id_index { 31 + struct index_entry_header header; 32 + struct object_id_index_key key; 33 + struct object_id_index_data data; 34 + } __packed; 35 + 36 + __le16 objid_index_name[] = {cpu_to_le16('$'), cpu_to_le16('O'), 0}; 37 + 38 + /* 39 + * open_object_id_index - Open the $Extend/$ObjId file and its index 40 + * @vol: NTFS volume structure 41 + * 42 + * Opens the $ObjId system file and retrieves its index context. 43 + * 44 + * Return: The index context if opened successfully, or NULL if an error 45 + * occurred. 46 + */ 47 + static struct ntfs_index_context *open_object_id_index(struct ntfs_volume *vol) 48 + { 49 + struct inode *dir_vi, *vi; 50 + struct ntfs_inode *dir_ni; 51 + struct ntfs_index_context *xo = NULL; 52 + struct ntfs_name *name = NULL; 53 + u64 mref; 54 + int uname_len; 55 + __le16 *uname; 56 + 57 + uname_len = ntfs_nlstoucs(vol, "$ObjId", 6, &uname, 58 + NTFS_MAX_NAME_LEN); 59 + if (uname_len < 0) 60 + return NULL; 61 + 62 + /* do not use path_name_to inode - could reopen root */ 63 + dir_vi = ntfs_iget(vol->sb, FILE_Extend); 64 + if (IS_ERR(dir_vi)) { 65 + kmem_cache_free(ntfs_name_cache, uname); 66 + return NULL; 67 + } 68 + dir_ni = NTFS_I(dir_vi); 69 + 70 + mutex_lock_nested(&dir_ni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 71 + mref = ntfs_lookup_inode_by_name(dir_ni, uname, uname_len, &name); 72 + mutex_unlock(&dir_ni->mrec_lock); 73 + kfree(name); 74 + kmem_cache_free(ntfs_name_cache, uname); 75 + if (IS_ERR_MREF(mref)) 76 + goto put_dir_vi; 77 + 78 + vi = ntfs_iget(vol->sb, MREF(mref)); 79 + if (IS_ERR(vi)) 80 + goto put_dir_vi; 81 + 82 + xo = ntfs_index_ctx_get(NTFS_I(vi), objid_index_name, 2); 83 + if (!xo) 84 + iput(vi); 85 + put_dir_vi: 86 + iput(dir_vi); 87 + return xo; 88 + } 89 + 90 + 91 + /* 92 + * remove_object_id_index - Remove an object id index entry if attribute present 93 + * @ni: NTFS inode structure containing the attribute 94 + * @xo: Index context for the object id index 95 + * 96 + * Reads the existing object ID attribute and removes it from the index. 97 + * 98 + * Return: 0 on success, or a negative error code on failure. 99 + */ 100 + static int remove_object_id_index(struct ntfs_inode *ni, struct ntfs_index_context *xo) 101 + { 102 + struct object_id_index_key key = {0}; 103 + s64 size; 104 + 105 + if (ni->data_size == 0) 106 + return -ENODATA; 107 + 108 + /* read the existing object id attribute */ 109 + size = ntfs_inode_attr_pread(VFS_I(ni), 0, sizeof(struct guid), 110 + (char *)&key); 111 + if (size != sizeof(struct guid)) 112 + return -ENODATA; 113 + 114 + if (!ntfs_index_lookup(&key, sizeof(struct object_id_index_key), xo)) 115 + return ntfs_index_rm(xo); 116 + 117 + return 0; 118 + } 119 + 120 + /* 121 + * ntfs_delete_object_id_index - Delete an object_id index entry 122 + * @ni: NTFS inode structure 123 + * 124 + * Opens the object ID index and removes the entry corresponding to the inode. 125 + * 126 + * Return: 0 on success, or a negative error code on failure. 127 + */ 128 + int ntfs_delete_object_id_index(struct ntfs_inode *ni) 129 + { 130 + struct ntfs_index_context *xo; 131 + struct ntfs_inode *xoni; 132 + struct inode *attr_vi; 133 + int ret = 0; 134 + 135 + attr_vi = ntfs_attr_iget(VFS_I(ni), AT_OBJECT_ID, AT_UNNAMED, 0); 136 + if (IS_ERR(attr_vi)) 137 + return PTR_ERR(attr_vi); 138 + 139 + /* 140 + * read the existing object id and un-index it 141 + */ 142 + xo = open_object_id_index(ni->vol); 143 + if (xo) { 144 + xoni = xo->idx_ni; 145 + mutex_lock_nested(&xoni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); 146 + ret = remove_object_id_index(NTFS_I(attr_vi), xo); 147 + if (!ret) { 148 + ntfs_index_entry_mark_dirty(xo); 149 + mark_mft_record_dirty(xoni); 150 + } 151 + ntfs_index_ctx_put(xo); 152 + mutex_unlock(&xoni->mrec_lock); 153 + iput(VFS_I(xoni)); 154 + } 155 + 156 + iput(attr_vi); 157 + return ret; 158 + }
+15 -23
fs/ntfs/quota.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * quota.c - NTFS kernel quota ($Quota) handling. Part of the Linux-NTFS 4 - * project. 3 + * NTFS kernel quota ($Quota) handling. 5 4 * 6 5 * Copyright (c) 2004 Anton Altaparmakov 7 6 */ 8 - 9 - #ifdef NTFS_RW 10 7 11 8 #include "index.h" 12 9 #include "quota.h" 13 10 #include "debug.h" 14 11 #include "ntfs.h" 15 12 16 - /** 13 + /* 17 14 * ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume 18 15 * @vol: ntfs volume on which to mark the quotas out of date 19 16 * 20 17 * Mark the quotas out of date on the ntfs volume @vol and return 'true' on 21 18 * success and 'false' on error. 22 19 */ 23 - bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol) 20 + bool ntfs_mark_quotas_out_of_date(struct ntfs_volume *vol) 24 21 { 25 - ntfs_index_context *ictx; 26 - QUOTA_CONTROL_ENTRY *qce; 27 - const le32 qid = QUOTA_DEFAULTS_ID; 22 + struct ntfs_index_context *ictx; 23 + struct quota_control_entry *qce; 24 + const __le32 qid = QUOTA_DEFAULTS_ID; 28 25 int err; 29 26 30 27 ntfs_debug("Entering."); ··· 32 35 return false; 33 36 } 34 37 inode_lock(vol->quota_q_ino); 35 - ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino)); 38 + ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino), I30, 4); 36 39 if (!ictx) { 37 40 ntfs_error(vol->sb, "Failed to get index context."); 38 41 goto err_out; ··· 40 43 err = ntfs_index_lookup(&qid, sizeof(qid), ictx); 41 44 if (err) { 42 45 if (err == -ENOENT) 43 - ntfs_error(vol->sb, "Quota defaults entry is not " 44 - "present."); 46 + ntfs_error(vol->sb, "Quota defaults entry is not present."); 45 47 else 46 - ntfs_error(vol->sb, "Lookup of quota defaults entry " 47 - "failed."); 48 + ntfs_error(vol->sb, "Lookup of quota defaults entry failed."); 48 49 goto err_out; 49 50 } 50 - if (ictx->data_len < offsetof(QUOTA_CONTROL_ENTRY, sid)) { 51 - ntfs_error(vol->sb, "Quota defaults entry size is invalid. " 52 - "Run chkdsk."); 51 + if (ictx->data_len < offsetof(struct quota_control_entry, sid)) { 52 + ntfs_error(vol->sb, "Quota defaults entry size is invalid. Run chkdsk."); 53 53 goto err_out; 54 54 } 55 - qce = (QUOTA_CONTROL_ENTRY*)ictx->data; 55 + qce = (struct quota_control_entry *)ictx->data; 56 56 if (le32_to_cpu(qce->version) != QUOTA_VERSION) { 57 - ntfs_error(vol->sb, "Quota defaults entry version 0x%x is not " 58 - "supported.", le32_to_cpu(qce->version)); 57 + ntfs_error(vol->sb, 58 + "Quota defaults entry version 0x%x is not supported.", 59 + le32_to_cpu(qce->version)); 59 60 goto err_out; 60 61 } 61 62 ntfs_debug("Quota defaults flags = 0x%x.", le32_to_cpu(qce->flags)); ··· 75 80 */ 76 81 qce->flags |= QUOTA_FLAG_OUT_OF_DATE; 77 82 /* Ensure the modified flags are written to disk. */ 78 - ntfs_index_entry_flush_dcache_page(ictx); 79 83 ntfs_index_entry_mark_dirty(ictx); 80 84 set_done: 81 85 ntfs_index_ctx_put(ictx); ··· 93 99 inode_unlock(vol->quota_q_ino); 94 100 return false; 95 101 } 96 - 97 - #endif /* NTFS_RW */
+5 -8
fs/ntfs/sysctl.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * sysctl.c - Code for sysctl handling in NTFS Linux kernel driver. Part of 4 - * the Linux-NTFS project. Adapted from the old NTFS driver, 5 - * Copyright (C) 1997 Martin von Löwis, Régis Duchesne 3 + * Code for sysctl handling in NTFS Linux kernel driver. 6 4 * 5 + * Copyright (C) 1997 Martin von Löwis, Régis Duchesne 7 6 * Copyright (c) 2002-2005 Anton Altaparmakov 8 7 */ 9 8 ··· 19 20 #include "debug.h" 20 21 21 22 /* Definition of the ntfs sysctl. */ 22 - static struct ctl_table ntfs_sysctls[] = { 23 + static const struct ctl_table ntfs_sysctls[] = { 23 24 { 24 25 .procname = "ntfs-debug", 25 26 .data = &debug_msgs, /* Data pointer and size. */ ··· 27 28 .mode = 0644, /* Mode, proc handler. */ 28 29 .proc_handler = proc_dointvec 29 30 }, 31 + {} 30 32 }; 31 33 32 34 /* Storage for the sysctls header. */ 33 35 static struct ctl_table_header *sysctls_root_table; 34 36 35 - /** 37 + /* 36 38 * ntfs_sysctl - add or remove the debug sysctl 37 39 * @add: add (1) or remove (0) the sysctl 38 40 * ··· 42 42 int ntfs_sysctl(int add) 43 43 { 44 44 if (add) { 45 - BUG_ON(sysctls_root_table); 46 45 sysctls_root_table = register_sysctl("fs", ntfs_sysctls); 47 46 if (!sysctls_root_table) 48 47 return -ENOMEM; 49 48 } else { 50 - BUG_ON(!sysctls_root_table); 51 49 unregister_sysctl_table(sysctls_root_table); 52 50 sysctls_root_table = NULL; 53 51 } 54 52 return 0; 55 53 } 56 - 57 54 #endif /* CONFIG_SYSCTL */ 58 55 #endif /* DEBUG */
+172 -79
fs/ntfs/unistr.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project. 3 + * NTFS Unicode string handling. 4 4 * 5 5 * Copyright (c) 2001-2006 Anton Altaparmakov 6 6 */ 7 7 8 - #include <linux/slab.h> 9 - 10 - #include "types.h" 11 - #include "debug.h" 12 8 #include "ntfs.h" 13 9 14 10 /* ··· 33 37 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18, 34 38 }; 35 39 36 - /** 40 + /* 37 41 * ntfs_are_names_equal - compare two Unicode names for equality 38 42 * @s1: name to compare to @s2 39 43 * @s1_len: length in Unicode characters of @s1 ··· 47 51 * identical, or 'false' (0) if they are not identical. If @ic is IGNORE_CASE, 48 52 * the @upcase table is used to performa a case insensitive comparison. 49 53 */ 50 - bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len, 51 - const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic, 52 - const ntfschar *upcase, const u32 upcase_size) 54 + bool ntfs_are_names_equal(const __le16 *s1, size_t s1_len, 55 + const __le16 *s2, size_t s2_len, const u32 ic, 56 + const __le16 *upcase, const u32 upcase_size) 53 57 { 54 58 if (s1_len != s2_len) 55 59 return false; ··· 58 62 return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size); 59 63 } 60 64 61 - /** 65 + /* 62 66 * ntfs_collate_names - collate two Unicode names 63 67 * @name1: first Unicode name to compare 68 + * @name1_len: first Unicode name length 64 69 * @name2: second Unicode name to compare 70 + * @name2_len: second Unicode name length 65 71 * @err_val: if @name1 contains an invalid character return this value 66 72 * @ic: either CASE_SENSITIVE or IGNORE_CASE 67 73 * @upcase: upcase table (ignored if @ic is CASE_SENSITIVE) ··· 78 80 * 79 81 * The following characters are considered invalid: '"', '*', '<', '>' and '?'. 80 82 */ 81 - int ntfs_collate_names(const ntfschar *name1, const u32 name1_len, 82 - const ntfschar *name2, const u32 name2_len, 83 - const int err_val, const IGNORE_CASE_BOOL ic, 84 - const ntfschar *upcase, const u32 upcase_len) 83 + int ntfs_collate_names(const __le16 *name1, const u32 name1_len, 84 + const __le16 *name2, const u32 name2_len, 85 + const int err_val, const u32 ic, 86 + const __le16 *upcase, const u32 upcase_len) 85 87 { 86 88 u32 cnt, min_len; 87 89 u16 c1, c2; ··· 116 118 return 1; 117 119 } 118 120 119 - /** 121 + /* 120 122 * ntfs_ucsncmp - compare two little endian Unicode strings 121 123 * @s1: first string 122 124 * @s2: second string ··· 130 132 * if @s1 (or the first @n Unicode characters thereof) is found, respectively, 131 133 * to be less than, to match, or be greater than @s2. 132 134 */ 133 - int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n) 135 + int ntfs_ucsncmp(const __le16 *s1, const __le16 *s2, size_t n) 134 136 { 135 137 u16 c1, c2; 136 138 size_t i; ··· 148 150 return 0; 149 151 } 150 152 151 - /** 153 + /* 152 154 * ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case 153 155 * @s1: first string 154 156 * @s2: second string ··· 166 168 * if @s1 (or the first @n Unicode characters thereof) is found, respectively, 167 169 * to be less than, to match, or be greater than @s2. 168 170 */ 169 - int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n, 170 - const ntfschar *upcase, const u32 upcase_size) 171 + int ntfs_ucsncasecmp(const __le16 *s1, const __le16 *s2, size_t n, 172 + const __le16 *upcase, const u32 upcase_size) 171 173 { 172 174 size_t i; 173 175 u16 c1, c2; 174 176 175 177 for (i = 0; i < n; ++i) { 176 - if ((c1 = le16_to_cpu(s1[i])) < upcase_size) 178 + c1 = le16_to_cpu(s1[i]); 179 + if (c1 < upcase_size) 177 180 c1 = le16_to_cpu(upcase[c1]); 178 - if ((c2 = le16_to_cpu(s2[i])) < upcase_size) 181 + c2 = le16_to_cpu(s2[i]); 182 + if (c2 < upcase_size) 179 183 c2 = le16_to_cpu(upcase[c2]); 180 184 if (c1 < c2) 181 185 return -1; ··· 189 189 return 0; 190 190 } 191 191 192 - void ntfs_upcase_name(ntfschar *name, u32 name_len, const ntfschar *upcase, 193 - const u32 upcase_len) 192 + int ntfs_file_compare_values(const struct file_name_attr *file_name_attr1, 193 + const struct file_name_attr *file_name_attr2, 194 + const int err_val, const u32 ic, 195 + const __le16 *upcase, const u32 upcase_len) 194 196 { 195 - u32 i; 196 - u16 u; 197 - 198 - for (i = 0; i < name_len; i++) 199 - if ((u = le16_to_cpu(name[i])) < upcase_len) 200 - name[i] = upcase[u]; 201 - } 202 - 203 - void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr, 204 - const ntfschar *upcase, const u32 upcase_len) 205 - { 206 - ntfs_upcase_name((ntfschar*)&file_name_attr->file_name, 207 - file_name_attr->file_name_length, upcase, upcase_len); 208 - } 209 - 210 - int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1, 211 - FILE_NAME_ATTR *file_name_attr2, 212 - const int err_val, const IGNORE_CASE_BOOL ic, 213 - const ntfschar *upcase, const u32 upcase_len) 214 - { 215 - return ntfs_collate_names((ntfschar*)&file_name_attr1->file_name, 197 + return ntfs_collate_names((__le16 *)&file_name_attr1->file_name, 216 198 file_name_attr1->file_name_length, 217 - (ntfschar*)&file_name_attr2->file_name, 199 + (__le16 *)&file_name_attr2->file_name, 218 200 file_name_attr2->file_name_length, 219 201 err_val, ic, upcase, upcase_len); 220 202 } 221 203 222 - /** 204 + /* 223 205 * ntfs_nlstoucs - convert NLS string to little endian Unicode string 224 206 * @vol: ntfs volume which we are working with 225 207 * @ins: input NLS string buffer 226 208 * @ins_len: length of input string in bytes 227 209 * @outs: on return contains the allocated output Unicode string buffer 210 + * @max_name_len: maximum number of Unicode characters allowed for the output name 228 211 * 229 212 * Convert the input string @ins, which is in whatever format the loaded NLS 230 213 * map dictates, into a little endian, 2-byte Unicode string. ··· 225 242 * 226 243 * This might look a bit odd due to fast path optimization... 227 244 */ 228 - int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins, 229 - const int ins_len, ntfschar **outs) 245 + int ntfs_nlstoucs(const struct ntfs_volume *vol, const char *ins, 246 + const int ins_len, __le16 **outs, int max_name_len) 230 247 { 231 248 struct nls_table *nls = vol->nls_map; 232 - ntfschar *ucs; 249 + __le16 *ucs; 233 250 wchar_t wc; 234 251 int i, o, wc_len; 235 252 236 253 /* We do not trust outside sources. */ 237 254 if (likely(ins)) { 238 - ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS); 255 + if (max_name_len > NTFS_MAX_NAME_LEN) 256 + ucs = kvmalloc((max_name_len + 2) * sizeof(__le16), 257 + GFP_NOFS | __GFP_ZERO); 258 + else 259 + ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS); 239 260 if (likely(ucs)) { 240 - for (i = o = 0; i < ins_len; i += wc_len) { 241 - wc_len = nls->char2uni(ins + i, ins_len - i, 242 - &wc); 243 - if (likely(wc_len >= 0 && 244 - o < NTFS_MAX_NAME_LEN)) { 245 - if (likely(wc)) { 246 - ucs[o++] = cpu_to_le16(wc); 247 - continue; 248 - } /* else if (!wc) */ 249 - break; 250 - } /* else if (wc_len < 0 || 251 - o >= NTFS_MAX_NAME_LEN) */ 252 - goto name_err; 261 + if (vol->nls_utf8) { 262 + o = utf8s_to_utf16s(ins, ins_len, 263 + UTF16_LITTLE_ENDIAN, 264 + (wchar_t *)ucs, 265 + max_name_len + 2); 266 + if (o < 0 || o > max_name_len) { 267 + wc_len = o; 268 + goto name_err; 269 + } 270 + } else { 271 + for (i = o = 0; i < ins_len; i += wc_len) { 272 + wc_len = nls->char2uni(ins + i, ins_len - i, 273 + &wc); 274 + if (likely(wc_len >= 0 && 275 + o < max_name_len)) { 276 + if (likely(wc)) { 277 + ucs[o++] = cpu_to_le16(wc); 278 + continue; 279 + } /* else if (!wc) */ 280 + break; 281 + } 282 + 283 + goto name_err; 284 + } 253 285 } 254 286 ucs[o] = 0; 255 287 *outs = ucs; 256 288 return o; 257 289 } /* else if (!ucs) */ 258 - ntfs_error(vol->sb, "Failed to allocate buffer for converted " 259 - "name from ntfs_name_cache."); 290 + ntfs_debug("Failed to allocate buffer for converted name from ntfs_name_cache."); 260 291 return -ENOMEM; 261 292 } /* else if (!ins) */ 262 293 ntfs_error(vol->sb, "Received NULL pointer."); 263 294 return -EINVAL; 264 295 name_err: 265 - kmem_cache_free(ntfs_name_cache, ucs); 296 + if (max_name_len > NTFS_MAX_NAME_LEN) 297 + kvfree(ucs); 298 + else 299 + kmem_cache_free(ntfs_name_cache, ucs); 266 300 if (wc_len < 0) { 267 - ntfs_error(vol->sb, "Name using character set %s contains " 268 - "characters that cannot be converted to " 269 - "Unicode.", nls->charset); 301 + ntfs_debug("Name using character set %s contains characters that cannot be converted to Unicode.", 302 + nls->charset); 270 303 i = -EILSEQ; 271 - } else /* if (o >= NTFS_MAX_NAME_LEN) */ { 272 - ntfs_error(vol->sb, "Name is too long (maximum length for a " 273 - "name on NTFS is %d Unicode characters.", 274 - NTFS_MAX_NAME_LEN); 304 + } else { 305 + ntfs_debug("Name is too long (maximum length for a name on NTFS is %d Unicode characters.", 306 + max_name_len); 275 307 i = -ENAMETOOLONG; 276 308 } 277 309 return i; 278 310 } 279 311 280 - /** 312 + /* 281 313 * ntfs_ucstonls - convert little endian Unicode string to NLS string 282 314 * @vol: ntfs volume which we are working with 283 315 * @ins: input Unicode string buffer ··· 317 319 * 318 320 * This might look a bit odd due to fast path optimization... 319 321 */ 320 - int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins, 322 + int ntfs_ucstonls(const struct ntfs_volume *vol, const __le16 *ins, 321 323 const int ins_len, unsigned char **outs, int outs_len) 322 324 { 323 325 struct nls_table *nls = vol->nls_map; ··· 338 340 if (!ns) 339 341 goto mem_err_out; 340 342 } 343 + 344 + if (vol->nls_utf8) { 345 + o = utf16s_to_utf8s((const wchar_t *)ins, ins_len, 346 + UTF16_LITTLE_ENDIAN, ns, ns_len); 347 + if (o >= ns_len) { 348 + wc = -ENAMETOOLONG; 349 + goto conversion_err; 350 + } 351 + goto done; 352 + } 353 + 341 354 for (i = o = 0; i < ins_len; i++) { 342 - retry: wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o, 355 + retry: 356 + wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o, 343 357 ns_len - o); 344 358 if (wc > 0) { 345 359 o += wc; ··· 373 363 } /* wc < 0, real error. */ 374 364 goto conversion_err; 375 365 } 366 + done: 376 367 ns[o] = 0; 377 368 *outs = ns; 378 369 return o; ··· 381 370 ntfs_error(vol->sb, "Received NULL pointer."); 382 371 return -EINVAL; 383 372 conversion_err: 384 - ntfs_error(vol->sb, "Unicode name contains characters that cannot be " 385 - "converted to character set %s. You might want to " 386 - "try to use the mount option nls=utf8.", nls->charset); 373 + ntfs_error(vol->sb, 374 + "Unicode name contains characters that cannot be converted to character set %s. You might want to try to use the mount option nls=utf8.", 375 + nls->charset); 387 376 if (ns != *outs) 388 377 kfree(ns); 389 378 if (wc != -ENAMETOOLONG) ··· 392 381 mem_err_out: 393 382 ntfs_error(vol->sb, "Failed to allocate name!"); 394 383 return -ENOMEM; 384 + } 385 + 386 + /* 387 + * ntfs_ucsnlen - determine the length of a little endian Unicode string 388 + * @s: pointer to Unicode string 389 + * @maxlen: maximum length of string @s 390 + * 391 + * Return the number of Unicode characters in the little endian Unicode 392 + * string @s up to a maximum of maxlen Unicode characters, not including 393 + * the terminating (__le16)'\0'. If there is no (__le16)'\0' between @s 394 + * and @s + @maxlen, @maxlen is returned. 395 + * 396 + * This function never looks beyond @s + @maxlen. 397 + */ 398 + static u32 ntfs_ucsnlen(const __le16 *s, u32 maxlen) 399 + { 400 + u32 i; 401 + 402 + for (i = 0; i < maxlen; i++) { 403 + if (!le16_to_cpu(s[i])) 404 + break; 405 + } 406 + return i; 407 + } 408 + 409 + /* 410 + * ntfs_ucsndup - duplicate little endian Unicode string 411 + * @s: pointer to Unicode string 412 + * @maxlen: maximum length of string @s 413 + * 414 + * Return a pointer to a new little endian Unicode string which is a duplicate 415 + * of the string s. Memory for the new string is obtained with kmalloc, 416 + * and can be freed with kfree. 417 + * 418 + * A maximum of @maxlen Unicode characters are copied and a terminating 419 + * (__le16)'\0' little endian Unicode character is added. 420 + * 421 + * This function never looks beyond @s + @maxlen. 422 + * 423 + * Return a pointer to the new little endian Unicode string on success and NULL 424 + * on failure with errno set to the error code. 425 + */ 426 + __le16 *ntfs_ucsndup(const __le16 *s, u32 maxlen) 427 + { 428 + __le16 *dst; 429 + u32 len; 430 + 431 + len = ntfs_ucsnlen(s, maxlen); 432 + dst = kmalloc((len + 1) * sizeof(__le16), GFP_NOFS); 433 + if (dst) { 434 + memcpy(dst, s, len * sizeof(__le16)); 435 + dst[len] = cpu_to_le16(L'\0'); 436 + } 437 + return dst; 438 + } 439 + 440 + /* 441 + * ntfs_names_are_equal - compare two Unicode names for equality 442 + * @s1: name to compare to @s2 443 + * @s1_len: length in Unicode characters of @s1 444 + * @s2: name to compare to @s1 445 + * @s2_len: length in Unicode characters of @s2 446 + * @ic: ignore case bool 447 + * @upcase: upcase table (only if @ic == IGNORE_CASE) 448 + * @upcase_size: length in Unicode characters of @upcase (if present) 449 + * 450 + * Compare the names @s1 and @s2 and return TRUE (1) if the names are 451 + * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE, 452 + * the @upcase table is used to perform a case insensitive comparison. 453 + */ 454 + bool ntfs_names_are_equal(const __le16 *s1, size_t s1_len, 455 + const __le16 *s2, size_t s2_len, 456 + const u32 ic, 457 + const __le16 *upcase, const u32 upcase_size) 458 + { 459 + if (s1_len != s2_len) 460 + return false; 461 + if (!s1_len) 462 + return true; 463 + if (ic == CASE_SENSITIVE) 464 + return ntfs_ucsncmp(s1, s2, s1_len) ? false : true; 465 + return ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? false : true; 395 466 }
+4 -7
fs/ntfs/upcase.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 - * upcase.c - Generate the full NTFS Unicode upcase table in little endian. 4 - * Part of the Linux-NTFS project. 3 + * Generate the full NTFS Unicode upcase table in little endian. 5 4 * 6 5 * Copyright (c) 2001 Richard Russon <ntfs@flatcap.org> 7 6 * Copyright (c) 2001-2006 Anton Altaparmakov 8 7 */ 9 8 10 - #include "malloc.h" 11 9 #include "ntfs.h" 12 10 13 - ntfschar *generate_default_upcase(void) 11 + __le16 *generate_default_upcase(void) 14 12 { 15 13 static const int uc_run_table[][3] = { /* Start, End, Add */ 16 14 {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, ··· 50 52 }; 51 53 52 54 int i, r; 53 - ntfschar *uc; 55 + __le16 *uc; 54 56 55 - uc = ntfs_malloc_nofs(default_upcase_len * sizeof(ntfschar)); 57 + uc = kvcalloc(default_upcase_len, sizeof(__le16), GFP_NOFS); 56 58 if (!uc) 57 59 return uc; 58 - memset(uc, 0, default_upcase_len * sizeof(ntfschar)); 59 60 /* Generate the little endian Unicode upcase table used by ntfs. */ 60 61 for (i = 0; i < default_upcase_len; i++) 61 62 uc[i] = cpu_to_le16(i);
-70
fs/ntfs/usnjrnl.c
··· 1 - // SPDX-License-Identifier: GPL-2.0-or-later 2 - /* 3 - * usnjrnl.h - NTFS kernel transaction log ($UsnJrnl) handling. Part of the 4 - * Linux-NTFS project. 5 - * 6 - * Copyright (c) 2005 Anton Altaparmakov 7 - */ 8 - 9 - #ifdef NTFS_RW 10 - 11 - #include <linux/fs.h> 12 - #include <linux/highmem.h> 13 - #include <linux/mm.h> 14 - 15 - #include "aops.h" 16 - #include "debug.h" 17 - #include "endian.h" 18 - #include "time.h" 19 - #include "types.h" 20 - #include "usnjrnl.h" 21 - #include "volume.h" 22 - 23 - /** 24 - * ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume 25 - * @vol: ntfs volume on which to stamp the transaction log 26 - * 27 - * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return 28 - * 'true' on success and 'false' on error. 29 - * 30 - * This function assumes that the transaction log has already been loaded and 31 - * consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl(). 32 - */ 33 - bool ntfs_stamp_usnjrnl(ntfs_volume *vol) 34 - { 35 - ntfs_debug("Entering."); 36 - if (likely(!NVolUsnJrnlStamped(vol))) { 37 - sle64 stamp; 38 - struct page *page; 39 - USN_HEADER *uh; 40 - 41 - page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0); 42 - if (IS_ERR(page)) { 43 - ntfs_error(vol->sb, "Failed to read from " 44 - "$UsnJrnl/$DATA/$Max attribute."); 45 - return false; 46 - } 47 - uh = (USN_HEADER*)page_address(page); 48 - stamp = get_current_ntfs_time(); 49 - ntfs_debug("Stamping transaction log ($UsnJrnl): old " 50 - "journal_id 0x%llx, old lowest_valid_usn " 51 - "0x%llx, new journal_id 0x%llx, new " 52 - "lowest_valid_usn 0x%llx.", 53 - (long long)sle64_to_cpu(uh->journal_id), 54 - (long long)sle64_to_cpu(uh->lowest_valid_usn), 55 - (long long)sle64_to_cpu(stamp), 56 - i_size_read(vol->usnjrnl_j_ino)); 57 - uh->lowest_valid_usn = 58 - cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino)); 59 - uh->journal_id = stamp; 60 - flush_dcache_page(page); 61 - set_page_dirty(page); 62 - ntfs_unmap_page(page); 63 - /* Set the flag so we do not have to do it again on remount. */ 64 - NVolSetUsnJrnlStamped(vol); 65 - } 66 - ntfs_debug("Done."); 67 - return true; 68 - } 69 - 70 - #endif /* NTFS_RW */
-191
fs/ntfs/usnjrnl.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 - /* 3 - * usnjrnl.h - Defines for NTFS kernel transaction log ($UsnJrnl) handling. 4 - * Part of the Linux-NTFS project. 5 - * 6 - * Copyright (c) 2005 Anton Altaparmakov 7 - */ 8 - 9 - #ifndef _LINUX_NTFS_USNJRNL_H 10 - #define _LINUX_NTFS_USNJRNL_H 11 - 12 - #ifdef NTFS_RW 13 - 14 - #include "types.h" 15 - #include "endian.h" 16 - #include "layout.h" 17 - #include "volume.h" 18 - 19 - /* 20 - * Transaction log ($UsnJrnl) organization: 21 - * 22 - * The transaction log records whenever a file is modified in any way. So for 23 - * example it will record that file "blah" was written to at a particular time 24 - * but not what was written. If will record that a file was deleted or 25 - * created, that a file was truncated, etc. See below for all the reason 26 - * codes used. 27 - * 28 - * The transaction log is in the $Extend directory which is in the root 29 - * directory of each volume. If it is not present it means transaction 30 - * logging is disabled. If it is present it means transaction logging is 31 - * either enabled or in the process of being disabled in which case we can 32 - * ignore it as it will go away as soon as Windows gets its hands on it. 33 - * 34 - * To determine whether the transaction logging is enabled or in the process 35 - * of being disabled, need to check the volume flags in the 36 - * $VOLUME_INFORMATION attribute in the $Volume system file (which is present 37 - * in the root directory and has a fixed mft record number, see layout.h). 38 - * If the flag VOLUME_DELETE_USN_UNDERWAY is set it means the transaction log 39 - * is in the process of being disabled and if this flag is clear it means the 40 - * transaction log is enabled. 41 - * 42 - * The transaction log consists of two parts; the $DATA/$Max attribute as well 43 - * as the $DATA/$J attribute. $Max is a header describing the transaction 44 - * log whilst $J is the transaction log data itself as a sequence of variable 45 - * sized USN_RECORDs (see below for all the structures). 46 - * 47 - * We do not care about transaction logging at this point in time but we still 48 - * need to let windows know that the transaction log is out of date. To do 49 - * this we need to stamp the transaction log. This involves setting the 50 - * lowest_valid_usn field in the $DATA/$Max attribute to the usn to be used 51 - * for the next added USN_RECORD to the $DATA/$J attribute as well as 52 - * generating a new journal_id in $DATA/$Max. 53 - * 54 - * The journal_id is as of the current version (2.0) of the transaction log 55 - * simply the 64-bit timestamp of when the journal was either created or last 56 - * stamped. 57 - * 58 - * To determine the next usn there are two ways. The first is to parse 59 - * $DATA/$J and to find the last USN_RECORD in it and to add its record_length 60 - * to its usn (which is the byte offset in the $DATA/$J attribute). The 61 - * second is simply to take the data size of the attribute. Since the usns 62 - * are simply byte offsets into $DATA/$J, this is exactly the next usn. For 63 - * obvious reasons we use the second method as it is much simpler and faster. 64 - * 65 - * As an aside, note that to actually disable the transaction log, one would 66 - * need to set the VOLUME_DELETE_USN_UNDERWAY flag (see above), then go 67 - * through all the mft records on the volume and set the usn field in their 68 - * $STANDARD_INFORMATION attribute to zero. Once that is done, one would need 69 - * to delete the transaction log file, i.e. \$Extent\$UsnJrnl, and finally, 70 - * one would need to clear the VOLUME_DELETE_USN_UNDERWAY flag. 71 - * 72 - * Note that if a volume is unmounted whilst the transaction log is being 73 - * disabled, the process will continue the next time the volume is mounted. 74 - * This is why we can safely mount read-write when we see a transaction log 75 - * in the process of being deleted. 76 - */ 77 - 78 - /* Some $UsnJrnl related constants. */ 79 - #define UsnJrnlMajorVer 2 80 - #define UsnJrnlMinorVer 0 81 - 82 - /* 83 - * $DATA/$Max attribute. This is (always?) resident and has a fixed size of 84 - * 32 bytes. It contains the header describing the transaction log. 85 - */ 86 - typedef struct { 87 - /*Ofs*/ 88 - /* 0*/sle64 maximum_size; /* The maximum on-disk size of the $DATA/$J 89 - attribute. */ 90 - /* 8*/sle64 allocation_delta; /* Number of bytes by which to increase the 91 - size of the $DATA/$J attribute. */ 92 - /*0x10*/sle64 journal_id; /* Current id of the transaction log. */ 93 - /*0x18*/leUSN lowest_valid_usn; /* Lowest valid usn in $DATA/$J for the 94 - current journal_id. */ 95 - /* sizeof() = 32 (0x20) bytes */ 96 - } __attribute__ ((__packed__)) USN_HEADER; 97 - 98 - /* 99 - * Reason flags (32-bit). Cumulative flags describing the change(s) to the 100 - * file since it was last opened. I think the names speak for themselves but 101 - * if you disagree check out the descriptions in the Linux NTFS project NTFS 102 - * documentation: http://www.linux-ntfs.org/ 103 - */ 104 - enum { 105 - USN_REASON_DATA_OVERWRITE = cpu_to_le32(0x00000001), 106 - USN_REASON_DATA_EXTEND = cpu_to_le32(0x00000002), 107 - USN_REASON_DATA_TRUNCATION = cpu_to_le32(0x00000004), 108 - USN_REASON_NAMED_DATA_OVERWRITE = cpu_to_le32(0x00000010), 109 - USN_REASON_NAMED_DATA_EXTEND = cpu_to_le32(0x00000020), 110 - USN_REASON_NAMED_DATA_TRUNCATION= cpu_to_le32(0x00000040), 111 - USN_REASON_FILE_CREATE = cpu_to_le32(0x00000100), 112 - USN_REASON_FILE_DELETE = cpu_to_le32(0x00000200), 113 - USN_REASON_EA_CHANGE = cpu_to_le32(0x00000400), 114 - USN_REASON_SECURITY_CHANGE = cpu_to_le32(0x00000800), 115 - USN_REASON_RENAME_OLD_NAME = cpu_to_le32(0x00001000), 116 - USN_REASON_RENAME_NEW_NAME = cpu_to_le32(0x00002000), 117 - USN_REASON_INDEXABLE_CHANGE = cpu_to_le32(0x00004000), 118 - USN_REASON_BASIC_INFO_CHANGE = cpu_to_le32(0x00008000), 119 - USN_REASON_HARD_LINK_CHANGE = cpu_to_le32(0x00010000), 120 - USN_REASON_COMPRESSION_CHANGE = cpu_to_le32(0x00020000), 121 - USN_REASON_ENCRYPTION_CHANGE = cpu_to_le32(0x00040000), 122 - USN_REASON_OBJECT_ID_CHANGE = cpu_to_le32(0x00080000), 123 - USN_REASON_REPARSE_POINT_CHANGE = cpu_to_le32(0x00100000), 124 - USN_REASON_STREAM_CHANGE = cpu_to_le32(0x00200000), 125 - USN_REASON_CLOSE = cpu_to_le32(0x80000000), 126 - }; 127 - 128 - typedef le32 USN_REASON_FLAGS; 129 - 130 - /* 131 - * Source info flags (32-bit). Information about the source of the change(s) 132 - * to the file. For detailed descriptions of what these mean, see the Linux 133 - * NTFS project NTFS documentation: 134 - * http://www.linux-ntfs.org/ 135 - */ 136 - enum { 137 - USN_SOURCE_DATA_MANAGEMENT = cpu_to_le32(0x00000001), 138 - USN_SOURCE_AUXILIARY_DATA = cpu_to_le32(0x00000002), 139 - USN_SOURCE_REPLICATION_MANAGEMENT = cpu_to_le32(0x00000004), 140 - }; 141 - 142 - typedef le32 USN_SOURCE_INFO_FLAGS; 143 - 144 - /* 145 - * $DATA/$J attribute. This is always non-resident, is marked as sparse, and 146 - * is of variabled size. It consists of a sequence of variable size 147 - * USN_RECORDS. The minimum allocated_size is allocation_delta as 148 - * specified in $DATA/$Max. When the maximum_size specified in $DATA/$Max is 149 - * exceeded by more than allocation_delta bytes, allocation_delta bytes are 150 - * allocated and appended to the $DATA/$J attribute and an equal number of 151 - * bytes at the beginning of the attribute are freed and made sparse. Note the 152 - * making sparse only happens at volume checkpoints and hence the actual 153 - * $DATA/$J size can exceed maximum_size + allocation_delta temporarily. 154 - */ 155 - typedef struct { 156 - /*Ofs*/ 157 - /* 0*/le32 length; /* Byte size of this record (8-byte 158 - aligned). */ 159 - /* 4*/le16 major_ver; /* Major version of the transaction log used 160 - for this record. */ 161 - /* 6*/le16 minor_ver; /* Minor version of the transaction log used 162 - for this record. */ 163 - /* 8*/leMFT_REF mft_reference;/* The mft reference of the file (or 164 - directory) described by this record. */ 165 - /*0x10*/leMFT_REF parent_directory;/* The mft reference of the parent 166 - directory of the file described by this 167 - record. */ 168 - /*0x18*/leUSN usn; /* The usn of this record. Equals the offset 169 - within the $DATA/$J attribute. */ 170 - /*0x20*/sle64 time; /* Time when this record was created. */ 171 - /*0x28*/USN_REASON_FLAGS reason;/* Reason flags (see above). */ 172 - /*0x2c*/USN_SOURCE_INFO_FLAGS source_info;/* Source info flags (see above). */ 173 - /*0x30*/le32 security_id; /* File security_id copied from 174 - $STANDARD_INFORMATION. */ 175 - /*0x34*/FILE_ATTR_FLAGS file_attributes; /* File attributes copied from 176 - $STANDARD_INFORMATION or $FILE_NAME (not 177 - sure which). */ 178 - /*0x38*/le16 file_name_size; /* Size of the file name in bytes. */ 179 - /*0x3a*/le16 file_name_offset; /* Offset to the file name in bytes from the 180 - start of this record. */ 181 - /*0x3c*/ntfschar file_name[0]; /* Use when creating only. When reading use 182 - file_name_offset to determine the location 183 - of the name. */ 184 - /* sizeof() = 60 (0x3c) bytes */ 185 - } __attribute__ ((__packed__)) USN_RECORD; 186 - 187 - extern bool ntfs_stamp_usnjrnl(ntfs_volume *vol); 188 - 189 - #endif /* NTFS_RW */ 190 - 191 - #endif /* _LINUX_NTFS_USNJRNL_H */