Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
f86096b8
Commit
f86096b8
authored
Apr 29, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-ntfs.bkbits.net/ntfs-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
ad39cbdf
522c6443
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
614 additions
and
466 deletions
+614
-466
Documentation/filesystems/ntfs.txt
Documentation/filesystems/ntfs.txt
+13
-0
fs/ntfs/ChangeLog
fs/ntfs/ChangeLog
+25
-0
fs/ntfs/Makefile
fs/ntfs/Makefile
+1
-1
fs/ntfs/aops.c
fs/ntfs/aops.c
+17
-16
fs/ntfs/attrib.c
fs/ntfs/attrib.c
+29
-23
fs/ntfs/attrib.h
fs/ntfs/attrib.h
+4
-4
fs/ntfs/compress.c
fs/ntfs/compress.c
+73
-23
fs/ntfs/dir.c
fs/ntfs/dir.c
+72
-74
fs/ntfs/inode.c
fs/ntfs/inode.c
+119
-121
fs/ntfs/inode.h
fs/ntfs/inode.h
+16
-22
fs/ntfs/layout.h
fs/ntfs/layout.h
+106
-76
fs/ntfs/mft.c
fs/ntfs/mft.c
+14
-14
fs/ntfs/namei.c
fs/ntfs/namei.c
+5
-5
fs/ntfs/super.c
fs/ntfs/super.c
+110
-79
fs/ntfs/unistr.c
fs/ntfs/unistr.c
+5
-3
fs/ntfs/upcase.c
fs/ntfs/upcase.c
+5
-5
No files found.
Documentation/filesystems/ntfs.txt
View file @
f86096b8
...
@@ -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
...
...
fs/ntfs/ChangeLog
View file @
f86096b8
...
@@ -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
...
...
fs/ntfs/Makefile
View file @
f86096b8
...
@@ -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
...
...
fs/ntfs/aops.c
View file @
f86096b8
...
@@ -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
);
...
...
fs/ntfs/attrib.c
View file @
f86096b8
/**
/**
* 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_
parti
al
;
goto
do_
fin
al
;
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_
parti
al:
do_
fin
al:
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
;
}
}
...
...
fs/ntfs/attrib.h
View file @
f86096b8
...
@@ -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
);
...
...
fs/ntfs/compress.c
View file @
f86096b8
...
@@ -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,10 +207,19 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
...
@@ -173,10 +207,19 @@ 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. */
if
(
nr_completed_pages
>
0
)
{
struct
page
*
page
=
dest_pages
[
completed_pages
[
0
]];
ntfs_inode
*
ni
=
NTFS_I
(
page
->
mapping
->
host
);
for
(
i
=
0
;
i
<
nr_completed_pages
;
i
++
)
{
for
(
i
=
0
;
i
<
nr_completed_pages
;
i
++
)
{
int
di
=
completed_pages
[
i
];
int
di
=
completed_pages
[
i
];
dp
=
dest_pages
[
di
];
dp
=
dest_pages
[
di
];
/*
* If we are outside the initialized size, zero
* the out of bounds page range.
*/
handle_bounds_compressed_page
(
ni
,
dp
);
flush_dcache_page
(
dp
);
flush_dcache_page
(
dp
);
kunmap
(
dp
);
kunmap
(
dp
);
SetPageUptodate
(
dp
);
SetPageUptodate
(
dp
);
...
@@ -187,6 +230,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
...
@@ -187,6 +230,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
page_cache_release
(
dp
);
page_cache_release
(
dp
);
dest_pages
[
di
]
=
NULL
;
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
);
...
...
fs/ntfs/dir.c
View file @
f86096b8
/**
/**
* 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
)
...
...
fs/ntfs/inode.c
View file @
f86096b8
/**
/**
* 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
;
...
...
fs/ntfs/inode.h
View file @
f86096b8
...
@@ -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
...
...
fs/ntfs/layout.h
View file @
f86096b8
...
@@ -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
reserved
R
;
/* 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
reserved
1
[
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
{
/* 36*/
u8
reserved12
[
12
];
/* Reserved/alignment to 8-byte
boundary. */
boundary. */
/* sizeof() = 48 bytes */
}
__attribute__
((
__packed__
))
v1
;
/* NTFS 3.0 */
/* 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*/
struct
{
/* 3c*/
u32
reparse_point_tag
;
/* Type of reparse point,
/* 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
{
struct
{
/* Only valid when INDEX_ENTRY_END is not set. */
MFT_REF
indexed_file
;
/* The mft reference of the file
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).
*
*
...
...
fs/ntfs/mft.c
View file @
f86096b8
/**
/**
* 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."
);
...
...
fs/ntfs/namei.c
View file @
f86096b8
...
@@ -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
;
...
...
fs/ntfs/super.c
View file @
f86096b8
/*
/*
* 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 $B
ITMAP
, max_index = 0x%lx, max_size = 0x%x."
,
ntfs_debug
(
"Reading $B
itmap
, 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 each 4 bytes, subtract the number of set bits. If this
* 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().
*/
for
(
i
=
0
;
i
<
max_size
;
i
++
)
for
(
i
=
0
;
i
<
max_size
;
i
++
)
nr_free
+=
(
s64
)(
32
-
hweight32
(
b
[
i
])
);
nr_free
-=
(
s64
)
hweight32
(
kaddr
[
i
]
);
kunmap
(
page
);
kunmap
_atomic
(
kaddr
,
KM_USER0
);
page_cache_release
(
page
);
page_cache_release
(
page
);
}
}
if
(
max_size
==
PAGE_CACHE_SIZE
>>
2
)
{
ntfs_debug
(
"Finished reading $Bitmap, last index = 0x%lx."
,
index
-
1
);
/*
/*
* Get the multiples of 4 bytes in use in the final partial
* Fixup for eventual bits outside logical ntfs volume (see function
* page
.
* description above)
.
*/
*/
max_size
=
((((
vol
->
nr_clusters
+
7
)
>>
3
)
&
~
PAGE_CACHE_MASK
)
if
(
vol
->
nr_clusters
&
63
)
+
3
)
>>
2
;
nr_free
+=
64
-
(
vol
->
nr_clusters
&
63
);
/* If there is a partial page go back and do it. */
if
(
max_size
)
{
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
);
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
);
nr_free
-=
PAGE_CACHE_SIZE
*
8
;
continue
;
}
}
if
(
index
==
max_index
)
{
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
))
ntfs_debug
(
"Finished reading $MFT/$BITMAP, last index = 0x%lx."
,
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"
,
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-200
2
Anton Altaparmakov"
);
MODULE_DESCRIPTION
(
"NTFS 1.2/3.x driver - Copyright (c) 2001-200
3
Anton Altaparmakov"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
#ifdef DEBUG
#ifdef DEBUG
MODULE_PARM
(
debug_msgs
,
"i"
);
MODULE_PARM
(
debug_msgs
,
"i"
);
...
...
fs/ntfs/unistr.c
View file @
f86096b8
/*
/*
* 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
++
);
...
...
fs/ntfs/upcase.c
View file @
f86096b8
...
@@ -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
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment