Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2d4d6186
Commit
2d4d6186
authored
Jul 04, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-ntfs.bkbits.net/ntfs-tng-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
e21a85a7
1d209b00
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
514 additions
and
357 deletions
+514
-357
Documentation/filesystems/ntfs.txt
Documentation/filesystems/ntfs.txt
+3
-0
fs/ntfs/ChangeLog
fs/ntfs/ChangeLog
+11
-0
fs/ntfs/Makefile
fs/ntfs/Makefile
+1
-1
fs/ntfs/attrib.c
fs/ntfs/attrib.c
+487
-346
fs/ntfs/mst.c
fs/ntfs/mst.c
+2
-2
fs/ntfs/super.c
fs/ntfs/super.c
+10
-8
No files found.
Documentation/filesystems/ntfs.txt
View file @
2d4d6186
...
...
@@ -247,6 +247,9 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.14:
- Internal changes improving run list merging code and minor locking
change to not rely on BKL in ntfs_statfs().
2.0.13:
- Internal changes towards using iget5_locked() in preparation for
fake inodes and small cleanups to ntfs_volume structure.
...
...
fs/ntfs/ChangeLog
View file @
2d4d6186
...
...
@@ -28,6 +28,17 @@ ToDo:
- Enable NFS exporting of NTFS.
- Use fake inodes for address space i/o.
2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes.
- Change fs/ntfs/super.c::ntfs_statfs() to not rely on BKL by moving
the locking out of super.c::get_nr_free_mft_records() and taking and
dropping the mftbmp_lock rw_semaphore in ntfs_statfs() itself.
- Bring attribute run list merging code (fs/ntfs/attrib.c) in sync with
current userspace ntfs library code. This means that if a merge
fails the original run lists are always left unmodified instead of
being silently corrupted.
- Misc typo fixes.
2.0.13 - Use iget5_locked() in preparation for fake inodes and small cleanups.
- Remove nr_mft_bits and the now superfluous union with nr_mft_records
...
...
fs/ntfs/Makefile
View file @
2d4d6186
...
...
@@ -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.0.1
3
\"
EXTRA_CFLAGS
=
-DNTFS_VERSION
=
\"
2.0.1
4
\"
ifeq
($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS
+=
-DDEBUG
...
...
fs/ntfs/attrib.c
View file @
2d4d6186
...
...
@@ -27,338 +27,433 @@
/* Temporary helper functions -- might become macros */
/**
* rl_mm - run_list memmove
*
ntfs_
rl_mm - run_list memmove
*
* It is up to the caller to serialize access to the run list @base.
*/
static
inline
void
rl_mm
(
run_list_element
*
base
,
int
dst
,
int
src
,
int
size
)
static
inline
void
ntfs_rl_mm
(
run_list_element
*
base
,
int
dst
,
int
src
,
int
size
)
{
if
(
(
dst
!=
src
)
&&
(
size
>
0
))
memmove
(
base
+
dst
,
base
+
src
,
size
*
sizeof
(
*
base
));
if
(
likely
((
dst
!=
src
)
&&
(
size
>
0
)
))
memmove
(
base
+
dst
,
base
+
src
,
size
*
sizeof
(
*
base
));
}
/**
* rl_mc - run_list memory copy
*
ntfs_
rl_mc - run_list memory copy
*
* It is up to the caller to serialize access to the run lists @dstbase and
* @srcbase.
*/
static
inline
void
rl_mc
(
run_list_element
*
dstbase
,
int
dst
,
static
inline
void
ntfs_
rl_mc
(
run_list_element
*
dstbase
,
int
dst
,
run_list_element
*
srcbase
,
int
src
,
int
size
)
{
if
(
size
>
0
)
memcpy
(
dstbase
+
dst
,
srcbase
+
src
,
size
*
sizeof
(
*
dstbase
));
if
(
likely
(
size
>
0
)
)
memcpy
(
dstbase
+
dst
,
srcbase
+
src
,
size
*
sizeof
(
*
dstbase
));
}
/**
* ntfs_rl_realloc - Reallocate memory for run_lists
* @
orig: The original memory allocation
* @old
: The number of run_lists in the origina
l
* @new
: The number of run_lis
ts we need space for
* @
rl: original run list
* @old
_size: number of run list elements in the original run list @r
l
* @new
_size: number of run list elemen
ts we need space for
*
* As the run_lists grow, more memory will be required. To prevent the
* kernel having to allocate and reallocate large numbers of small bits of
* memory, this function returns and entire page of memory.
*
* It is up to the caller to serialize access to the run list @
orig
.
* It is up to the caller to serialize access to the run list @
rl
.
*
* N.B. If the new allocation doesn't require a different number of pages in
* memory, the function will return the original pointer.
*
*
Return: Pointer The newly allocated, or recycled,
memory.
*
*
Errors: -ENOMEM,
Not enough memory to allocate run list array.
*
-EINVAL,
Invalid parameters were passed in.
*
On success, return a pointer to the newly allocated, or recycled,
memory.
*
On error, return -errno. The following error codes are defined:
*
-ENOMEM -
Not enough memory to allocate run list array.
*
-EINVAL -
Invalid parameters were passed in.
*/
static
inline
run_list_element
*
ntfs_rl_realloc
(
run_list_element
*
orig
,
int
old
,
int
new
)
static
inline
run_list_element
*
ntfs_rl_realloc
(
run_list_element
*
rl
,
int
old
_size
,
int
new_size
)
{
run_list_element
*
nrl
;
run_list_element
*
n
ew_
rl
;
old
=
PAGE_ALIGN
(
old
*
sizeof
(
*
orig
));
new
=
PAGE_ALIGN
(
new
*
sizeof
(
*
orig
));
if
(
old
==
new
)
return
orig
;
old
_size
=
PAGE_ALIGN
(
old_size
*
sizeof
(
*
rl
));
new
_size
=
PAGE_ALIGN
(
new_size
*
sizeof
(
*
rl
));
if
(
old
_size
==
new_size
)
return
rl
;
n
rl
=
ntfs_malloc_nofs
(
new
);
if
(
!
nrl
)
return
ERR_PTR
(
-
ENOMEM
);
n
ew_rl
=
ntfs_malloc_nofs
(
new_size
);
if
(
unlikely
(
!
new_rl
)
)
return
ERR_PTR
(
-
ENOMEM
);
if
(
orig
)
{
memcpy
(
nrl
,
orig
,
min
(
old
,
new
));
ntfs_free
(
orig
);
if
(
likely
(
rl
!=
NULL
))
{
if
(
unlikely
(
old_size
>
new_size
))
old_size
=
new_size
;
memcpy
(
new_rl
,
rl
,
old_size
);
ntfs_free
(
rl
);
}
return
nrl
;
return
n
ew_
rl
;
}
/**
* ntfs_
rl_merge - Join together two run_lists
* @
one: The first run_list and destination
* @
two: The second run_li
st
* ntfs_
are_rl_mergeable - test if two run lists can be joined together
* @
dst: original run list
* @
src: new run list to test for mergeability with @d
st
*
*
If possible merge together two run_lists.
For this, their VCNs and LCNs
*
Test if two run lists can be joined together.
For this, their VCNs and LCNs
* must be adjacent.
*
* It is up to the caller to serialize access to the run lists @
one and @two
.
* It is up to the caller to serialize access to the run lists @
dst and @src
.
*
* Return: TRUE Success, the run
_lists were merged
* FALSE Failure, the run
_lists were not merged
* Return: TRUE Success, the run
lists can be merged.
* FALSE Failure, the run
lists cannot be merged.
*/
static
inline
BOOL
ntfs_rl_merge
(
run_list_element
*
one
,
run_list_element
*
two
)
static
inline
BOOL
ntfs_are_rl_mergeable
(
run_list_element
*
dst
,
run_list_element
*
src
)
{
BUG_ON
(
!
one
||
!
two
);
BUG_ON
(
!
dst
||
!
src
);
if
((
one
->
lcn
<
0
)
||
(
two
->
lcn
<
0
))
/* Are we merging holes? */
if
((
dst
->
lcn
<
0
)
||
(
src
->
lcn
<
0
))
/* Are we merging holes? */
return
FALSE
;
if
((
one
->
lcn
+
one
->
length
)
!=
two
->
lcn
)
/* Are the runs contiguous? */
if
((
dst
->
lcn
+
dst
->
length
)
!=
src
->
lcn
)
/* Are the runs contiguous? */
return
FALSE
;
if
((
one
->
vcn
+
one
->
length
)
!=
two
->
vcn
)
/* Are the runs misaligned? */
if
((
dst
->
vcn
+
dst
->
length
)
!=
src
->
vcn
)
/* Are the runs misaligned? */
return
FALSE
;
one
->
length
+=
two
->
length
;
return
TRUE
;
}
/**
* ntfs_rl_append - Append a run_list after the given element
* @orig: The original run_list to be worked on.
* @osize: The number of elements in @orig (including end marker).
* @new: The run_list to be inserted.
* @nsize: The number of elements in @new (excluding end marker).
* @loc: Append the new run_list after this element in @orig.
* __ntfs_rl_merge - merge two run lists without testing if they can be merged
* @dst: original, destination run list
* @src: new run list to merge with @dst
*
*
Append a run_list after element @loc in @orig. Merge the right end of
*
the new run_list, if necessary. Adjust the size of the hole before
the
*
appended run_
list.
*
Merge the two run lists, writing into the destination run list @dst. The
*
caller must make sure the run lists can be merged or this will corrupt
the
*
destination run
list.
*
* It is up to the caller to serialize access to the run lists @orig and @new.
* It is up to the caller to serialize access to the run lists @dst and @src.
*/
static
inline
void
__ntfs_rl_merge
(
run_list_element
*
dst
,
run_list_element
*
src
)
{
dst
->
length
+=
src
->
length
;
}
/**
* ntfs_rl_merge - test if two run lists can be joined together and merge them
* @dst: original, destination run list
* @src: new run list to merge with @dst
*
* Return: Pointer, The new, combined, run_list
* Test if two run lists can be joined together. For this, their VCNs and LCNs
* must be adjacent. If they can be merged, perform the merge, writing into
* the destination run list @dst.
*
* Errors: -ENOMEM, Not enough memory to allocate run list array.
* -EINVAL, Invalid parameters were passed in.
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* Return: TRUE Success, the run lists have been merged.
* FALSE Failure, the run lists cannot be merged and have not been
* modified.
*/
static
inline
run_list_element
*
ntfs_rl_append
(
run_list_element
*
orig
,
int
osize
,
run_list_element
*
new
,
int
nsize
,
int
loc
)
static
inline
BOOL
ntfs_rl_merge
(
run_list_element
*
dst
,
run_list_element
*
src
)
{
BOOL
merge
=
ntfs_are_rl_mergeable
(
dst
,
src
);
if
(
merge
)
__ntfs_rl_merge
(
dst
,
src
);
return
merge
;
}
/**
* ntfs_rl_append - append a run list after a given element
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: run list to be inserted into @dst
* @ssize: number of elements in @src (excluding end marker)
* @loc: append the new run list @src after this element in @dst
*
* Append the run list @src after element @loc in @dst. Merge the right end of
* the new run list, if necessary. Adjust the size of the hole before the
* appended run list.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static
inline
run_list_element
*
ntfs_rl_append
(
run_list_element
*
dst
,
int
dsize
,
run_list_element
*
src
,
int
ssize
,
int
loc
)
{
run_list_element
*
res
;
BOOL
right
;
int
magic
;
BUG_ON
(
!
orig
||
!
new
);
BUG_ON
(
!
dst
||
!
src
);
/* First, check if the right hand end needs merging. */
right
=
ntfs_are_rl_mergeable
(
src
+
ssize
-
1
,
dst
+
loc
+
1
);
/* Space required: @dst size + @src size, less one if we merged. */
dst
=
ntfs_rl_realloc
(
dst
,
dsize
,
dsize
+
ssize
-
right
);
if
(
IS_ERR
(
dst
))
return
dst
;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run lists.
*/
/* First, merge the right hand end, if necessary. */
right
=
ntfs_rl_merge
(
new
+
nsize
-
1
,
orig
+
loc
+
1
);
if
(
right
)
__ntfs_rl_merge
(
src
+
ssize
-
1
,
dst
+
loc
+
1
);
/* Space required: Orig size + New size, less one if we merged. */
res
=
ntfs_rl_realloc
(
orig
,
osize
,
osize
+
nsize
-
right
);
if
(
IS_ERR
(
res
))
return
res
;
magic
=
loc
+
ssize
;
/* Move the tail of
Orig out of the way, then copy in New
. */
rl_mm
(
res
,
loc
+
1
+
nsize
,
loc
+
1
+
right
,
o
size
-
loc
-
1
-
right
);
rl_mc
(
res
,
loc
+
1
,
new
,
0
,
n
size
);
/* Move the tail of
@dst out of the way, then copy in @src
. */
ntfs_rl_mm
(
dst
,
magic
+
1
,
loc
+
1
+
right
,
d
size
-
loc
-
1
-
right
);
ntfs_rl_mc
(
dst
,
loc
+
1
,
src
,
0
,
s
size
);
/* Adjust the size of the preceding hole. */
res
[
loc
].
length
=
res
[
loc
+
1
].
vcn
-
res
[
loc
].
vcn
;
dst
[
loc
].
length
=
dst
[
loc
+
1
].
vcn
-
dst
[
loc
].
vcn
;
/* We may have changed the length of the file, so fix the end marker */
if
(
res
[
loc
+
nsize
+
1
].
lcn
==
LCN_ENOENT
)
res
[
loc
+
nsize
+
1
].
vcn
=
res
[
loc
+
nsize
].
vcn
+
res
[
loc
+
nsize
].
length
;
if
(
dst
[
magic
+
1
].
lcn
==
LCN_ENOENT
)
dst
[
magic
+
1
].
vcn
=
dst
[
magic
].
vcn
+
dst
[
magic
].
length
;
return
res
;
return
dst
;
}
/**
* ntfs_rl_insert - Insert a run_list into another
* @orig: The original run_list to be worked on.
* @osize: The number of elements in @orig (including end marker).
* @new: The run_list to be inserted.
* @nsize: The number of elements in @new (excluding end marker).
* @loc: Insert the new run_list before this element in @orig.
*
* Insert a run_list before element @loc in @orig. Merge the left end of
* the new run_list, if necessary. Adjust the size of the hole after the
* inserted run_list.
*
* It is up to the caller to serialize access to the run lists @orig and @new.
*
* Return: Pointer, The new, combined, run_list
*
* Errors: -ENOMEM, Not enough memory to allocate run list array.
* -EINVAL, Invalid parameters were passed in.
* ntfs_rl_insert - insert a run list into another
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: new run list to be inserted
* @ssize: number of elements in @src (excluding end marker)
* @loc: insert the new run list @src before this element in @dst
*
* Insert the run list @src before element @loc in the run list @dst. Merge the
* left end of the new run list, if necessary. Adjust the size of the hole
* after the inserted run list.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static
inline
run_list_element
*
ntfs_rl_insert
(
run_list_element
*
orig
,
int
osize
,
run_list_element
*
new
,
int
n
size
,
int
loc
)
static
inline
run_list_element
*
ntfs_rl_insert
(
run_list_element
*
dst
,
int
dsize
,
run_list_element
*
src
,
int
s
size
,
int
loc
)
{
run_list_element
*
res
;
BOOL
left
=
FALSE
;
BOOL
disc
=
FALSE
;
/* Discontinuity */
BOOL
hole
=
FALSE
;
/* Following a hole */
int
magic
;
BUG_ON
(
!
orig
||
!
new
);
BUG_ON
(
!
dst
||
!
src
);
/* disc => Discontinuity between the end of
Orig and the start of New
.
/* disc => Discontinuity between the end of
@dst and the start of @src
.
* This means we might need to insert a hole.
* hole =>
Orig
ends with a hole or an unmapped region which we can
* hole =>
@dst
ends with a hole or an unmapped region which we can
* extend to match the discontinuity. */
if
(
loc
==
0
)
{
disc
=
(
new
[
0
].
vcn
>
0
);
}
else
{
left
=
ntfs_rl_merge
(
orig
+
loc
-
1
,
new
);
if
(
loc
==
0
)
disc
=
(
src
[
0
].
vcn
>
0
);
else
{
s64
merged_length
;
left
=
ntfs_are_rl_mergeable
(
dst
+
loc
-
1
,
src
);
merged_length
=
dst
[
loc
-
1
].
length
;
if
(
left
)
merged_length
+=
src
->
length
;
disc
=
(
new
[
0
].
vcn
>
(
orig
[
loc
-
1
].
vcn
+
orig
[
loc
-
1
].
length
)
);
disc
=
(
src
[
0
].
vcn
>
dst
[
loc
-
1
].
vcn
+
merged_length
);
if
(
disc
)
hole
=
(
orig
[
loc
-
1
].
lcn
==
LCN_HOLE
);
hole
=
(
dst
[
loc
-
1
].
lcn
==
LCN_HOLE
);
}
/* Space required: Orig size + New size, less one if we merged,
* plus one if there was a discontinuity, less one for a trailing hole */
res
=
ntfs_rl_realloc
(
orig
,
osize
,
osize
+
nsize
-
left
+
disc
-
hole
);
if
(
IS_ERR
(
res
))
return
res
;
/* Space required: @dst size + @src size, less one if we merged, plus
* one if there was a discontinuity, less one for a trailing hole. */
dst
=
ntfs_rl_realloc
(
dst
,
dsize
,
dsize
+
ssize
-
left
+
disc
-
hole
);
if
(
IS_ERR
(
dst
))
return
dst
;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run list.
*/
if
(
left
)
__ntfs_rl_merge
(
dst
+
loc
-
1
,
src
);
/* Move the tail of Orig out of the way, then copy in New. */
rl_mm
(
res
,
loc
+
nsize
-
left
+
disc
-
hole
,
loc
,
osize
-
loc
);
rl_mc
(
res
,
loc
+
disc
-
hole
,
new
,
left
,
nsize
-
left
);
magic
=
loc
+
ssize
-
left
+
disc
-
hole
;
/* Move the tail of @dst out of the way, then copy in @src. */
ntfs_rl_mm
(
dst
,
magic
,
loc
,
dsize
-
loc
);
ntfs_rl_mc
(
dst
,
loc
+
disc
-
hole
,
src
,
left
,
ssize
-
left
);
/* Adjust the VCN of the last run ... */
if
(
res
[
loc
+
nsize
-
left
+
disc
-
hole
].
lcn
<=
LCN_HOLE
)
{
res
[
loc
+
nsize
-
left
+
disc
-
hole
].
vcn
=
res
[
loc
+
nsize
-
left
+
disc
-
hole
-
1
].
vcn
+
res
[
loc
+
nsize
-
left
+
disc
-
hole
-
1
].
length
;
}
if
(
dst
[
magic
].
lcn
<=
LCN_HOLE
)
dst
[
magic
].
vcn
=
dst
[
magic
-
1
].
vcn
+
dst
[
magic
-
1
].
length
;
/* ... and the length. */
if
((
res
[
loc
+
nsize
-
left
+
disc
-
hole
].
lcn
==
LCN_HOLE
)
||
(
res
[
loc
+
nsize
-
left
+
disc
-
hole
].
lcn
==
LCN_RL_NOT_MAPPED
))
{
res
[
loc
+
nsize
-
left
+
disc
-
hole
].
length
=
res
[
loc
+
nsize
-
left
+
disc
-
hole
+
1
].
vcn
-
res
[
loc
+
nsize
-
left
+
disc
-
hole
].
vcn
;
}
if
(
dst
[
magic
].
lcn
==
LCN_HOLE
||
dst
[
magic
].
lcn
==
LCN_RL_NOT_MAPPED
)
dst
[
magic
].
length
=
dst
[
magic
+
1
].
vcn
-
dst
[
magic
].
vcn
;
/* Writing beyond the end of the file and there's a discontinuity. */
if
(
disc
)
{
if
(
hole
)
{
res
[
loc
-
1
].
length
=
res
[
loc
].
vcn
-
res
[
loc
-
1
].
vcn
;
}
else
{
if
(
hole
)
dst
[
loc
-
1
].
length
=
dst
[
loc
].
vcn
-
dst
[
loc
-
1
].
vcn
;
else
{
if
(
loc
>
0
)
{
res
[
loc
].
vcn
=
res
[
loc
-
1
].
vcn
+
res
[
loc
-
1
].
length
;
res
[
loc
].
length
=
res
[
loc
+
1
].
vcn
-
res
[
loc
].
vcn
;
dst
[
loc
].
vcn
=
dst
[
loc
-
1
].
vcn
+
dst
[
loc
-
1
].
length
;
dst
[
loc
].
length
=
dst
[
loc
+
1
].
vcn
-
dst
[
loc
].
vcn
;
}
else
{
res
[
loc
].
vcn
=
0
;
res
[
loc
].
length
=
res
[
loc
+
1
].
vcn
;
dst
[
loc
].
vcn
=
0
;
dst
[
loc
].
length
=
dst
[
loc
+
1
].
vcn
;
}
res
[
loc
].
lcn
=
LCN_RL_NOT_MAPPED
;
dst
[
loc
].
lcn
=
LCN_RL_NOT_MAPPED
;
}
if
(
res
[
loc
+
nsize
-
left
+
disc
].
lcn
==
LCN_ENOENT
)
res
[
loc
+
nsize
-
left
+
disc
].
vcn
=
res
[
loc
+
nsize
-
left
+
disc
-
1
].
vcn
+
res
[
loc
+
nsize
-
left
+
disc
-
1
].
length
;
}
magic
+=
hole
;
return
res
;
if
(
dst
[
magic
].
lcn
==
LCN_ENOENT
)
dst
[
magic
].
vcn
=
dst
[
magic
-
1
].
vcn
+
dst
[
magic
-
1
].
length
;
}
return
dst
;
}
/**
* ntfs_rl_replace - Overwrite a run_list element with another run_list
* @orig: The original run_list to be worked on.
* @osize: The number of elements in @orig (including end marker).
* @new: The run_list to be inserted.
* @nsize: The number of elements in @new (excluding end marker).
* @loc: Index of run_list @orig to overwrite with @new.
*
* Replace the run_list at @loc with @new. Merge the left and right ends of
* the inserted run_list, if necessary.
*
* It is up to the caller to serialize access to the run lists @orig and @new.
*
* Return: Pointer, The new, combined, run_list
*
* Errors: -ENOMEM, Not enough memory to allocate run list array.
* -EINVAL, Invalid parameters were passed in.
* ntfs_rl_replace - overwrite a run_list element with another run list
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: new run list to be inserted
* @ssize: number of elements in @src (excluding end marker)
* @loc: index in run list @dst to overwrite with @src
*
* Replace the run list element @dst at @loc with @src. Merge the left and
* right ends of the inserted run list, if necessary.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static
inline
run_list_element
*
ntfs_rl_replace
(
run_list_element
*
orig
,
int
osize
,
run_list_element
*
new
,
int
n
size
,
int
loc
)
static
inline
run_list_element
*
ntfs_rl_replace
(
run_list_element
*
dst
,
int
dsize
,
run_list_element
*
src
,
int
s
size
,
int
loc
)
{
run_list_element
*
res
;
BOOL
left
=
FALSE
;
BOOL
right
;
int
magic
;
BUG_ON
(
!
orig
||
!
new
);
BUG_ON
(
!
dst
||
!
src
);
/* First, merge the left and right ends, if necessary. */
right
=
ntfs_
rl_merge
(
new
+
nsize
-
1
,
orig
+
loc
+
1
);
right
=
ntfs_
are_rl_mergeable
(
src
+
ssize
-
1
,
dst
+
loc
+
1
);
if
(
loc
>
0
)
left
=
ntfs_rl_merge
(
orig
+
loc
-
1
,
new
);
left
=
ntfs_are_rl_mergeable
(
dst
+
loc
-
1
,
src
);
/* Allocate some space. We'll need less if the left, right, or both
* ends were merged. */
dst
=
ntfs_rl_realloc
(
dst
,
dsize
,
dsize
+
ssize
-
left
-
right
);
if
(
IS_ERR
(
dst
))
return
dst
;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run lists.
*/
if
(
right
)
__ntfs_rl_merge
(
src
+
ssize
-
1
,
dst
+
loc
+
1
);
if
(
left
)
__ntfs_rl_merge
(
dst
+
loc
-
1
,
src
);
/* Allocate some space. We'll need less if the left, right
* or both ends were merged. */
res
=
ntfs_rl_realloc
(
orig
,
osize
,
osize
+
nsize
-
left
-
right
);
if
(
IS_ERR
(
res
))
return
res
;
/* FIXME: What does this mean? (AIA) */
magic
=
loc
+
ssize
-
left
;
/* Move the tail of Orig out of the way, then copy in New. */
rl_mm
(
res
,
loc
+
nsize
-
left
,
loc
+
right
+
1
,
osize
-
loc
-
right
-
1
);
rl_mc
(
res
,
loc
,
new
,
left
,
nsize
-
left
);
/* Move the tail of @dst out of the way, then copy in @src. */
ntfs_rl_mm
(
dst
,
magic
,
loc
+
right
+
1
,
dsize
-
loc
-
right
-
1
);
ntfs_rl_mc
(
dst
,
loc
,
src
,
left
,
ssize
-
left
);
/* We may have changed the length of the file, so fix the end marker */
if
(
res
[
loc
+
nsize
-
left
].
lcn
==
LCN_ENOENT
)
res
[
loc
+
nsize
-
left
].
vcn
=
res
[
loc
+
nsize
-
left
-
1
].
vcn
+
res
[
loc
+
nsize
-
left
-
1
].
length
;
return
res
;
if
(
dst
[
magic
].
lcn
==
LCN_ENOENT
)
dst
[
magic
].
vcn
=
dst
[
magic
-
1
].
vcn
+
dst
[
magic
-
1
].
length
;
return
dst
;
}
/**
* ntfs_rl_split - Insert a run_list into the centre of a hole
* @orig: The original run_list to be worked on.
* @osize: The number of elements in @orig (including end marker).
* @new: The run_list to be inserted.
* @nsize: The number of elements in @new (excluding end marker).
* @loc: Index of run_list in @orig to split with @new.
*
* Split the run_list at @loc into two and insert @new. No merging of
* run_lists is necessary. Adjust the size of the holes either side.
*
* It is up to the caller to serialize access to the run lists @orig and @new.
*
* Return: Pointer, The new, combined, run_list
*
* Errors: -ENOMEM, Not enough memory to allocate run list array.
* -EINVAL, Invalid parameters were passed in.
* ntfs_rl_split - insert a run list into the centre of a hole
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: new run list to be inserted
* @ssize: number of elements in @src (excluding end marker)
* @loc: index in run list @dst at which to split and insert @src
*
* Split the run list @dst at @loc into two and insert @new in between the two
* fragments. No merging of run lists is necessary. Adjust the size of the
* holes either side.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static
inline
run_list_element
*
ntfs_rl_split
(
run_list_element
*
orig
,
int
o
size
,
run_list_element
*
new
,
int
n
size
,
int
loc
)
static
inline
run_list_element
*
ntfs_rl_split
(
run_list_element
*
dst
,
int
d
size
,
run_list_element
*
src
,
int
s
size
,
int
loc
)
{
run_list_element
*
res
;
BUG_ON
(
!
orig
||
!
new
);
BUG_ON
(
!
dst
||
!
src
);
/* Space required: Orig size + New size + One new hole. */
res
=
ntfs_rl_realloc
(
orig
,
osize
,
osize
+
nsize
+
1
);
if
(
IS_ERR
(
res
))
return
res
;
/* Space required: @dst size + @src size + one new hole. */
dst
=
ntfs_rl_realloc
(
dst
,
dsize
,
dsize
+
ssize
+
1
);
if
(
IS_ERR
(
dst
))
return
dst
;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run lists.
*/
/* Move the tail of
Orig out of the way, then copy in New
. */
rl_mm
(
res
,
loc
+
1
+
nsize
,
loc
,
o
size
-
loc
);
rl_mc
(
res
,
loc
+
1
,
new
,
0
,
n
size
);
/* Move the tail of
@dst out of the way, then copy in @src
. */
ntfs_rl_mm
(
dst
,
loc
+
1
+
ssize
,
loc
,
d
size
-
loc
);
ntfs_rl_mc
(
dst
,
loc
+
1
,
src
,
0
,
s
size
);
/* Adjust the size of the holes either size of
New
. */
res
[
loc
].
length
=
res
[
loc
+
1
].
vcn
-
res
[
loc
].
vcn
;
res
[
loc
+
nsize
+
1
].
vcn
=
res
[
loc
+
nsize
].
vcn
+
res
[
loc
+
n
size
].
length
;
res
[
loc
+
nsize
+
1
].
length
=
res
[
loc
+
nsize
+
2
].
vcn
-
res
[
loc
+
n
size
+
1
].
vcn
;
/* Adjust the size of the holes either size of
@src
. */
dst
[
loc
].
length
=
dst
[
loc
+
1
].
vcn
-
dst
[
loc
].
vcn
;
dst
[
loc
+
ssize
+
1
].
vcn
=
dst
[
loc
+
ssize
].
vcn
+
dst
[
loc
+
s
size
].
length
;
dst
[
loc
+
ssize
+
1
].
length
=
dst
[
loc
+
ssize
+
2
].
vcn
-
dst
[
loc
+
s
size
+
1
].
vcn
;
return
res
;
return
dst
;
}
/**
* merge_run_lists - merge two run_lists into one
* @drl:
The original run_list.
* @srl:
The new run_list to be merge into @drl.
*
ntfs_
merge_run_lists - merge two run_lists into one
* @drl:
original run list to be worked on
* @srl:
new run list to be merged into @drl
*
* First we sanity check the two run
_lists to make sure that they are sensible
* a
nd can be merged. The @srl run_list must be either after the @drl run_list
*
or completely within a hole
in @drl.
* First we sanity check the two run
lists @srl and @drl to make sure that they
* a
re sensible and can be merged. The run list @srl must be either after the
*
run list @drl or completely within a hole (or unmapped region)
in @drl.
*
* It is up to the caller to serialize access to the run lists @drl and @srl.
*
...
...
@@ -366,25 +461,28 @@ static inline run_list_element *ntfs_rl_split(run_list_element *orig, int osize,
* 1. When attribute lists are used and a further extent is being mapped.
* 2. When new clusters are allocated to fill a hole or extend a file.
*
* There are four possible ways @srl can be merged. It can be inserted at
* the beginning of a hole; split the hole in two; appended at the end of
* a hole; replace the whole hole. It can also be appended to the end of
* the run_list, which is just a variant of the insert case.
*
* N.B. Either, or both, of the input pointers may be freed if the function
* is successful. Only the returned pointer may be used.
*
* If the function fails, neither of the input run_lists may be safe.
*
* Return: Pointer, The resultant merged run_list.
*
* Errors: -ENOMEM, Not enough memory to allocate run list array.
* -EINVAL, Invalid parameters were passed in.
* -ERANGE, The run_lists overlap and cannot be merged.
* There are four possible ways @srl can be merged. It can:
* - be inserted at the beginning of a hole,
* - split the hole in two and be inserted between the two fragments,
* - be appended at the end of a hole, or it can
* - replace the whole hole.
* It can also be appended to the end of the run list, which is just a variant
* of the insert case.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @drl and @srl are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
* -ERANGE - The run lists overlap and cannot be merged.
*/
run_list_element
*
merge_run_lists
(
run_list_element
*
drl
,
run_list_element
*
srl
)
run_list_element
*
ntfs_merge_run_lists
(
run_list_element
*
drl
,
run_list_element
*
srl
)
{
run_list_element
*
nrl
;
/* New run list. */
int
di
,
si
;
/* Current index into @[ds]rl. */
int
sstart
;
/* First index with lcn > LCN_RL_NOT_MAPPED. */
int
dins
;
/* Index into @drl at which to insert @srl. */
...
...
@@ -392,49 +490,49 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
int
dfinal
,
sfinal
;
/* The last index into @[ds]rl with
lcn >= LCN_HOLE. */
int
marker
=
0
;
VCN
marker_vcn
=
0
;
#if
1
ntfs_debug
(
"dst:"
);
ntfs_debug_dump_runlist
(
drl
);
ntfs_debug
(
"src:"
);
ntfs_debug_dump_runlist
(
srl
);
#if
def DEBUG
ntfs_debug
(
"dst:"
);
ntfs_debug_dump_runlist
(
drl
);
ntfs_debug
(
"src:"
);
ntfs_debug_dump_runlist
(
srl
);
#endif
/* Check for silly calling... */
if
(
unlikely
(
!
srl
))
if
(
unlikely
(
!
srl
))
return
drl
;
if
(
unlikely
(
IS_ERR
(
srl
)
||
IS_ERR
(
drl
)))
return
ERR_PTR
(
-
EINVAL
);
if
(
unlikely
(
IS_ERR
(
srl
)
||
IS_ERR
(
drl
)))
return
ERR_PTR
(
-
EINVAL
);
/* Check for the case where the first mapping is being done now. */
if
(
unlikely
(
!
drl
))
{
nrl
=
srl
;
if
(
unlikely
(
!
drl
))
{
drl
=
srl
;
/* Complete the source run list if necessary. */
if
(
unlikely
(
s
rl
[
0
].
vcn
))
{
if
(
unlikely
(
d
rl
[
0
].
vcn
))
{
/* Scan to the end of the source run list. */
for
(
send
=
0
;
likely
(
srl
[
send
].
length
);
s
end
++
)
for
(
dend
=
0
;
likely
(
drl
[
dend
].
length
);
d
end
++
)
;
nrl
=
ntfs_rl_realloc
(
srl
,
send
,
s
end
+
1
);
if
(
!
nrl
)
return
ERR_PTR
(
-
ENOMEM
)
;
rl_mm
(
nrl
,
1
,
0
,
s
end
);
nrl
[
0
].
vcn
=
0
;
/* Add start element. */
n
rl
[
0
].
lcn
=
LCN_RL_NOT_MAPPED
;
nrl
[
0
].
length
=
n
rl
[
1
].
vcn
;
drl
=
ntfs_rl_realloc
(
drl
,
dend
,
d
end
+
1
);
if
(
IS_ERR
(
drl
)
)
return
drl
;
/* Insert start element at the front of the run list. */
ntfs_rl_mm
(
drl
,
1
,
0
,
d
end
);
drl
[
0
].
vcn
=
0
;
d
rl
[
0
].
lcn
=
LCN_RL_NOT_MAPPED
;
drl
[
0
].
length
=
d
rl
[
1
].
vcn
;
}
goto
finished
;
}
si
=
di
=
0
;
/* Skip
the unmapped start element(s) in each run_list if presen
t. */
/* Skip
any unmapped start element(s) in the source run_lis
t. */
while
(
srl
[
si
].
length
&&
srl
[
si
].
lcn
<
(
LCN
)
LCN_HOLE
)
si
++
;
/* Can't have an entirely unmapped s
rl run_
list. */
BUG_ON
(
!
srl
[
si
].
length
);
/* Can't have an entirely unmapped s
ource run
list. */
BUG_ON
(
!
srl
[
si
].
length
);
/* Record the starting points. */
sstart
=
si
;
...
...
@@ -445,19 +543,16 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
* appended to @drl.
*/
for
(;
drl
[
di
].
length
;
di
++
)
{
if
(
(
drl
[
di
].
vcn
+
drl
[
di
].
length
)
>
srl
[
sstart
].
vcn
)
if
(
drl
[
di
].
vcn
+
drl
[
di
].
length
>
srl
[
sstart
].
vcn
)
break
;
}
dins
=
di
;
/* Sanity check for illegal overlaps. */
if
((
drl
[
di
].
vcn
==
srl
[
si
].
vcn
)
&&
(
drl
[
di
].
lcn
>=
0
)
&&
(
srl
[
si
].
lcn
>=
0
))
{
ntfs_error
(
NULL
,
"Run lists overlap. Cannot merge! Returning "
"ERANGE."
);
nrl
=
ERR_PTR
(
-
ERANGE
);
goto
exit
;
if
((
drl
[
di
].
vcn
==
srl
[
si
].
vcn
)
&&
(
drl
[
di
].
lcn
>=
0
)
&&
(
srl
[
si
].
lcn
>=
0
))
{
ntfs_error
(
NULL
,
"Run lists overlap. Cannot merge!"
);
return
ERR_PTR
(
-
ERANGE
);
}
/* Scan to the end of both run lists in order to know their sizes. */
...
...
@@ -466,9 +561,8 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
for
(
dend
=
di
;
drl
[
dend
].
length
;
dend
++
)
;
if
(
srl
[
send
].
lcn
==
LCN_ENOENT
)
{
marker
=
send
;
}
if
(
srl
[
send
].
lcn
==
(
LCN
)
LCN_ENOENT
)
marker_vcn
=
srl
[
marker
=
send
].
vcn
;
/* Scan to the last element with lcn >= LCN_HOLE. */
for
(
sfinal
=
send
;
sfinal
>=
0
&&
srl
[
sfinal
].
lcn
<
LCN_HOLE
;
sfinal
--
)
...
...
@@ -479,96 +573,142 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
{
BOOL
start
;
BOOL
finish
;
int
ds
=
dend
+
1
;
/* Number of elements in drl & srl */
int
ds
=
dend
+
1
;
/* Number of elements in drl & srl */
int
ss
=
sfinal
-
sstart
+
1
;
start
=
((
drl
[
dins
].
lcn
<
LCN_RL_NOT_MAPPED
)
||
/* End of file */
(
drl
[
dins
].
vcn
==
srl
[
sstart
].
vcn
));
/* Start of hole */
finish
=
((
drl
[
dins
].
lcn
>=
LCN_RL_NOT_MAPPED
)
&&
/* End of file */
((
drl
[
dins
].
vcn
+
drl
[
dins
].
length
)
<=
/* End of hole */
(
srl
[
send
-
1
].
vcn
+
srl
[
send
-
1
].
length
)));
(
srl
[
send
-
1
].
vcn
+
srl
[
send
-
1
].
length
)));
/* Or we'll lose an end marker */
if
(
start
&&
finish
&&
(
drl
[
dins
].
length
==
0
))
ss
++
;
if
(
marker
&&
(
drl
[
dins
].
vcn
+
drl
[
dins
].
length
>
srl
[
send
-
1
].
vcn
))
if
(
marker
&&
(
drl
[
dins
].
vcn
+
drl
[
dins
].
length
>
srl
[
send
-
1
].
vcn
))
finish
=
FALSE
;
#if 0
ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
ntfs_debug("start = %i, finish = %i", start, finish);
ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins);
#endif
if
(
start
)
if
(
start
)
{
if
(
finish
)
nrl
=
ntfs_rl_replace
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
drl
=
ntfs_rl_replace
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
else
nrl
=
ntfs_rl_insert
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
else
drl
=
ntfs_rl_insert
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
}
else
{
if
(
finish
)
nrl
=
ntfs_rl_append
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
drl
=
ntfs_rl_append
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
else
nrl
=
ntfs_rl_split
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
if
(
marker
&&
!
IS_ERR
(
nrl
))
{
for
(
ds
=
0
;
nrl
[
ds
].
length
;
ds
++
)
drl
=
ntfs_rl_split
(
drl
,
ds
,
srl
+
sstart
,
ss
,
dins
);
}
if
(
IS_ERR
(
drl
))
{
ntfs_error
(
NULL
,
"Merge failed."
);
return
drl
;
}
ntfs_free
(
srl
);
if
(
marker
)
{
ntfs_debug
(
"Triggering marker code."
);
for
(
ds
=
dend
;
drl
[
ds
].
length
;
ds
++
)
;
nrl
=
ntfs_rl_insert
(
nrl
,
ds
+
1
,
srl
+
marker
,
1
,
ds
);
/* We only need to care if @srl ended after @drl. */
if
(
drl
[
ds
].
vcn
<=
marker_vcn
)
{
int
slots
=
0
;
if
(
drl
[
ds
].
vcn
==
marker_vcn
)
{
ntfs_debug
(
"Old marker = 0x%Lx, replacing with "
"LCN_ENOENT.
\n
"
,
(
unsigned
long
long
)
drl
[
ds
].
lcn
);
drl
[
ds
].
lcn
=
(
LCN
)
LCN_ENOENT
;
goto
finished
;
}
/*
* We need to create an unmapped run list element in
* @drl or extend an existing one before adding the
* ENOENT terminator.
*/
if
(
drl
[
ds
].
lcn
==
(
LCN
)
LCN_ENOENT
)
{
ds
--
;
slots
=
1
;
}
if
(
drl
[
ds
].
lcn
!=
(
LCN
)
LCN_RL_NOT_MAPPED
)
{
/* Add an unmapped run list element. */
if
(
!
slots
)
{
/* FIXME/TODO: We need to have the
* extra memory already! (AIA) */
drl
=
ntfs_rl_realloc
(
drl
,
ds
,
ds
+
2
);
if
(
!
drl
)
goto
critical_error
;
slots
=
2
;
}
ds
++
;
/* Need to set vcn if it isn't set already. */
if
(
slots
!=
1
)
drl
[
ds
].
vcn
=
drl
[
ds
-
1
].
vcn
+
drl
[
ds
-
1
].
length
;
drl
[
ds
].
lcn
=
(
LCN
)
LCN_RL_NOT_MAPPED
;
/* We now used up a slot. */
slots
--
;
}
drl
[
ds
].
length
=
marker_vcn
-
drl
[
ds
].
vcn
;
/* Finally add the ENOENT terminator. */
ds
++
;
if
(
!
slots
)
{
/* FIXME/TODO: We need to have the extra
* memory already! (AIA) */
drl
=
ntfs_rl_realloc
(
drl
,
ds
,
ds
+
1
);
if
(
!
drl
)
goto
critical_error
;
}
drl
[
ds
].
vcn
=
marker_vcn
;
drl
[
ds
].
lcn
=
(
LCN
)
LCN_ENOENT
;
drl
[
ds
].
length
=
(
s64
)
0
;
}
}
}
if
(
likely
(
!
IS_ERR
(
nrl
)))
{
/* The merge was completed successfully. */
finished:
if
(
nrl
!=
srl
)
ntfs_free
(
srl
);
/*ntfs_debug ("Done.");*/
/*ntfs_debug ("Merged run list:");*/
#if 1
ntfs_debug
(
"res:"
);
ntfs_debug_dump_runlist
(
nrl
);
#endif
}
else
{
ntfs_error
(
NULL
,
"Merge failed, returning error code %ld."
,
-
PTR_ERR
(
nrl
));
}
exit:
return
nrl
;
/* The merge was completed successfully. */
ntfs_debug
(
"Merged run list:"
);
ntfs_debug_dump_runlist
(
drl
);
return
drl
;
critical_error:
/* Critical error! We cannot afford to fail here. */
ntfs_error
(
NULL
,
"Critical error! Not enough memory."
);
panic
(
"NTFS: Cannot continue."
);
}
/**
* decompress_mapping_pairs - convert mapping pairs array to run list
* @vol: ntfs volume on which the attribute resides
* @attr: attribute record whose mapping pairs array to decompress
* @run_list: optional run list in which to insert @attr's run list
*
* Decompress the attribute @attr's mapping pairs array into a run_list and
* return the run list or -errno on error. If @run_list is not NULL then
* the mapping pairs array of @attr is decompressed and the run list inserted
* into the appropriate place in @run_list. If this is the case and the
* function returns success, the original pointer passed into @run_list is no
* longer valid.
* @old_rl: optional run list in which to insert @attr's run list
*
* It is up to the caller to serialize access to the run list @old_rl.
*
* Check the return value for error with IS_ERR(ret_val). If this is FALSE,
* the function was successful, the return value is the new run list, and if
* an existing run list pointer was passed in, this is no longer valid.
* If IS_ERR(ret_val) returns true, there was an error, the return value is not
* a run_list pointer and the existing run list pointer if one was passed in
* has not been touched. In this case use PTR_ERR(ret_val) to obtain the error
* code. Following error codes are defined:
* -ENOMEM Not enough memory to allocate run list array.
* -EIO Corrupt run list.
* -EINVAL Invalid parameters were passed in.
* -ERANGE The two run lists overlap.
* Decompress the attribute @attr's mapping pairs array into a run list. On
* success, return the decompressed run list.
*
* If @old_rl is not NULL, decompressed run list is inserted into the
* appropriate place in @old_rl and the resultant, combined run list is
* returned. The original @old_rl is deallocated.
*
* On error, return -errno. @old_rl is left unmodified in that case.
*
* The following error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EIO - Corrupt run list.
* -EINVAL - Invalid parameters were passed in.
* -ERANGE - The two run lists overlap.
*
* FIXME: For now we take the conceptionally simplest approach of creating the
* new run list disregarding the already existing one and then splicing the
* two into one if that is possible (we check for overlap and discard the new
* run list if overlap present
and return error
).
* two into one
,
if that is possible (we check for overlap and discard the new
* run list if overlap present
before returning ERR_PTR(-ERANGE)
).
*/
run_list_element
*
decompress_mapping_pairs
(
const
ntfs_volume
*
vol
,
const
ATTR_RECORD
*
attr
,
run_list_element
*
old_rl
)
...
...
@@ -576,12 +716,12 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
VCN
vcn
;
/* Current vcn. */
LCN
lcn
;
/* Current lcn. */
s64
deltaxcn
;
/* Change in [vl]cn. */
run_list_element
*
rl
=
NULL
;
/* The output run_list. */
run_list_element
*
rl2
;
/* Temporary run_list. */
run_list_element
*
rl
;
/* The output run list. */
u8
*
buf
;
/* Current position in mapping pairs array. */
u8
*
attr_end
;
/* End of attribute. */
int
rlsize
;
/* Size of run_list buffer. */
int
rlpos
;
/* Current run_list position. */
int
rlsize
;
/* Size of run list buffer. */
u16
rlpos
;
/* Current run list position in units of
run_list_elements. */
u8
b
;
/* Current byte offset in buf. */
#ifdef DEBUG
...
...
@@ -602,14 +742,12 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
ntfs_error
(
vol
->
sb
,
"Corrupt attribute."
);
return
ERR_PTR
(
-
EIO
);
}
/* Current position in run
_
list array. */
/* Current position in run
list array. */
rlpos
=
0
;
/* Allocate first page. */
rl
=
ntfs_malloc_nofs
(
PAGE_SIZE
);
/* Allocate first page
and set current run list size to one page
. */
rl
=
ntfs_malloc_nofs
(
rlsize
=
PAGE_SIZE
);
if
(
unlikely
(
!
rl
))
return
ERR_PTR
(
-
ENOMEM
);
/* Current run_list buffer size in bytes. */
rlsize
=
PAGE_SIZE
;
/* Insert unmapped starting element if necessary. */
if
(
vcn
)
{
rl
->
vcn
=
(
VCN
)
0
;
...
...
@@ -624,18 +762,20 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
* operates on whole pages only.
*/
if
(((
rlpos
+
3
)
*
sizeof
(
*
old_rl
))
>
rlsize
)
{
run_list_element
*
rl2
;
rl2
=
ntfs_malloc_nofs
(
rlsize
+
(
int
)
PAGE_SIZE
);
if
(
unlikely
(
!
rl2
))
{
ntfs_free
(
rl
);
return
ERR_PTR
(
-
ENOMEM
);
}
mem
move
(
rl2
,
rl
,
rlsize
);
mem
cpy
(
rl2
,
rl
,
rlsize
);
ntfs_free
(
rl
);
rl
=
rl2
;
rlsize
+=
PAGE_SIZE
;
}
/* Enter the current vcn into the current run_list element. */
(
rl
+
rlpos
)
->
vcn
=
vcn
;
rl
[
rlpos
].
vcn
=
vcn
;
/*
* Get the change in vcn, i.e. the run length in clusters.
* Doing it this way ensures that we signextend negative values.
...
...
@@ -664,10 +804,10 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
goto
err_out
;
}
/*
* Enter the current run length into the current run
_
list
* Enter the current run length into the current run
list
* element.
*/
(
rl
+
rlpos
)
->
length
=
deltaxcn
;
rl
[
rlpos
].
length
=
deltaxcn
;
/* Increment the current vcn by the current run length. */
vcn
+=
deltaxcn
;
/*
...
...
@@ -676,7 +816,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
* to LCN_HOLE.
*/
if
(
!
(
*
buf
&
0xf0
))
(
rl
+
rlpos
)
->
lcn
=
(
LCN
)
LCN_HOLE
;
rl
[
rlpos
].
lcn
=
(
LCN
)
LCN_HOLE
;
else
{
/* Get the lcn change which really can be negative. */
u8
b2
=
*
buf
&
0xf
;
...
...
@@ -709,7 +849,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
goto
err_out
;
}
/* Enter the current lcn into the run_list element. */
(
rl
+
rlpos
)
->
lcn
=
lcn
;
rl
[
rlpos
].
lcn
=
lcn
;
}
/* Get to the next run_list element. */
rlpos
++
;
...
...
@@ -729,7 +869,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
"non-resident attribute."
);
goto
err_out
;
}
/* Setup not mapped run
_
list element if this is the base extent. */
/* Setup not mapped run
list element if this is the base extent. */
if
(
!
attr
->
_ANR
(
lowest_vcn
))
{
VCN
max_cluster
;
...
...
@@ -742,13 +882,13 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
* likely, there are more extents following this one.
*/
if
(
deltaxcn
<
--
max_cluster
)
{
//RAR
ntfs_debug("More extents to follow; deltaxcn = 0x%Lx, "
//RAR
"max_cluster = 0x%Lx",
//RAR
(long long)deltaxcn,
//RAR
(long long)max_cluster);
(
rl
+
rlpos
)
->
vcn
=
vcn
;
vcn
+=
(
rl
+
rlpos
)
->
length
=
max_cluster
-
deltaxcn
;
(
rl
+
rlpos
)
->
lcn
=
(
LCN
)
LCN_RL_NOT_MAPPED
;
ntfs_debug
(
"More extents to follow; deltaxcn = 0x%Lx, "
"max_cluster = 0x%Lx"
,
(
long
long
)
deltaxcn
,
(
long
long
)
max_cluster
);
rl
[
rlpos
].
vcn
=
vcn
;
vcn
+=
rl
[
rlpos
].
length
=
max_cluster
-
deltaxcn
;
rl
[
rlpos
].
lcn
=
(
LCN
)
LCN_RL_NOT_MAPPED
;
rlpos
++
;
}
else
if
(
unlikely
(
deltaxcn
>
max_cluster
))
{
ntfs_error
(
vol
->
sb
,
"Corrupt attribute. deltaxcn = "
...
...
@@ -757,25 +897,26 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
(
long
long
)
max_cluster
);
goto
mpa_err
;
}
(
rl
+
rlpos
)
->
lcn
=
(
LCN
)
LCN_ENOENT
;
rl
[
rlpos
].
lcn
=
(
LCN
)
LCN_ENOENT
;
}
else
/* Not the base extent. There may be more extents to follow. */
(
rl
+
rlpos
)
->
lcn
=
(
LCN
)
LCN_RL_NOT_MAPPED
;
rl
[
rlpos
].
lcn
=
(
LCN
)
LCN_RL_NOT_MAPPED
;
/* Setup terminating run_list element. */
(
rl
+
rlpos
)
->
vcn
=
vcn
;
(
rl
+
rlpos
)
->
length
=
(
s64
)
0
;
//RAR ntfs_debug("Mapping pairs array successfully decompressed.");
//RAR ntfs_debug_dump_runlist(rl);
rl
[
rlpos
].
vcn
=
vcn
;
rl
[
rlpos
].
length
=
(
s64
)
0
;
/* If no existing run list was specified, we are done. */
if
(
!
old_rl
)
if
(
!
old_rl
)
{
ntfs_debug
(
"Mapping pairs array successfully decompressed:"
);
ntfs_debug_dump_runlist
(
rl
);
return
rl
;
}
/* Now combine the new and old run lists checking for overlaps. */
rl2
=
merge_run_lists
(
old_rl
,
rl
);
if
(
likely
(
!
IS_ERR
(
rl2
)))
return
rl2
;
old_rl
=
ntfs_
merge_run_lists
(
old_rl
,
rl
);
if
(
likely
(
!
IS_ERR
(
old_rl
)))
return
old_rl
;
ntfs_free
(
rl
);
ntfs_error
(
vol
->
sb
,
"Failed to merge run lists."
);
return
rl2
;
return
old_rl
;
io_error:
ntfs_error
(
vol
->
sb
,
"Corrupt attribute."
);
err_out:
...
...
fs/ntfs/mst.c
View file @
2d4d6186
...
...
@@ -48,7 +48,7 @@ int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
usa_ofs
=
le16_to_cpu
(
b
->
usa_ofs
);
/* Decrement usa_count to get number of fixups. */
usa_count
=
le16_to_cpu
(
b
->
usa_count
)
-
1
;
/* Size and align
e
ment checks. */
/* Size and alignment checks. */
if
(
size
&
(
NTFS_BLOCK_SIZE
-
1
)
||
usa_ofs
&
1
||
usa_ofs
+
(
usa_count
*
2
)
>
size
||
...
...
@@ -132,7 +132,7 @@ int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
usa_ofs
=
le16_to_cpu
(
b
->
usa_ofs
);
/* Decrement usa_count to get number of fixups. */
usa_count
=
le16_to_cpu
(
b
->
usa_count
)
-
1
;
/* Size and align
e
ment checks. */
/* Size and alignment checks. */
if
(
size
&
(
NTFS_BLOCK_SIZE
-
1
)
||
usa_ofs
&
1
||
usa_ofs
+
(
usa_count
*
2
)
>
size
||
...
...
fs/ntfs/super.c
View file @
2d4d6186
...
...
@@ -1077,7 +1077,7 @@ static BOOL load_system_files(ntfs_volume *vol)
* releases all inodes and memory belonging to the NTFS specific part of the
* super block.
*/
void
ntfs_put_super
(
struct
super_block
*
vfs_sb
)
static
void
ntfs_put_super
(
struct
super_block
*
vfs_sb
)
{
ntfs_volume
*
vol
=
NTFS_SB
(
vfs_sb
);
...
...
@@ -1155,7 +1155,7 @@ void ntfs_put_super(struct super_block *vfs_sb)
* Errors are ignored and we just return the number of free clusters we have
* found. This means we return an underestimate on error.
*/
s64
get_nr_free_clusters
(
ntfs_volume
*
vol
)
s
tatic
s
64
get_nr_free_clusters
(
ntfs_volume
*
vol
)
{
struct
address_space
*
mapping
=
vol
->
lcnbmp_ino
->
i_mapping
;
filler_t
*
readpage
=
(
filler_t
*
)
mapping
->
a_ops
->
readpage
;
...
...
@@ -1227,7 +1227,7 @@ s64 get_nr_free_clusters(ntfs_volume *vol)
}
/**
* get_nr_free_mft_records - return the number of free inodes on a volume
*
__
get_nr_free_mft_records - return the number of free inodes on a volume
* @vol: ntfs volume for which to obtain free inode count
*
* Calculate the number of free mft records (inodes) on the mounted NTFS
...
...
@@ -1235,8 +1235,10 @@ s64 get_nr_free_clusters(ntfs_volume *vol)
*
* Errors are ignored and we just return the number of free inodes we have
* found. This means we return an underestimate on error.
*
* NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing.
*/
unsigned
long
get_nr_free_mft_records
(
ntfs_volume
*
vol
)
static
unsigned
long
__
get_nr_free_mft_records
(
ntfs_volume
*
vol
)
{
struct
address_space
*
mapping
;
filler_t
*
readpage
;
...
...
@@ -1247,7 +1249,6 @@ unsigned long get_nr_free_mft_records(ntfs_volume *vol)
ntfs_debug
(
"Entering."
);
/* Serialize accesses to the inode bitmap. */
down_read
(
&
vol
->
mftbmp_lock
);
mapping
=
&
vol
->
mftbmp_mapping
;
readpage
=
(
filler_t
*
)
mapping
->
a_ops
->
readpage
;
/*
...
...
@@ -1307,7 +1308,6 @@ unsigned long get_nr_free_mft_records(ntfs_volume *vol)
}
ntfs_debug
(
"Finished reading $MFT/$BITMAP, last index = 0x%lx"
,
index
-
1
);
up_read
(
&
vol
->
mftbmp_lock
);
ntfs_debug
(
"Exiting."
);
return
nr_free
;
}
...
...
@@ -1330,7 +1330,7 @@ unsigned long get_nr_free_mft_records(ntfs_volume *vol)
*
* Return 0 on success or -errno on error.
*/
int
ntfs_statfs
(
struct
super_block
*
sb
,
struct
statfs
*
sfs
)
static
int
ntfs_statfs
(
struct
super_block
*
sb
,
struct
statfs
*
sfs
)
{
ntfs_volume
*
vol
=
NTFS_SB
(
sb
);
s64
size
;
...
...
@@ -1354,10 +1354,12 @@ int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
size
=
0LL
;
/* Free blocks avail to non-superuser, same as above on NTFS. */
sfs
->
f_bavail
=
sfs
->
f_bfree
=
size
;
down_read
(
&
vol
->
mftbmp_lock
);
/* Total file nodes in file system (at this moment in time). */
sfs
->
f_files
=
vol
->
mft_ino
->
i_size
>>
vol
->
mft_record_size_bits
;
/* Free file nodes in fs (based on current total count). */
sfs
->
f_ffree
=
get_nr_free_mft_records
(
vol
);
sfs
->
f_ffree
=
__get_nr_free_mft_records
(
vol
);
up_read
(
&
vol
->
mftbmp_lock
);
/*
* File system id. This is extremely *nix flavour dependent and even
* within Linux itself all fs do their own thing. I interpret this to
...
...
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