Commit f86096b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-ntfs.bkbits.net/ntfs-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents ad39cbdf 522c6443
...@@ -247,6 +247,19 @@ ChangeLog ...@@ -247,6 +247,19 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.4:
- Minor update allowing compilation with all gcc versions (well, the
ones the kernel can be compiled with anyway).
2.1.3:
- Major bug fixes for reading files and volumes in corner cases which
were being hit by Windows 2k/XP users.
2.1.2:
- Major bug fixes aleviating the hangs in statfs experienced by some
users.
2.1.1:
- Update handling of compressed files so people no longer get the
frequently reported warning messages about initialized_size !=
data_size.
2.1.0: 2.1.0:
- Add configuration option for developmental write support. - Add configuration option for developmental write support.
- Initial implementation of file overwriting. (Writes to resident files - Initial implementation of file overwriting. (Writes to resident files
......
...@@ -20,6 +20,31 @@ ToDo: ...@@ -20,6 +20,31 @@ ToDo:
sufficient for synchronisation here. We then just need to make sure sufficient for synchronisation here. We then just need to make sure
ntfs_readpage/writepage/truncate interoperate properly with us. ntfs_readpage/writepage/truncate interoperate properly with us.
2.1.4 - Reduce compiler requirements.
- Remove all uses of unnamed structs and unions in the driver to make
old and newer gcc versions happy. Makes it a bit uglier IMO but at
least people will stop hassling me about it.
2.1.3 - Important bug fixes in corner cases.
- super.c::parse_ntfs_boot_sector(): Correct the check for 64-bit
clusters. (Philipp Thomas)
- attrib.c::load_attribute_list(): Fix bug when initialized_size is a
multiple of the block_size but not the cluster size. (Szabolcs
Szakacsits <szaka@sienet.hu>)
2.1.2 - Important bug fixes aleviating the hangs in statfs.
- Fix buggy free cluster and free inode determination logic.
2.1.1 - Minor updates.
- Add handling for initialized_size != data_size in compressed files.
- Reduce function local stack usage from 0x3d4 bytes to just noise in
fs/ntfs/upcase.c. (Randy Dunlap <rddunlap@osdl.ord>)
- Remove compiler warnings for newer gcc.
2.1.0 - First steps towards write support: implement file overwrite. 2.1.0 - First steps towards write support: implement file overwrite.
- Add configuration option for developmental write support with an - Add configuration option for developmental write support with an
......
...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o ...@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \ ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.0\" EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.4\"
ifeq ($(CONFIG_NTFS_DEBUG),y) ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG EXTRA_CFLAGS += -DDEBUG
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* aops.c - NTFS kernel address space operations and page cache handling. * aops.c - NTFS kernel address space operations and page cache handling.
* Part of the Linux-NTFS project. * Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -111,7 +111,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) ...@@ -111,7 +111,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
unsigned int i, recs, nr_err; unsigned int i, recs, nr_err;
u32 rec_size; u32 rec_size;
rec_size = ni->_IDM(index_block_size); rec_size = ni->itype.index.block_size;
recs = PAGE_CACHE_SIZE / rec_size; recs = PAGE_CACHE_SIZE / rec_size;
addr = kmap_atomic(page, KM_BIO_SRC_IRQ); addr = kmap_atomic(page, KM_BIO_SRC_IRQ);
for (i = nr_err = 0; i < recs; i++) { for (i = nr_err = 0; i < recs; i++) {
...@@ -124,7 +124,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) ...@@ -124,7 +124,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
ni->mft_no ? "index" : "mft", ni->mft_no ? "index" : "mft",
(long long)(((s64)page->index << (long long)(((s64)page->index <<
PAGE_CACHE_SHIFT >> PAGE_CACHE_SHIFT >>
ni->_IDM(index_block_size_bits)) + i)); ni->itype.index.block_size_bits) + i));
} }
flush_dcache_page(page); flush_dcache_page(page);
kunmap_atomic(addr, KM_BIO_SRC_IRQ); kunmap_atomic(addr, KM_BIO_SRC_IRQ);
...@@ -383,7 +383,7 @@ int ntfs_readpage(struct file *file, struct page *page) ...@@ -383,7 +383,7 @@ int ntfs_readpage(struct file *file, struct page *page)
if (!NInoAttr(ni)) if (!NInoAttr(ni))
base_ni = ni; base_ni = ni;
else else
base_ni = ni->_INE(base_ntfs_ino); base_ni = ni->ext.base_ntfs_ino;
/* Map, pin, and lock the mft record. */ /* Map, pin, and lock the mft record. */
mrec = map_mft_record(base_ni); mrec = map_mft_record(base_ni);
...@@ -406,7 +406,7 @@ int ntfs_readpage(struct file *file, struct page *page) ...@@ -406,7 +406,7 @@ int ntfs_readpage(struct file *file, struct page *page)
attr_pos = page->index << PAGE_CACHE_SHIFT; attr_pos = page->index << PAGE_CACHE_SHIFT;
/* The total length of the attribute value. */ /* The total length of the attribute value. */
attr_len = le32_to_cpu(ctx->attr->_ARA(value_length)); attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
addr = kmap(page); addr = kmap(page);
/* Copy over in bounds data, zeroing the remainder of the page. */ /* Copy over in bounds data, zeroing the remainder of the page. */
...@@ -418,8 +418,8 @@ int ntfs_readpage(struct file *file, struct page *page) ...@@ -418,8 +418,8 @@ int ntfs_readpage(struct file *file, struct page *page)
memset(addr + bytes, 0, PAGE_CACHE_SIZE - bytes); memset(addr + bytes, 0, PAGE_CACHE_SIZE - bytes);
/* Copy the data to the page. */ /* Copy the data to the page. */
memcpy(addr, attr_pos + (char*)ctx->attr + memcpy(addr, attr_pos + (char*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset)), le16_to_cpu(
bytes); ctx->attr->data.resident.value_offset), bytes);
} else } else
memset(addr, 0, PAGE_CACHE_SIZE); memset(addr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page); flush_dcache_page(page);
...@@ -892,7 +892,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -892,7 +892,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
if (!NInoAttr(ni)) if (!NInoAttr(ni))
base_ni = ni; base_ni = ni;
else else
base_ni = ni->_INE(base_ntfs_ino); base_ni = ni->ext.base_ntfs_ino;
/* Map, pin, and lock the mft record. */ /* Map, pin, and lock the mft record. */
m = map_mft_record(base_ni); m = map_mft_record(base_ni);
...@@ -917,7 +917,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -917,7 +917,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
attr_pos = page->index << PAGE_CACHE_SHIFT; attr_pos = page->index << PAGE_CACHE_SHIFT;
/* The total length of the attribute value. */ /* The total length of the attribute value. */
attr_len = le32_to_cpu(ctx->attr->_ARA(value_length)); attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
if (unlikely(vi->i_size != attr_len)) { if (unlikely(vi->i_size != attr_len)) {
ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match " ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match "
...@@ -956,8 +956,9 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc) ...@@ -956,8 +956,9 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
kaddr = kmap_atomic(page, KM_USER0); kaddr = kmap_atomic(page, KM_USER0);
/* Copy the data from the page to the mft record. */ /* Copy the data from the page to the mft record. */
memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->_ARA(value_offset)) + memcpy((u8*)ctx->attr + le16_to_cpu(
attr_pos, kaddr, bytes); ctx->attr->data.resident.value_offset) + attr_pos,
kaddr, bytes);
flush_dcache_mft_record_page(ctx->ntfs_ino); flush_dcache_mft_record_page(ctx->ntfs_ino);
#if 0 #if 0
/* Zero out of bounds area. */ /* Zero out of bounds area. */
...@@ -1656,7 +1657,7 @@ static int ntfs_commit_write(struct file *file, struct page *page, ...@@ -1656,7 +1657,7 @@ static int ntfs_commit_write(struct file *file, struct page *page,
if (!NInoAttr(ni)) if (!NInoAttr(ni))
base_ni = ni; base_ni = ni;
else else
base_ni = ni->_INE(base_ntfs_ino); base_ni = ni->ext.base_ntfs_ino;
/* Map, pin, and lock the mft record. */ /* Map, pin, and lock the mft record. */
m = map_mft_record(base_ni); m = map_mft_record(base_ni);
...@@ -1681,7 +1682,7 @@ static int ntfs_commit_write(struct file *file, struct page *page, ...@@ -1681,7 +1682,7 @@ static int ntfs_commit_write(struct file *file, struct page *page,
attr_pos = page->index << PAGE_CACHE_SHIFT; attr_pos = page->index << PAGE_CACHE_SHIFT;
/* The total length of the attribute value. */ /* The total length of the attribute value. */
attr_len = le32_to_cpu(ctx->attr->_ARA(value_length)); attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
if (unlikely(vi->i_size != attr_len)) { if (unlikely(vi->i_size != attr_len)) {
ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match " ntfs_error(vi->i_sb, "BUG()! i_size (0x%Lx) doesn't match "
...@@ -1705,8 +1706,8 @@ static int ntfs_commit_write(struct file *file, struct page *page, ...@@ -1705,8 +1706,8 @@ static int ntfs_commit_write(struct file *file, struct page *page,
* Calculate the address of the attribute value corresponding to the * Calculate the address of the attribute value corresponding to the
* beginning of the current data @page. * beginning of the current data @page.
*/ */
kattr = (u8*)ctx->attr + le16_to_cpu(ctx->attr->_ARA(value_offset)) + kattr = (u8*)ctx->attr + le16_to_cpu(
attr_pos; ctx->attr->data.resident.value_offset) + attr_pos;
kaddr = kmap_atomic(page, KM_USER0); kaddr = kmap_atomic(page, KM_USER0);
......
/** /**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (C) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -731,17 +731,18 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol, ...@@ -731,17 +731,18 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
#ifdef DEBUG #ifdef DEBUG
/* Make sure attr exists and is non-resident. */ /* Make sure attr exists and is non-resident. */
if (!attr || !attr->non_resident || if (!attr || !attr->non_resident || sle64_to_cpu(
sle64_to_cpu(attr->_ANR(lowest_vcn)) < (VCN)0) { attr->data.non_resident.lowest_vcn) < (VCN)0) {
ntfs_error(vol->sb, "Invalid arguments."); ntfs_error(vol->sb, "Invalid arguments.");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
#endif #endif
/* Start at vcn = lowest_vcn and lcn 0. */ /* Start at vcn = lowest_vcn and lcn 0. */
vcn = sle64_to_cpu(attr->_ANR(lowest_vcn)); vcn = sle64_to_cpu(attr->data.non_resident.lowest_vcn);
lcn = 0; lcn = 0;
/* Get start of the mapping pairs array. */ /* Get start of the mapping pairs array. */
buf = (u8*)attr + le16_to_cpu(attr->_ANR(mapping_pairs_offset)); buf = (u8*)attr + le16_to_cpu(
attr->data.non_resident.mapping_pairs_offset);
attr_end = (u8*)attr + le32_to_cpu(attr->length); attr_end = (u8*)attr + le32_to_cpu(attr->length);
if (unlikely(buf < (u8*)attr || buf > attr_end)) { if (unlikely(buf < (u8*)attr || buf > attr_end)) {
ntfs_error(vol->sb, "Corrupt attribute."); ntfs_error(vol->sb, "Corrupt attribute.");
...@@ -867,7 +868,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol, ...@@ -867,7 +868,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
* If there is a highest_vcn specified, it must be equal to the final * If there is a highest_vcn specified, it must be equal to the final
* vcn in the run list - 1, or something has gone badly wrong. * vcn in the run list - 1, or something has gone badly wrong.
*/ */
deltaxcn = sle64_to_cpu(attr->_ANR(highest_vcn)); deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);
if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) { if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) {
mpa_err: mpa_err:
ntfs_error(vol->sb, "Corrupt mapping pairs array in " ntfs_error(vol->sb, "Corrupt mapping pairs array in "
...@@ -875,10 +876,11 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol, ...@@ -875,10 +876,11 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
goto err_out; goto err_out;
} }
/* Setup not mapped run list element if this is the base extent. */ /* Setup not mapped run list element if this is the base extent. */
if (!attr->_ANR(lowest_vcn)) { if (!attr->data.non_resident.lowest_vcn) {
VCN max_cluster; VCN max_cluster;
max_cluster = (sle64_to_cpu(attr->_ANR(allocated_size)) + max_cluster = (sle64_to_cpu(
attr->data.non_resident.allocated_size) +
vol->cluster_size - 1) >> vol->cluster_size - 1) >>
vol->cluster_size_bits; vol->cluster_size_bits;
/* /*
...@@ -951,7 +953,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn) ...@@ -951,7 +953,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
if (!NInoAttr(ni)) if (!NInoAttr(ni))
base_ni = ni; base_ni = ni;
else else
base_ni = ni->_INE(base_ntfs_ino); base_ni = ni->ext.base_ntfs_ino;
mrec = map_mft_record(base_ni); mrec = map_mft_record(base_ni);
if (IS_ERR(mrec)) if (IS_ERR(mrec))
...@@ -1180,19 +1182,23 @@ BOOL find_attr(const ATTR_TYPES type, const uchar_t *name, const u32 name_len, ...@@ -1180,19 +1182,23 @@ BOOL find_attr(const ATTR_TYPES type, const uchar_t *name, const u32 name_len,
return TRUE; return TRUE;
/* @val is present; compare values. */ /* @val is present; compare values. */
else { else {
u32 vl;
register int rc; register int rc;
vl = le32_to_cpu(a->data.resident.value_length);
if (vl > val_len)
vl = val_len;
rc = memcmp(val, (u8*)a + le16_to_cpu( rc = memcmp(val, (u8*)a + le16_to_cpu(
a->_ARA(value_offset)), a->data.resident.value_offset), vl);
min_t(const u32, val_len,
le32_to_cpu(a->_ARA(value_length))));
/* /*
* If @val collates before the current attribute's * If @val collates before the current attribute's
* value, there is no matching attribute. * value, there is no matching attribute.
*/ */
if (!rc) { if (!rc) {
register u32 avl; register u32 avl;
avl = le32_to_cpu(a->_ARA(value_length)); avl = le32_to_cpu(
a->data.resident.value_length);
if (val_len == avl) if (val_len == avl)
return TRUE; return TRUE;
if (val_len < avl) if (val_len < avl)
...@@ -1235,11 +1241,9 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al, ...@@ -1235,11 +1241,9 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al,
unsigned char block_size_bits = sb->s_blocksize_bits; unsigned char block_size_bits = sb->s_blocksize_bits;
ntfs_debug("Entering."); ntfs_debug("Entering.");
#ifdef DEBUG
if (!vol || !run_list || !al || size <= 0 || initialized_size < 0 || if (!vol || !run_list || !al || size <= 0 || initialized_size < 0 ||
initialized_size > size) initialized_size > size)
return -EINVAL; return -EINVAL;
#endif
if (!initialized_size) { if (!initialized_size) {
memset(al, 0, size); memset(al, 0, size);
return 0; return 0;
...@@ -1270,8 +1274,8 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al, ...@@ -1270,8 +1274,8 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al,
"read attribute list."); "read attribute list.");
goto err_out; goto err_out;
} }
if (al + block_size > al_end) if (al + block_size >= al_end)
goto do_partial; goto do_final;
memcpy(al, bh->b_data, block_size); memcpy(al, bh->b_data, block_size);
brelse(bh); brelse(bh);
al += block_size; al += block_size;
...@@ -1285,7 +1289,7 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al, ...@@ -1285,7 +1289,7 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al,
done: done:
up_read(&run_list->lock); up_read(&run_list->lock);
return err; return err;
do_partial: do_final:
if (al < al_end) { if (al < al_end) {
/* Partial block. */ /* Partial block. */
memcpy(al, bh->b_data, al_end - al); memcpy(al, bh->b_data, al_end - al);
...@@ -1546,9 +1550,11 @@ static BOOL find_external_attr(const ATTR_TYPES type, const uchar_t *name, ...@@ -1546,9 +1550,11 @@ static BOOL find_external_attr(const ATTR_TYPES type, const uchar_t *name,
* If no @val specified or @val specified and it matches, we * If no @val specified or @val specified and it matches, we
* have found it! * have found it!
*/ */
if (!val || (!a->non_resident && le32_to_cpu(a->_ARA(value_length)) if (!val || (!a->non_resident && le32_to_cpu(
== val_len && !memcmp((u8*)a + a->data.resident.value_length) == val_len &&
le16_to_cpu(a->_ARA(value_offset)), val, val_len))) { !memcmp((u8*)a +
le16_to_cpu(a->data.resident.value_offset),
val, val_len))) {
ntfs_debug("Done, found."); ntfs_debug("Done, found.");
return TRUE; return TRUE;
} }
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* attrib.h - Defines for attribute handling in NTFS Linux kernel driver. * attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
* Part of the Linux-NTFS project. * Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (C) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -93,8 +93,8 @@ extern int load_attribute_list(ntfs_volume *vol, run_list *rl, u8 *al, ...@@ -93,8 +93,8 @@ extern int load_attribute_list(ntfs_volume *vol, run_list *rl, u8 *al,
static inline s64 attribute_value_length(const ATTR_RECORD *a) static inline s64 attribute_value_length(const ATTR_RECORD *a)
{ {
if (!a->non_resident) if (!a->non_resident)
return (s64)le32_to_cpu(a->_ARA(value_length)); return (s64)le32_to_cpu(a->data.resident.value_length);
return sle64_to_cpu(a->_ANR(data_size)); return sle64_to_cpu(a->data.non_resident.data_size);
} }
extern void reinit_attr_search_ctx(attr_search_context *ctx); extern void reinit_attr_search_ctx(attr_search_context *ctx);
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* compress.c - NTFS kernel compressed attributes handling. * compress.c - NTFS kernel compressed attributes handling.
* Part of the Linux-NTFS project. * Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (C) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -44,7 +44,7 @@ typedef enum { ...@@ -44,7 +44,7 @@ typedef enum {
* The maximum compression block size is by definition 16 * the cluster * The maximum compression block size is by definition 16 * the cluster
* size, with the maximum supported cluster size being 4kiB. Thus the * size, with the maximum supported cluster size being 4kiB. Thus the
* maximum compression buffer size is 64kiB, so we use this when * maximum compression buffer size is 64kiB, so we use this when
* initializing the per-CPU buffers. * initializing the compression buffer.
*/ */
NTFS_MAX_CB_SIZE = 64 * 1024, NTFS_MAX_CB_SIZE = 64 * 1024,
} ntfs_compression_constants; } ntfs_compression_constants;
...@@ -88,6 +88,40 @@ void free_compression_buffers(void) ...@@ -88,6 +88,40 @@ void free_compression_buffers(void)
ntfs_compression_buffer = NULL; ntfs_compression_buffer = NULL;
} }
/**
* zero_partial_compressed_page - zero out of bounds compressed page region
*/
static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
{
u8 *kp = page_address(page);
unsigned int kp_ofs;
ntfs_debug("Zeroing page region outside initialized size.");
if (((s64)page->index << PAGE_CACHE_SHIFT) >= ni->initialized_size) {
/*
* FIXME: Using clear_page() will become wrong when we get
* PAGE_CACHE_SIZE != PAGE_SIZE but for now there is no problem.
*/
clear_page(kp);
return;
}
kp_ofs = ni->initialized_size & ~PAGE_CACHE_MASK;
memset(kp + kp_ofs, 0, PAGE_CACHE_SIZE - kp_ofs);
return;
}
/**
* handle_bounds_compressed_page - test for&handle out of bounds compressed page
*/
static inline void handle_bounds_compressed_page(ntfs_inode *ni,
struct page *page)
{
if ((page->index >= (ni->initialized_size >> PAGE_CACHE_SHIFT)) &&
(ni->initialized_size < VFS_I(ni)->i_size))
zero_partial_compressed_page(ni, page);
return;
}
/** /**
* ntfs_decompress - decompress a compression block into an array of pages * ntfs_decompress - decompress a compression block into an array of pages
* @dest_pages: destination array of pages * @dest_pages: destination array of pages
...@@ -164,7 +198,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index, ...@@ -164,7 +198,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
cb - cb_start); cb - cb_start);
/* Have we reached the end of the compression block? */ /* Have we reached the end of the compression block? */
if (cb == cb_end || !le16_to_cpup(cb)) { if (cb == cb_end || !le16_to_cpup((u16*)cb)) {
int i; int i;
ntfs_debug("Completed. Returning success (0)."); ntfs_debug("Completed. Returning success (0).");
...@@ -173,19 +207,29 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index, ...@@ -173,19 +207,29 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
/* We can sleep from now on, so we drop lock. */ /* We can sleep from now on, so we drop lock. */
spin_unlock(&ntfs_cb_lock); spin_unlock(&ntfs_cb_lock);
/* Second stage: finalize completed pages. */ /* Second stage: finalize completed pages. */
for (i = 0; i < nr_completed_pages; i++) { if (nr_completed_pages > 0) {
int di = completed_pages[i]; struct page *page = dest_pages[completed_pages[0]];
ntfs_inode *ni = NTFS_I(page->mapping->host);
dp = dest_pages[di];
flush_dcache_page(dp); for (i = 0; i < nr_completed_pages; i++) {
kunmap(dp); int di = completed_pages[i];
SetPageUptodate(dp);
unlock_page(dp); dp = dest_pages[di];
if (di == xpage) /*
*xpage_done = 1; * If we are outside the initialized size, zero
else * the out of bounds page range.
page_cache_release(dp); */
dest_pages[di] = NULL; handle_bounds_compressed_page(ni, dp);
flush_dcache_page(dp);
kunmap(dp);
SetPageUptodate(dp);
unlock_page(dp);
if (di == xpage)
*xpage_done = 1;
else
page_cache_release(dp);
dest_pages[di] = NULL;
}
} }
return err; return err;
} }
...@@ -204,7 +248,8 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index, ...@@ -204,7 +248,8 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
/* Setup the current sub-block source pointers and validate range. */ /* Setup the current sub-block source pointers and validate range. */
cb_sb_start = cb; cb_sb_start = cb;
cb_sb_end = cb_sb_start + (le16_to_cpup(cb) & NTFS_SB_SIZE_MASK) + 3; cb_sb_end = cb_sb_start + (le16_to_cpup((u16*)cb) & NTFS_SB_SIZE_MASK)
+ 3;
if (cb_sb_end > cb_end) if (cb_sb_end > cb_end)
goto return_overflow; goto return_overflow;
...@@ -225,7 +270,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index, ...@@ -225,7 +270,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
dp_addr = (u8*)page_address(dp) + do_sb_start; dp_addr = (u8*)page_address(dp) + do_sb_start;
/* Now, we are ready to process the current sub-block (sb). */ /* Now, we are ready to process the current sub-block (sb). */
if (!(le16_to_cpup(cb) & NTFS_SB_IS_COMPRESSED)) { if (!(le16_to_cpup((u16*)cb) & NTFS_SB_IS_COMPRESSED)) {
ntfs_debug("Found uncompressed sub-block."); ntfs_debug("Found uncompressed sub-block.");
/* This sb is not compressed, just copy it into destination. */ /* This sb is not compressed, just copy it into destination. */
...@@ -330,7 +375,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index, ...@@ -330,7 +375,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
lg++; lg++;
/* Get the phrase token into i. */ /* Get the phrase token into i. */
pt = le16_to_cpup(cb); pt = le16_to_cpup((u16*)cb);
/* /*
* Calculate starting position of the byte sequence in * Calculate starting position of the byte sequence in
...@@ -432,7 +477,7 @@ int ntfs_read_compressed_block(struct page *page) ...@@ -432,7 +477,7 @@ int ntfs_read_compressed_block(struct page *page)
u8 *cb, *cb_pos, *cb_end; u8 *cb, *cb_pos, *cb_end;
struct buffer_head **bhs; struct buffer_head **bhs;
unsigned long offset, index = page->index; unsigned long offset, index = page->index;
u32 cb_size = ni->_ICF(compression_block_size); u32 cb_size = ni->itype.compressed.block_size;
u64 cb_size_mask = cb_size - 1UL; u64 cb_size_mask = cb_size - 1UL;
VCN vcn; VCN vcn;
LCN lcn; LCN lcn;
...@@ -447,7 +492,7 @@ int ntfs_read_compressed_block(struct page *page) ...@@ -447,7 +492,7 @@ int ntfs_read_compressed_block(struct page *page)
& ~cb_size_mask) >> vol->cluster_size_bits; & ~cb_size_mask) >> vol->cluster_size_bits;
/* Number of compression blocks (cbs) in the wanted vcn range. */ /* Number of compression blocks (cbs) in the wanted vcn range. */
unsigned int nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits unsigned int nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits
>> ni->_ICF(compression_block_size_bits); >> ni->itype.compressed.block_size_bits;
/* /*
* Number of pages required to store the uncompressed data from all * Number of pages required to store the uncompressed data from all
* compression blocks (cbs) overlapping @page. Due to alignment * compression blocks (cbs) overlapping @page. Due to alignment
...@@ -528,7 +573,7 @@ int ntfs_read_compressed_block(struct page *page) ...@@ -528,7 +573,7 @@ int ntfs_read_compressed_block(struct page *page)
*/ */
cur_page = 0; cur_page = 0;
cur_ofs = 0; cur_ofs = 0;
cb_clusters = ni->_ICF(compression_block_clusters); cb_clusters = ni->itype.compressed.block_clusters;
do_next_cb: do_next_cb:
nr_cbs--; nr_cbs--;
nr_bhs = 0; nr_bhs = 0;
...@@ -763,6 +808,11 @@ int ntfs_read_compressed_block(struct page *page) ...@@ -763,6 +808,11 @@ int ntfs_read_compressed_block(struct page *page)
for (; cur2_page < cb_max_page; cur2_page++) { for (; cur2_page < cb_max_page; cur2_page++) {
page = pages[cur2_page]; page = pages[cur2_page];
if (page) { if (page) {
/*
* If we are outside the initialized size, zero
* the out of bounds page range.
*/
handle_bounds_compressed_page(ni, page);
flush_dcache_page(page); flush_dcache_page(page);
kunmap(page); kunmap(page);
SetPageUptodate(page); SetPageUptodate(page);
......
/** /**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project. * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -105,7 +105,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -105,7 +105,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
} }
/* Get to the index root value (it's been verified in read_inode). */ /* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr + ir = (INDEX_ROOT*)((u8*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset))); le16_to_cpu(ctx->attr->data.resident.value_offset));
index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
/* The first index entry. */ /* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ir->index + ie = (INDEX_ENTRY*)((u8*)&ir->index +
...@@ -114,18 +114,18 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -114,18 +114,18 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* Loop until we exceed valid memory (corruption case) or until we * Loop until we exceed valid memory (corruption case) or until we
* reach the last entry. * reach the last entry.
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) index_end)
goto dir_err_out; goto dir_err_out;
/* /*
* The last entry cannot contain a name. It can however contain * The last entry cannot contain a name. It can however contain
* a pointer to a child node in the B+tree so we just break out. * a pointer to a child node in the B+tree so we just break out.
*/ */
if (ie->_IEH(flags) & INDEX_ENTRY_END) if (ie->flags & INDEX_ENTRY_END)
break; break;
/* /*
* We perform a case sensitive comparison and if that matches * We perform a case sensitive comparison and if that matches
...@@ -159,7 +159,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -159,7 +159,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
} }
} }
name->mref = le64_to_cpu( name->mref = le64_to_cpu(
ie->_IIF(indexed_file)); ie->data.dir.indexed_file);
name->type = FILE_NAME_DOS; name->type = FILE_NAME_DOS;
name->len = 0; name->len = 0;
*res = name; *res = name;
...@@ -168,7 +168,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -168,7 +168,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
kfree(name); kfree(name);
*res = NULL; *res = NULL;
} }
mref = le64_to_cpu(ie->_IIF(indexed_file)); mref = le64_to_cpu(ie->data.dir.indexed_file);
put_attr_search_ctx(ctx); put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni); unmap_mft_record(dir_ni);
return mref; return mref;
...@@ -211,7 +211,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -211,7 +211,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
err = -ENOMEM; err = -ENOMEM;
goto err_out; goto err_out;
} }
name->mref = le64_to_cpu(ie->_IIF(indexed_file)); name->mref = le64_to_cpu(ie->data.dir.indexed_file);
name->type = type; name->type = type;
if (type != FILE_NAME_DOS) { if (type != FILE_NAME_DOS) {
name->len = len; name->len = len;
...@@ -265,7 +265,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -265,7 +265,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* we have got a matching name cached in name in which case return the * we have got a matching name cached in name in which case return the
* mft reference associated with it. * mft reference associated with it.
*/ */
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) { if (!(ie->flags & INDEX_ENTRY_NODE)) {
if (name) { if (name) {
put_attr_search_ctx(ctx); put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni); unmap_mft_record(dir_ni);
...@@ -284,7 +284,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -284,7 +284,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto err_out; goto err_out;
} }
/* Get the starting vcn of the index_block holding the child node. */ /* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8); vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping; ia_mapping = VFS_I(dir_ni)->i_mapping;
/* /*
* We are done with the index root and the mft record. Release them, * We are done with the index root and the mft record. Release them,
...@@ -301,7 +301,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -301,7 +301,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* disk if necessary. * disk if necessary.
*/ */
page = ntfs_map_page(ia_mapping, vcn << page = ntfs_map_page(ia_mapping, vcn <<
dir_ni->_IDM(index_vcn_size_bits) >> PAGE_CACHE_SHIFT); dir_ni->itype.index.vcn_size_bits >> PAGE_CACHE_SHIFT);
if (IS_ERR(page)) { if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.", ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page)); -PTR_ERR(page));
...@@ -312,7 +312,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -312,7 +312,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
fast_descend_into_child_node: fast_descend_into_child_node:
/* Get to the index allocation block. */ /* Get to the index allocation block. */
ia = (INDEX_ALLOCATION*)(kaddr + ((vcn << ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
dir_ni->_IDM(index_vcn_size_bits)) & ~PAGE_CACHE_MASK)); dir_ni->itype.index.vcn_size_bits) & ~PAGE_CACHE_MASK));
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) { if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Out of bounds check failed. Corrupt directory " ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
...@@ -331,18 +331,18 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -331,18 +331,18 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto unm_err_out; goto unm_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) { dir_ni->itype.index.block_size) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx has a size (%u) differing from the " "0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory " "directory specified size (%u). Directory "
"inode is corrupt or driver bug.", "inode is corrupt or driver bug.",
(long long)vcn, dir_ni->mft_no, (long long)vcn, dir_ni->mft_no,
le32_to_cpu(ia->index.allocated_size) + 0x18, le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size)); dir_ni->itype.index.block_size);
err = -EIO; err = -EIO;
goto unm_err_out; goto unm_err_out;
} }
index_end = (u8*)ia + dir_ni->_IDM(index_block_size); index_end = (u8*)ia + dir_ni->itype.index.block_size;
if (index_end > kaddr + PAGE_CACHE_SIZE) { if (index_end > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx crosses page boundary. Impossible! " "0x%lx crosses page boundary. Impossible! "
...@@ -352,7 +352,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -352,7 +352,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto unm_err_out; goto unm_err_out;
} }
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) { if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory " ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
"inode 0x%lx exceeds maximum size.", "inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no); (long long)vcn, dir_ni->mft_no);
...@@ -367,11 +367,11 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -367,11 +367,11 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* loop until we exceed valid memory (corruption case) or until we * loop until we exceed valid memory (corruption case) or until we
* reach the last entry. * reach the last entry.
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
/* Bounds check. */ /* Bounds check. */
if ((u8*)ie < (u8*)ia || (u8*)ie + if ((u8*)ie < (u8*)ia || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) { index_end) {
ntfs_error(sb, "Index entry out of bounds in " ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%lx.", "directory inode 0x%lx.",
...@@ -383,7 +383,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -383,7 +383,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* The last entry cannot contain a name. It can however contain * The last entry cannot contain a name. It can however contain
* a pointer to a child node in the B+tree so we just break out. * a pointer to a child node in the B+tree so we just break out.
*/ */
if (ie->_IEH(flags) & INDEX_ENTRY_END) if (ie->flags & INDEX_ENTRY_END)
break; break;
/* /*
* We perform a case sensitive comparison and if that matches * We perform a case sensitive comparison and if that matches
...@@ -417,7 +417,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -417,7 +417,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
} }
} }
name->mref = le64_to_cpu( name->mref = le64_to_cpu(
ie->_IIF(indexed_file)); ie->data.dir.indexed_file);
name->type = FILE_NAME_DOS; name->type = FILE_NAME_DOS;
name->len = 0; name->len = 0;
*res = name; *res = name;
...@@ -426,7 +426,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -426,7 +426,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
kfree(name); kfree(name);
*res = NULL; *res = NULL;
} }
mref = le64_to_cpu(ie->_IIF(indexed_file)); mref = le64_to_cpu(ie->data.dir.indexed_file);
ntfs_unmap_page(page); ntfs_unmap_page(page);
return mref; return mref;
} }
...@@ -469,7 +469,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -469,7 +469,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
err = -ENOMEM; err = -ENOMEM;
goto unm_err_out; goto unm_err_out;
} }
name->mref = le64_to_cpu(ie->_IIF(indexed_file)); name->mref = le64_to_cpu(ie->data.dir.indexed_file);
name->type = type; name->type = type;
if (type != FILE_NAME_DOS) { if (type != FILE_NAME_DOS) {
name->len = len; name->len = len;
...@@ -521,7 +521,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -521,7 +521,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* We have finished with this index buffer without success. Check for * We have finished with this index buffer without success. Check for
* the presence of a child node. * the presence of a child node.
*/ */
if (ie->_IEH(flags) & INDEX_ENTRY_NODE) { if (ie->flags & INDEX_ENTRY_NODE) {
if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
ntfs_error(sb, "Index entry with child node found in " ntfs_error(sb, "Index entry with child node found in "
"a leaf node in directory inode 0x%lx.", "a leaf node in directory inode 0x%lx.",
...@@ -531,8 +531,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -531,8 +531,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
} }
/* Child node present, descend into it. */ /* Child node present, descend into it. */
old_vcn = vcn; old_vcn = vcn;
vcn = sle64_to_cpup((u8*)ie + vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
le16_to_cpu(ie->_IEH(length)) - 8);
if (vcn >= 0) { if (vcn >= 0) {
/* If vcn is in the same page cache page as old_vcn we /* If vcn is in the same page cache page as old_vcn we
* recycle the mapped page. */ * recycle the mapped page. */
...@@ -646,7 +645,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -646,7 +645,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
} }
/* Get to the index root value (it's been verified in read_inode). */ /* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr + ir = (INDEX_ROOT*)((u8*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset))); le16_to_cpu(ctx->attr->data.resident.value_offset));
index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
/* The first index entry. */ /* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ir->index + ie = (INDEX_ENTRY*)((u8*)&ir->index +
...@@ -655,18 +654,18 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -655,18 +654,18 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* Loop until we exceed valid memory (corruption case) or until we * Loop until we exceed valid memory (corruption case) or until we
* reach the last entry. * reach the last entry.
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) index_end)
goto dir_err_out; goto dir_err_out;
/* /*
* The last entry cannot contain a name. It can however contain * The last entry cannot contain a name. It can however contain
* a pointer to a child node in the B+tree so we just break out. * a pointer to a child node in the B+tree so we just break out.
*/ */
if (ie->_IEH(flags) & INDEX_ENTRY_END) if (ie->flags & INDEX_ENTRY_END)
break; break;
/* /*
* If the current entry has a name type of POSIX, the name is * If the current entry has a name type of POSIX, the name is
...@@ -691,7 +690,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -691,7 +690,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ie->key.file_name.file_name_length, ic, ie->key.file_name.file_name_length, ic,
vol->upcase, vol->upcase_len)) { vol->upcase, vol->upcase_len)) {
found_it: found_it:
mref = le64_to_cpu(ie->_IIF(indexed_file)); mref = le64_to_cpu(ie->data.dir.indexed_file);
put_attr_search_ctx(ctx); put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni); unmap_mft_record(dir_ni);
return mref; return mref;
...@@ -738,7 +737,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -738,7 +737,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* We have finished with this index without success. Check for the * We have finished with this index without success. Check for the
* presence of a child node. * presence of a child node.
*/ */
if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) { if (!(ie->flags & INDEX_ENTRY_NODE)) {
/* No child node, return -ENOENT. */ /* No child node, return -ENOENT. */
err = -ENOENT; err = -ENOENT;
goto err_out; goto err_out;
...@@ -752,7 +751,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -752,7 +751,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto err_out; goto err_out;
} }
/* Get the starting vcn of the index_block holding the child node. */ /* Get the starting vcn of the index_block holding the child node. */
vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8); vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
ia_mapping = VFS_I(dir_ni)->i_mapping; ia_mapping = VFS_I(dir_ni)->i_mapping;
/* /*
* We are done with the index root and the mft record. Release them, * We are done with the index root and the mft record. Release them,
...@@ -769,7 +768,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -769,7 +768,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* disk if necessary. * disk if necessary.
*/ */
page = ntfs_map_page(ia_mapping, vcn << page = ntfs_map_page(ia_mapping, vcn <<
dir_ni->_IDM(index_vcn_size_bits) >> PAGE_CACHE_SHIFT); dir_ni->itype.index.vcn_size_bits >> PAGE_CACHE_SHIFT);
if (IS_ERR(page)) { if (IS_ERR(page)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.", ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page)); -PTR_ERR(page));
...@@ -780,7 +779,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -780,7 +779,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
fast_descend_into_child_node: fast_descend_into_child_node:
/* Get to the index allocation block. */ /* Get to the index allocation block. */
ia = (INDEX_ALLOCATION*)(kaddr + ((vcn << ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
dir_ni->_IDM(index_vcn_size_bits)) & ~PAGE_CACHE_MASK)); dir_ni->itype.index.vcn_size_bits) & ~PAGE_CACHE_MASK));
/* Bounds checks. */ /* Bounds checks. */
if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) { if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Out of bounds check failed. Corrupt directory " ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
...@@ -799,18 +798,18 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -799,18 +798,18 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto unm_err_out; goto unm_err_out;
} }
if (le32_to_cpu(ia->index.allocated_size) + 0x18 != if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
dir_ni->_IDM(index_block_size)) { dir_ni->itype.index.block_size) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx has a size (%u) differing from the " "0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory " "directory specified size (%u). Directory "
"inode is corrupt or driver bug.", "inode is corrupt or driver bug.",
(long long)vcn, dir_ni->mft_no, (long long)vcn, dir_ni->mft_no,
le32_to_cpu(ia->index.allocated_size) + 0x18, le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->_IDM(index_block_size)); dir_ni->itype.index.block_size);
err = -EIO; err = -EIO;
goto unm_err_out; goto unm_err_out;
} }
index_end = (u8*)ia + dir_ni->_IDM(index_block_size); index_end = (u8*)ia + dir_ni->itype.index.block_size;
if (index_end > kaddr + PAGE_CACHE_SIZE) { if (index_end > kaddr + PAGE_CACHE_SIZE) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx crosses page boundary. Impossible! " "0x%lx crosses page boundary. Impossible! "
...@@ -820,7 +819,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -820,7 +819,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto unm_err_out; goto unm_err_out;
} }
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) { if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory " ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
"inode 0x%lx exceeds maximum size.", "inode 0x%lx exceeds maximum size.",
(long long)vcn, dir_ni->mft_no); (long long)vcn, dir_ni->mft_no);
...@@ -835,11 +834,11 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -835,11 +834,11 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* loop until we exceed valid memory (corruption case) or until we * loop until we exceed valid memory (corruption case) or until we
* reach the last entry. * reach the last entry.
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
/* Bounds check. */ /* Bounds check. */
if ((u8*)ie < (u8*)ia || (u8*)ie + if ((u8*)ie < (u8*)ia || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end) { index_end) {
ntfs_error(sb, "Index entry out of bounds in " ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%lx.", "directory inode 0x%lx.",
...@@ -851,7 +850,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -851,7 +850,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* The last entry cannot contain a name. It can however contain * The last entry cannot contain a name. It can however contain
* a pointer to a child node in the B+tree so we just break out. * a pointer to a child node in the B+tree so we just break out.
*/ */
if (ie->_IEH(flags) & INDEX_ENTRY_END) if (ie->flags & INDEX_ENTRY_END)
break; break;
/* /*
* If the current entry has a name type of POSIX, the name is * If the current entry has a name type of POSIX, the name is
...@@ -876,7 +875,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -876,7 +875,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
ie->key.file_name.file_name_length, ic, ie->key.file_name.file_name_length, ic,
vol->upcase, vol->upcase_len)) { vol->upcase, vol->upcase_len)) {
found_it2: found_it2:
mref = le64_to_cpu(ie->_IIF(indexed_file)); mref = le64_to_cpu(ie->data.dir.indexed_file);
ntfs_unmap_page(page); ntfs_unmap_page(page);
return mref; return mref;
} }
...@@ -922,7 +921,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -922,7 +921,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
* We have finished with this index buffer without success. Check for * We have finished with this index buffer without success. Check for
* the presence of a child node. * the presence of a child node.
*/ */
if (ie->_IEH(flags) & INDEX_ENTRY_NODE) { if (ie->flags & INDEX_ENTRY_NODE) {
if ((ia->index.flags & NODE_MASK) == LEAF_NODE) { if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
ntfs_error(sb, "Index entry with child node found in " ntfs_error(sb, "Index entry with child node found in "
"a leaf node in directory inode 0x%lx.", "a leaf node in directory inode 0x%lx.",
...@@ -932,8 +931,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname, ...@@ -932,8 +931,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
} }
/* Child node present, descend into it. */ /* Child node present, descend into it. */
old_vcn = vcn; old_vcn = vcn;
vcn = sle64_to_cpup((u8*)ie + vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
le16_to_cpu(ie->_IEH(length)) - 8);
if (vcn >= 0) { if (vcn >= 0) {
/* If vcn is in the same page cache page as old_vcn we /* If vcn is in the same page cache page as old_vcn we
* recycle the mapped page. */ * recycle the mapped page. */
...@@ -1007,7 +1005,7 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos, ...@@ -1007,7 +1005,7 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
if (index_type == INDEX_TYPE_ALLOCATION) if (index_type == INDEX_TYPE_ALLOCATION)
*fpos = (u8*)ie - (u8*)iu.ia + *fpos = (u8*)ie - (u8*)iu.ia +
(sle64_to_cpu(iu.ia->index_block_vcn) << (sle64_to_cpu(iu.ia->index_block_vcn) <<
ndir->_IDM(index_vcn_size_bits)) + ndir->itype.index.vcn_size_bits) +
vol->mft_record_size; vol->mft_record_size;
else /* if (index_type == INDEX_TYPE_ROOT) */ else /* if (index_type == INDEX_TYPE_ROOT) */
*fpos = (u8*)ie - (u8*)iu.ir; *fpos = (u8*)ie - (u8*)iu.ir;
...@@ -1016,11 +1014,11 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos, ...@@ -1016,11 +1014,11 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
ntfs_debug("Skipping DOS name space entry."); ntfs_debug("Skipping DOS name space entry.");
return 0; return 0;
} }
if (MREF_LE(ie->_IIF(indexed_file)) == FILE_root) { if (MREF_LE(ie->data.dir.indexed_file) == FILE_root) {
ntfs_debug("Skipping root directory self reference entry."); ntfs_debug("Skipping root directory self reference entry.");
return 0; return 0;
} }
if (MREF_LE(ie->_IIF(indexed_file)) < FILE_first_user && if (MREF_LE(ie->data.dir.indexed_file) < FILE_first_user &&
!NVolShowSystemFiles(vol)) { !NVolShowSystemFiles(vol)) {
ntfs_debug("Skipping system file."); ntfs_debug("Skipping system file.");
return 0; return 0;
...@@ -1039,10 +1037,10 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos, ...@@ -1039,10 +1037,10 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
dt_type = DT_REG; dt_type = DT_REG;
ntfs_debug("Calling filldir for %s with len %i, fpos 0x%Lx, inode " ntfs_debug("Calling filldir for %s with len %i, fpos 0x%Lx, inode "
"0x%lx, DT_%s.", name, name_len, *fpos, "0x%lx, DT_%s.", name, name_len, *fpos,
MREF_LE(ie->_IIF(indexed_file)), MREF_LE(ie->data.dir.indexed_file),
dt_type == DT_DIR ? "DIR" : "REG"); dt_type == DT_DIR ? "DIR" : "REG");
return filldir(dirent, name, name_len, *fpos, return filldir(dirent, name, name_len, *fpos,
MREF_LE(ie->_IIF(indexed_file)), dt_type); MREF_LE(ie->data.dir.indexed_file), dt_type);
} }
/* /*
...@@ -1139,7 +1137,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1139,7 +1137,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
/* Get to the index root value (it's been verified in read_inode). */ /* Get to the index root value (it's been verified in read_inode). */
ir = (INDEX_ROOT*)((u8*)ctx->attr + ir = (INDEX_ROOT*)((u8*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset))); le16_to_cpu(ctx->attr->data.resident.value_offset));
index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
/* The first index entry. */ /* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ir->index + ie = (INDEX_ENTRY*)((u8*)&ir->index +
...@@ -1149,16 +1147,16 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1149,16 +1147,16 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
* reach the last entry or until filldir tells us it has had enough * reach the last entry or until filldir tells us it has had enough
* or signals an error (both covered by the rc test). * or signals an error (both covered by the rc test).
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
ntfs_debug("In index root, offset 0x%x.", (u8*)ie - (u8*)ir); ntfs_debug("In index root, offset 0x%x.", (u8*)ie - (u8*)ir);
/* Bounds checks. */ /* Bounds checks. */
if (unlikely((u8*)ie < (u8*)ctx->mrec || (u8*)ie + if (unlikely((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end)) index_end))
goto err_out; goto err_out;
/* The last entry cannot contain a name. */ /* The last entry cannot contain a name. */
if (ie->_IEH(flags) & INDEX_ENTRY_END) if (ie->flags & INDEX_ENTRY_END)
break; break;
/* Skip index root entry if continuing previous readdir. */ /* Skip index root entry if continuing previous readdir. */
if (ir_pos > (u8*)ie - (u8*)ir) if (ir_pos > (u8*)ie - (u8*)ir)
...@@ -1192,7 +1190,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1192,7 +1190,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Get the offset into the index allocation attribute. */ /* Get the offset into the index allocation attribute. */
ia_pos = (s64)fpos - vol->mft_record_size; ia_pos = (s64)fpos - vol->mft_record_size;
ia_mapping = vdir->i_mapping; ia_mapping = vdir->i_mapping;
bmp_vi = ndir->_IDM(bmp_ino); bmp_vi = ndir->itype.index.bmp_ino;
if (unlikely(!bmp_vi)) { if (unlikely(!bmp_vi)) {
ntfs_debug("Inode %lu, regetting index bitmap.", vdir->i_ino); ntfs_debug("Inode %lu, regetting index bitmap.", vdir->i_ino);
bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4); bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
...@@ -1201,11 +1199,11 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1201,11 +1199,11 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
err = PTR_ERR(bmp_vi); err = PTR_ERR(bmp_vi);
goto err_out; goto err_out;
} }
ndir->_IDM(bmp_ino) = bmp_vi; ndir->itype.index.bmp_ino = bmp_vi;
} }
bmp_mapping = bmp_vi->i_mapping; bmp_mapping = bmp_vi->i_mapping;
/* Get the starting bitmap bit position and sanity check it. */ /* Get the starting bitmap bit position and sanity check it. */
bmp_pos = ia_pos >> ndir->_IDM(index_block_size_bits); bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
if (unlikely(bmp_pos >> 3 >= bmp_vi->i_size)) { if (unlikely(bmp_pos >> 3 >= bmp_vi->i_size)) {
ntfs_error(sb, "Current index allocation position exceeds " ntfs_error(sb, "Current index allocation position exceeds "
"index bitmap size."); "index bitmap size.");
...@@ -1245,7 +1243,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1245,7 +1243,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= vdir->i_size)) if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= vdir->i_size))
goto unm_EOD; goto unm_EOD;
ia_pos = (bmp_pos + cur_bmp_pos) << ia_pos = (bmp_pos + cur_bmp_pos) <<
ndir->_IDM(index_block_size_bits); ndir->itype.index.block_size_bits;
} }
ntfs_debug("Handling index buffer 0x%Lx.", ntfs_debug("Handling index buffer 0x%Lx.",
(long long)bmp_pos + cur_bmp_pos); (long long)bmp_pos + cur_bmp_pos);
...@@ -1269,7 +1267,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1269,7 +1267,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
} }
/* Get the current index buffer. */ /* Get the current index buffer. */
ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_CACHE_MASK & ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_CACHE_MASK &
~(s64)(ndir->_IDM(index_block_size) - 1))); ~(s64)(ndir->itype.index.block_size - 1)));
/* Bounds checks. */ /* Bounds checks. */
if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE)) { if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE)) {
ntfs_error(sb, "Out of bounds check failed. Corrupt directory " ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
...@@ -1277,45 +1275,45 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1277,45 +1275,45 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto err_out; goto err_out;
} }
if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos & if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
~(s64)(ndir->_IDM(index_block_size) - 1)) >> ~(s64)(ndir->itype.index.block_size - 1)) >>
ndir->_IDM(index_vcn_size_bits))) { ndir->itype.index.vcn_size_bits)) {
ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is " ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
"different from expected VCN (0x%Lx). " "different from expected VCN (0x%Lx). "
"Directory inode 0x%lx is corrupt or driver " "Directory inode 0x%lx is corrupt or driver "
"bug. ", "bug. ",
(long long)sle64_to_cpu(ia->index_block_vcn), (long long)sle64_to_cpu(ia->index_block_vcn),
(long long)ia_pos >> (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), vdir->i_ino); ndir->itype.index.vcn_size_bits, vdir->i_ino);
goto err_out; goto err_out;
} }
if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 != if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 !=
ndir->_IDM(index_block_size))) { ndir->itype.index.block_size)) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx has a size (%u) differing from the " "0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory " "directory specified size (%u). Directory "
"inode is corrupt or driver bug.", "inode is corrupt or driver bug.",
(long long)ia_pos >> (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), vdir->i_ino, ndir->itype.index.vcn_size_bits, vdir->i_ino,
le32_to_cpu(ia->index.allocated_size) + 0x18, le32_to_cpu(ia->index.allocated_size) + 0x18,
ndir->_IDM(index_block_size)); ndir->itype.index.block_size);
goto err_out; goto err_out;
} }
index_end = (u8*)ia + ndir->_IDM(index_block_size); index_end = (u8*)ia + ndir->itype.index.block_size;
if (unlikely(index_end > kaddr + PAGE_CACHE_SIZE)) { if (unlikely(index_end > kaddr + PAGE_CACHE_SIZE)) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode " ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx crosses page boundary. Impossible! " "0x%lx crosses page boundary. Impossible! "
"Cannot access! This is probably a bug in the " "Cannot access! This is probably a bug in the "
"driver.", (long long)ia_pos >> "driver.", (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), vdir->i_ino); ndir->itype.index.vcn_size_bits, vdir->i_ino);
goto err_out; goto err_out;
} }
ia_start = ia_pos & ~(s64)(ndir->_IDM(index_block_size) - 1); ia_start = ia_pos & ~(s64)(ndir->itype.index.block_size - 1);
index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length); index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
if (unlikely(index_end > (u8*)ia + ndir->_IDM(index_block_size))) { if (unlikely(index_end > (u8*)ia + ndir->itype.index.block_size)) {
ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory " ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
"inode 0x%lx exceeds maximum size.", "inode 0x%lx exceeds maximum size.",
(long long)ia_pos >> (long long)ia_pos >>
ndir->_IDM(index_vcn_size_bits), vdir->i_ino); ndir->itype.index.vcn_size_bits, vdir->i_ino);
goto err_out; goto err_out;
} }
/* The first index entry in this index buffer. */ /* The first index entry in this index buffer. */
...@@ -1326,17 +1324,17 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -1326,17 +1324,17 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
* reach the last entry or until filldir tells us it has had enough * reach the last entry or until filldir tells us it has had enough
* or signals an error (both covered by the rc test). * or signals an error (both covered by the rc test).
*/ */
for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) { for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
ntfs_debug("In index allocation, offset 0x%Lx.", ntfs_debug("In index allocation, offset 0x%Lx.",
(long long)ia_start + ((u8*)ie - (u8*)ia)); (long long)ia_start + ((u8*)ie - (u8*)ia));
/* Bounds checks. */ /* Bounds checks. */
if (unlikely((u8*)ie < (u8*)ia || (u8*)ie + if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
sizeof(INDEX_ENTRY_HEADER) > index_end || sizeof(INDEX_ENTRY_HEADER) > index_end ||
(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) > (u8*)ie + le16_to_cpu(ie->key_length) >
index_end)) index_end))
goto err_out; goto err_out;
/* The last entry cannot contain a name. */ /* The last entry cannot contain a name. */
if (ie->_IEH(flags) & INDEX_ENTRY_END) if (ie->flags & INDEX_ENTRY_END)
break; break;
/* Skip index block entry if continuing previous readdir. */ /* Skip index block entry if continuing previous readdir. */
if (ia_pos - ia_start > (u8*)ie - (u8*)ia) if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
......
/** /**
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project. * inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -336,14 +336,14 @@ static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ...@@ -336,14 +336,14 @@ static void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ni->attr_list_size = 0; ni->attr_list_size = 0;
ni->attr_list = NULL; ni->attr_list = NULL;
init_run_list(&ni->attr_list_rl); init_run_list(&ni->attr_list_rl);
ni->_IDM(bmp_ino) = NULL; ni->itype.index.bmp_ino = NULL;
ni->_IDM(index_block_size) = 0; ni->itype.index.block_size = 0;
ni->_IDM(index_vcn_size) = 0; ni->itype.index.vcn_size = 0;
ni->_IDM(index_block_size_bits) = 0; ni->itype.index.block_size_bits = 0;
ni->_IDM(index_vcn_size_bits) = 0; ni->itype.index.vcn_size_bits = 0;
init_MUTEX(&ni->extent_lock); init_MUTEX(&ni->extent_lock);
ni->nr_extents = 0; ni->nr_extents = 0;
ni->_INE(base_ntfs_ino) = NULL; ni->ext.base_ntfs_ino = NULL;
return; return;
} }
...@@ -426,14 +426,14 @@ static int ntfs_is_extended_system_file(attr_search_context *ctx) ...@@ -426,14 +426,14 @@ static int ntfs_is_extended_system_file(attr_search_context *ctx)
"chkdsk."); "chkdsk.");
return -EIO; return -EIO;
} }
if (!(attr->_ARA(resident_flags) & RESIDENT_ATTR_IS_INDEXED)) { if (!(attr->data.resident.flags & RESIDENT_ATTR_IS_INDEXED)) {
ntfs_error(ctx->ntfs_ino->vol->sb, "Unindexed file " ntfs_error(ctx->ntfs_ino->vol->sb, "Unindexed file "
"name. You should run chkdsk."); "name. You should run chkdsk.");
return -EIO; return -EIO;
} }
file_name_attr = (FILE_NAME_ATTR*)((u8*)attr + file_name_attr = (FILE_NAME_ATTR*)((u8*)attr +
le16_to_cpu(attr->_ARA(value_offset))); le16_to_cpu(attr->data.resident.value_offset));
p2 = (u8*)attr + le32_to_cpu(attr->_ARA(value_length)); p2 = (u8*)attr + le32_to_cpu(attr->data.resident.value_length);
if (p2 < (u8*)attr || p2 > p) if (p2 < (u8*)attr || p2 > p)
goto err_corrupt_attr; goto err_corrupt_attr;
/* This attribute is ok, but is it in the $Extend directory? */ /* This attribute is ok, but is it in the $Extend directory? */
...@@ -578,7 +578,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -578,7 +578,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
/* Get the standard information attribute value. */ /* Get the standard information attribute value. */
si = (STANDARD_INFORMATION*)((char*)ctx->attr + si = (STANDARD_INFORMATION*)((char*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset))); le16_to_cpu(ctx->attr->data.resident.value_offset));
/* Transfer information from the standard information into vfs_ino. */ /* Transfer information from the standard information into vfs_ino. */
/* /*
...@@ -633,7 +633,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -633,7 +633,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
NInoSetAttrListNonResident(ni); NInoSetAttrListNonResident(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "Attribute list has non " ntfs_error(vi->i_sb, "Attribute list has non "
"zero lowest_vcn. Inode is " "zero lowest_vcn. Inode is "
"corrupt. You should run " "corrupt. You should run "
...@@ -659,17 +659,17 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -659,17 +659,17 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* Now load the attribute list. */ /* Now load the attribute list. */
if ((err = load_attribute_list(vol, &ni->attr_list_rl, if ((err = load_attribute_list(vol, &ni->attr_list_rl,
ni->attr_list, ni->attr_list_size, ni->attr_list, ni->attr_list_size,
sle64_to_cpu( sle64_to_cpu(ctx->attr->data.
ctx->attr->_ANR(initialized_size))))) { non_resident.initialized_size)))) {
ntfs_error(vi->i_sb, "Failed to load " ntfs_error(vi->i_sb, "Failed to load "
"attribute list attribute."); "attribute list attribute.");
goto unm_err_out; goto unm_err_out;
} }
} else /* if (!ctx.attr->non_resident) */ { } else /* if (!ctx.attr->non_resident) */ {
if ((u8*)ctx->attr + le16_to_cpu( if ((u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset)) + ctx->attr->data.resident.value_offset) +
le32_to_cpu( le32_to_cpu(
ctx->attr->_ARA(value_length)) > ctx->attr->data.resident.value_length) >
(u8*)ctx->mrec + vol->mft_record_size) { (u8*)ctx->mrec + vol->mft_record_size) {
ntfs_error(vi->i_sb, "Corrupt attribute list " ntfs_error(vi->i_sb, "Corrupt attribute list "
"in inode."); "in inode.");
...@@ -677,9 +677,9 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -677,9 +677,9 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
/* Now copy the attribute list. */ /* Now copy the attribute list. */
memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset)), ctx->attr->data.resident.value_offset),
le32_to_cpu( le32_to_cpu(
ctx->attr->_ARA(value_length))); ctx->attr->data.resident.value_length));
} }
} }
skip_attr_list_load: skip_attr_list_load:
...@@ -728,9 +728,10 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -728,9 +728,10 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) if (ctx->attr->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni); NInoSetSparse(ni);
ir = (INDEX_ROOT*)((char*)ctx->attr + ir = (INDEX_ROOT*)((char*)ctx->attr + le16_to_cpu(
le16_to_cpu(ctx->attr->_ARA(value_offset))); ctx->attr->data.resident.value_offset));
ir_end = (char*)ir + le32_to_cpu(ctx->attr->_ARA(value_length)); ir_end = (char*)ir + le32_to_cpu(
ctx->attr->data.resident.value_length);
if (ir_end > (char*)ctx->mrec + vol->mft_record_size) { if (ir_end > (char*)ctx->mrec + vol->mft_record_size) {
ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is " ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is "
"corrupt."); "corrupt.");
...@@ -752,41 +753,41 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -752,41 +753,41 @@ static int ntfs_read_locked_inode(struct inode *vi)
"COLLATION_FILE_NAME. Not allowed."); "COLLATION_FILE_NAME. Not allowed.");
goto unm_err_out; goto unm_err_out;
} }
ni->_IDM(index_block_size) = le32_to_cpu(ir->index_block_size); ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
if (ni->_IDM(index_block_size) & if (ni->itype.index.block_size &
(ni->_IDM(index_block_size) - 1)) { (ni->itype.index.block_size - 1)) {
ntfs_error(vi->i_sb, "Index block size (%u) is not a " ntfs_error(vi->i_sb, "Index block size (%u) is not a "
"power of two.", "power of two.",
ni->_IDM(index_block_size)); ni->itype.index.block_size);
goto unm_err_out; goto unm_err_out;
} }
if (ni->_IDM(index_block_size) > PAGE_CACHE_SIZE) { if (ni->itype.index.block_size > PAGE_CACHE_SIZE) {
ntfs_error(vi->i_sb, "Index block size (%u) > " ntfs_error(vi->i_sb, "Index block size (%u) > "
"PAGE_CACHE_SIZE (%ld) is not " "PAGE_CACHE_SIZE (%ld) is not "
"supported. Sorry.", "supported. Sorry.",
ni->_IDM(index_block_size), ni->itype.index.block_size,
PAGE_CACHE_SIZE); PAGE_CACHE_SIZE);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
if (ni->_IDM(index_block_size) < NTFS_BLOCK_SIZE) { if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) {
ntfs_error(vi->i_sb, "Index block size (%u) < " ntfs_error(vi->i_sb, "Index block size (%u) < "
"NTFS_BLOCK_SIZE (%i) is not " "NTFS_BLOCK_SIZE (%i) is not "
"supported. Sorry.", "supported. Sorry.",
ni->_IDM(index_block_size), ni->itype.index.block_size,
NTFS_BLOCK_SIZE); NTFS_BLOCK_SIZE);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->_IDM(index_block_size_bits) = ni->itype.index.block_size_bits =
ffs(ni->_IDM(index_block_size)) - 1; ffs(ni->itype.index.block_size) - 1;
/* Determine the size of a vcn in the directory index. */ /* Determine the size of a vcn in the directory index. */
if (vol->cluster_size <= ni->_IDM(index_block_size)) { if (vol->cluster_size <= ni->itype.index.block_size) {
ni->_IDM(index_vcn_size) = vol->cluster_size; ni->itype.index.vcn_size = vol->cluster_size;
ni->_IDM(index_vcn_size_bits) = vol->cluster_size_bits; ni->itype.index.vcn_size_bits = vol->cluster_size_bits;
} else { } else {
ni->_IDM(index_vcn_size) = vol->sector_size; ni->itype.index.vcn_size = vol->sector_size;
ni->_IDM(index_vcn_size_bits) = vol->sector_size_bits; ni->itype.index.vcn_size_bits = vol->sector_size_bits;
} }
/* Setup the index allocation attribute, even if not present. */ /* Setup the index allocation attribute, even if not present. */
...@@ -836,18 +837,19 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -836,18 +837,19 @@ static int ntfs_read_locked_inode(struct inode *vi)
"is compressed."); "is compressed.");
goto unm_err_out; goto unm_err_out;
} }
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of " ntfs_error(vi->i_sb, "First extent of "
"$INDEX_ALLOCATION attribute has non " "$INDEX_ALLOCATION attribute has non "
"zero lowest_vcn. Inode is corrupt. " "zero lowest_vcn. Inode is corrupt. "
"You should run chkdsk."); "You should run chkdsk.");
goto unm_err_out; goto unm_err_out;
} }
vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size)); vi->i_size = sle64_to_cpu(
ctx->attr->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->_ANR(initialized_size)); ctx->attr->data.non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->_ANR(allocated_size)); ctx->attr->data.non_resident.allocated_size);
/* /*
* We are done with the mft record, so we release it. Otherwise * We are done with the mft record, so we release it. Otherwise
* we would deadlock in ntfs_attr_iget(). * we would deadlock in ntfs_attr_iget().
...@@ -863,7 +865,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -863,7 +865,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = PTR_ERR(bvi); err = PTR_ERR(bvi);
goto unm_err_out; goto unm_err_out;
} }
ni->_IDM(bmp_ino) = bvi; ni->itype.index.bmp_ino = bvi;
bni = NTFS_I(bvi); bni = NTFS_I(bvi);
if (NInoCompressed(bni) || NInoEncrypted(bni) || if (NInoCompressed(bni) || NInoEncrypted(bni) ||
NInoSparse(bni)) { NInoSparse(bni)) {
...@@ -873,7 +875,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -873,7 +875,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
/* Consistency check bitmap size vs. index allocation size. */ /* Consistency check bitmap size vs. index allocation size. */
if ((bvi->i_size << 3) < (vi->i_size >> if ((bvi->i_size << 3) < (vi->i_size >>
ni->_IDM(index_block_size_bits))) { ni->itype.index.block_size_bits)) {
ntfs_error(vi->i_sb, "Index bitmap too small (0x%Lx) " ntfs_error(vi->i_sb, "Index bitmap too small (0x%Lx) "
"for index allocation (0x%Lx).", "for index allocation (0x%Lx).",
bvi->i_size << 3, vi->i_size); bvi->i_size << 3, vi->i_size);
...@@ -950,25 +952,28 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -950,25 +952,28 @@ static int ntfs_read_locked_inode(struct inode *vi)
"corrupt file."); "corrupt file.");
goto unm_err_out; goto unm_err_out;
} }
ni->_ICF(compression_block_clusters) = 1U << ni->itype.compressed.block_clusters = 1U <<
ctx->attr->_ANR(compression_unit); ctx->attr->data.non_resident.
if (ctx->attr->_ANR(compression_unit) != 4) { compression_unit;
if (ctx->attr->data.non_resident.
compression_unit != 4) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit " "nonstandard compression unit "
"(%u instead of 4). Cannot " "(%u instead of 4). Cannot "
"handle this. This might " "handle this. This might "
"indicate corruption so you " "indicate corruption so you "
"should run chkdsk.", "should run chkdsk.",
ctx->attr->_ANR(compression_unit)); ctx->attr->data.non_resident.
compression_unit);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->_ICF(compression_block_size) = 1U << ( ni->itype.compressed.block_size = 1U << (
ctx->attr->_ANR( ctx->attr->data.non_resident.
compression_unit) + compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->_ICF(compression_block_size_bits) = ffs( ni->itype.compressed.block_size_bits = ffs(
ni->_ICF(compression_block_size)) - 1; ni->itype.compressed.block_size) - 1;
} }
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
...@@ -980,7 +985,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -980,7 +985,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
} }
if (ctx->attr->flags & ATTR_IS_SPARSE) if (ctx->attr->flags & ATTR_IS_SPARSE)
NInoSetSparse(ni); NInoSetSparse(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of $DATA " ntfs_error(vi->i_sb, "First extent of $DATA "
"attribute has non zero " "attribute has non zero "
"lowest_vcn. Inode is corrupt. " "lowest_vcn. Inode is corrupt. "
...@@ -988,24 +993,18 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -988,24 +993,18 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto unm_err_out; goto unm_err_out;
} }
/* Setup all the sizes. */ /* Setup all the sizes. */
vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size)); vi->i_size = sle64_to_cpu(
ctx->attr->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->_ANR(initialized_size)); ctx->attr->data.non_resident.
initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->_ANR(allocated_size)); ctx->attr->data.non_resident.
allocated_size);
if (NInoCompressed(ni)) { if (NInoCompressed(ni)) {
ni->_ICF(compressed_size) = sle64_to_cpu( ni->itype.compressed.size = sle64_to_cpu(
ctx->attr->_ANR(compressed_size)); ctx->attr->data.non_resident.
if (vi->i_size != ni->initialized_size) compressed_size);
ntfs_warning(vi->i_sb, "BUG: Found "
"compressed file with "
"data_size not equal to "
"initialized_size. This will "
"probably cause problems when "
"trying to access the file. "
"Please notify linux-ntfs-dev@"
"lists.sf.net that you saw "
"this message. Thanks!");
} }
} else { /* Resident attribute. */ } else { /* Resident attribute. */
/* /*
...@@ -1015,7 +1014,8 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1015,7 +1014,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
* path. (Probably only affects truncate().) * path. (Probably only affects truncate().)
*/ */
vi->i_size = ni->initialized_size = ni->allocated_size = vi->i_size = ni->initialized_size = ni->allocated_size =
le32_to_cpu(ctx->attr->_ARA(value_length)); le32_to_cpu(
ctx->attr->data.resident.value_length);
} }
no_data_attr_special_case: no_data_attr_special_case:
/* We are done with the mft record, so we release it. */ /* We are done with the mft record, so we release it. */
...@@ -1049,7 +1049,7 @@ static int ntfs_read_locked_inode(struct inode *vi) ...@@ -1049,7 +1049,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (!NInoCompressed(ni)) if (!NInoCompressed(ni))
vi->i_blocks = ni->allocated_size >> 9; vi->i_blocks = ni->allocated_size >> 9;
else else
vi->i_blocks = ni->_ICF(compressed_size) >> 9; vi->i_blocks = ni->itype.compressed.size >> 9;
ntfs_debug("Done."); ntfs_debug("Done.");
return 0; return 0;
...@@ -1146,7 +1146,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1146,7 +1146,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
* read code paths. * read code paths.
*/ */
vi->i_size = ni->initialized_size = ni->allocated_size = vi->i_size = ni->initialized_size = ni->allocated_size =
le32_to_cpu(ctx->attr->_ARA(value_length)); le32_to_cpu(ctx->attr->data.resident.value_length);
} else { } else {
NInoSetNonResident(ni); NInoSetNonResident(ni);
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
...@@ -1189,25 +1189,27 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1189,25 +1189,27 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"corrupt file."); "corrupt file.");
goto unm_err_out; goto unm_err_out;
} }
ni->_ICF(compression_block_clusters) = 1U << ni->itype.compressed.block_clusters = 1U <<
ctx->attr->_ANR(compression_unit); ctx->attr->data.non_resident.
if (ctx->attr->_ANR(compression_unit) != 4) { compression_unit;
if (ctx->attr->data.non_resident.compression_unit != 4) {
ntfs_error(vi->i_sb, "Found " ntfs_error(vi->i_sb, "Found "
"nonstandard compression unit " "nonstandard compression unit "
"(%u instead of 4). Cannot " "(%u instead of 4). Cannot "
"handle this. This might " "handle this. This might "
"indicate corruption so you " "indicate corruption so you "
"should run chkdsk.", "should run chkdsk.",
ctx->attr->_ANR(compression_unit)); ctx->attr->data.non_resident.
compression_unit);
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto unm_err_out; goto unm_err_out;
} }
ni->_ICF(compression_block_size) = 1U << ( ni->itype.compressed.block_size = 1U << (
ctx->attr->_ANR( ctx->attr->data.non_resident.
compression_unit) + compression_unit +
vol->cluster_size_bits); vol->cluster_size_bits);
ni->_ICF(compression_block_size_bits) = ffs( ni->itype.compressed.block_size_bits = ffs(
ni->_ICF(compression_block_size)) - 1; ni->itype.compressed.block_size) - 1;
} }
if (ctx->attr->flags & ATTR_IS_ENCRYPTED) { if (ctx->attr->flags & ATTR_IS_ENCRYPTED) {
if (ctx->attr->flags & ATTR_COMPRESSION_MASK) { if (ctx->attr->flags & ATTR_COMPRESSION_MASK) {
...@@ -1242,30 +1244,23 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1242,30 +1244,23 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
} }
NInoSetSparse(ni); NInoSetSparse(ni);
} }
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(vi->i_sb, "First extent of attribute has " ntfs_error(vi->i_sb, "First extent of attribute has "
"non-zero lowest_vcn. Inode is " "non-zero lowest_vcn. Inode is "
"corrupt. You should run chkdsk."); "corrupt. You should run chkdsk.");
goto unm_err_out; goto unm_err_out;
} }
/* Setup all the sizes. */ /* Setup all the sizes. */
vi->i_size = sle64_to_cpu(ctx->attr->_ANR(data_size)); vi->i_size = sle64_to_cpu(
ctx->attr->data.non_resident.data_size);
ni->initialized_size = sle64_to_cpu( ni->initialized_size = sle64_to_cpu(
ctx->attr->_ANR(initialized_size)); ctx->attr->data.non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
ctx->attr->_ANR(allocated_size)); ctx->attr->data.non_resident.allocated_size);
if (NInoCompressed(ni)) { if (NInoCompressed(ni)) {
ni->_ICF(compressed_size) = sle64_to_cpu( ni->itype.compressed.size = sle64_to_cpu(
ctx->attr->_ANR(compressed_size)); ctx->attr->data.non_resident.
if (vi->i_size != ni->initialized_size) compressed_size);
ntfs_warning(vi->i_sb, "Compressed attribute "
"with data_size unequal to "
"initialized size found. This "
"will probably cause problems "
"when trying to access the "
"file. Please notify "
"linux-ntfs-dev@lists.sf.net "
"that you saw this message.");
} }
} }
...@@ -1277,14 +1272,14 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) ...@@ -1277,14 +1272,14 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
if (!NInoCompressed(ni)) if (!NInoCompressed(ni))
vi->i_blocks = ni->allocated_size >> 9; vi->i_blocks = ni->allocated_size >> 9;
else else
vi->i_blocks = ni->_ICF(compressed_size) >> 9; vi->i_blocks = ni->itype.compressed.size >> 9;
/* /*
* Make sure the base inode doesn't go away and attach it to the * Make sure the base inode doesn't go away and attach it to the
* attribute inode. * attribute inode.
*/ */
igrab(base_vi); igrab(base_vi);
ni->_INE(base_ntfs_ino) = base_ni; ni->ext.base_ntfs_ino = base_ni;
ni->nr_extents = -1; ni->nr_extents = -1;
put_attr_search_ctx(ctx); put_attr_search_ctx(ctx);
...@@ -1371,8 +1366,8 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1371,8 +1366,8 @@ void ntfs_read_inode_mount(struct inode *vi)
* This sets up our little cheat allowing us to reuse the async io * This sets up our little cheat allowing us to reuse the async io
* completion handler for directories. * completion handler for directories.
*/ */
ni->_IDM(index_block_size) = vol->mft_record_size; ni->itype.index.block_size = vol->mft_record_size;
ni->_IDM(index_block_size_bits) = vol->mft_record_size_bits; ni->itype.index.block_size_bits = vol->mft_record_size_bits;
/* Very important! Needed to be able to call map_mft_record*(). */ /* Very important! Needed to be able to call map_mft_record*(). */
vol->mft_ino = vi; vol->mft_ino = vi;
...@@ -1456,7 +1451,7 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1456,7 +1451,7 @@ void ntfs_read_inode_mount(struct inode *vi)
} }
if (ctx->attr->non_resident) { if (ctx->attr->non_resident) {
NInoSetAttrListNonResident(ni); NInoSetAttrListNonResident(ni);
if (ctx->attr->_ANR(lowest_vcn)) { if (ctx->attr->data.non_resident.lowest_vcn) {
ntfs_error(sb, "Attribute list has non zero " ntfs_error(sb, "Attribute list has non zero "
"lowest_vcn. $MFT is corrupt. " "lowest_vcn. $MFT is corrupt. "
"You should run chkdsk."); "You should run chkdsk.");
...@@ -1476,8 +1471,8 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1476,8 +1471,8 @@ void ntfs_read_inode_mount(struct inode *vi)
/* Now load the attribute list. */ /* Now load the attribute list. */
if ((err = load_attribute_list(vol, &ni->attr_list_rl, if ((err = load_attribute_list(vol, &ni->attr_list_rl,
ni->attr_list, ni->attr_list_size, ni->attr_list, ni->attr_list_size,
sle64_to_cpu( sle64_to_cpu(ctx->attr->data.
ctx->attr->_ANR(initialized_size))))) { non_resident.initialized_size)))) {
ntfs_error(sb, "Failed to load attribute list " ntfs_error(sb, "Failed to load attribute list "
"attribute with error code %i.", "attribute with error code %i.",
-err); -err);
...@@ -1485,9 +1480,9 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1485,9 +1480,9 @@ void ntfs_read_inode_mount(struct inode *vi)
} }
} else /* if (!ctx.attr->non_resident) */ { } else /* if (!ctx.attr->non_resident) */ {
if ((u8*)ctx->attr + le16_to_cpu( if ((u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset)) + ctx->attr->data.resident.value_offset) +
le32_to_cpu( le32_to_cpu(
ctx->attr->_ARA(value_length)) > ctx->attr->data.resident.value_length) >
(u8*)ctx->mrec + vol->mft_record_size) { (u8*)ctx->mrec + vol->mft_record_size) {
ntfs_error(sb, "Corrupt attribute list " ntfs_error(sb, "Corrupt attribute list "
"attribute."); "attribute.");
...@@ -1495,9 +1490,9 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1495,9 +1490,9 @@ void ntfs_read_inode_mount(struct inode *vi)
} }
/* Now copy the attribute list. */ /* Now copy the attribute list. */
memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu( memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset)), ctx->attr->data.resident.value_offset),
le32_to_cpu( le32_to_cpu(
ctx->attr->_ARA(value_length))); ctx->attr->data.resident.value_length));
} }
/* The attribute list is now setup in memory. */ /* The attribute list is now setup in memory. */
/* /*
...@@ -1606,7 +1601,7 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1606,7 +1601,7 @@ void ntfs_read_inode_mount(struct inode *vi)
if (!next_vcn) { if (!next_vcn) {
u64 ll; u64 ll;
if (attr->_ANR(lowest_vcn)) { if (attr->data.non_resident.lowest_vcn) {
ntfs_error(sb, "First extent of $DATA " ntfs_error(sb, "First extent of $DATA "
"attribute has non zero " "attribute has non zero "
"lowest_vcn. $MFT is corrupt. " "lowest_vcn. $MFT is corrupt. "
...@@ -1614,14 +1609,16 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1614,14 +1609,16 @@ void ntfs_read_inode_mount(struct inode *vi)
goto put_err_out; goto put_err_out;
} }
/* Get the last vcn in the $DATA attribute. */ /* Get the last vcn in the $DATA attribute. */
last_vcn = sle64_to_cpu(attr->_ANR(allocated_size)) >> last_vcn = sle64_to_cpu(
vol->cluster_size_bits; attr->data.non_resident.allocated_size)
>> vol->cluster_size_bits;
/* Fill in the inode size. */ /* Fill in the inode size. */
vi->i_size = sle64_to_cpu(attr->_ANR(data_size)); vi->i_size = sle64_to_cpu(
ni->initialized_size = sle64_to_cpu( attr->data.non_resident.data_size);
attr->_ANR(initialized_size)); ni->initialized_size = sle64_to_cpu(attr->data.
non_resident.initialized_size);
ni->allocated_size = sle64_to_cpu( ni->allocated_size = sle64_to_cpu(
attr->_ANR(allocated_size)); attr->data.non_resident.allocated_size);
/* Set the number of mft records. */ /* Set the number of mft records. */
ll = vi->i_size >> vol->mft_record_size_bits; ll = vi->i_size >> vol->mft_record_size_bits;
/* /*
...@@ -1687,7 +1684,7 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1687,7 +1684,7 @@ void ntfs_read_inode_mount(struct inode *vi)
} }
/* Get the lowest vcn for the next extent. */ /* Get the lowest vcn for the next extent. */
highest_vcn = sle64_to_cpu(attr->_ANR(highest_vcn)); highest_vcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);
next_vcn = highest_vcn + 1; next_vcn = highest_vcn + 1;
/* Only one extent or error, which we catch below. */ /* Only one extent or error, which we catch below. */
...@@ -1695,7 +1692,8 @@ void ntfs_read_inode_mount(struct inode *vi) ...@@ -1695,7 +1692,8 @@ void ntfs_read_inode_mount(struct inode *vi)
break; break;
/* Avoid endless loops due to corruption. */ /* Avoid endless loops due to corruption. */
if (next_vcn < sle64_to_cpu(attr->_ANR(lowest_vcn))) { if (next_vcn < sle64_to_cpu(
attr->data.non_resident.lowest_vcn)) {
ntfs_error(sb, "$MFT has corrupt attribute list " ntfs_error(sb, "$MFT has corrupt attribute list "
"attribute. Run chkdsk."); "attribute. Run chkdsk.");
goto put_err_out; goto put_err_out;
...@@ -1796,9 +1794,9 @@ void ntfs_put_inode(struct inode *vi) ...@@ -1796,9 +1794,9 @@ void ntfs_put_inode(struct inode *vi)
ntfs_inode *ni; ntfs_inode *ni;
ni = NTFS_I(vi); ni = NTFS_I(vi);
if (NInoIndexAllocPresent(ni) && ni->_IDM(bmp_ino)) { if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) {
iput(ni->_IDM(bmp_ino)); iput(ni->itype.index.bmp_ino);
ni->_IDM(bmp_ino) = NULL; ni->itype.index.bmp_ino = NULL;
} }
} }
return; return;
...@@ -1831,8 +1829,8 @@ void __ntfs_clear_inode(ntfs_inode *ni) ...@@ -1831,8 +1829,8 @@ void __ntfs_clear_inode(ntfs_inode *ni)
// FIXME: Handle dirty case for each extent inode! // FIXME: Handle dirty case for each extent inode!
for (i = 0; i < ni->nr_extents; i++) for (i = 0; i < ni->nr_extents; i++)
ntfs_clear_extent_inode(ni->_INE(extent_ntfs_inos)[i]); ntfs_clear_extent_inode(ni->ext.extent_ntfs_inos[i]);
kfree(ni->_INE(extent_ntfs_inos)); kfree(ni->ext.extent_ntfs_inos);
} }
/* Free all alocated memory. */ /* Free all alocated memory. */
down_write(&ni->run_list.lock); down_write(&ni->run_list.lock);
...@@ -1888,9 +1886,9 @@ void ntfs_clear_big_inode(struct inode *vi) ...@@ -1888,9 +1886,9 @@ void ntfs_clear_big_inode(struct inode *vi)
if (NInoAttr(ni)) { if (NInoAttr(ni)) {
/* Release the base inode if we are holding it. */ /* Release the base inode if we are holding it. */
if (ni->nr_extents == -1) { if (ni->nr_extents == -1) {
iput(VFS_I(ni->_INE(base_ntfs_ino))); iput(VFS_I(ni->ext.base_ntfs_ino));
ni->nr_extents = 0; ni->nr_extents = 0;
ni->_INE(base_ntfs_ino) = NULL; ni->ext.base_ntfs_ino = NULL;
} }
} }
return; return;
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of * inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
* the Linux-NTFS project. * the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -93,23 +93,21 @@ struct _ntfs_inode { ...@@ -93,23 +93,21 @@ struct _ntfs_inode {
struct { /* It is a directory or $MFT. */ struct { /* It is a directory or $MFT. */
struct inode *bmp_ino; /* Attribute inode for the struct inode *bmp_ino; /* Attribute inode for the
directory index $BITMAP. */ directory index $BITMAP. */
u32 index_block_size; /* Size of an index block. */ u32 block_size; /* Size of an index block. */
u32 index_vcn_size; /* Size of a vcn in this u32 vcn_size; /* Size of a vcn in this
directory index. */ directory index. */
u8 index_block_size_bits; /* Log2 of the above. */ u8 block_size_bits; /* Log2 of the above. */
u8 index_vcn_size_bits; /* Log2 of the above. */ u8 vcn_size_bits; /* Log2 of the above. */
} SN(idm); } index;
struct { /* It is a compressed file or fake inode. */ struct { /* It is a compressed file or fake inode. */
s64 compressed_size; /* Copy from $DATA. */ s64 size; /* Copy of compressed_size from
u32 compression_block_size; /* Size of a compression $DATA. */
block (cb). */ u32 block_size; /* Size of a compression block
u8 compression_block_size_bits; /* Log2 of the size of (cb). */
a cb. */ u8 block_size_bits; /* Log2 of the size of a cb. */
u8 compression_block_clusters; /* Number of clusters u8 block_clusters; /* Number of clusters per cb. */
per compression } compressed;
block. */ } itype;
} SN(icf);
} SN(idc);
struct semaphore extent_lock; /* Lock for accessing/modifying the struct semaphore extent_lock; /* Lock for accessing/modifying the
below . */ below . */
s32 nr_extents; /* For a base mft record, the number of attached extent s32 nr_extents; /* For a base mft record, the number of attached extent
...@@ -126,13 +124,9 @@ struct _ntfs_inode { ...@@ -126,13 +124,9 @@ struct _ntfs_inode {
record. For fake inodes, the record. For fake inodes, the
real (base) inode to which real (base) inode to which
the attribute belongs. */ the attribute belongs. */
} SN(ine); } ext;
}; };
#define _IDM(X) SC(idc.idm,X)
#define _ICF(X) SC(idc.icf,X)
#define _INE(X) SC(ine,X)
/* /*
* Defined bits for the state field in the ntfs_inode structure. * Defined bits for the state field in the ntfs_inode structure.
* (f) = files only, (d) = directories only, (a) = attributes/fake inodes only * (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS * layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
* project. * project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (C) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -296,7 +296,11 @@ typedef u64 MFT_REF; ...@@ -296,7 +296,11 @@ typedef u64 MFT_REF;
*/ */
typedef struct { typedef struct {
/*Ofs*/ /*Ofs*/
/* 0*/ NTFS_RECORD SN(mnr); /* Usually the magic is "FILE". */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Usually the magic is "FILE". */
u16 usa_ofs; /* See NTFS_RECORD definition above. */
u16 usa_count; /* See NTFS_RECORD definition above. */
/* 8*/ u64 lsn; /* $LogFile sequence number for this record. /* 8*/ u64 lsn; /* $LogFile sequence number for this record.
Changed every time the record is modified. */ Changed every time the record is modified. */
/* 16*/ u16 sequence_number; /* Number of times this mft record has been /* 16*/ u16 sequence_number; /* Number of times this mft record has been
...@@ -360,8 +364,6 @@ typedef struct { ...@@ -360,8 +364,6 @@ typedef struct {
*/ */
} __attribute__ ((__packed__)) MFT_RECORD; } __attribute__ ((__packed__)) MFT_RECORD;
#define _MNR(X) SC(mnr,X)
/* /*
* System defined attributes (32-bit). Each attribute type has a corresponding * System defined attributes (32-bit). Each attribute type has a corresponding
* attribute name (Unicode string of maximum 64 character length) as described * attribute name (Unicode string of maximum 64 character length) as described
...@@ -612,10 +614,10 @@ typedef struct { ...@@ -612,10 +614,10 @@ typedef struct {
have a name present as this might have a name present as this might
not have a length of a multiple not have a length of a multiple
of 8-bytes. */ of 8-bytes. */
/* 22 */ RESIDENT_ATTR_FLAGS resident_flags; /* See above. */ /* 22 */ RESIDENT_ATTR_FLAGS flags; /* See above. */
/* 23 */ s8 reservedR; /* Reserved/alignment to 8-byte /* 23 */ s8 reserved; /* Reserved/alignment to 8-byte
boundary. */ boundary. */
} SN(ara) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) resident;
/* Non-resident attributes. */ /* Non-resident attributes. */
struct { struct {
/* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number /* 16*/ VCN lowest_vcn; /* Lowest valid virtual cluster number
...@@ -641,7 +643,7 @@ typedef struct { ...@@ -641,7 +643,7 @@ typedef struct {
compressed. (This effectively limits the compressed. (This effectively limits the
compression unit size to be a power of two compression unit size to be a power of two
clusters.) WinNT4 only uses a value of 4. */ clusters.) WinNT4 only uses a value of 4. */
/* 35*/ u8 reserved1[5]; /* Align to 8-byte boundary. */ /* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */
/* The sizes below are only used when lowest_vcn is zero, as otherwise it would /* The sizes below are only used when lowest_vcn is zero, as otherwise it would
be difficult to keep them up-to-date.*/ be difficult to keep them up-to-date.*/
/* 40*/ s64 allocated_size; /* Byte size of disk space /* 40*/ s64 allocated_size; /* Byte size of disk space
...@@ -665,13 +667,10 @@ typedef struct { ...@@ -665,13 +667,10 @@ typedef struct {
cluster size. Represents the actual amount of cluster size. Represents the actual amount of
disk space being used on the disk. */ disk space being used on the disk. */
/* sizeof(compressed attr) = 72*/ /* sizeof(compressed attr) = 72*/
} SN(anr) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) non_resident;
} SN(aua) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) data;
} __attribute__ ((__packed__)) ATTR_RECORD; } __attribute__ ((__packed__)) ATTR_RECORD;
#define _ARA(X) SC(aua.ara,X)
#define _ANR(X) SC(aua.anr,X)
typedef ATTR_RECORD ATTR_REC; typedef ATTR_RECORD ATTR_REC;
/* /*
...@@ -763,11 +762,13 @@ typedef struct { ...@@ -763,11 +762,13 @@ typedef struct {
disabled altogether for speed. */ disabled altogether for speed. */
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ /* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 36*/ union { /* 36*/ union {
/* NTFS 1.2 (and previous, presumably) */ /* NTFS 1.2 */
/* 36 */ u8 reserved12[12]; /* Reserved/alignment to 8-byte struct {
boundary. */ /* 36*/ u8 reserved12[12]; /* Reserved/alignment to 8-byte
/* sizeof() = 48 bytes */ boundary. */
/* NTFS 3.0 */ } __attribute__ ((__packed__)) v1;
/* sizeof() = 48 bytes */
/* NTFS 3.x */
struct { struct {
/* /*
* If a volume has been upgraded from a previous NTFS version, then these * If a volume has been upgraded from a previous NTFS version, then these
...@@ -777,12 +778,12 @@ typedef struct { ...@@ -777,12 +778,12 @@ typedef struct {
* the fields are present. Maybe just check like this: * the fields are present. Maybe just check like this:
* if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) { * if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) {
* Assume NTFS 1.2- format. * Assume NTFS 1.2- format.
* If (volume version is 3.0+) * If (volume version is 3.x)
* Upgrade attribute to NTFS 3.0 format. * Upgrade attribute to NTFS 3.x format.
* else * else
* Use NTFS 1.2- format for access. * Use NTFS 1.2- format for access.
* } else * } else
* Use NTFS 3.0 format for access. * Use NTFS 3.x format for access.
* Only problem is that it might be legal to set the length of the value to * Only problem is that it might be legal to set the length of the value to
* arbitrarily large values thus spoiling this check. - But chkdsk probably * arbitrarily large values thus spoiling this check. - But chkdsk probably
* views that as a corruption, assuming that it behaves like this for all * views that as a corruption, assuming that it behaves like this for all
...@@ -818,13 +819,11 @@ typedef struct { ...@@ -818,13 +819,11 @@ typedef struct {
partition. This, in contrast to disabling the partition. This, in contrast to disabling the
journal is a very fast process, so the user journal is a very fast process, so the user
won't even notice it. */ won't even notice it. */
} SN(svs); } __attribute__ ((__packed__)) v3;
} SN(sei); /* sizeof() = 72 bytes (NTFS 3.x) */
/* sizeof() = 72 bytes (NTFS 3.0) */ } __attribute__ ((__packed__)) ver;
} __attribute__ ((__packed__)) STANDARD_INFORMATION; } __attribute__ ((__packed__)) STANDARD_INFORMATION;
#define _SVS(X) SC(sei.svs,X)
/* /*
* Attribute: Attribute list (0x20). * Attribute: Attribute list (0x20).
* *
...@@ -956,21 +955,20 @@ typedef struct { ...@@ -956,21 +955,20 @@ typedef struct {
pack the extended attributes pack the extended attributes
(EAs), if such are present.*/ (EAs), if such are present.*/
/* 3e*/ u16 reserved; /* Reserved for alignment. */ /* 3e*/ u16 reserved; /* Reserved for alignment. */
} SN(fea) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) ea;
/* 3c*/ u32 reparse_point_tag; /* Type of reparse point, /* 3c*/ struct {
/* 3c*/ u32 reparse_point_tag; /* Type of reparse point,
present only in reparse present only in reparse
points and only if there are points and only if there are
no EAs. */ no EAs. */
} SN(fer) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) rp;
} __attribute__ ((__packed__)) type;
/* 40*/ u8 file_name_length; /* Length of file name in /* 40*/ u8 file_name_length; /* Length of file name in
(Unicode) characters. */ (Unicode) characters. */
/* 41*/ FILE_NAME_TYPE_FLAGS file_name_type; /* Namespace of the file name.*/ /* 41*/ FILE_NAME_TYPE_FLAGS file_name_type; /* Namespace of the file name.*/
/* 42*/ uchar_t file_name[0]; /* File name in Unicode. */ /* 42*/ uchar_t file_name[0]; /* File name in Unicode. */
} __attribute__ ((__packed__)) FILE_NAME_ATTR; } __attribute__ ((__packed__)) FILE_NAME_ATTR;
#define _FEA(X) SC(fer.fea,X)
#define _FER(X) SC(fer,X)
/* /*
* GUID structures store globally unique identifiers (GUID). A GUID is a * GUID structures store globally unique identifiers (GUID). A GUID is a
* 128-bit value consisting of one group of eight hexadecimal digits, followed * 128-bit value consisting of one group of eight hexadecimal digits, followed
...@@ -1008,9 +1006,9 @@ typedef struct { ...@@ -1008,9 +1006,9 @@ typedef struct {
GUID birth_volume_id; GUID birth_volume_id;
GUID birth_object_id; GUID birth_object_id;
GUID domain_id; GUID domain_id;
} SN(obv) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) origin;
u8 extended_info[48]; u8 extended_info[48];
} SN(oei) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) opt;
} __attribute__ ((__packed__)) OBJ_ID_INDEX_DATA; } __attribute__ ((__packed__)) OBJ_ID_INDEX_DATA;
/* /*
...@@ -1032,13 +1030,11 @@ typedef struct { ...@@ -1032,13 +1030,11 @@ typedef struct {
GUID birth_object_id; /* Unique id of file when it was GUID birth_object_id; /* Unique id of file when it was
first created. */ first created. */
GUID domain_id; /* Reserved, zero. */ GUID domain_id; /* Reserved, zero. */
} SN(obv) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) origin;
u8 extended_info[48]; u8 extended_info[48];
} SN(oei) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) opt;
} __attribute__ ((__packed__)) OBJECT_ID_ATTR; } __attribute__ ((__packed__)) OBJECT_ID_ATTR;
#define _OBV(X) SC(oei.obv,X)
/* /*
* The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in * The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
* the SID structure (see below). * the SID structure (see below).
...@@ -1174,14 +1170,12 @@ typedef enum { /* Identifier authority. */ ...@@ -1174,14 +1170,12 @@ typedef enum { /* Identifier authority. */
*/ */
typedef union { typedef union {
struct { struct {
u32 low_part; /* Low 32-bits. */ u32 low; /* Low 32-bits. */
u16 high_part; /* High 16-bits. */ u16 high; /* High 16-bits. */
} SN(sia) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) parts;
u8 value[6]; /* Value as individual bytes. */ u8 value[6]; /* Value as individual bytes. */
} __attribute__ ((__packed__)) SID_IDENTIFIER_AUTHORITY; } __attribute__ ((__packed__)) SID_IDENTIFIER_AUTHORITY;
#define _SIA(X) SC(sia,X)
/* /*
* The SID structure is a variable-length structure used to uniquely identify * The SID structure is a variable-length structure used to uniquely identify
* users or groups. SID stands for security identifier. * users or groups. SID stands for security identifier.
...@@ -1287,9 +1281,10 @@ typedef enum { ...@@ -1287,9 +1281,10 @@ typedef enum {
* data depends on the ACE type. * data depends on the ACE type.
*/ */
typedef struct { typedef struct {
ACE_TYPES type; /* Type of the ACE. */ /*Ofs*/
ACE_FLAGS flags; /* Flags describing the ACE. */ /* 0*/ ACE_TYPES type; /* Type of the ACE. */
u16 size; /* Size in bytes of the ACE. */ /* 1*/ ACE_FLAGS flags; /* Flags describing the ACE. */
/* 2*/ u16 size; /* Size in bytes of the ACE. */
} __attribute__ ((__packed__)) ACE_HEADER; } __attribute__ ((__packed__)) ACE_HEADER;
/* /*
...@@ -1446,12 +1441,15 @@ typedef struct { ...@@ -1446,12 +1441,15 @@ typedef struct {
* ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE * ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
*/ */
typedef struct { typedef struct {
ACE_HEADER SN(aah); /* The ACE header. */ /* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
ACCESS_MASK mask; /* Access mask associated with the ACE. */ ACE_TYPES type; /* Type of the ACE. */
SID sid; /* The SID associated with the ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */
u16 size; /* Size in bytes of the ACE. */
/* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */
/* 8*/ SID sid; /* The SID associated with the ACE. */
} __attribute__ ((__packed__)) ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, } __attribute__ ((__packed__)) ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE,
SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE; SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE;
#define _AAH(X) SC(aah,X)
/* /*
* The object ACE flags (32-bit). * The object ACE flags (32-bit).
...@@ -1462,12 +1460,17 @@ typedef enum { ...@@ -1462,12 +1460,17 @@ typedef enum {
} OBJECT_ACE_FLAGS; } OBJECT_ACE_FLAGS;
typedef struct { typedef struct {
ACE_HEADER SN(aah); /* The ACE_HEADER. */ /* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
ACCESS_MASK mask; /* Access mask associated with the ACE. */ ACE_TYPES type; /* Type of the ACE. */
OBJECT_ACE_FLAGS flags; /* Flags describing the object ACE. */ ACE_FLAGS flags; /* Flags describing the ACE. */
GUID object_type; u16 size; /* Size in bytes of the ACE. */
GUID inherited_object_type; /* 4*/ ACCESS_MASK mask; /* Access mask associated with the ACE. */
SID sid; /* The SID associated with the ACE. */
/* 8*/ OBJECT_ACE_FLAGS object_flags; /* Flags describing the object ACE. */
/* 12*/ GUID object_type;
/* 28*/ GUID inherited_object_type;
/* 44*/ SID sid; /* The SID associated with the ACE. */
} __attribute__ ((__packed__)) ACCESS_ALLOWED_OBJECT_ACE, } __attribute__ ((__packed__)) ACCESS_ALLOWED_OBJECT_ACE,
ACCESS_DENIED_OBJECT_ACE, ACCESS_DENIED_OBJECT_ACE,
SYSTEM_AUDIT_OBJECT_ACE, SYSTEM_AUDIT_OBJECT_ACE,
...@@ -1711,13 +1714,17 @@ typedef struct { ...@@ -1711,13 +1714,17 @@ typedef struct {
* $SDS data stream and the second copy will be at offset 0x451d0. * $SDS data stream and the second copy will be at offset 0x451d0.
*/ */
typedef struct { typedef struct {
SECURITY_DESCRIPTOR_HEADER SN(sdh); /* The security descriptor header. */ /*Ofs*/
SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security /* 0 SECURITY_DESCRIPTOR_HEADER; -- Unfolded here as gcc doesn't like
unnamed structs. */
u32 hash; /* Hash of the security descriptor. */
u32 security_id; /* The security_id assigned to the descriptor. */
u64 offset; /* Byte offset of this entry in the $SDS stream. */
u32 length; /* Size in bytes of this entry in $SDS stream. */
/* 20*/ SECURITY_DESCRIPTOR_RELATIVE sid; /* The self-relative security
descriptor. */ descriptor. */
} __attribute__ ((__packed__)) SDS_ENTRY; } __attribute__ ((__packed__)) SDS_ENTRY;
#define _SDH(X) SC(sdh,X)
/* /*
* The index entry key used in the $SII index. The collation type is * The index entry key used in the $SII index. The collation type is
* COLLATION_NTOFS_ULONG. * COLLATION_NTOFS_ULONG.
...@@ -1888,7 +1895,11 @@ typedef struct { ...@@ -1888,7 +1895,11 @@ typedef struct {
* index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER. * index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
*/ */
typedef struct { typedef struct {
/* 0*/ NTFS_RECORD SN(inr); /* Magic is "INDX". */ /* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Magic is "INDX". */
u16 usa_ofs; /* See NTFS_RECORD definition. */
u16 usa_count; /* See NTFS_RECORD definition. */
/* 8*/ s64 lsn; /* $LogFile sequence number of the last /* 8*/ s64 lsn; /* $LogFile sequence number of the last
modification of this index block. */ modification of this index block. */
/* 16*/ VCN index_block_vcn; /* Virtual cluster number of the index block. /* 16*/ VCN index_block_vcn; /* Virtual cluster number of the index block.
...@@ -1909,8 +1920,6 @@ typedef struct { ...@@ -1909,8 +1920,6 @@ typedef struct {
*/ */
} __attribute__ ((__packed__)) INDEX_BLOCK; } __attribute__ ((__packed__)) INDEX_BLOCK;
#define _INR(X) SC(inr,X)
typedef INDEX_BLOCK INDEX_ALLOCATION; typedef INDEX_BLOCK INDEX_ALLOCATION;
/* /*
...@@ -2014,19 +2023,21 @@ typedef enum { ...@@ -2014,19 +2023,21 @@ typedef enum {
* This the index entry header (see below). * This the index entry header (see below).
*/ */
typedef struct { typedef struct {
/* 0*/ union { /* Only valid when INDEX_ENTRY_END is not set. */ /* 0*/ union {
MFT_REF indexed_file; /* The mft reference of the file struct { /* Only valid when INDEX_ENTRY_END is not set. */
MFT_REF indexed_file; /* The mft reference of the file
described by this index described by this index
entry. Used for directory entry. Used for directory
indexes. */ indexes. */
} __attribute__ ((__packed__)) dir;
struct { /* Used for views/indexes to find the entry's data. */ struct { /* Used for views/indexes to find the entry's data. */
u16 data_offset; /* Data byte offset from this u16 data_offset; /* Data byte offset from this
INDEX_ENTRY. Follows the INDEX_ENTRY. Follows the
index key. */ index key. */
u16 data_length; /* Data length in bytes. */ u16 data_length; /* Data length in bytes. */
u32 reservedV; /* Reserved (zero). */ u32 reservedV; /* Reserved (zero). */
} SN(iev) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) vi;
} SN(iif) __attribute__ ((__packed__)); } __attribute__ ((__packed__)) data;
/* 8*/ u16 length; /* Byte size of this index entry, multiple of /* 8*/ u16 length; /* Byte size of this index entry, multiple of
8-bytes. */ 8-bytes. */
/* 10*/ u16 key_length; /* Byte size of the key value, which is in the /* 10*/ u16 key_length; /* Byte size of the key value, which is in the
...@@ -2037,9 +2048,6 @@ typedef struct { ...@@ -2037,9 +2048,6 @@ typedef struct {
/* sizeof() = 16 bytes */ /* sizeof() = 16 bytes */
} __attribute__ ((__packed__)) INDEX_ENTRY_HEADER; } __attribute__ ((__packed__)) INDEX_ENTRY_HEADER;
#define _IIF(X) SC(ieh.iif,X)
#define _IEV(X) SC(iif.iev,X)
/* /*
* This is an index entry. A sequence of such entries follows each INDEX_HEADER * This is an index entry. A sequence of such entries follows each INDEX_HEADER
* structure. Together they make up a complete index. The index follows either * structure. Together they make up a complete index. The index follows either
...@@ -2048,7 +2056,31 @@ typedef struct { ...@@ -2048,7 +2056,31 @@ typedef struct {
* NOTE: Before NTFS 3.0 only filename attributes were indexed. * NOTE: Before NTFS 3.0 only filename attributes were indexed.
*/ */
typedef struct { typedef struct {
/* 0*/ INDEX_ENTRY_HEADER SN(ieh); /* The index entry header (see above). */ /*Ofs*/
/* 0 INDEX_ENTRY_HEADER; -- Unfolded here as gcc dislikes unnamed structs. */
union {
struct { /* Only valid when INDEX_ENTRY_END is not set. */
MFT_REF indexed_file; /* The mft reference of the file
described by this index
entry. Used for directory
indexes. */
} __attribute__ ((__packed__)) dir;
struct { /* Used for views/indexes to find the entry's data. */
u16 data_offset; /* Data byte offset from this
INDEX_ENTRY. Follows the
index key. */
u16 data_length; /* Data length in bytes. */
u32 reservedV; /* Reserved (zero). */
} __attribute__ ((__packed__)) vi;
} __attribute__ ((__packed__)) data;
u16 length; /* Byte size of this index entry, multiple of
8-bytes. */
u16 key_length; /* Byte size of the key value, which is in the
index entry. It follows field reserved. Not
multiple of 8-bytes. */
INDEX_ENTRY_FLAGS flags; /* Bit field of INDEX_ENTRY_* flags. */
u16 reserved; /* Reserved/align to 8-byte boundary. */
/* 16*/ union { /* The key of the indexed attribute. NOTE: Only present /* 16*/ union { /* The key of the indexed attribute. NOTE: Only present
if INDEX_ENTRY_END bit in flags is not set. NOTE: On if INDEX_ENTRY_END bit in flags is not set. NOTE: On
NTFS versions before 3.0 the only valid key is the NTFS versions before 3.0 the only valid key is the
...@@ -2060,7 +2092,8 @@ typedef struct { ...@@ -2060,7 +2092,8 @@ typedef struct {
GUID object_id; /* $O index in FILE_Extend/$ObjId: The GUID object_id; /* $O index in FILE_Extend/$ObjId: The
object_id of the mft record found in object_id of the mft record found in
the data part of the index. */ the data part of the index. */
REPARSE_INDEX_KEY SN(iri); /* $R index in FILE_Extend/$Reparse. */ REPARSE_INDEX_KEY reparse; /* $R index in
FILE_Extend/$Reparse. */
SID sid; /* $O index in FILE_Extend/$Quota: SID sid; /* $O index in FILE_Extend/$Quota:
SID of the owner of the user_id. */ SID of the owner of the user_id. */
u32 owner_id; /* $Q index in FILE_Extend/$Quota: u32 owner_id; /* $Q index in FILE_Extend/$Quota:
...@@ -2083,9 +2116,6 @@ typedef struct { ...@@ -2083,9 +2116,6 @@ typedef struct {
// where sizeof(VCN) can be hardcoded as 8 if wanted. */ // where sizeof(VCN) can be hardcoded as 8 if wanted. */
} __attribute__ ((__packed__)) INDEX_ENTRY; } __attribute__ ((__packed__)) INDEX_ENTRY;
#define _IEH(X) SC(ieh,X)
#define _IRI(X) SC(key.iri,X)
/* /*
* Attribute: Bitmap (0xb0). * Attribute: Bitmap (0xb0).
* *
......
/** /**
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project. * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon. * Copyright (c) 2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -39,18 +39,18 @@ static void __format_mft_record(MFT_RECORD *m, const int size, ...@@ -39,18 +39,18 @@ static void __format_mft_record(MFT_RECORD *m, const int size,
ATTR_RECORD *a; ATTR_RECORD *a;
memset(m, 0, size); memset(m, 0, size);
m->_MNR(magic) = magic_FILE; m->magic = magic_FILE;
/* Aligned to 2-byte boundary. */ /* Aligned to 2-byte boundary. */
m->_MNR(usa_ofs) = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1); m->usa_ofs = cpu_to_le16((sizeof(MFT_RECORD) + 1) & ~1);
m->_MNR(usa_count) = cpu_to_le16(size / NTFS_BLOCK_SIZE + 1); m->usa_count = cpu_to_le16(size / NTFS_BLOCK_SIZE + 1);
/* Set the update sequence number to 1. */ /* Set the update sequence number to 1. */
*(u16*)((char*)m + ((sizeof(MFT_RECORD) + 1) & ~1)) = cpu_to_le16(1); *(u16*)((char*)m + ((sizeof(MFT_RECORD) + 1) & ~1)) = cpu_to_le16(1);
m->lsn = cpu_to_le64(0LL); m->lsn = cpu_to_le64(0LL);
m->sequence_number = cpu_to_le16(1); m->sequence_number = cpu_to_le16(1);
m->link_count = cpu_to_le16(0); m->link_count = cpu_to_le16(0);
/* Aligned to 8-byte boundary. */ /* Aligned to 8-byte boundary. */
m->attrs_offset = cpu_to_le16((le16_to_cpu(m->_MNR(usa_ofs)) + m->attrs_offset = cpu_to_le16((le16_to_cpu(m->usa_ofs) +
(le16_to_cpu(m->_MNR(usa_count)) << 1) + 7) & ~7); (le16_to_cpu(m->usa_count) << 1) + 7) & ~7);
m->flags = cpu_to_le16(0); m->flags = cpu_to_le16(0);
/* /*
* Using attrs_offset plus eight bytes (for the termination attribute), * Using attrs_offset plus eight bytes (for the termination attribute),
...@@ -329,7 +329,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -329,7 +329,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
*/ */
down(&base_ni->extent_lock); down(&base_ni->extent_lock);
if (base_ni->nr_extents > 0) { if (base_ni->nr_extents > 0) {
extent_nis = base_ni->_INE(extent_ntfs_inos); extent_nis = base_ni->ext.extent_ntfs_inos;
for (i = 0; i < base_ni->nr_extents; i++) { for (i = 0; i < base_ni->nr_extents; i++) {
if (mft_no != extent_nis[i]->mft_no) if (mft_no != extent_nis[i]->mft_no)
continue; continue;
...@@ -374,7 +374,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -374,7 +374,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ni->vol = base_ni->vol; ni->vol = base_ni->vol;
ni->seq_no = seq_no; ni->seq_no = seq_no;
ni->nr_extents = -1; ni->nr_extents = -1;
ni->_INE(base_ntfs_ino) = base_ni; ni->ext.base_ntfs_ino = base_ni;
/* Now map the record. */ /* Now map the record. */
m = map_mft_record(ni); m = map_mft_record(ni);
if (unlikely(IS_ERR(m))) { if (unlikely(IS_ERR(m))) {
...@@ -404,14 +404,14 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref, ...@@ -404,14 +404,14 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
m = ERR_PTR(-ENOMEM); m = ERR_PTR(-ENOMEM);
goto unm_err_out; goto unm_err_out;
} }
if (base_ni->_INE(extent_ntfs_inos)) { if (base_ni->ext.extent_ntfs_inos) {
memcpy(tmp, base_ni->_INE(extent_ntfs_inos), new_size - memcpy(tmp, base_ni->ext.extent_ntfs_inos, new_size -
4 * sizeof(ntfs_inode *)); 4 * sizeof(ntfs_inode *));
kfree(base_ni->_INE(extent_ntfs_inos)); kfree(base_ni->ext.extent_ntfs_inos);
} }
base_ni->_INE(extent_ntfs_inos) = tmp; base_ni->ext.extent_ntfs_inos = tmp;
} }
base_ni->_INE(extent_ntfs_inos)[base_ni->nr_extents++] = ni; base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
up(&base_ni->extent_lock); up(&base_ni->extent_lock);
atomic_dec(&base_ni->count); atomic_dec(&base_ni->count);
ntfs_debug("Done 2."); ntfs_debug("Done 2.");
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS * namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
* project. * project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -210,12 +210,12 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent) ...@@ -210,12 +210,12 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
a = ctx->attr; a = ctx->attr;
if (a->non_resident || a->flags) if (a->non_resident || a->flags)
goto eio_err_out; goto eio_err_out;
val_len = le32_to_cpu(a->_ARA(value_length)); val_len = le32_to_cpu(a->data.resident.value_length);
if (le16_to_cpu(a->_ARA(value_offset)) + val_len > if (le16_to_cpu(a->data.resident.value_offset) +
le32_to_cpu(a->length)) val_len > le32_to_cpu(a->length))
goto eio_err_out; goto eio_err_out;
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu( fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
ctx->attr->_ARA(value_offset))); ctx->attr->data.resident.value_offset));
if ((u32)(fn->file_name_length * sizeof(uchar_t) + if ((u32)(fn->file_name_length * sizeof(uchar_t) +
sizeof(FILE_NAME_ATTR)) > val_len) sizeof(FILE_NAME_ATTR)) > val_len)
goto eio_err_out; goto eio_err_out;
......
/* /*
* super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001,2002 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001,2002 Richard Russon. * Copyright (c) 2001,2002 Richard Russon
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -619,9 +619,8 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) ...@@ -619,9 +619,8 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
* the same as it is much faster on 32-bit CPUs. * the same as it is much faster on 32-bit CPUs.
*/ */
ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits; ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits;
if ((u64)ll >= 1ULL << (sizeof(unsigned long) * 8)) { if ((u64)ll >= 1ULL << 32) {
ntfs_error(vol->sb, "Cannot handle %i-bit clusters. Sorry.", ntfs_error(vol->sb, "Cannot handle 64-bit clusters. Sorry.");
sizeof(unsigned long) * 4);
return FALSE; return FALSE;
} }
vol->nr_clusters = ll; vol->nr_clusters = ll;
...@@ -884,10 +883,10 @@ static BOOL load_system_files(ntfs_volume *vol) ...@@ -884,10 +883,10 @@ static BOOL load_system_files(ntfs_volume *vol)
goto iput_volume_failed; goto iput_volume_failed;
} }
vi = (VOLUME_INFORMATION*)((char*)ctx->attr + vi = (VOLUME_INFORMATION*)((char*)ctx->attr +
le16_to_cpu(ctx->attr->_ARA(value_offset))); le16_to_cpu(ctx->attr->data.resident.value_offset));
/* Some bounds checks. */ /* Some bounds checks. */
if ((u8*)vi < (u8*)ctx->attr || (u8*)vi + if ((u8*)vi < (u8*)ctx->attr || (u8*)vi +
le32_to_cpu(ctx->attr->_ARA(value_length)) > le32_to_cpu(ctx->attr->data.resident.value_length) >
(u8*)ctx->attr + le32_to_cpu(ctx->attr->length)) (u8*)ctx->attr + le32_to_cpu(ctx->attr->length))
goto err_put_vol; goto err_put_vol;
/* Setup volume flags and version. */ /* Setup volume flags and version. */
...@@ -1060,78 +1059,93 @@ static void ntfs_put_super(struct super_block *vfs_sb) ...@@ -1060,78 +1059,93 @@ static void ntfs_put_super(struct super_block *vfs_sb)
* get_nr_free_clusters - return the number of free clusters on a volume * get_nr_free_clusters - return the number of free clusters on a volume
* @vol: ntfs volume for which to obtain free cluster count * @vol: ntfs volume for which to obtain free cluster count
* *
* Calculate the number of free clusters on the mounted NTFS volume @vol. * Calculate the number of free clusters on the mounted NTFS volume @vol. We
* actually calculate the number of clusters in use instead because this
* allows us to not care about partial pages as these will be just zero filled
* and hence not be counted as allocated clusters.
* *
* Errors are ignored and we just return the number of free clusters we have * The only particularity is that clusters beyond the end of the logical ntfs
* found. This means we return an underestimate on error. * volume will be marked as allocated to prevent errors which means we have to
* discount those at the end. This is important as the cluster bitmap always
* has a size in multiples of 8 bytes, i.e. up to 63 clusters could be outside
* the logical volume and marked in use when they are not as they do not exist.
*
* If any pages cannot be read we assume all clusters in the erroring pages are
* in use. This means we return an underestimate on errors which is better than
* an overestimate.
*/ */
static s64 get_nr_free_clusters(ntfs_volume *vol) static s64 get_nr_free_clusters(ntfs_volume *vol)
{ {
s64 nr_free = vol->nr_clusters;
u32 *kaddr;
struct address_space *mapping = vol->lcnbmp_ino->i_mapping; struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
filler_t *readpage = (filler_t*)mapping->a_ops->readpage; filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
struct page *page; struct page *page;
unsigned long index, max_index; unsigned long index, max_index;
unsigned int max_size, i; unsigned int max_size;
s64 nr_free = 0LL;
u32 *b;
ntfs_debug("Entering."); ntfs_debug("Entering.");
/* Serialize accesses to the cluster bitmap. */ /* Serialize accesses to the cluster bitmap. */
down_read(&vol->lcnbmp_lock); down_read(&vol->lcnbmp_lock);
/* /*
* Convert the number of bits into bytes rounded up, then convert into * Convert the number of bits into bytes rounded up, then convert into
* multiples of PAGE_CACHE_SIZE. * multiples of PAGE_CACHE_SIZE, rounding up so that if we have one
* full and one partial page max_index = 2.
*/ */
max_index = (vol->nr_clusters + 7) >> (3 + PAGE_CACHE_SHIFT); max_index = (((vol->nr_clusters + 7) >> 3) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
/* Use multiples of 4 bytes. */ /* Use multiples of 4 bytes. */
max_size = PAGE_CACHE_SIZE >> 2; max_size = PAGE_CACHE_SIZE >> 2;
ntfs_debug("Reading $BITMAP, max_index = 0x%lx, max_size = 0x%x.", ntfs_debug("Reading $Bitmap, max_index = 0x%lx, max_size = 0x%x.",
max_index, max_size); max_index, max_size);
for (index = 0UL; index < max_index;) { for (index = 0UL; index < max_index; index++) {
handle_partial_page: unsigned int i;
/* /*
* Read the page from page cache, getting it from backing store * Read the page from page cache, getting it from backing store
* if necessary, and increment the use count. * if necessary, and increment the use count.
*/ */
page = read_cache_page(mapping, index++, (filler_t*)readpage, page = read_cache_page(mapping, index, (filler_t*)readpage,
NULL); NULL);
/* Ignore pages which errored synchronously. */ /* Ignore pages which errored synchronously. */
if (IS_ERR(page)) { if (IS_ERR(page)) {
ntfs_debug("Sync read_cache_page() error. Skipping " ntfs_debug("Sync read_cache_page() error. Skipping "
"page (index 0x%lx).", index - 1); "page (index 0x%lx).", index);
nr_free -= PAGE_CACHE_SIZE * 8;
continue; continue;
} }
wait_on_page_locked(page); wait_on_page_locked(page);
/* Ignore pages which errored asynchronously. */
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
ntfs_debug("Async read_cache_page() error. Skipping " ntfs_debug("Async read_cache_page() error. Skipping "
"page (index 0x%lx).", index - 1); "page (index 0x%lx).", index);
/* Ignore pages which errored asynchronously. */
page_cache_release(page); page_cache_release(page);
nr_free -= PAGE_CACHE_SIZE * 8;
continue; continue;
} }
b = (u32*)kmap(page); kaddr = (u32*)kmap_atomic(page, KM_USER0);
/* For each 4 bytes, add up the number zero bits. */
for (i = 0; i < max_size; i++)
nr_free += (s64)(32 - hweight32(b[i]));
kunmap(page);
page_cache_release(page);
}
if (max_size == PAGE_CACHE_SIZE >> 2) {
/* /*
* Get the multiples of 4 bytes in use in the final partial * For each 4 bytes, subtract the number of set bits. If this
* page. * is the last page and it is partial we don't really care as
* it just means we do a little extra work but it won't affect
* the result as all out of range bytes are set to zero by
* ntfs_readpage().
*/ */
max_size = ((((vol->nr_clusters + 7) >> 3) & ~PAGE_CACHE_MASK) for (i = 0; i < max_size; i++)
+ 3) >> 2; nr_free -= (s64)hweight32(kaddr[i]);
/* If there is a partial page go back and do it. */ kunmap_atomic(kaddr, KM_USER0);
if (max_size) { page_cache_release(page);
ntfs_debug("Handling partial page, max_size = 0x%x.",
max_size);
goto handle_partial_page;
}
} }
ntfs_debug("Finished reading $BITMAP, last index = 0x%lx", index - 1); ntfs_debug("Finished reading $Bitmap, last index = 0x%lx.", index - 1);
/*
* Fixup for eventual bits outside logical ntfs volume (see function
* description above).
*/
if (vol->nr_clusters & 63)
nr_free += 64 - (vol->nr_clusters & 63);
up_read(&vol->lcnbmp_lock); up_read(&vol->lcnbmp_lock);
/* If errors occured we may well have gone below zero, fix this. */
if (nr_free < 0)
nr_free = 0;
ntfs_debug("Exiting."); ntfs_debug("Exiting.");
return nr_free; return nr_free;
} }
...@@ -1141,64 +1155,81 @@ static s64 get_nr_free_clusters(ntfs_volume *vol) ...@@ -1141,64 +1155,81 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
* @vol: ntfs volume for which to obtain free inode count * @vol: ntfs volume for which to obtain free inode count
* *
* Calculate the number of free mft records (inodes) on the mounted NTFS * Calculate the number of free mft records (inodes) on the mounted NTFS
* volume @vol. * volume @vol. We actually calculate the number of mft records in use instead
* because this allows us to not care about partial pages as these will be just
* zero filled and hence not be counted as allocated mft record.
* *
* Errors are ignored and we just return the number of free inodes we have * If any pages cannot be read we assume all mft records in the erroring pages
* found. This means we return an underestimate on error. * are in use. This means we return an underestimate on errors which is better
* than an overestimate.
* *
* NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing. * NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing.
*/ */
static unsigned long __get_nr_free_mft_records(ntfs_volume *vol) static unsigned long __get_nr_free_mft_records(ntfs_volume *vol)
{ {
struct address_space *mapping; s64 nr_free = vol->nr_mft_records;
u32 *kaddr;
struct address_space *mapping = vol->mftbmp_ino->i_mapping;
filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
struct page *page; struct page *page;
unsigned long index, max_index, nr_free = 0; unsigned long index, max_index;
unsigned int max_size, i; unsigned int max_size;
u32 *b;
mapping = vol->mftbmp_ino->i_mapping; ntfs_debug("Entering.");
/* /*
* Convert the number of bits into bytes rounded up to a multiple of 8 * Convert the number of bits into bytes rounded up, then convert into
* bytes, then convert into multiples of PAGE_CACHE_SIZE. * multiples of PAGE_CACHE_SIZE, rounding up so that if we have one
* full and one partial page max_index = 2.
*/ */
max_index = (((vol->nr_mft_records + 7) >> 3) + 7) >> PAGE_CACHE_SHIFT; max_index = (((vol->nr_mft_records + 7) >> 3) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
/* Use multiples of 4 bytes. */ /* Use multiples of 4 bytes. */
max_size = PAGE_CACHE_SIZE >> 2; max_size = PAGE_CACHE_SIZE >> 2;
ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = " ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
"0x%x.", max_index, max_size); "0x%x.", max_index, max_size);
for (index = 0UL; index < max_index;) { for (index = 0UL; index < max_index; index++) {
handle_partial_page: unsigned int i;
page = ntfs_map_page(mapping, index++); /*
* Read the page from page cache, getting it from backing store
* if necessary, and increment the use count.
*/
page = read_cache_page(mapping, index, (filler_t*)readpage,
NULL);
/* Ignore pages which errored synchronously. */
if (IS_ERR(page)) { if (IS_ERR(page)) {
ntfs_debug("ntfs_map_page() error. Skipping page " ntfs_debug("Sync read_cache_page() error. Skipping "
"(index 0x%lx).", index - 1); "page (index 0x%lx).", index);
nr_free -= PAGE_CACHE_SIZE * 8;
continue; continue;
} }
b = (u32*)page_address(page); wait_on_page_locked(page);
/* For each 4 bytes, add up the number of zero bits. */ /* Ignore pages which errored asynchronously. */
for (i = 0; i < max_size; i++) if (!PageUptodate(page)) {
nr_free += 32 - hweight32(b[i]); ntfs_debug("Async read_cache_page() error. Skipping "
ntfs_unmap_page(page); "page (index 0x%lx).", index);
} page_cache_release(page);
if (index == max_index) { nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
kaddr = (u32*)kmap_atomic(page, KM_USER0);
/* /*
* Get the multiples of 4 bytes in use in the final partial * For each 4 bytes, subtract the number of set bits. If this
* page. * is the last page and it is partial we don't really care as
* it just means we do a little extra work but it won't affect
* the result as all out of range bytes are set to zero by
* ntfs_readpage().
*/ */
max_size = ((((((vol->nr_mft_records + 7) >> 3) + 7) & ~7) & for (i = 0; i < max_size; i++)
~PAGE_CACHE_MASK) + 3) >> 2; nr_free -= (s64)hweight32(kaddr[i]);
/* If there is a partial page go back and do it. */ kunmap_atomic(kaddr, KM_USER0);
if (max_size) { page_cache_release(page);
/* Compensate for out of bounds zero bits. */
if ((i = vol->nr_mft_records & 31))
nr_free -= 32 - i;
ntfs_debug("Handling partial page, max_size = 0x%x",
max_size);
goto handle_partial_page;
}
} }
ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx", ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx.",
index - 1); index - 1);
/* If errors occured we may well have gone below zero, fix this. */
if (nr_free < 0)
nr_free = 0;
ntfs_debug("Exiting.");
return nr_free; return nr_free;
} }
...@@ -1761,7 +1792,7 @@ static void __exit exit_ntfs_fs(void) ...@@ -1761,7 +1792,7 @@ static void __exit exit_ntfs_fs(void)
} }
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>"); MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2002 Anton Altaparmakov"); MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2003 Anton Altaparmakov");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef DEBUG #ifdef DEBUG
MODULE_PARM(debug_msgs, "i"); MODULE_PARM(debug_msgs, "i");
......
/* /*
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project. * unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
* *
* Copyright (c) 2001 Anton Altaparmakov. * Copyright (c) 2001-2003 Anton Altaparmakov
* *
* This program/include file is free software; you can redistribute it and/or * This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published * modify it under the terms of the GNU General Public License as published
...@@ -96,10 +96,12 @@ int ntfs_collate_names(const uchar_t *name1, const u32 name1_len, ...@@ -96,10 +96,12 @@ int ntfs_collate_names(const uchar_t *name1, const u32 name1_len,
const int err_val, const IGNORE_CASE_BOOL ic, const int err_val, const IGNORE_CASE_BOOL ic,
const uchar_t *upcase, const u32 upcase_len) const uchar_t *upcase, const u32 upcase_len)
{ {
u32 cnt; u32 cnt, min_len;
const u32 min_len = min_t(const u32, name1_len, name2_len);
uchar_t c1, c2; uchar_t c1, c2;
min_len = name1_len;
if (name1_len > name2_len)
min_len = name2_len;
for (cnt = 0; cnt < min_len; ++cnt) { for (cnt = 0; cnt < min_len; ++cnt) {
c1 = le16_to_cpu(*name1++); c1 = le16_to_cpu(*name1++);
c2 = le16_to_cpu(*name2++); c2 = le16_to_cpu(*name2++);
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* upcase.c - Generate the full NTFS Unicode upcase table in little endian. * upcase.c - Generate the full NTFS Unicode upcase table in little endian.
* Part of the Linux-NTFS project. * Part of the Linux-NTFS project.
* *
* Copyright (C) 2001 Richard Russon <ntfs@flatcap.org> * Copyright (c) 2001 Richard Russon <ntfs@flatcap.org>
* Copyright (c) 2001,2002 Anton Altaparmakov * Copyright (c) 2001-2003 Anton Altaparmakov
* *
* Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov. * Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov.
* Modified for kernel inclusion 10 September 2001 by Anton Altparmakov. * Modified for kernel inclusion 10 September 2001 by Anton Altparmakov.
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
uchar_t *generate_default_upcase(void) uchar_t *generate_default_upcase(void)
{ {
const int uc_run_table[][3] = { /* Start, End, Add */ static const int uc_run_table[][3] = { /* Start, End, Add */
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, {0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100}, {0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
...@@ -45,7 +45,7 @@ uchar_t *generate_default_upcase(void) ...@@ -45,7 +45,7 @@ uchar_t *generate_default_upcase(void)
{0} {0}
}; };
const int uc_dup_table[][2] = { /* Start, End */ static const int uc_dup_table[][2] = { /* Start, End */
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC}, {0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB}, {0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5}, {0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
...@@ -55,7 +55,7 @@ uchar_t *generate_default_upcase(void) ...@@ -55,7 +55,7 @@ uchar_t *generate_default_upcase(void)
{0} {0}
}; };
const int uc_word_table[][2] = { /* Offset, Value */ static const int uc_word_table[][2] = { /* Offset, Value */
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196}, {0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C}, {0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D}, {0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment