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
Kirill Smelkov
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
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:
- Add configuration option for developmental write support.
- Initial implementation of file overwriting. (Writes to resident files
...
...
fs/ntfs/ChangeLog
View file @
f86096b8
...
...
@@ -20,6 +20,31 @@ ToDo:
sufficient for synchronisation here. We then just need to make sure
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.
- 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
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
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.1.
0
\"
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.1.
4
\"
ifeq
($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS
+=
-DDEBUG
...
...
fs/ntfs/aops.c
View file @
f86096b8
...
...
@@ -2,8 +2,8 @@
* aops.c - NTFS kernel address space operations and page cache handling.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (c) 2002 Richard Russon
.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* 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
...
...
@@ -111,7 +111,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
unsigned
int
i
,
recs
,
nr_err
;
u32
rec_size
;
rec_size
=
ni
->
_IDM
(
index_block_size
)
;
rec_size
=
ni
->
itype
.
index
.
block_size
;
recs
=
PAGE_CACHE_SIZE
/
rec_size
;
addr
=
kmap_atomic
(
page
,
KM_BIO_SRC_IRQ
);
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)
ni
->
mft_no
?
"index"
:
"mft"
,
(
long
long
)(((
s64
)
page
->
index
<<
PAGE_CACHE_SHIFT
>>
ni
->
_IDM
(
index_block_size_bits
)
)
+
i
));
ni
->
itype
.
index
.
block_size_bits
)
+
i
));
}
flush_dcache_page
(
page
);
kunmap_atomic
(
addr
,
KM_BIO_SRC_IRQ
);
...
...
@@ -383,7 +383,7 @@ int ntfs_readpage(struct file *file, struct page *page)
if
(
!
NInoAttr
(
ni
))
base_ni
=
ni
;
else
base_ni
=
ni
->
_INE
(
base_ntfs_ino
)
;
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
/* Map, pin, and lock the mft record. */
mrec
=
map_mft_record
(
base_ni
);
...
...
@@ -406,7 +406,7 @@ int ntfs_readpage(struct file *file, struct page *page)
attr_pos
=
page
->
index
<<
PAGE_CACHE_SHIFT
;
/* 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
);
/* Copy over in bounds data, zeroing the remainder of the page. */
...
...
@@ -418,8 +418,8 @@ int ntfs_readpage(struct file *file, struct page *page)
memset
(
addr
+
bytes
,
0
,
PAGE_CACHE_SIZE
-
bytes
);
/* Copy the data to the page. */
memcpy
(
addr
,
attr_pos
+
(
char
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)),
bytes
);
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
),
bytes
);
}
else
memset
(
addr
,
0
,
PAGE_CACHE_SIZE
);
flush_dcache_page
(
page
);
...
...
@@ -892,7 +892,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
if
(
!
NInoAttr
(
ni
))
base_ni
=
ni
;
else
base_ni
=
ni
->
_INE
(
base_ntfs_ino
)
;
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
/* Map, pin, and lock the mft record. */
m
=
map_mft_record
(
base_ni
);
...
...
@@ -917,7 +917,7 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
attr_pos
=
page
->
index
<<
PAGE_CACHE_SHIFT
;
/* 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
))
{
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)
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
/* Copy the data from the page to the mft record. */
memcpy
((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
))
+
attr_pos
,
kaddr
,
bytes
);
memcpy
((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
)
+
attr_pos
,
kaddr
,
bytes
);
flush_dcache_mft_record_page
(
ctx
->
ntfs_ino
);
#if 0
/* Zero out of bounds area. */
...
...
@@ -1656,7 +1657,7 @@ static int ntfs_commit_write(struct file *file, struct page *page,
if
(
!
NInoAttr
(
ni
))
base_ni
=
ni
;
else
base_ni
=
ni
->
_INE
(
base_ntfs_ino
)
;
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
/* Map, pin, and lock the mft record. */
m
=
map_mft_record
(
base_ni
);
...
...
@@ -1681,7 +1682,7 @@ static int ntfs_commit_write(struct file *file, struct page *page,
attr_pos
=
page
->
index
<<
PAGE_CACHE_SHIFT
;
/* 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
))
{
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,
* Calculate the address of the attribute value corresponding to the
* beginning of the current data @page.
*/
kattr
=
(
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
))
+
attr_pos
;
kattr
=
(
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
)
+
attr_pos
;
kaddr
=
kmap_atomic
(
page
,
KM_USER0
);
...
...
fs/ntfs/attrib.c
View file @
f86096b8
/**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (
C) 2002 Richard Russon.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (
c) 2002 Richard Russon
*
* 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
...
...
@@ -731,17 +731,18 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
#ifdef DEBUG
/* Make sure attr exists and is non-resident. */
if
(
!
attr
||
!
attr
->
non_resident
||
sle64_to_cpu
(
attr
->
_ANR
(
lowest_vcn
)
)
<
(
VCN
)
0
)
{
if
(
!
attr
||
!
attr
->
non_resident
||
sle64_to_cpu
(
attr
->
data
.
non_resident
.
lowest_vcn
)
<
(
VCN
)
0
)
{
ntfs_error
(
vol
->
sb
,
"Invalid arguments."
);
return
ERR_PTR
(
-
EINVAL
);
}
#endif
/* 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
;
/* 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
);
if
(
unlikely
(
buf
<
(
u8
*
)
attr
||
buf
>
attr_end
))
{
ntfs_error
(
vol
->
sb
,
"Corrupt attribute."
);
...
...
@@ -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
* 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
))
{
mpa_err:
ntfs_error
(
vol
->
sb
,
"Corrupt mapping pairs array in "
...
...
@@ -875,10 +876,11 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
goto
err_out
;
}
/* 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
;
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_bits
;
/*
...
...
@@ -951,7 +953,7 @@ int map_run_list(ntfs_inode *ni, VCN vcn)
if
(
!
NInoAttr
(
ni
))
base_ni
=
ni
;
else
base_ni
=
ni
->
_INE
(
base_ntfs_ino
)
;
base_ni
=
ni
->
ext
.
base_ntfs_ino
;
mrec
=
map_mft_record
(
base_ni
);
if
(
IS_ERR
(
mrec
))
...
...
@@ -1180,19 +1182,23 @@ BOOL find_attr(const ATTR_TYPES type, const uchar_t *name, const u32 name_len,
return
TRUE
;
/* @val is present; compare values. */
else
{
u32
vl
;
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
(
a
->
_ARA
(
value_offset
)),
min_t
(
const
u32
,
val_len
,
le32_to_cpu
(
a
->
_ARA
(
value_length
))));
a
->
data
.
resident
.
value_offset
),
vl
);
/*
* If @val collates before the current attribute's
* value, there is no matching attribute.
*/
if
(
!
rc
)
{
register
u32
avl
;
avl
=
le32_to_cpu
(
a
->
_ARA
(
value_length
));
avl
=
le32_to_cpu
(
a
->
data
.
resident
.
value_length
);
if
(
val_len
==
avl
)
return
TRUE
;
if
(
val_len
<
avl
)
...
...
@@ -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
;
ntfs_debug
(
"Entering."
);
#ifdef DEBUG
if
(
!
vol
||
!
run_list
||
!
al
||
size
<=
0
||
initialized_size
<
0
||
initialized_size
>
size
)
return
-
EINVAL
;
#endif
if
(
!
initialized_size
)
{
memset
(
al
,
0
,
size
);
return
0
;
...
...
@@ -1270,8 +1274,8 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al,
"read attribute list."
);
goto
err_out
;
}
if
(
al
+
block_size
>
al_end
)
goto
do_
parti
al
;
if
(
al
+
block_size
>
=
al_end
)
goto
do_
fin
al
;
memcpy
(
al
,
bh
->
b_data
,
block_size
);
brelse
(
bh
);
al
+=
block_size
;
...
...
@@ -1285,7 +1289,7 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al,
done:
up_read
(
&
run_list
->
lock
);
return
err
;
do_
parti
al:
do_
fin
al:
if
(
al
<
al_end
)
{
/* Partial block. */
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,
* If no @val specified or @val specified and it matches, we
* have found it!
*/
if
(
!
val
||
(
!
a
->
non_resident
&&
le32_to_cpu
(
a
->
_ARA
(
value_length
))
==
val_len
&&
!
memcmp
((
u8
*
)
a
+
le16_to_cpu
(
a
->
_ARA
(
value_offset
)),
val
,
val_len
)))
{
if
(
!
val
||
(
!
a
->
non_resident
&&
le32_to_cpu
(
a
->
data
.
resident
.
value_length
)
==
val_len
&&
!
memcmp
((
u8
*
)
a
+
le16_to_cpu
(
a
->
data
.
resident
.
value_offset
),
val
,
val_len
)))
{
ntfs_debug
(
"Done, found."
);
return
TRUE
;
}
...
...
fs/ntfs/attrib.h
View file @
f86096b8
...
...
@@ -2,8 +2,8 @@
* attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (
C) 2002 Richard Russon.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (
c) 2002 Richard Russon
*
* 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
...
...
@@ -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
)
{
if
(
!
a
->
non_resident
)
return
(
s64
)
le32_to_cpu
(
a
->
_ARA
(
value_length
)
);
return
sle64_to_cpu
(
a
->
_ANR
(
data_size
)
);
return
(
s64
)
le32_to_cpu
(
a
->
data
.
resident
.
value_length
);
return
sle64_to_cpu
(
a
->
data
.
non_resident
.
data_size
);
}
extern
void
reinit_attr_search_ctx
(
attr_search_context
*
ctx
);
...
...
fs/ntfs/compress.c
View file @
f86096b8
...
...
@@ -2,8 +2,8 @@
* compress.c - NTFS kernel compressed attributes handling.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (
C) 2002 Richard Russon.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (
c) 2002 Richard Russon
*
* 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
...
...
@@ -44,7 +44,7 @@ typedef enum {
* The maximum compression block size is by definition 16 * the cluster
* size, with the maximum supported cluster size being 4kiB. Thus the
* 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_compression_constants
;
...
...
@@ -88,6 +88,40 @@ void free_compression_buffers(void)
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
* @dest_pages: destination array of pages
...
...
@@ -164,7 +198,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
cb
-
cb_start
);
/* 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
;
ntfs_debug
(
"Completed. Returning success (0)."
);
...
...
@@ -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. */
spin_unlock
(
&
ntfs_cb_lock
);
/* 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
++
)
{
int
di
=
completed_pages
[
i
];
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
);
kunmap
(
dp
);
SetPageUptodate
(
dp
);
...
...
@@ -187,6 +230,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
page_cache_release
(
dp
);
dest_pages
[
di
]
=
NULL
;
}
}
return
err
;
}
...
...
@@ -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. */
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
)
goto
return_overflow
;
...
...
@@ -225,7 +270,7 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
dp_addr
=
(
u8
*
)
page_address
(
dp
)
+
do_sb_start
;
/* 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."
);
/* 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,
lg
++
;
/* 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
...
...
@@ -432,7 +477,7 @@ int ntfs_read_compressed_block(struct page *page)
u8
*
cb
,
*
cb_pos
,
*
cb_end
;
struct
buffer_head
**
bhs
;
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
;
VCN
vcn
;
LCN
lcn
;
...
...
@@ -447,7 +492,7 @@ int ntfs_read_compressed_block(struct page *page)
&
~
cb_size_mask
)
>>
vol
->
cluster_size_bits
;
/* Number of compression blocks (cbs) in the wanted vcn range. */
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
* compression blocks (cbs) overlapping @page. Due to alignment
...
...
@@ -528,7 +573,7 @@ int ntfs_read_compressed_block(struct page *page)
*/
cur_page
=
0
;
cur_ofs
=
0
;
cb_clusters
=
ni
->
_ICF
(
compression_block_clusters
)
;
cb_clusters
=
ni
->
itype
.
compressed
.
block_clusters
;
do_next_cb:
nr_cbs
--
;
nr_bhs
=
0
;
...
...
@@ -763,6 +808,11 @@ int ntfs_read_compressed_block(struct page *page)
for
(;
cur2_page
<
cb_max_page
;
cur2_page
++
)
{
page
=
pages
[
cur2_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
);
kunmap
(
page
);
SetPageUptodate
(
page
);
...
...
fs/ntfs/dir.c
View file @
f86096b8
/**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (c) 2002 Richard Russon
.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* 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
...
...
@@ -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). */
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
);
/* The first index entry. */
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,
* Loop until we exceed valid memory (corruption case) or until we
* 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. */
if
((
u8
*
)
ie
<
(
u8
*
)
ctx
->
mrec
||
(
u8
*
)
ie
+
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
)
goto
dir_err_out
;
/*
* 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.
*/
if
(
ie
->
_IEH
(
flags
)
&
INDEX_ENTRY_END
)
if
(
ie
->
flags
&
INDEX_ENTRY_END
)
break
;
/*
* 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,
}
}
name
->
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
)
);
ie
->
data
.
dir
.
indexed_file
);
name
->
type
=
FILE_NAME_DOS
;
name
->
len
=
0
;
*
res
=
name
;
...
...
@@ -168,7 +168,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
kfree
(
name
);
*
res
=
NULL
;
}
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
)
);
mref
=
le64_to_cpu
(
ie
->
data
.
dir
.
indexed_file
);
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
dir_ni
);
return
mref
;
...
...
@@ -211,7 +211,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
err
=
-
ENOMEM
;
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
;
if
(
type
!=
FILE_NAME_DOS
)
{
name
->
len
=
len
;
...
...
@@ -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
* mft reference associated with it.
*/
if
(
!
(
ie
->
_IEH
(
flags
)
&
INDEX_ENTRY_NODE
))
{
if
(
!
(
ie
->
flags
&
INDEX_ENTRY_NODE
))
{
if
(
name
)
{
put_attr_search_ctx
(
ctx
);
unmap_mft_record
(
dir_ni
);
...
...
@@ -284,7 +284,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto
err_out
;
}
/* 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
;
/*
* 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,
* disk if necessary.
*/
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
))
{
ntfs_error
(
sb
,
"Failed to map directory index page, error %ld."
,
-
PTR_ERR
(
page
));
...
...
@@ -312,7 +312,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
fast_descend_into_child_node:
/* Get to the index allocation block. */
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. */
if
((
u8
*
)
ia
<
kaddr
||
(
u8
*
)
ia
>
kaddr
+
PAGE_CACHE_SIZE
)
{
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,
goto
unm_err_out
;
}
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 "
"0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory "
"inode is corrupt or driver bug."
,
(
long
long
)
vcn
,
dir_ni
->
mft_no
,
le32_to_cpu
(
ia
->
index
.
allocated_size
)
+
0x18
,
dir_ni
->
_IDM
(
index_block_size
)
);
dir_ni
->
itype
.
index
.
block_size
);
err
=
-
EIO
;
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
)
{
ntfs_error
(
sb
,
"Index buffer (VCN 0x%Lx) of directory inode "
"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,
goto
unm_err_out
;
}
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 "
"inode 0x%lx exceeds maximum size."
,
(
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,
* loop until we exceed valid memory (corruption case) or until we
* 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. */
if
((
u8
*
)
ie
<
(
u8
*
)
ia
||
(
u8
*
)
ie
+
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
)
{
ntfs_error
(
sb
,
"Index entry out of bounds in "
"directory inode 0x%lx."
,
...
...
@@ -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
* 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
;
/*
* 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,
}
}
name
->
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
)
);
ie
->
data
.
dir
.
indexed_file
);
name
->
type
=
FILE_NAME_DOS
;
name
->
len
=
0
;
*
res
=
name
;
...
...
@@ -426,7 +426,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
kfree
(
name
);
*
res
=
NULL
;
}
mref
=
le64_to_cpu
(
ie
->
_IIF
(
indexed_file
)
);
mref
=
le64_to_cpu
(
ie
->
data
.
dir
.
indexed_file
);
ntfs_unmap_page
(
page
);
return
mref
;
}
...
...
@@ -469,7 +469,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
err
=
-
ENOMEM
;
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
;
if
(
type
!=
FILE_NAME_DOS
)
{
name
->
len
=
len
;
...
...
@@ -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
* 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
)
{
ntfs_error
(
sb
,
"Index entry with child node found in "
"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,
}
/* Child node present, descend into it. */
old_vcn
=
vcn
;
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
);
if
(
vcn
>=
0
)
{
/* If vcn is in the same page cache page as old_vcn we
* recycle the mapped page. */
...
...
@@ -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). */
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);
/* The first index entry. */
ie = (INDEX_ENTRY*)((u8*)&ir->index +
...
...
@@ -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
* 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. */
if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
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)
goto dir_err_out;
/*
* 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.
*/
if (ie->
_IEH(flags)
& INDEX_ENTRY_END)
if (ie->
flags
& INDEX_ENTRY_END)
break;
/*
* 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,
ie->key.file_name.file_name_length, ic,
vol->upcase, vol->upcase_len)) {
found_it:
mref = le64_to_cpu(ie->
_IIF(indexed_file)
);
mref = le64_to_cpu(ie->
data.dir.indexed_file
);
put_attr_search_ctx(ctx);
unmap_mft_record(dir_ni);
return mref;
...
...
@@ -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
* presence of a child node.
*/
if (!(ie->
_IEH(flags)
& INDEX_ENTRY_NODE)) {
if (!(ie->
flags
& INDEX_ENTRY_NODE)) {
/* No child node, return -ENOENT. */
err = -ENOENT;
goto err_out;
...
...
@@ -752,7 +751,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto err_out;
}
/* 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;
/*
* 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,
* disk if necessary.
*/
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)) {
ntfs_error(sb, "Failed to map directory index page, error %ld.",
-PTR_ERR(page));
...
...
@@ -780,7 +779,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
fast_descend_into_child_node:
/* Get to the index allocation block. */
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. */
if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
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,
goto unm_err_out;
}
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 "
"0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory "
"inode is corrupt or driver bug.",
(long long)vcn, dir_ni->mft_no,
le32_to_cpu(ia->index.allocated_size) + 0x18,
dir_ni->
_IDM(index_block_size)
);
dir_ni->
itype.index.block_size
);
err = -EIO;
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) {
ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx crosses page boundary. Impossible! "
...
...
@@ -820,7 +819,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
goto unm_err_out;
}
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 "
"inode 0x%lx exceeds maximum size.",
(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,
* loop until we exceed valid memory (corruption case) or until we
* 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. */
if ((u8*)ie < (u8*)ia || (u8*)ie +
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) {
ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%lx.",
...
...
@@ -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
* 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;
/*
* 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,
ie->key.file_name.file_name_length, ic,
vol->upcase, vol->upcase_len)) {
found_it2:
mref = le64_to_cpu(ie->
_IIF(indexed_file)
);
mref = le64_to_cpu(ie->
data.dir.indexed_file
);
ntfs_unmap_page(page);
return mref;
}
...
...
@@ -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
* 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) {
ntfs_error(sb, "Index entry with child node found in "
"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,
}
/* Child node present, descend into it. */
old_vcn = vcn;
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);
if (vcn >= 0) {
/* If vcn is in the same page cache page as old_vcn we
* recycle the mapped page. */
...
...
@@ -1007,7 +1005,7 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
if
(
index_type
==
INDEX_TYPE_ALLOCATION
)
*
fpos
=
(
u8
*
)
ie
-
(
u8
*
)
iu
.
ia
+
(
sle64_to_cpu
(
iu
.
ia
->
index_block_vcn
)
<<
ndir
->
_IDM
(
index_vcn_size_bits
)
)
+
ndir
->
itype
.
index
.
vcn_size_bits
)
+
vol
->
mft_record_size
;
else
/* if (index_type == INDEX_TYPE_ROOT) */
*
fpos
=
(
u8
*
)
ie
-
(
u8
*
)
iu
.
ir
;
...
...
@@ -1016,11 +1014,11 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
ntfs_debug
(
"Skipping DOS name space entry."
);
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."
);
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
))
{
ntfs_debug
(
"Skipping system file."
);
return
0
;
...
...
@@ -1039,10 +1037,10 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
dt_type
=
DT_REG
;
ntfs_debug
(
"Calling filldir for %s with len %i, fpos 0x%Lx, inode "
"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"
);
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)
}
/* Get to the index root value (it's been verified in read_inode). */
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
);
/* The first index entry. */
ie
=
(
INDEX_ENTRY
*
)((
u8
*
)
&
ir
->
index
+
...
...
@@ -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
* 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
);
/* Bounds checks. */
if
(
unlikely
((
u8
*
)
ie
<
(
u8
*
)
ctx
->
mrec
||
(
u8
*
)
ie
+
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
))
goto
err_out
;
/* The last entry cannot contain a name. */
if
(
ie
->
_IEH
(
flags
)
&
INDEX_ENTRY_END
)
if
(
ie
->
flags
&
INDEX_ENTRY_END
)
break
;
/* Skip index root entry if continuing previous readdir. */
if
(
ir_pos
>
(
u8
*
)
ie
-
(
u8
*
)
ir
)
...
...
@@ -1192,7 +1190,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Get the offset into the index allocation attribute. */
ia_pos
=
(
s64
)
fpos
-
vol
->
mft_record_size
;
ia_mapping
=
vdir
->
i_mapping
;
bmp_vi
=
ndir
->
_IDM
(
bmp_ino
)
;
bmp_vi
=
ndir
->
itype
.
index
.
bmp_ino
;
if
(
unlikely
(
!
bmp_vi
))
{
ntfs_debug
(
"Inode %lu, regetting index bitmap."
,
vdir
->
i_ino
);
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)
err
=
PTR_ERR
(
bmp_vi
);
goto
err_out
;
}
ndir
->
_IDM
(
bmp_ino
)
=
bmp_vi
;
ndir
->
itype
.
index
.
bmp_ino
=
bmp_vi
;
}
bmp_mapping
=
bmp_vi
->
i_mapping
;
/* 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
))
{
ntfs_error
(
sb
,
"Current index allocation position exceeds "
"index bitmap size."
);
...
...
@@ -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
))
goto
unm_EOD
;
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."
,
(
long
long
)
bmp_pos
+
cur_bmp_pos
);
...
...
@@ -1269,7 +1267,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
/* Get the current index buffer. */
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. */
if
(
unlikely
((
u8
*
)
ia
<
kaddr
||
(
u8
*
)
ia
>
kaddr
+
PAGE_CACHE_SIZE
))
{
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)
goto
err_out
;
}
if
(
unlikely
(
sle64_to_cpu
(
ia
->
index_block_vcn
)
!=
(
ia_pos
&
~
(
s64
)(
ndir
->
_IDM
(
index_block_size
)
-
1
))
>>
ndir
->
_IDM
(
index_vcn_size_bits
)
))
{
~
(
s64
)(
ndir
->
itype
.
index
.
block_size
-
1
))
>>
ndir
->
itype
.
index
.
vcn_size_bits
))
{
ntfs_error
(
sb
,
"Actual VCN (0x%Lx) of index buffer is "
"different from expected VCN (0x%Lx). "
"Directory inode 0x%lx is corrupt or driver "
"bug. "
,
(
long
long
)
sle64_to_cpu
(
ia
->
index_block_vcn
),
(
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
;
}
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 "
"0x%lx has a size (%u) differing from the "
"directory specified size (%u). Directory "
"inode is corrupt or driver bug."
,
(
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
,
ndir
->
_IDM
(
index_block_size
)
);
ndir
->
itype
.
index
.
block_size
);
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
))
{
ntfs_error
(
sb
,
"Index buffer (VCN 0x%Lx) of directory inode "
"0x%lx crosses page boundary. Impossible! "
"Cannot access! This is probably a bug in the "
"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
;
}
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
);
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 "
"inode 0x%lx exceeds maximum size."
,
(
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
;
}
/* The first index entry in this index buffer. */
...
...
@@ -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
* 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."
,
(
long
long
)
ia_start
+
((
u8
*
)
ie
-
(
u8
*
)
ia
));
/* Bounds checks. */
if
(
unlikely
((
u8
*
)
ie
<
(
u8
*
)
ia
||
(
u8
*
)
ie
+
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
))
goto
err_out
;
/* The last entry cannot contain a name. */
if
(
ie
->
_IEH
(
flags
)
&
INDEX_ENTRY_END
)
if
(
ie
->
flags
&
INDEX_ENTRY_END
)
break
;
/* Skip index block entry if continuing previous readdir. */
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.
*
* 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
* 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)
ni
->
attr_list_size
=
0
;
ni
->
attr_list
=
NULL
;
init_run_list
(
&
ni
->
attr_list_rl
);
ni
->
_IDM
(
bmp_ino
)
=
NULL
;
ni
->
_IDM
(
index_block_size
)
=
0
;
ni
->
_IDM
(
index_vcn_size
)
=
0
;
ni
->
_IDM
(
index_block_size_bits
)
=
0
;
ni
->
_IDM
(
index_vcn_size_bits
)
=
0
;
ni
->
itype
.
index
.
bmp_ino
=
NULL
;
ni
->
itype
.
index
.
block_size
=
0
;
ni
->
itype
.
index
.
vcn_size
=
0
;
ni
->
itype
.
index
.
block_size_bits
=
0
;
ni
->
itype
.
index
.
vcn_size_bits
=
0
;
init_MUTEX
(
&
ni
->
extent_lock
);
ni
->
nr_extents
=
0
;
ni
->
_INE
(
base_ntfs_ino
)
=
NULL
;
ni
->
ext
.
base_ntfs_ino
=
NULL
;
return
;
}
...
...
@@ -426,14 +426,14 @@ static int ntfs_is_extended_system_file(attr_search_context *ctx)
"chkdsk."
);
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 "
"name. You should run chkdsk."
);
return
-
EIO
;
}
file_name_attr
=
(
FILE_NAME_ATTR
*
)((
u8
*
)
attr
+
le16_to_cpu
(
attr
->
_ARA
(
value_offset
)
));
p2
=
(
u8
*
)
attr
+
le32_to_cpu
(
attr
->
_ARA
(
value_length
)
);
le16_to_cpu
(
attr
->
data
.
resident
.
value_offset
));
p2
=
(
u8
*
)
attr
+
le32_to_cpu
(
attr
->
data
.
resident
.
value_length
);
if
(
p2
<
(
u8
*
)
attr
||
p2
>
p
)
goto
err_corrupt_attr
;
/* This attribute is ok, but is it in the $Extend directory? */
...
...
@@ -578,7 +578,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
/* Get the standard information attribute value. */
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. */
/*
...
...
@@ -633,7 +633,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
if
(
ctx
->
attr
->
non_resident
)
{
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 "
"zero lowest_vcn. Inode is "
"corrupt. You should run "
...
...
@@ -659,17 +659,17 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* Now load the attribute list. */
if
((
err
=
load_attribute_list
(
vol
,
&
ni
->
attr_list_rl
,
ni
->
attr_list
,
ni
->
attr_list_size
,
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
initialized_size
)
))))
{
sle64_to_cpu
(
ctx
->
attr
->
data
.
non_resident
.
initialized_size
))))
{
ntfs_error
(
vi
->
i_sb
,
"Failed to load "
"attribute list attribute."
);
goto
unm_err_out
;
}
}
else
/* if (!ctx.attr->non_resident) */
{
if
((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)
)
+
ctx
->
attr
->
data
.
resident
.
value_offset
)
+
le32_to_cpu
(
ctx
->
attr
->
_ARA
(
value_length
)
)
>
ctx
->
attr
->
data
.
resident
.
value_length
)
>
(
u8
*
)
ctx
->
mrec
+
vol
->
mft_record_size
)
{
ntfs_error
(
vi
->
i_sb
,
"Corrupt attribute list "
"in inode."
);
...
...
@@ -677,9 +677,9 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
/* Now copy the attribute list. */
memcpy
(
ni
->
attr_list
,
(
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)
),
ctx
->
attr
->
data
.
resident
.
value_offset
),
le32_to_cpu
(
ctx
->
attr
->
_ARA
(
value_length
)
));
ctx
->
attr
->
data
.
resident
.
value_length
));
}
}
skip_attr_list_load:
...
...
@@ -728,9 +728,10 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
if
(
ctx
->
attr
->
flags
&
ATTR_IS_SPARSE
)
NInoSetSparse
(
ni
);
ir
=
(
INDEX_ROOT
*
)((
char
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)));
ir_end
=
(
char
*
)
ir
+
le32_to_cpu
(
ctx
->
attr
->
_ARA
(
value_length
));
ir
=
(
INDEX_ROOT
*
)((
char
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_offset
));
ir_end
=
(
char
*
)
ir
+
le32_to_cpu
(
ctx
->
attr
->
data
.
resident
.
value_length
);
if
(
ir_end
>
(
char
*
)
ctx
->
mrec
+
vol
->
mft_record_size
)
{
ntfs_error
(
vi
->
i_sb
,
"$INDEX_ROOT attribute is "
"corrupt."
);
...
...
@@ -752,41 +753,41 @@ static int ntfs_read_locked_inode(struct inode *vi)
"COLLATION_FILE_NAME. Not allowed."
);
goto
unm_err_out
;
}
ni
->
_IDM
(
index_block_size
)
=
le32_to_cpu
(
ir
->
index_block_size
);
if
(
ni
->
_IDM
(
index_block_size
)
&
(
ni
->
_IDM
(
index_block_size
)
-
1
))
{
ni
->
itype
.
index
.
block_size
=
le32_to_cpu
(
ir
->
index_block_size
);
if
(
ni
->
itype
.
index
.
block_size
&
(
ni
->
itype
.
index
.
block_size
-
1
))
{
ntfs_error
(
vi
->
i_sb
,
"Index block size (%u) is not a "
"power of two."
,
ni
->
_IDM
(
index_block_size
)
);
ni
->
itype
.
index
.
block_size
);
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) > "
"PAGE_CACHE_SIZE (%ld) is not "
"supported. Sorry."
,
ni
->
_IDM
(
index_block_size
)
,
ni
->
itype
.
index
.
block_size
,
PAGE_CACHE_SIZE
);
err
=
-
EOPNOTSUPP
;
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_BLOCK_SIZE (%i) is not "
"supported. Sorry."
,
ni
->
_IDM
(
index_block_size
)
,
ni
->
itype
.
index
.
block_size
,
NTFS_BLOCK_SIZE
);
err
=
-
EOPNOTSUPP
;
goto
unm_err_out
;
}
ni
->
_IDM
(
index_block_size_bits
)
=
ffs
(
ni
->
_IDM
(
index_block_size
)
)
-
1
;
ni
->
itype
.
index
.
block_size_bits
=
ffs
(
ni
->
itype
.
index
.
block_size
)
-
1
;
/* Determine the size of a vcn in the directory index. */
if
(
vol
->
cluster_size
<=
ni
->
_IDM
(
index_block_size
)
)
{
ni
->
_IDM
(
index_vcn_size
)
=
vol
->
cluster_size
;
ni
->
_IDM
(
index_vcn_size_bits
)
=
vol
->
cluster_size_bits
;
if
(
vol
->
cluster_size
<=
ni
->
itype
.
index
.
block_size
)
{
ni
->
itype
.
index
.
vcn_size
=
vol
->
cluster_size
;
ni
->
itype
.
index
.
vcn_size_bits
=
vol
->
cluster_size_bits
;
}
else
{
ni
->
_IDM
(
index_vcn_size
)
=
vol
->
sector_size
;
ni
->
_IDM
(
index_vcn_size_bits
)
=
vol
->
sector_size_bits
;
ni
->
itype
.
index
.
vcn_size
=
vol
->
sector_size
;
ni
->
itype
.
index
.
vcn_size_bits
=
vol
->
sector_size_bits
;
}
/* Setup the index allocation attribute, even if not present. */
...
...
@@ -836,18 +837,19 @@ static int ntfs_read_locked_inode(struct inode *vi)
"is compressed."
);
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 "
"$INDEX_ALLOCATION attribute has non "
"zero lowest_vcn. Inode is corrupt. "
"You should run chkdsk."
);
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
(
ctx
->
attr
->
_ANR
(
initialized_size
)
);
ctx
->
attr
->
data
.
non_resident
.
initialized_size
);
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 would deadlock in ntfs_attr_iget().
...
...
@@ -863,7 +865,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
err
=
PTR_ERR
(
bvi
);
goto
unm_err_out
;
}
ni
->
_IDM
(
bmp_ino
)
=
bvi
;
ni
->
itype
.
index
.
bmp_ino
=
bvi
;
bni
=
NTFS_I
(
bvi
);
if
(
NInoCompressed
(
bni
)
||
NInoEncrypted
(
bni
)
||
NInoSparse
(
bni
))
{
...
...
@@ -873,7 +875,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
/* Consistency check bitmap size vs. index allocation 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) "
"for index allocation (0x%Lx)."
,
bvi
->
i_size
<<
3
,
vi
->
i_size
);
...
...
@@ -950,25 +952,28 @@ static int ntfs_read_locked_inode(struct inode *vi)
"corrupt file."
);
goto
unm_err_out
;
}
ni
->
_ICF
(
compression_block_clusters
)
=
1U
<<
ctx
->
attr
->
_ANR
(
compression_unit
);
if
(
ctx
->
attr
->
_ANR
(
compression_unit
)
!=
4
)
{
ni
->
itype
.
compressed
.
block_clusters
=
1U
<<
ctx
->
attr
->
data
.
non_resident
.
compression_unit
;
if
(
ctx
->
attr
->
data
.
non_resident
.
compression_unit
!=
4
)
{
ntfs_error
(
vi
->
i_sb
,
"Found "
"nonstandard compression unit "
"(%u instead of 4). Cannot "
"handle this. This might "
"indicate corruption so you "
"should run chkdsk."
,
ctx
->
attr
->
_ANR
(
compression_unit
));
ctx
->
attr
->
data
.
non_resident
.
compression_unit
);
err
=
-
EOPNOTSUPP
;
goto
unm_err_out
;
}
ni
->
_ICF
(
compression_block_size
)
=
1U
<<
(
ctx
->
attr
->
_ANR
(
compression_unit
)
+
ni
->
itype
.
compressed
.
block_size
=
1U
<<
(
ctx
->
attr
->
data
.
non_resident
.
compression_unit
+
vol
->
cluster_size_bits
);
ni
->
_ICF
(
compression_block_size_bits
)
=
ffs
(
ni
->
_ICF
(
compression_block_size
)
)
-
1
;
ni
->
itype
.
compressed
.
block_size_bits
=
ffs
(
ni
->
itype
.
compressed
.
block_size
)
-
1
;
}
if
(
ctx
->
attr
->
flags
&
ATTR_IS_ENCRYPTED
)
{
if
(
ctx
->
attr
->
flags
&
ATTR_COMPRESSION_MASK
)
{
...
...
@@ -980,7 +985,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
if
(
ctx
->
attr
->
flags
&
ATTR_IS_SPARSE
)
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 "
"attribute has non zero "
"lowest_vcn. Inode is corrupt. "
...
...
@@ -988,24 +993,18 @@ static int ntfs_read_locked_inode(struct inode *vi)
goto
unm_err_out
;
}
/* 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
(
ctx
->
attr
->
_ANR
(
initialized_size
));
ctx
->
attr
->
data
.
non_resident
.
initialized_size
);
ni
->
allocated_size
=
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
allocated_size
));
ctx
->
attr
->
data
.
non_resident
.
allocated_size
);
if
(
NInoCompressed
(
ni
))
{
ni
->
_ICF
(
compressed_size
)
=
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
compressed_size
));
if
(
vi
->
i_size
!=
ni
->
initialized_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!"
);
ni
->
itype
.
compressed
.
size
=
sle64_to_cpu
(
ctx
->
attr
->
data
.
non_resident
.
compressed_size
);
}
}
else
{
/* Resident attribute. */
/*
...
...
@@ -1015,7 +1014,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
* path. (Probably only affects truncate().)
*/
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:
/* We are done with the mft record, so we release it. */
...
...
@@ -1049,7 +1049,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
if
(
!
NInoCompressed
(
ni
))
vi
->
i_blocks
=
ni
->
allocated_size
>>
9
;
else
vi
->
i_blocks
=
ni
->
_ICF
(
compressed_size
)
>>
9
;
vi
->
i_blocks
=
ni
->
itype
.
compressed
.
size
>>
9
;
ntfs_debug
(
"Done."
);
return
0
;
...
...
@@ -1146,7 +1146,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
* read code paths.
*/
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
{
NInoSetNonResident
(
ni
);
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)
"corrupt file."
);
goto
unm_err_out
;
}
ni
->
_ICF
(
compression_block_clusters
)
=
1U
<<
ctx
->
attr
->
_ANR
(
compression_unit
);
if
(
ctx
->
attr
->
_ANR
(
compression_unit
)
!=
4
)
{
ni
->
itype
.
compressed
.
block_clusters
=
1U
<<
ctx
->
attr
->
data
.
non_resident
.
compression_unit
;
if
(
ctx
->
attr
->
data
.
non_resident
.
compression_unit
!=
4
)
{
ntfs_error
(
vi
->
i_sb
,
"Found "
"nonstandard compression unit "
"(%u instead of 4). Cannot "
"handle this. This might "
"indicate corruption so you "
"should run chkdsk."
,
ctx
->
attr
->
_ANR
(
compression_unit
));
ctx
->
attr
->
data
.
non_resident
.
compression_unit
);
err
=
-
EOPNOTSUPP
;
goto
unm_err_out
;
}
ni
->
_ICF
(
compression_block_size
)
=
1U
<<
(
ctx
->
attr
->
_ANR
(
compression_unit
)
+
ni
->
itype
.
compressed
.
block_size
=
1U
<<
(
ctx
->
attr
->
data
.
non_resident
.
compression_unit
+
vol
->
cluster_size_bits
);
ni
->
_ICF
(
compression_block_size_bits
)
=
ffs
(
ni
->
_ICF
(
compression_block_size
)
)
-
1
;
ni
->
itype
.
compressed
.
block_size_bits
=
ffs
(
ni
->
itype
.
compressed
.
block_size
)
-
1
;
}
if
(
ctx
->
attr
->
flags
&
ATTR_IS_ENCRYPTED
)
{
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)
}
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 "
"non-zero lowest_vcn. Inode is "
"corrupt. You should run chkdsk."
);
goto
unm_err_out
;
}
/* 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
(
ctx
->
attr
->
_ANR
(
initialized_size
)
);
ctx
->
attr
->
data
.
non_resident
.
initialized_size
);
ni
->
allocated_size
=
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
allocated_size
)
);
ctx
->
attr
->
data
.
non_resident
.
allocated_size
);
if
(
NInoCompressed
(
ni
))
{
ni
->
_ICF
(
compressed_size
)
=
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
compressed_size
));
if
(
vi
->
i_size
!=
ni
->
initialized_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."
);
ni
->
itype
.
compressed
.
size
=
sle64_to_cpu
(
ctx
->
attr
->
data
.
non_resident
.
compressed_size
);
}
}
...
...
@@ -1277,14 +1272,14 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
if
(
!
NInoCompressed
(
ni
))
vi
->
i_blocks
=
ni
->
allocated_size
>>
9
;
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
* attribute inode.
*/
igrab
(
base_vi
);
ni
->
_INE
(
base_ntfs_ino
)
=
base_ni
;
ni
->
ext
.
base_ntfs_ino
=
base_ni
;
ni
->
nr_extents
=
-
1
;
put_attr_search_ctx
(
ctx
);
...
...
@@ -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
* completion handler for directories.
*/
ni
->
_IDM
(
index_block_size
)
=
vol
->
mft_record_size
;
ni
->
_IDM
(
index_block_size_bits
)
=
vol
->
mft_record_size_bits
;
ni
->
itype
.
index
.
block_size
=
vol
->
mft_record_size
;
ni
->
itype
.
index
.
block_size_bits
=
vol
->
mft_record_size_bits
;
/* Very important! Needed to be able to call map_mft_record*(). */
vol
->
mft_ino
=
vi
;
...
...
@@ -1456,7 +1451,7 @@ void ntfs_read_inode_mount(struct inode *vi)
}
if
(
ctx
->
attr
->
non_resident
)
{
NInoSetAttrListNonResident
(
ni
);
if
(
ctx
->
attr
->
_ANR
(
lowest_vcn
)
)
{
if
(
ctx
->
attr
->
data
.
non_resident
.
lowest_vcn
)
{
ntfs_error
(
sb
,
"Attribute list has non zero "
"lowest_vcn. $MFT is corrupt. "
"You should run chkdsk."
);
...
...
@@ -1476,8 +1471,8 @@ void ntfs_read_inode_mount(struct inode *vi)
/* Now load the attribute list. */
if
((
err
=
load_attribute_list
(
vol
,
&
ni
->
attr_list_rl
,
ni
->
attr_list
,
ni
->
attr_list_size
,
sle64_to_cpu
(
ctx
->
attr
->
_ANR
(
initialized_size
)
))))
{
sle64_to_cpu
(
ctx
->
attr
->
data
.
non_resident
.
initialized_size
))))
{
ntfs_error
(
sb
,
"Failed to load attribute list "
"attribute with error code %i."
,
-
err
);
...
...
@@ -1485,9 +1480,9 @@ void ntfs_read_inode_mount(struct inode *vi)
}
}
else
/* if (!ctx.attr->non_resident) */
{
if
((
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)
)
+
ctx
->
attr
->
data
.
resident
.
value_offset
)
+
le32_to_cpu
(
ctx
->
attr
->
_ARA
(
value_length
)
)
>
ctx
->
attr
->
data
.
resident
.
value_length
)
>
(
u8
*
)
ctx
->
mrec
+
vol
->
mft_record_size
)
{
ntfs_error
(
sb
,
"Corrupt attribute list "
"attribute."
);
...
...
@@ -1495,9 +1490,9 @@ void ntfs_read_inode_mount(struct inode *vi)
}
/* Now copy the attribute list. */
memcpy
(
ni
->
attr_list
,
(
u8
*
)
ctx
->
attr
+
le16_to_cpu
(
ctx
->
attr
->
_ARA
(
value_offset
)
),
ctx
->
attr
->
data
.
resident
.
value_offset
),
le32_to_cpu
(
ctx
->
attr
->
_ARA
(
value_length
)
));
ctx
->
attr
->
data
.
resident
.
value_length
));
}
/* The attribute list is now setup in memory. */
/*
...
...
@@ -1606,7 +1601,7 @@ void ntfs_read_inode_mount(struct inode *vi)
if
(
!
next_vcn
)
{
u64
ll
;
if
(
attr
->
_ANR
(
lowest_vcn
)
)
{
if
(
attr
->
data
.
non_resident
.
lowest_vcn
)
{
ntfs_error
(
sb
,
"First extent of $DATA "
"attribute has non zero "
"lowest_vcn. $MFT is corrupt. "
...
...
@@ -1614,14 +1609,16 @@ void ntfs_read_inode_mount(struct inode *vi)
goto
put_err_out
;
}
/* Get the last vcn in the $DATA attribute. */
last_vcn
=
sle64_to_cpu
(
attr
->
_ANR
(
allocated_size
))
>>
vol
->
cluster_size_bits
;
last_vcn
=
sle64_to_cpu
(
attr
->
data
.
non_resident
.
allocated_size
)
>>
vol
->
cluster_size_bits
;
/* Fill in the inode size. */
vi
->
i_size
=
sle64_to_cpu
(
attr
->
_ANR
(
data_size
));
ni
->
initialized_size
=
sle64_to_cpu
(
attr
->
_ANR
(
initialized_size
));
vi
->
i_size
=
sle64_to_cpu
(
attr
->
data
.
non_resident
.
data_size
);
ni
->
initialized_size
=
sle64_to_cpu
(
attr
->
data
.
non_resident
.
initialized_size
);
ni
->
allocated_size
=
sle64_to_cpu
(
attr
->
_ANR
(
allocated_size
)
);
attr
->
data
.
non_resident
.
allocated_size
);
/* Set the number of mft records. */
ll
=
vi
->
i_size
>>
vol
->
mft_record_size_bits
;
/*
...
...
@@ -1687,7 +1684,7 @@ void ntfs_read_inode_mount(struct inode *vi)
}
/* 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
;
/* Only one extent or error, which we catch below. */
...
...
@@ -1695,7 +1692,8 @@ void ntfs_read_inode_mount(struct inode *vi)
break
;
/* 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 "
"attribute. Run chkdsk."
);
goto
put_err_out
;
...
...
@@ -1796,9 +1794,9 @@ void ntfs_put_inode(struct inode *vi)
ntfs_inode
*
ni
;
ni
=
NTFS_I
(
vi
);
if
(
NInoIndexAllocPresent
(
ni
)
&&
ni
->
_IDM
(
bmp_ino
)
)
{
iput
(
ni
->
_IDM
(
bmp_ino
)
);
ni
->
_IDM
(
bmp_ino
)
=
NULL
;
if
(
NInoIndexAllocPresent
(
ni
)
&&
ni
->
itype
.
index
.
bmp_ino
)
{
iput
(
ni
->
itype
.
index
.
bmp_ino
);
ni
->
itype
.
index
.
bmp_ino
=
NULL
;
}
}
return
;
...
...
@@ -1831,8 +1829,8 @@ void __ntfs_clear_inode(ntfs_inode *ni)
// FIXME: Handle dirty case for each extent inode!
for
(
i
=
0
;
i
<
ni
->
nr_extents
;
i
++
)
ntfs_clear_extent_inode
(
ni
->
_INE
(
extent_ntfs_inos
)
[
i
]);
kfree
(
ni
->
_INE
(
extent_ntfs_inos
)
);
ntfs_clear_extent_inode
(
ni
->
ext
.
extent_ntfs_inos
[
i
]);
kfree
(
ni
->
ext
.
extent_ntfs_inos
);
}
/* Free all alocated memory. */
down_write
(
&
ni
->
run_list
.
lock
);
...
...
@@ -1888,9 +1886,9 @@ void ntfs_clear_big_inode(struct inode *vi)
if
(
NInoAttr
(
ni
))
{
/* Release the base inode if we are holding it. */
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
->
_INE
(
base_ntfs_ino
)
=
NULL
;
ni
->
ext
.
base_ntfs_ino
=
NULL
;
}
}
return
;
...
...
fs/ntfs/inode.h
View file @
f86096b8
...
...
@@ -2,8 +2,8 @@
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
* the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (c) 2002 Richard Russon
.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* 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
...
...
@@ -93,23 +93,21 @@ struct _ntfs_inode {
struct
{
/* It is a directory or $MFT. */
struct
inode
*
bmp_ino
;
/* Attribute inode for the
directory index $BITMAP. */
u32
index_block_size
;
/* Size of an index block. */
u32
index_vcn_size
;
/* Size of a vcn in this
u32
block_size
;
/* Size of an index block. */
u32
vcn_size
;
/* Size of a vcn in this
directory index. */
u8
index_block_size_bits
;
/* Log2 of the above. */
u8
index_
vcn_size_bits
;
/* Log2 of the above. */
}
SN
(
idm
)
;
u8
block_size_bits
;
/* Log2 of the above. */
u8
vcn_size_bits
;
/* Log2 of the above. */
}
index
;
struct
{
/* It is a compressed file or fake inode. */
s64
compressed_size
;
/* Copy from $DATA. */
u32
compression_block_size
;
/* Size of a compression
block (cb). */
u8
compression_block_size_bits
;
/* Log2 of the size of
a cb. */
u8
compression_block_clusters
;
/* Number of clusters
per compression
block. */
}
SN
(
icf
);
}
SN
(
idc
);
s64
size
;
/* Copy of compressed_size from
$DATA. */
u32
block_size
;
/* Size of a compression block
(cb). */
u8
block_size_bits
;
/* Log2 of the size of a cb. */
u8
block_clusters
;
/* Number of clusters per cb. */
}
compressed
;
}
itype
;
struct
semaphore
extent_lock
;
/* Lock for accessing/modifying the
below . */
s32
nr_extents
;
/* For a base mft record, the number of attached extent
...
...
@@ -126,13 +124,9 @@ struct _ntfs_inode {
record. For fake inodes, the
real (base) inode to which
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.
* (f) = files only, (d) = directories only, (a) = attributes/fake inodes only
...
...
fs/ntfs/layout.h
View file @
f86096b8
...
...
@@ -2,8 +2,8 @@
* layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (
C) 2002 Richard Russon.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (
c) 2002 Richard Russon
*
* 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
...
...
@@ -296,7 +296,11 @@ typedef u64 MFT_REF;
*/
typedef
struct
{
/*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.
Changed every time the record is modified. */
/* 16*/
u16
sequence_number
;
/* Number of times this mft record has been
...
...
@@ -360,8 +364,6 @@ typedef struct {
*/
}
__attribute__
((
__packed__
))
MFT_RECORD
;
#define _MNR(X) SC(mnr,X)
/*
* System defined attributes (32-bit). Each attribute type has a corresponding
* attribute name (Unicode string of maximum 64 character length) as described
...
...
@@ -612,10 +614,10 @@ typedef struct {
have a name present as this might
not have a length of a multiple
of 8-bytes. */
/* 22 */
RESIDENT_ATTR_FLAGS
resident_
flags
;
/* See above. */
/* 23 */
s8
reserved
R
;
/* Reserved/alignment to 8-byte
/* 22 */
RESIDENT_ATTR_FLAGS
flags
;
/* See above. */
/* 23 */
s8
reserved
;
/* Reserved/alignment to 8-byte
boundary. */
}
SN
(
ara
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
resident
;
/* Non-resident attributes. */
struct
{
/* 16*/
VCN
lowest_vcn
;
/* Lowest valid virtual cluster number
...
...
@@ -641,7 +643,7 @@ typedef struct {
compressed. (This effectively limits the
compression unit size to be a power of two
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
be difficult to keep them up-to-date.*/
/* 40*/
s64
allocated_size
;
/* Byte size of disk space
...
...
@@ -665,13 +667,10 @@ typedef struct {
cluster size. Represents the actual amount of
disk space being used on the disk. */
/* sizeof(compressed attr) = 72*/
}
SN
(
anr
)
__attribute__
((
__packed__
))
;
}
SN
(
aua
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
non_resident
;
}
__attribute__
((
__packed__
))
data
;
}
__attribute__
((
__packed__
))
ATTR_RECORD
;
#define _ARA(X) SC(aua.ara,X)
#define _ANR(X) SC(aua.anr,X)
typedef
ATTR_RECORD
ATTR_REC
;
/*
...
...
@@ -763,11 +762,13 @@ typedef struct {
disabled altogether for speed. */
/* 32*/
FILE_ATTR_FLAGS
file_attributes
;
/* Flags describing the file. */
/* 36*/
union
{
/* NTFS 1.2 (and previous, presumably) */
/* 36 */
u8
reserved12
[
12
];
/* Reserved/alignment to 8-byte
/* NTFS 1.2 */
struct
{
/* 36*/
u8
reserved12
[
12
];
/* Reserved/alignment to 8-byte
boundary. */
/* sizeof() = 48 bytes */
/* NTFS 3.0 */
}
__attribute__
((
__packed__
))
v1
;
/* sizeof() = 48 bytes */
/* NTFS 3.x */
struct
{
/*
* If a volume has been upgraded from a previous NTFS version, then these
...
...
@@ -777,12 +778,12 @@ typedef struct {
* the fields are present. Maybe just check like this:
* if (resident.ValueLength < sizeof(STANDARD_INFORMATION)) {
* Assume NTFS 1.2- format.
* If (volume version is 3.
0+
)
* Upgrade attribute to NTFS 3.
0
format.
* If (volume version is 3.
x
)
* Upgrade attribute to NTFS 3.
x
format.
* else
* Use NTFS 1.2- format for access.
* } 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
* arbitrarily large values thus spoiling this check. - But chkdsk probably
* views that as a corruption, assuming that it behaves like this for all
...
...
@@ -818,13 +819,11 @@ typedef struct {
partition. This, in contrast to disabling the
journal is a very fast process, so the user
won't even notice it. */
}
SN
(
svs
)
;
}
SN
(
sei
);
/* sizeof() = 72 bytes (NTFS 3.0) */
}
__attribute__
((
__packed__
))
v3
;
/* sizeof() = 72 bytes (NTFS 3.x) */
}
__attribute__
((
__packed__
))
ver
;
}
__attribute__
((
__packed__
))
STANDARD_INFORMATION
;
#define _SVS(X) SC(sei.svs,X)
/*
* Attribute: Attribute list (0x20).
*
...
...
@@ -956,21 +955,20 @@ typedef struct {
pack the extended attributes
(EAs), if such are present.*/
/* 3e*/
u16
reserved
;
/* Reserved for alignment. */
}
SN
(
fea
)
__attribute__
((
__packed__
));
}
__attribute__
((
__packed__
))
ea
;
/* 3c*/
struct
{
/* 3c*/
u32
reparse_point_tag
;
/* Type of reparse point,
present only in reparse
points and only if there are
no EAs. */
}
SN
(
fer
)
__attribute__
((
__packed__
));
}
__attribute__
((
__packed__
))
rp
;
}
__attribute__
((
__packed__
))
type
;
/* 40*/
u8
file_name_length
;
/* Length of file name in
(Unicode) characters. */
/* 41*/
FILE_NAME_TYPE_FLAGS
file_name_type
;
/* Namespace of the file name.*/
/* 42*/
uchar_t
file_name
[
0
];
/* File name in Unicode. */
}
__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
* 128-bit value consisting of one group of eight hexadecimal digits, followed
...
...
@@ -1008,9 +1006,9 @@ typedef struct {
GUID
birth_volume_id
;
GUID
birth_object_id
;
GUID
domain_id
;
}
SN
(
obv
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
origin
;
u8
extended_info
[
48
];
}
SN
(
oei
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
opt
;
}
__attribute__
((
__packed__
))
OBJ_ID_INDEX_DATA
;
/*
...
...
@@ -1032,13 +1030,11 @@ typedef struct {
GUID
birth_object_id
;
/* Unique id of file when it was
first created. */
GUID
domain_id
;
/* Reserved, zero. */
}
SN
(
obv
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
origin
;
u8
extended_info
[
48
];
}
SN
(
oei
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
opt
;
}
__attribute__
((
__packed__
))
OBJECT_ID_ATTR
;
#define _OBV(X) SC(oei.obv,X)
/*
* The pre-defined IDENTIFIER_AUTHORITIES used as SID_IDENTIFIER_AUTHORITY in
* the SID structure (see below).
...
...
@@ -1174,14 +1170,12 @@ typedef enum { /* Identifier authority. */
*/
typedef
union
{
struct
{
u32
low
_part
;
/* Low 32-bits. */
u16
high
_part
;
/* High 16-bits. */
}
SN
(
sia
)
__attribute__
((
__packed__
))
;
u32
low
;
/* Low 32-bits. */
u16
high
;
/* High 16-bits. */
}
__attribute__
((
__packed__
))
parts
;
u8
value
[
6
];
/* Value as individual bytes. */
}
__attribute__
((
__packed__
))
SID_IDENTIFIER_AUTHORITY
;
#define _SIA(X) SC(sia,X)
/*
* The SID structure is a variable-length structure used to uniquely identify
* users or groups. SID stands for security identifier.
...
...
@@ -1287,9 +1281,10 @@ typedef enum {
* data depends on the ACE type.
*/
typedef
struct
{
ACE_TYPES
type
;
/* Type of the ACE. */
ACE_FLAGS
flags
;
/* Flags describing the ACE. */
u16
size
;
/* Size in bytes of the ACE. */
/*Ofs*/
/* 0*/
ACE_TYPES
type
;
/* Type of the ACE. */
/* 1*/
ACE_FLAGS
flags
;
/* Flags describing the ACE. */
/* 2*/
u16
size
;
/* Size in bytes of the ACE. */
}
__attribute__
((
__packed__
))
ACE_HEADER
;
/*
...
...
@@ -1446,12 +1441,15 @@ typedef struct {
* ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE
*/
typedef
struct
{
ACE_HEADER
SN
(
aah
);
/* The ACE header. */
ACCESS_MASK
mask
;
/* Access mask associated with the ACE. */
SID
sid
;
/* The SID associated with the ACE. */
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
ACE_TYPES
type
;
/* Type of the ACE. */
ACE_FLAGS
flags
;
/* Flags describing the ACE. */
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
,
SYSTEM_AUDIT_ACE
,
SYSTEM_ALARM_ACE
;
#define _AAH(X) SC(aah,X)
/*
* The object ACE flags (32-bit).
...
...
@@ -1462,12 +1460,17 @@ typedef enum {
}
OBJECT_ACE_FLAGS
;
typedef
struct
{
ACE_HEADER
SN
(
aah
);
/* The ACE_HEADER. */
ACCESS_MASK
mask
;
/* Access mask associated with the ACE. */
OBJECT_ACE_FLAGS
flags
;
/* Flags describing the object ACE. */
GUID
object_type
;
GUID
inherited_object_type
;
SID
sid
;
/* The SID associated with the ACE. */
/* 0 ACE_HEADER; -- Unfolded here as gcc doesn't like unnamed structs. */
ACE_TYPES
type
;
/* Type of the ACE. */
ACE_FLAGS
flags
;
/* Flags describing the ACE. */
u16
size
;
/* Size in bytes of the ACE. */
/* 4*/
ACCESS_MASK
mask
;
/* Access mask associated with the ACE. */
/* 8*/
OBJECT_ACE_FLAGS
object_flags
;
/* Flags describing the object ACE. */
/* 12*/
GUID
object_type
;
/* 28*/
GUID
inherited_object_type
;
/* 44*/
SID
sid
;
/* The SID associated with the ACE. */
}
__attribute__
((
__packed__
))
ACCESS_ALLOWED_OBJECT_ACE
,
ACCESS_DENIED_OBJECT_ACE
,
SYSTEM_AUDIT_OBJECT_ACE
,
...
...
@@ -1711,13 +1714,17 @@ typedef struct {
* $SDS data stream and the second copy will be at offset 0x451d0.
*/
typedef
struct
{
SECURITY_DESCRIPTOR_HEADER
SN
(
sdh
);
/* The security descriptor header. */
SECURITY_DESCRIPTOR_RELATIVE
sid
;
/* The self-relative security
/*Ofs*/
/* 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. */
}
__attribute__
((
__packed__
))
SDS_ENTRY
;
#define _SDH(X) SC(sdh,X)
/*
* The index entry key used in the $SII index. The collation type is
* COLLATION_NTOFS_ULONG.
...
...
@@ -1888,7 +1895,11 @@ typedef struct {
* index entries (INDEX_ENTRY structures), as described by the INDEX_HEADER.
*/
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
modification of this index block. */
/* 16*/
VCN
index_block_vcn
;
/* Virtual cluster number of the index block.
...
...
@@ -1909,8 +1920,6 @@ typedef struct {
*/
}
__attribute__
((
__packed__
))
INDEX_BLOCK
;
#define _INR(X) SC(inr,X)
typedef
INDEX_BLOCK
INDEX_ALLOCATION
;
/*
...
...
@@ -2014,19 +2023,21 @@ typedef enum {
* This the index entry header (see below).
*/
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
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). */
}
SN
(
iev
)
__attribute__
((
__packed__
))
;
}
SN
(
iif
)
__attribute__
((
__packed__
))
;
}
__attribute__
((
__packed__
))
vi
;
}
__attribute__
((
__packed__
))
data
;
/* 8*/
u16
length
;
/* Byte size of this index entry, multiple of
8-bytes. */
/* 10*/
u16
key_length
;
/* Byte size of the key value, which is in the
...
...
@@ -2037,9 +2048,6 @@ typedef struct {
/* sizeof() = 16 bytes */
}
__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
* structure. Together they make up a complete index. The index follows either
...
...
@@ -2048,7 +2056,31 @@ typedef struct {
* NOTE: Before NTFS 3.0 only filename attributes were indexed.
*/
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
if INDEX_ENTRY_END bit in flags is not set. NOTE: On
NTFS versions before 3.0 the only valid key is the
...
...
@@ -2060,7 +2092,8 @@ typedef struct {
GUID
object_id
;
/* $O index in FILE_Extend/$ObjId: The
object_id of the mft record found in
the data part of the index. */
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 of the owner of the user_id. */
u32
owner_id
;
/* $Q index in FILE_Extend/$Quota:
...
...
@@ -2083,9 +2116,6 @@ typedef struct {
// where sizeof(VCN) can be hardcoded as 8 if wanted. */
}
__attribute__
((
__packed__
))
INDEX_ENTRY
;
#define _IEH(X) SC(ieh,X)
#define _IRI(X) SC(key.iri,X)
/*
* Attribute: Bitmap (0xb0).
*
...
...
fs/ntfs/mft.c
View file @
f86096b8
/**
* mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (c) 2002 Richard Russon
.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* 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
...
...
@@ -39,18 +39,18 @@ static void __format_mft_record(MFT_RECORD *m, const int size,
ATTR_RECORD
*
a
;
memset
(
m
,
0
,
size
);
m
->
_MNR
(
magic
)
=
magic_FILE
;
m
->
magic
=
magic_FILE
;
/* Aligned to 2-byte boundary. */
m
->
_MNR
(
usa_ofs
)
=
cpu_to_le16
((
sizeof
(
MFT_RECORD
)
+
1
)
&
~
1
);
m
->
_MNR
(
usa_count
)
=
cpu_to_le16
(
size
/
NTFS_BLOCK_SIZE
+
1
);
m
->
usa_ofs
=
cpu_to_le16
((
sizeof
(
MFT_RECORD
)
+
1
)
&
~
1
);
m
->
usa_count
=
cpu_to_le16
(
size
/
NTFS_BLOCK_SIZE
+
1
);
/* Set the update sequence number to 1. */
*
(
u16
*
)((
char
*
)
m
+
((
sizeof
(
MFT_RECORD
)
+
1
)
&
~
1
))
=
cpu_to_le16
(
1
);
m
->
lsn
=
cpu_to_le64
(
0LL
);
m
->
sequence_number
=
cpu_to_le16
(
1
);
m
->
link_count
=
cpu_to_le16
(
0
);
/* Aligned to 8-byte boundary. */
m
->
attrs_offset
=
cpu_to_le16
((
le16_to_cpu
(
m
->
_MNR
(
usa_ofs
)
)
+
(
le16_to_cpu
(
m
->
_MNR
(
usa_count
)
)
<<
1
)
+
7
)
&
~
7
);
m
->
attrs_offset
=
cpu_to_le16
((
le16_to_cpu
(
m
->
usa_ofs
)
+
(
le16_to_cpu
(
m
->
usa_count
)
<<
1
)
+
7
)
&
~
7
);
m
->
flags
=
cpu_to_le16
(
0
);
/*
* 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,
*/
down
(
&
base_ni
->
extent_lock
);
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
++
)
{
if
(
mft_no
!=
extent_nis
[
i
]
->
mft_no
)
continue
;
...
...
@@ -374,7 +374,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
ni
->
vol
=
base_ni
->
vol
;
ni
->
seq_no
=
seq_no
;
ni
->
nr_extents
=
-
1
;
ni
->
_INE
(
base_ntfs_ino
)
=
base_ni
;
ni
->
ext
.
base_ntfs_ino
=
base_ni
;
/* Now map the record. */
m
=
map_mft_record
(
ni
);
if
(
unlikely
(
IS_ERR
(
m
)))
{
...
...
@@ -404,14 +404,14 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
m
=
ERR_PTR
(
-
ENOMEM
);
goto
unm_err_out
;
}
if
(
base_ni
->
_INE
(
extent_ntfs_inos
)
)
{
memcpy
(
tmp
,
base_ni
->
_INE
(
extent_ntfs_inos
)
,
new_size
-
if
(
base_ni
->
ext
.
extent_ntfs_inos
)
{
memcpy
(
tmp
,
base_ni
->
ext
.
extent_ntfs_inos
,
new_size
-
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
);
atomic_dec
(
&
base_ni
->
count
);
ntfs_debug
(
"Done 2."
);
...
...
fs/ntfs/namei.c
View file @
f86096b8
...
...
@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. 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
* 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)
a
=
ctx
->
attr
;
if
(
a
->
non_resident
||
a
->
flags
)
goto
eio_err_out
;
val_len
=
le32_to_cpu
(
a
->
_ARA
(
value_length
)
);
if
(
le16_to_cpu
(
a
->
_ARA
(
value_offset
))
+
val_len
>
le32_to_cpu
(
a
->
length
))
val_len
=
le32_to_cpu
(
a
->
data
.
resident
.
value_length
);
if
(
le16_to_cpu
(
a
->
data
.
resident
.
value_offset
)
+
val_len
>
le32_to_cpu
(
a
->
length
))
goto
eio_err_out
;
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
)
+
sizeof
(
FILE_NAME_ATTR
))
>
val_len
)
goto
eio_err_out
;
...
...
fs/ntfs/super.c
View file @
f86096b8
/*
* super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001
,2002 Anton Altaparmakov.
* Copyright (c) 2001,2002 Richard Russon
.
* Copyright (c) 2001
-2003 Anton Altaparmakov
* Copyright (c) 2001,2002 Richard Russon
*
* 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
...
...
@@ -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.
*/
ll
=
sle64_to_cpu
(
b
->
number_of_sectors
)
>>
sectors_per_cluster_bits
;
if
((
u64
)
ll
>=
1ULL
<<
(
sizeof
(
unsigned
long
)
*
8
))
{
ntfs_error
(
vol
->
sb
,
"Cannot handle %i-bit clusters. Sorry."
,
sizeof
(
unsigned
long
)
*
4
);
if
((
u64
)
ll
>=
1ULL
<<
32
)
{
ntfs_error
(
vol
->
sb
,
"Cannot handle 64-bit clusters. Sorry."
);
return
FALSE
;
}
vol
->
nr_clusters
=
ll
;
...
...
@@ -884,10 +883,10 @@ static BOOL load_system_files(ntfs_volume *vol)
goto
iput_volume_failed
;
}
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. */
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
))
goto
err_put_vol
;
/* Setup volume flags and version. */
...
...
@@ -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
* @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
* found. This means we return an underestimate on error.
* The only particularity is that clusters beyond the end of the logical ntfs
* 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
)
{
s64
nr_free
=
vol
->
nr_clusters
;
u32
*
kaddr
;
struct
address_space
*
mapping
=
vol
->
lcnbmp_ino
->
i_mapping
;
filler_t
*
readpage
=
(
filler_t
*
)
mapping
->
a_ops
->
readpage
;
struct
page
*
page
;
unsigned
long
index
,
max_index
;
unsigned
int
max_size
,
i
;
s64
nr_free
=
0LL
;
u32
*
b
;
unsigned
int
max_size
;
ntfs_debug
(
"Entering."
);
/* Serialize accesses to the cluster bitmap. */
down_read
(
&
vol
->
lcnbmp_lock
);
/*
* 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. */
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
);
for
(
index
=
0UL
;
index
<
max_index
;)
{
handle_partial_page:
for
(
index
=
0UL
;
index
<
max_index
;
index
++
)
{
unsigned
int
i
;
/*
* 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
,
page
=
read_cache_page
(
mapping
,
index
,
(
filler_t
*
)
readpage
,
NULL
);
/* Ignore pages which errored synchronously. */
if
(
IS_ERR
(
page
))
{
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
;
}
wait_on_page_locked
(
page
);
/* Ignore pages which errored asynchronously. */
if
(
!
PageUptodate
(
page
))
{
ntfs_debug
(
"Async read_cache_page() error. Skipping "
"page (index 0x%lx)."
,
index
-
1
);
/* Ignore pages which errored asynchronously. */
"page (index 0x%lx)."
,
index
);
page_cache_release
(
page
);
nr_free
-=
PAGE_CACHE_SIZE
*
8
;
continue
;
}
b
=
(
u32
*
)
kmap
(
page
);
/* For each 4 bytes, add up the number zero bits. */
kaddr
=
(
u32
*
)
kmap_atomic
(
page
,
KM_USER0
);
/*
* 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
++
)
nr_free
+=
(
s64
)(
32
-
hweight32
(
b
[
i
])
);
kunmap
(
page
);
nr_free
-=
(
s64
)
hweight32
(
kaddr
[
i
]
);
kunmap
_atomic
(
kaddr
,
KM_USER0
);
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
* page
.
* Fixup for eventual bits outside logical ntfs volume (see function
* description above)
.
*/
max_size
=
((((
vol
->
nr_clusters
+
7
)
>>
3
)
&
~
PAGE_CACHE_MASK
)
+
3
)
>>
2
;
/* 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
);
if
(
vol
->
nr_clusters
&
63
)
nr_free
+=
64
-
(
vol
->
nr_clusters
&
63
);
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."
);
return
nr_free
;
}
...
...
@@ -1141,64 +1155,81 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
* @vol: ntfs volume for which to obtain free inode count
*
* 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
* found. This means we return an underestimate on error.
* If any pages cannot be read we assume all mft records in the erroring pages
* 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.
*/
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
;
unsigned
long
index
,
max_index
,
nr_free
=
0
;
unsigned
int
max_size
,
i
;
u32
*
b
;
unsigned
long
index
,
max_index
;
unsigned
int
max_size
;
mapping
=
vol
->
mftbmp_ino
->
i_mapping
;
ntfs_debug
(
"Entering."
)
;
/*
* Convert the number of bits into bytes rounded up to a multiple of 8
* bytes, then convert into multiples of PAGE_CACHE_SIZE.
* Convert the number of bits into bytes rounded up, then convert into
* 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. */
max_size
=
PAGE_CACHE_SIZE
>>
2
;
ntfs_debug
(
"Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
"0x%x."
,
max_index
,
max_size
);
for
(
index
=
0UL
;
index
<
max_index
;)
{
handle_partial_page:
page
=
ntfs_map_page
(
mapping
,
index
++
);
for
(
index
=
0UL
;
index
<
max_index
;
index
++
)
{
unsigned
int
i
;
/*
* 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
))
{
ntfs_debug
(
"ntfs_map_page() error. Skipping page "
"(index 0x%lx)."
,
index
-
1
);
ntfs_debug
(
"Sync read_cache_page() error. Skipping "
"page (index 0x%lx)."
,
index
);
nr_free
-=
PAGE_CACHE_SIZE
*
8
;
continue
;
}
b
=
(
u32
*
)
page_address
(
page
);
/* For each 4 bytes, add up the number of zero bits. */
for
(
i
=
0
;
i
<
max_size
;
i
++
)
nr_free
+=
32
-
hweight32
(
b
[
i
]);
ntfs_unmap_page
(
page
);
wait_on_page_locked
(
page
);
/* Ignore pages which errored asynchronously. */
if
(
!
PageUptodate
(
page
))
{
ntfs_debug
(
"Async read_cache_page() error. Skipping "
"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
* page.
* 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().
*/
max_size
=
((((((
vol
->
nr_mft_records
+
7
)
>>
3
)
+
7
)
&
~
7
)
&
~
PAGE_CACHE_MASK
)
+
3
)
>>
2
;
/* If there is a partial page go back and do it. */
if
(
max_size
)
{
/* Compensate for out of bounds zero bits. */
if
((
i
=
vol
->
nr_mft_records
&
31
))
nr_free
-=
32
-
i
;
ntfs_debug
(
"Handling partial page, max_size = 0x%x"
,
max_size
);
goto
handle_partial_page
;
}
}
ntfs_debug
(
"Finished reading $MFT/$BITMAP, last index = 0x%lx"
,
for
(
i
=
0
;
i
<
max_size
;
i
++
)
nr_free
-=
(
s64
)
hweight32
(
kaddr
[
i
]);
kunmap_atomic
(
kaddr
,
KM_USER0
);
page_cache_release
(
page
);
}
ntfs_debug
(
"Finished reading $MFT/$BITMAP, last index = 0x%lx."
,
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
;
}
...
...
@@ -1761,7 +1792,7 @@ static void __exit exit_ntfs_fs(void)
}
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"
);
#ifdef DEBUG
MODULE_PARM
(
debug_msgs
,
"i"
);
...
...
fs/ntfs/unistr.c
View file @
f86096b8
/*
* 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
* 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,
const
int
err_val
,
const
IGNORE_CASE_BOOL
ic
,
const
uchar_t
*
upcase
,
const
u32
upcase_len
)
{
u32
cnt
;
const
u32
min_len
=
min_t
(
const
u32
,
name1_len
,
name2_len
);
u32
cnt
,
min_len
;
uchar_t
c1
,
c2
;
min_len
=
name1_len
;
if
(
name1_len
>
name2_len
)
min_len
=
name2_len
;
for
(
cnt
=
0
;
cnt
<
min_len
;
++
cnt
)
{
c1
=
le16_to_cpu
(
*
name1
++
);
c2
=
le16_to_cpu
(
*
name2
++
);
...
...
fs/ntfs/upcase.c
View file @
f86096b8
...
...
@@ -2,8 +2,8 @@
* upcase.c - Generate the full NTFS Unicode upcase table in little endian.
* Part of the Linux-NTFS project.
*
* Copyright (
C
) 2001 Richard Russon <ntfs@flatcap.org>
* Copyright (c) 2001
,2002
Anton Altaparmakov
* Copyright (
c
) 2001 Richard Russon <ntfs@flatcap.org>
* Copyright (c) 2001
-2003
Anton Altaparmakov
*
* Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov.
* Modified for kernel inclusion 10 September 2001 by Anton Altparmakov.
...
...
@@ -28,7 +28,7 @@
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
},
{
0x00E0
,
0x00F7
,
-
32
},
{
0x045E
,
0x0460
,
-
80
},
{
0x1F72
,
0x1F76
,
86
},
{
0x00F8
,
0x00FF
,
-
32
},
{
0x0561
,
0x0587
,
-
48
},
{
0x1F76
,
0x1F78
,
100
},
...
...
@@ -45,7 +45,7 @@ uchar_t *generate_default_upcase(void)
{
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
},
{
0x0132
,
0x0137
},
{
0x01B3
,
0x01B7
},
{
0x0460
,
0x0481
},
{
0x04D0
,
0x04EB
},
{
0x0139
,
0x0149
},
{
0x01CD
,
0x01DD
},
{
0x0490
,
0x04BF
},
{
0x04EE
,
0x04F5
},
...
...
@@ -55,7 +55,7 @@ uchar_t *generate_default_upcase(void)
{
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
},
{
0x0183
,
0x0182
},
{
0x01B0
,
0x01AF
},
{
0x0253
,
0x0181
},
{
0x026F
,
0x019C
},
{
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