Commit b425c8c5 authored by Anton Altaparmakov's avatar Anton Altaparmakov
parents a05ba456 92fe7b9e
......@@ -457,6 +457,11 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.27:
- Implement page migration support so the kernel can move memory used
by NTFS files and directories around for management purposes.
- Add support for writing to sparse files created with Windows XP SP2.
- Many minor improvements and bug fixes.
2.1.26:
- Implement support for sector sizes above 512 bytes (up to the maximum
supported by NTFS which is 4096 bytes).
......
......@@ -16,8 +16,34 @@ ToDo/Notes:
inode having been discarded already. Whether this can actually ever
happen is unclear however so it is worth waiting until someone hits
the problem.
- Enable the code for setting the NT4 compatibility flag when we start
making NTFS 1.2 specific modifications.
2.1.27 - Various bug fixes and cleanups.
- Fix two compiler warnings on Alpha. Thanks to Andrew Morton for
reporting them.
- Fix an (innocent) off-by-one error in the runlist code.
- Fix a buggette in an "should be impossible" case handling where we
continued the attribute lookup loop instead of aborting it.
- Use buffer_migrate_page() for the ->migratepage function of all ntfs
address space operations.
- Fix comparison of $MFT and $MFTMirr to not bail out when there are
unused, invalid mft records which are the same in both $MFT and
$MFTMirr.
- Add support for sparse files which have a compression unit of 0.
- Remove all the make_bad_inode() calls. This should only be called
from read inode and new inode code paths.
- Limit name length in fs/ntfs/unistr.c::ntfs_nlstoucs() to maximum
allowed by NTFS, i.e. 255 Unicode characters, not including the
terminating NULL (which is not stored on disk).
- Improve comments on file attribute flags in fs/ntfs/layout.h.
- Fix a bug in fs/ntfs/inode.c::ntfs_read_locked_index_inode() where we
forgot to update a temporary variable so loading index inodes which
have an index allocation attribute failed.
- Add a missing call to flush_dcache_mft_record_page() in
fs/ntfs/inode.c::ntfs_write_inode().
- Handle the recently introduced -ENAMETOOLONG return value from
fs/ntfs/unistr.c::ntfs_nlstoucs() in fs/ntfs/namei.c::ntfs_lookup().
- Semaphore to mutex conversion. (Ingo Molnar)
2.1.26 - Minor bug fixes and updates.
......
......@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.26\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.27\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
......@@ -22,6 +22,7 @@
*/
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
......@@ -1277,18 +1278,18 @@ static int ntfs_write_mst_block(struct page *page,
tni = locked_nis[nr_locked_nis];
/* Get the base inode. */
down(&tni->extent_lock);
mutex_lock(&tni->extent_lock);
if (tni->nr_extents >= 0)
base_tni = tni;
else {
base_tni = tni->ext.base_ntfs_ino;
BUG_ON(!base_tni);
}
up(&tni->extent_lock);
mutex_unlock(&tni->extent_lock);
ntfs_debug("Unlocking %s inode 0x%lx.",
tni == base_tni ? "base" : "extent",
tni->mft_no);
up(&tni->mrec_lock);
mutex_unlock(&tni->mrec_lock);
atomic_dec(&tni->count);
iput(VFS_I(base_tni));
}
......@@ -1529,7 +1530,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
"error %i.", err);
SetPageError(page);
NVolSetErrors(ni->vol);
make_bad_inode(vi);
}
unlock_page(page);
if (ctx)
......@@ -1551,6 +1551,9 @@ struct address_space_operations ntfs_aops = {
#ifdef NTFS_RW
.writepage = ntfs_writepage, /* Write dirty page to disk. */
#endif /* NTFS_RW */
.migratepage = buffer_migrate_page, /* Move a page cache page from
one physical page to an
other. */
};
/**
......@@ -1567,6 +1570,9 @@ struct address_space_operations ntfs_mst_aops = {
without touching the buffers
belonging to the page. */
#endif /* NTFS_RW */
.migratepage = buffer_migrate_page, /* Move a page cache page from
one physical page to an
other. */
};
#ifdef NTFS_RW
......
/**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2001-2006 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -1048,7 +1048,7 @@ static int ntfs_external_attr_find(const ATTR_TYPE type,
le32_to_cpu(ctx->mrec->bytes_allocated))
break;
if (a->type == AT_END)
continue;
break;
if (!a->length)
break;
if (al_entry->instance != a->instance)
......@@ -1695,7 +1695,9 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
a->data.non_resident.initialized_size =
cpu_to_sle64(attr_size);
if (NInoSparse(ni) || NInoCompressed(ni)) {
a->data.non_resident.compression_unit = 4;
a->data.non_resident.compression_unit = 0;
if (NInoCompressed(ni) || vol->major_ver < 3)
a->data.non_resident.compression_unit = 4;
a->data.non_resident.compressed_size =
a->data.non_resident.allocated_size;
} else
......@@ -1714,13 +1716,20 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
ni->allocated_size = new_size;
if (NInoSparse(ni) || NInoCompressed(ni)) {
ni->itype.compressed.size = ni->allocated_size;
ni->itype.compressed.block_size = 1U <<
(a->data.non_resident.compression_unit +
vol->cluster_size_bits);
ni->itype.compressed.block_size_bits =
ffs(ni->itype.compressed.block_size) - 1;
ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.compression_unit;
if (a->data.non_resident.compression_unit) {
ni->itype.compressed.block_size = 1U << (a->data.
non_resident.compression_unit +
vol->cluster_size_bits);
ni->itype.compressed.block_size_bits =
ffs(ni->itype.compressed.block_size) -
1;
ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.compression_unit;
} else {
ni->itype.compressed.block_size = 0;
ni->itype.compressed.block_size_bits = 0;
ni->itype.compressed.block_clusters = 0;
}
vi->i_blocks = ni->itype.compressed.size >> 9;
} else
vi->i_blocks = ni->allocated_size >> 9;
......@@ -2429,16 +2438,12 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
"chkdsk to recover.", IS_ERR(m) ?
"restore attribute search context" :
"truncate attribute runlist");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else if (mp_rebuilt) {
if (ntfs_attr_record_resize(m, a, attr_len)) {
ntfs_error(vol->sb, "Failed to restore attribute "
"record in error code path. Run "
"chkdsk to recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else /* if (success) */ {
if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
......@@ -2451,8 +2456,6 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
"mapping pairs array in error "
"code path. Run chkdsk to "
"recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
}
flush_dcache_mft_record_page(ctx->ntfs_ino);
......
......@@ -67,7 +67,7 @@ static DEFINE_SPINLOCK(ntfs_cb_lock);
/**
* allocate_compression_buffers - allocate the decompression buffers
*
* Caller has to hold the ntfs_lock semaphore.
* Caller has to hold the ntfs_lock mutex.
*
* Return 0 on success or -ENOMEM if the allocations failed.
*/
......@@ -84,7 +84,7 @@ int allocate_compression_buffers(void)
/**
* free_compression_buffers - free the decompression buffers
*
* Caller has to hold the ntfs_lock semaphore.
* Caller has to hold the ntfs_lock mutex.
*/
void free_compression_buffers(void)
{
......
......@@ -1207,8 +1207,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
"attribute runlist in error code "
"path. Run chkdsk to recover the "
"lost cluster.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else /* if (success) */ {
status.runlist_merged = 0;
......@@ -1239,8 +1237,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
ntfs_error(vol->sb, "Failed to restore attribute "
"record in error code path. Run "
"chkdsk to recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
} else /* if (success) */ {
if (ntfs_mapping_pairs_build(vol, (u8*)a +
......@@ -1253,8 +1249,6 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
"mapping pairs array in error "
"code path. Run chkdsk to "
"recover.");
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
NVolSetErrors(vol);
}
flush_dcache_mft_record_page(ctx->ntfs_ino);
......@@ -1623,11 +1617,8 @@ static inline int ntfs_commit_pages_after_non_resident_write(
unmap_mft_record(base_ni);
ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error "
"code %i).", err);
if (err != -ENOMEM) {
if (err != -ENOMEM)
NVolSetErrors(ni->vol);
make_bad_inode(VFS_I(base_ni));
make_bad_inode(vi);
}
return err;
}
......@@ -1802,8 +1793,6 @@ static int ntfs_commit_pages_after_write(struct page **pages,
ntfs_error(vi->i_sb, "Resident attribute commit write failed "
"with error %i.", err);
NVolSetErrors(ni->vol);
make_bad_inode(VFS_I(base_ni));
make_bad_inode(vi);
}
if (ctx)
ntfs_attr_put_search_ctx(ctx);
......
/**
* inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2001-2006 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
......@@ -19,13 +19,19 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/mount.h>
#include <linux/mutex.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include "aops.h"
#include "attrib.h"
#include "bitmap.h"
#include "dir.h"
#include "debug.h"
#include "inode.h"
......@@ -382,7 +388,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
atomic_set(&ni->count, 1);
ni->vol = NTFS_SB(sb);
ntfs_init_runlist(&ni->runlist);
init_MUTEX(&ni->mrec_lock);
mutex_init(&ni->mrec_lock);
ni->page = NULL;
ni->page_ofs = 0;
ni->attr_list_size = 0;
......@@ -394,7 +400,7 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ni->itype.index.collation_rule = 0;
ni->itype.index.block_size_bits = 0;
ni->itype.index.vcn_size_bits = 0;
init_MUTEX(&ni->extent_lock);
mutex_init(&ni->extent_lock);
ni->nr_extents = 0;
ni->ext.base_ntfs_ino = NULL;
}
......@@ -1064,10 +1070,10 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (a->non_resident) {
NInoSetNonResident(ni);
if (NInoCompressed(ni) || NInoSparse(ni)) {
if (a->data.non_resident.compression_unit !=
4) {
if (NInoCompressed(ni) && a->data.non_resident.
compression_unit != 4) {
ntfs_error(vi->i_sb, "Found "
"nonstandard "
"non-standard "
"compression unit (%u "
"instead of 4). "
"Cannot handle this.",
......@@ -1076,16 +1082,26 @@ static int ntfs_read_locked_inode(struct inode *vi)
err = -EOPNOTSUPP;
goto unm_err_out;
}
ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.
compression_unit;
ni->itype.compressed.block_size = 1U << (
a->data.non_resident.
compression_unit +
vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ffs(
ni->itype.compressed.
block_size) - 1;
if (a->data.non_resident.compression_unit) {
ni->itype.compressed.block_size = 1U <<
(a->data.non_resident.
compression_unit +
vol->cluster_size_bits);
ni->itype.compressed.block_size_bits =
ffs(ni->itype.
compressed.
block_size) - 1;
ni->itype.compressed.block_clusters =
1U << a->data.
non_resident.
compression_unit;
} else {
ni->itype.compressed.block_size = 0;
ni->itype.compressed.block_size_bits =
0;
ni->itype.compressed.block_clusters =
0;
}
ni->itype.compressed.size = sle64_to_cpu(
a->data.non_resident.
compressed_size);
......@@ -1338,8 +1354,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
goto unm_err_out;
}
if (NInoCompressed(ni) || NInoSparse(ni)) {
if (a->data.non_resident.compression_unit != 4) {
ntfs_error(vi->i_sb, "Found nonstandard "
if (NInoCompressed(ni) && a->data.non_resident.
compression_unit != 4) {
ntfs_error(vi->i_sb, "Found non-standard "
"compression unit (%u instead "
"of 4). Cannot handle this.",
a->data.non_resident.
......@@ -1347,13 +1364,22 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
err = -EOPNOTSUPP;
goto unm_err_out;
}
ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.compression_unit;
ni->itype.compressed.block_size = 1U << (
a->data.non_resident.compression_unit +
vol->cluster_size_bits);
ni->itype.compressed.block_size_bits = ffs(
ni->itype.compressed.block_size) - 1;
if (a->data.non_resident.compression_unit) {
ni->itype.compressed.block_size = 1U <<
(a->data.non_resident.
compression_unit +
vol->cluster_size_bits);
ni->itype.compressed.block_size_bits =
ffs(ni->itype.compressed.
block_size) - 1;
ni->itype.compressed.block_clusters = 1U <<
a->data.non_resident.
compression_unit;
} else {
ni->itype.compressed.block_size = 0;
ni->itype.compressed.block_size_bits = 0;
ni->itype.compressed.block_clusters = 0;
}
ni->itype.compressed.size = sle64_to_cpu(
a->data.non_resident.compressed_size);
}
......@@ -1406,7 +1432,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len,
base_vi->i_ino);
make_bad_inode(vi);
make_bad_inode(base_vi);
if (err != -ENOMEM)
NVolSetErrors(vol);
return err;
......@@ -1591,6 +1616,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
"$INDEX_ALLOCATION attribute.");
goto unm_err_out;
}
a = ctx->attr;
if (!a->non_resident) {
ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is "
"resident.");
......@@ -2823,11 +2849,8 @@ int ntfs_truncate(struct inode *vi)
old_bad_out:
old_size = -1;
bad_out:
if (err != -ENOMEM && err != -EOPNOTSUPP) {
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
if (err != -ENOMEM && err != -EOPNOTSUPP)
NVolSetErrors(vol);
}
if (err != -EOPNOTSUPP)
NInoSetTruncateFailed(ni);
else if (old_size >= 0)
......@@ -2842,11 +2865,8 @@ int ntfs_truncate(struct inode *vi)
ntfs_debug("Failed. Returning error code %i.", err);
return err;
conv_err_out:
if (err != -ENOMEM && err != -EOPNOTSUPP) {
make_bad_inode(vi);
make_bad_inode(VFS_I(base_ni));
if (err != -ENOMEM && err != -EOPNOTSUPP)
NVolSetErrors(vol);
}
if (err != -EOPNOTSUPP)
NInoSetTruncateFailed(ni);
else
......@@ -3044,15 +3064,18 @@ int ntfs_write_inode(struct inode *vi, int sync)
* record will be cleaned and written out to disk below, i.e. before
* this function returns.
*/
if (modified && !NInoTestSetDirty(ctx->ntfs_ino))
mark_ntfs_record_dirty(ctx->ntfs_ino->page,
ctx->ntfs_ino->page_ofs);
if (modified) {
flush_dcache_mft_record_page(ctx->ntfs_ino);
if (!NInoTestSetDirty(ctx->ntfs_ino))
mark_ntfs_record_dirty(ctx->ntfs_ino->page,
ctx->ntfs_ino->page_ofs);
}
ntfs_attr_put_search_ctx(ctx);
/* Now the access times are updated, write the base mft record. */
if (NInoDirty(ni))
err = write_mft_record(ni, m, sync);
/* Write all attached extent mft records. */
down(&ni->extent_lock);
mutex_lock(&ni->extent_lock);
if (ni->nr_extents > 0) {
ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
int i;
......@@ -3079,7 +3102,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
}
}
}
up(&ni->extent_lock);
mutex_unlock(&ni->extent_lock);
unmap_mft_record(ni);
if (unlikely(err))
goto err_out;
......@@ -3094,9 +3117,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
"retries later.");
mark_inode_dirty(vi);
} else {
ntfs_error(vi->i_sb, "Failed (error code %i): Marking inode "
"as bad. You should run chkdsk.", -err);
make_bad_inode(vi);
ntfs_error(vi->i_sb, "Failed (error %i): Run chkdsk.", -err);
NVolSetErrors(ni->vol);
}
return err;
......
......@@ -24,12 +24,13 @@
#ifndef _LINUX_NTFS_INODE_H
#define _LINUX_NTFS_INODE_H
#include <linux/mm.h>
#include <asm/atomic.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
#include "layout.h"
#include "volume.h"
......@@ -81,7 +82,7 @@ struct _ntfs_inode {
* The following fields are only valid for real inodes and extent
* inodes.
*/
struct semaphore mrec_lock; /* Lock for serializing access to the
struct mutex mrec_lock; /* Lock for serializing access to the
mft record belonging to this inode. */
struct page *page; /* The page containing the mft record of the
inode. This should only be touched by the
......@@ -119,7 +120,7 @@ struct _ntfs_inode {
u8 block_clusters; /* Number of clusters per cb. */
} compressed;
} itype;
struct semaphore extent_lock; /* Lock for accessing/modifying the
struct mutex extent_lock; /* Lock for accessing/modifying the
below . */
s32 nr_extents; /* For a base mft record, the number of attached extent
inodes (0 if none), for extent records and for fake
......
......@@ -769,7 +769,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.
Sparse files also have this set to 4. */
Sparse files have this set to 0 on XPSP2. */
/* 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.*/
......@@ -801,13 +801,16 @@ typedef struct {
typedef ATTR_RECORD ATTR_REC;
/*
* File attribute flags (32-bit).
* File attribute flags (32-bit) appearing in the file_attributes fields of the
* STANDARD_INFORMATION attribute of MFT_RECORDs and the FILENAME_ATTR
* attributes of MFT_RECORDs and directory index entries.
*
* All of the below flags appear in the directory index entries but only some
* appear in the STANDARD_INFORMATION attribute whilst only some others appear
* in the FILENAME_ATTR attribute of MFT_RECORDs. Unless otherwise stated the
* flags appear in all of the above.
*/
enum {
/*
* The following flags are only present in the STANDARD_INFORMATION
* attribute (in the field file_attributes).
*/
FILE_ATTR_READONLY = const_cpu_to_le32(0x00000001),
FILE_ATTR_HIDDEN = const_cpu_to_le32(0x00000002),
FILE_ATTR_SYSTEM = const_cpu_to_le32(0x00000004),
......@@ -839,18 +842,14 @@ enum {
F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask
is used to to obtain all flags that are valid for setting. */
/*
* The following flag is only present in the FILE_NAME attribute (in
* the field file_attributes).
* The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all
* FILENAME_ATTR attributes but not in the STANDARD_INFORMATION
* attribute of an mft record.
*/
FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000),
/* Note, this is a copy of the corresponding bit from the mft record,
telling us whether this is a directory or not, i.e. whether it has
an index root attribute or not. */
/*
* The following flag is present both in the STANDARD_INFORMATION
* attribute and in the FILE_NAME attribute (in the field
* file_attributes).
*/
FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000),
/* Note, this is a copy of the corresponding bit from the mft record,
telling us whether this file has a view index present (eg. object id
......@@ -891,7 +890,7 @@ typedef struct {
Windows this is only updated when
accessed if some time delta has
passed since the last update. Also,
last access times updates can be
last access time updates can be
disabled altogether for speed. */
/* 32*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 36*/ union {
......@@ -1076,16 +1075,21 @@ typedef struct {
/* 20*/ sle64 last_access_time; /* Time this mft record was last
accessed. */
/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space
for the data attribute. So for
normal $DATA, this is the
for the unnamed data attribute. So
for normal $DATA, this is the
allocated_size from the unnamed
$DATA attribute and for compressed
and/or sparse $DATA, this is the
compressed_size from the unnamed
$DATA attribute. NOTE: This is a
multiple of the cluster size. */
/* 30*/ sle64 data_size; /* Byte size of actual data in data
attribute. */
$DATA attribute. For a directory or
other inode without an unnamed $DATA
attribute, this is always 0. NOTE:
This is a multiple of the cluster
size. */
/* 30*/ sle64 data_size; /* Byte size of actual data in unnamed
data attribute. For a directory or
other inode without an unnamed $DATA
attribute, this is always 0. */
/* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */
/* 3c*/ union {
/* 3c*/ struct {
......
......@@ -93,6 +93,7 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
"Run chkdsk.", ni->mft_no);
ntfs_unmap_page(page);
page = ERR_PTR(-EIO);
NVolSetErrors(vol);
}
err_out:
ni->page = NULL;
......@@ -104,8 +105,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
* map_mft_record - map, pin and lock an mft record
* @ni: ntfs inode whose MFT record to map
*
* First, take the mrec_lock semaphore. We might now be sleeping, while waiting
* for the semaphore if it was already locked by someone else.
* First, take the mrec_lock mutex. We might now be sleeping, while waiting
* for the mutex if it was already locked by someone else.
*
* The page of the record is mapped using map_mft_record_page() before being
* returned to the caller.
......@@ -135,9 +136,9 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni)
* So that code will end up having to own the mrec_lock of all mft
* records/inodes present in the page before I/O can proceed. In that case we
* wouldn't need to bother with PG_locked and PG_uptodate as nobody will be
* accessing anything without owning the mrec_lock semaphore. But we do need
* to use them because of the read_cache_page() invocation and the code becomes
* so much simpler this way that it is well worth it.
* accessing anything without owning the mrec_lock mutex. But we do need to
* use them because of the read_cache_page() invocation and the code becomes so
* much simpler this way that it is well worth it.
*
* The mft record is now ours and we return a pointer to it. You need to check
* the returned pointer with IS_ERR() and if that is true, PTR_ERR() will return
......@@ -160,13 +161,13 @@ MFT_RECORD *map_mft_record(ntfs_inode *ni)
atomic_inc(&ni->count);
/* Serialize access to this mft record. */
down(&ni->mrec_lock);
mutex_lock(&ni->mrec_lock);
m = map_mft_record_page(ni);
if (likely(!IS_ERR(m)))
return m;
up(&ni->mrec_lock);
mutex_unlock(&ni->mrec_lock);
atomic_dec(&ni->count);
ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
return m;
......@@ -217,7 +218,7 @@ void unmap_mft_record(ntfs_inode *ni)
ntfs_debug("Entering for mft_no 0x%lx.", ni->mft_no);
unmap_mft_record_page(ni);
up(&ni->mrec_lock);
mutex_unlock(&ni->mrec_lock);
atomic_dec(&ni->count);
/*
* If pure ntfs_inode, i.e. no vfs inode attached, we leave it to
......@@ -261,7 +262,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
* in which case just return it. If not found, add it to the base
* inode before returning it.
*/
down(&base_ni->extent_lock);
mutex_lock(&base_ni->extent_lock);
if (base_ni->nr_extents > 0) {
extent_nis = base_ni->ext.extent_ntfs_inos;
for (i = 0; i < base_ni->nr_extents; i++) {
......@@ -274,7 +275,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
}
}
if (likely(ni != NULL)) {
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/* We found the record; just have to map and return it. */
m = map_mft_record(ni);
......@@ -301,7 +302,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
/* Record wasn't there. Get a new ntfs inode and initialize it. */
ni = ntfs_new_extent_inode(base_ni->vol->sb, mft_no);
if (unlikely(!ni)) {
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
return ERR_PTR(-ENOMEM);
}
......@@ -312,7 +313,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
/* Now map the record. */
m = map_mft_record(ni);
if (IS_ERR(m)) {
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
ntfs_clear_extent_inode(ni);
goto map_err_out;
......@@ -347,14 +348,14 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
base_ni->ext.extent_ntfs_inos = tmp;
}
base_ni->ext.extent_ntfs_inos[base_ni->nr_extents++] = ni;
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
ntfs_debug("Done 2.");
*ntfs_ino = ni;
return m;
unm_err_out:
unmap_mft_record(ni);
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
atomic_dec(&base_ni->count);
/*
* If the extent inode was not attached to the base inode we need to
......@@ -399,12 +400,12 @@ void __mark_mft_record_dirty(ntfs_inode *ni)
BUG_ON(NInoAttr(ni));
mark_ntfs_record_dirty(ni->page, ni->page_ofs);
/* Determine the base vfs inode and mark it dirty, too. */
down(&ni->extent_lock);
mutex_lock(&ni->extent_lock);
if (likely(ni->nr_extents >= 0))
base_ni = ni;
else
base_ni = ni->ext.base_ntfs_ino;
up(&ni->extent_lock);
mutex_unlock(&ni->extent_lock);
__mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC);
}
......@@ -650,10 +651,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
* fs/ntfs/aops.c::mark_ntfs_record_dirty().
*
* On success, clean the mft record and return 0. On error, leave the mft
* record dirty and return -errno. The caller should call make_bad_inode() on
* the base inode to ensure no more access happens to this inode. We do not do
* it here as the caller may want to finish writing other extent mft records
* first to minimize on-disk metadata inconsistencies.
* record dirty and return -errno.
*
* NOTE: We always perform synchronous i/o and ignore the @sync parameter.
* However, if the mft record has a counterpart in the mft mirror and @sync is
......@@ -983,7 +981,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
}
ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
/* The inode is not dirty, try to take the mft record lock. */
if (unlikely(down_trylock(&ni->mrec_lock))) {
if (unlikely(!mutex_trylock(&ni->mrec_lock))) {
ntfs_debug("Mft record 0x%lx is already locked, do "
"not write it.", mft_no);
atomic_dec(&ni->count);
......@@ -1043,13 +1041,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* corresponding to this extent mft record attached.
*/
ni = NTFS_I(vi);
down(&ni->extent_lock);
mutex_lock(&ni->extent_lock);
if (ni->nr_extents <= 0) {
/*
* The base inode has no attached extent inodes, write this
* extent mft record.
*/
up(&ni->extent_lock);
mutex_unlock(&ni->extent_lock);
iput(vi);
ntfs_debug("Base inode 0x%lx has no attached extent inodes, "
"write the extent record.", na.mft_no);
......@@ -1072,7 +1070,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* extent mft record.
*/
if (!eni) {
up(&ni->extent_lock);
mutex_unlock(&ni->extent_lock);
iput(vi);
ntfs_debug("Extent inode 0x%lx is not attached to its base "
"inode 0x%lx, write the extent record.",
......@@ -1083,12 +1081,12 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
mft_no, na.mft_no);
/* Take a reference to the extent ntfs inode. */
atomic_inc(&eni->count);
up(&ni->extent_lock);
mutex_unlock(&ni->extent_lock);
/*
* Found the extent inode coresponding to this extent mft record.
* Try to take the mft record lock.
*/
if (unlikely(down_trylock(&eni->mrec_lock))) {
if (unlikely(!mutex_trylock(&eni->mrec_lock))) {
atomic_dec(&eni->count);
iput(vi);
ntfs_debug("Extent mft record 0x%lx is already locked, do "
......@@ -2711,7 +2709,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
* have its page mapped and it is very easy to do.
*/
atomic_inc(&ni->count);
down(&ni->mrec_lock);
mutex_lock(&ni->mrec_lock);
ni->page = page;
ni->page_ofs = ofs;
/*
......@@ -2798,22 +2796,22 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
BUG_ON(NInoAttr(ni));
BUG_ON(ni->nr_extents != -1);
down(&ni->extent_lock);
mutex_lock(&ni->extent_lock);
base_ni = ni->ext.base_ntfs_ino;
up(&ni->extent_lock);
mutex_unlock(&ni->extent_lock);
BUG_ON(base_ni->nr_extents <= 0);
ntfs_debug("Entering for extent inode 0x%lx, base inode 0x%lx.\n",
mft_no, base_ni->mft_no);
down(&base_ni->extent_lock);
mutex_lock(&base_ni->extent_lock);
/* Make sure we are holding the only reference to the extent inode. */
if (atomic_read(&ni->count) > 2) {
ntfs_error(vol->sb, "Tried to free busy extent inode 0x%lx, "
"not freeing.", base_ni->mft_no);
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
return -EBUSY;
}
......@@ -2831,7 +2829,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
break;
}
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
if (unlikely(err)) {
ntfs_error(vol->sb, "Extent inode 0x%lx is not attached to "
......@@ -2890,7 +2888,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
return 0;
rollback:
/* Rollback what we did... */
down(&base_ni->extent_lock);
mutex_lock(&base_ni->extent_lock);
extent_nis = base_ni->ext.extent_ntfs_inos;
if (!(base_ni->nr_extents & 3)) {
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*);
......@@ -2899,7 +2897,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
if (unlikely(!extent_nis)) {
ntfs_error(vol->sb, "Failed to allocate internal "
"buffer during rollback.%s", es);
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
NVolSetErrors(vol);
goto rollback_error;
}
......@@ -2914,7 +2912,7 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
m->flags |= MFT_RECORD_IN_USE;
m->sequence_number = old_seq_no;
extent_nis[base_ni->nr_extents++] = ni;
up(&base_ni->extent_lock);
mutex_unlock(&base_ni->extent_lock);
mark_mft_record_dirty(ni);
return err;
}
......
......@@ -97,10 +97,7 @@ extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync);
* uptodate.
*
* On success, clean the mft record and return 0. On error, leave the mft
* record dirty and return -errno. The caller should call make_bad_inode() on
* the base inode to ensure no more access happens to this inode. We do not do
* it here as the caller may want to finish writing other extent mft records
* first to minimize on-disk metadata inconsistencies.
* record dirty and return -errno.
*/
static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync)
{
......
......@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2006 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
......@@ -115,7 +115,9 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
&uname);
if (uname_len < 0) {
ntfs_error(vol->sb, "Failed to convert name to Unicode.");
if (uname_len != -ENAMETOOLONG)
ntfs_error(vol->sb, "Failed to convert name to "
"Unicode.");
return ERR_PTR(uname_len);
}
mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
......@@ -157,7 +159,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
/* Return the error code. */
return (struct dentry *)dent_inode;
}
/* It is guaranteed that name is no longer allocated at this point. */
/* It is guaranteed that @name is no longer allocated at this point. */
if (MREF_ERR(mref) == -ENOENT) {
ntfs_debug("Entry was not found, adding negative dentry.");
/* The dcache will handle negative entries. */
......@@ -168,7 +170,6 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
"code %i.", -MREF_ERR(mref));
return ERR_PTR(MREF_ERR(mref));
// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
{
......
......@@ -91,7 +91,7 @@ extern void free_compression_buffers(void);
/* From fs/ntfs/super.c */
#define default_upcase_len 0x10000
extern struct semaphore ntfs_lock;
extern struct mutex ntfs_lock;
typedef struct {
int val;
......
......@@ -381,6 +381,7 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst,
static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
int dsize, runlist_element *src, int ssize, int loc)
{
signed delta;
BOOL left = FALSE; /* Left end of @src needs merging. */
BOOL right = FALSE; /* Right end of @src needs merging. */
int tail; /* Start of tail of @dst. */
......@@ -396,11 +397,14 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
left = ntfs_are_rl_mergeable(dst + loc - 1, src);
/*
* Allocate some space. We will need less if the left, right, or both
* ends get merged.
* ends get merged. The -1 accounts for the run being replaced.
*/
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right);
if (IS_ERR(dst))
return dst;
delta = ssize - 1 - left - right;
if (delta > 0) {
dst = ntfs_rl_realloc(dst, dsize, dsize + delta);
if (IS_ERR(dst))
return dst;
}
/*
* We are guaranteed to succeed from here so can start modifying the
* original runlists.
......
......@@ -1099,26 +1099,38 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
kmirr = page_address(mirr_page);
++index;
}
/* Make sure the record is ok. */
if (ntfs_is_baad_recordp((le32*)kmft)) {
ntfs_error(sb, "Incomplete multi sector transfer "
"detected in mft record %i.", i);
/* Do not check the record if it is not in use. */
if (((MFT_RECORD*)kmft)->flags & MFT_RECORD_IN_USE) {
/* Make sure the record is ok. */
if (ntfs_is_baad_recordp((le32*)kmft)) {
ntfs_error(sb, "Incomplete multi sector "
"transfer detected in mft "
"record %i.", i);
mm_unmap_out:
ntfs_unmap_page(mirr_page);
ntfs_unmap_page(mirr_page);
mft_unmap_out:
ntfs_unmap_page(mft_page);
return FALSE;
ntfs_unmap_page(mft_page);
return FALSE;
}
}
if (ntfs_is_baad_recordp((le32*)kmirr)) {
ntfs_error(sb, "Incomplete multi sector transfer "
"detected in mft mirror record %i.", i);
goto mm_unmap_out;
/* Do not check the mirror record if it is not in use. */
if (((MFT_RECORD*)kmirr)->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp((le32*)kmirr)) {
ntfs_error(sb, "Incomplete multi sector "
"transfer detected in mft "
"mirror record %i.", i);
goto mm_unmap_out;
}
}
/* Get the amount of data in the current record. */
bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use);
if (!bytes || bytes > vol->mft_record_size) {
if (bytes < sizeof(MFT_RECORD_OLD) ||
bytes > vol->mft_record_size ||
ntfs_is_baad_recordp((le32*)kmft)) {
bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use);
if (!bytes || bytes > vol->mft_record_size)
if (bytes < sizeof(MFT_RECORD_OLD) ||
bytes > vol->mft_record_size ||
ntfs_is_baad_recordp((le32*)kmirr))
bytes = vol->mft_record_size;
}
/* Compare the two records. */
......@@ -1665,11 +1677,11 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
ntfs_debug("Read %llu bytes from $UpCase (expected %zu bytes).",
i_size, 64 * 1024 * sizeof(ntfschar));
iput(ino);
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (!default_upcase) {
ntfs_debug("Using volume specified $UpCase since default is "
"not present.");
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
return TRUE;
}
max = default_upcase_len;
......@@ -1683,12 +1695,12 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
vol->upcase = default_upcase;
vol->upcase_len = max;
ntfs_nr_upcase_users++;
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
ntfs_debug("Volume specified $UpCase matches default. Using "
"default.");
return TRUE;
}
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
ntfs_debug("Using volume specified $UpCase since it does not match "
"the default.");
return TRUE;
......@@ -1697,17 +1709,17 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
ntfs_free(vol->upcase);
vol->upcase = NULL;
upcase_failed:
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (default_upcase) {
vol->upcase = default_upcase;
vol->upcase_len = default_upcase_len;
ntfs_nr_upcase_users++;
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
"default.");
return TRUE;
}
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
ntfs_error(sb, "Failed to initialize upcase table.");
return FALSE;
}
......@@ -2183,12 +2195,12 @@ static BOOL load_system_files(ntfs_volume *vol)
iput_upcase_err_out:
#endif /* NTFS_RW */
vol->upcase_len = 0;
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--;
vol->upcase = NULL;
}
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
if (vol->upcase) {
ntfs_free(vol->upcase);
vol->upcase = NULL;
......@@ -2393,7 +2405,7 @@ static void ntfs_put_super(struct super_block *sb)
* Destroy the global default upcase table if necessary. Also decrease
* the number of upcase users if we are a user.
*/
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--;
vol->upcase = NULL;
......@@ -2404,7 +2416,7 @@ static void ntfs_put_super(struct super_block *sb)
}
if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
free_compression_buffers();
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
if (vol->upcase) {
ntfs_free(vol->upcase);
vol->upcase = NULL;
......@@ -2878,7 +2890,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
ntfs_error(sb, "Failed to load essential metadata.");
goto iput_tmp_ino_err_out_now;
}
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
/*
* The current mount is a compression user if the cluster size is
* less than or equal 4kiB.
......@@ -2889,7 +2901,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
ntfs_error(NULL, "Failed to allocate buffers "
"for compression engine.");
ntfs_nr_compression_users--;
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
goto iput_tmp_ino_err_out_now;
}
}
......@@ -2901,7 +2913,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
if (!default_upcase)
default_upcase = generate_default_upcase();
ntfs_nr_upcase_users++;
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
/*
* From now on, ignore @silent parameter. If we fail below this line,
* it will be due to a corrupt fs or a system error, so we report it.
......@@ -2919,12 +2931,12 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
atomic_inc(&vol->root_ino->i_count);
ntfs_debug("Exiting, status successful.");
/* Release the default upcase if it has no users. */
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (!--ntfs_nr_upcase_users && default_upcase) {
ntfs_free(default_upcase);
default_upcase = NULL;
}
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
sb->s_export_op = &ntfs_export_ops;
lock_kernel();
return 0;
......@@ -2992,12 +3004,12 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
vol->attrdef = NULL;
}
vol->upcase_len = 0;
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--;
vol->upcase = NULL;
}
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
if (vol->upcase) {
ntfs_free(vol->upcase);
vol->upcase = NULL;
......@@ -3012,14 +3024,14 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
* Decrease the number of upcase users and destroy the global default
* upcase table if necessary.
*/
down(&ntfs_lock);
mutex_lock(&ntfs_lock);
if (!--ntfs_nr_upcase_users && default_upcase) {
ntfs_free(default_upcase);
default_upcase = NULL;
}
if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
free_compression_buffers();
up(&ntfs_lock);
mutex_unlock(&ntfs_lock);
iput_tmp_ino_err_out_now:
iput(tmp_ino);
if (vol->mft_ino && vol->mft_ino != tmp_ino)
......@@ -3078,8 +3090,8 @@ static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep,
struct kmem_cache *ntfs_attr_ctx_cache;
struct kmem_cache *ntfs_index_ctx_cache;
/* Driver wide semaphore. */
DECLARE_MUTEX(ntfs_lock);
/* Driver wide mutex. */
DEFINE_MUTEX(ntfs_lock);
static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
......@@ -3234,7 +3246,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-2005 Anton Altaparmakov");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2006 Anton Altaparmakov");
MODULE_VERSION(NTFS_VERSION);
MODULE_LICENSE("GPL");
#ifdef DEBUG
......
/*
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2001-2006 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
......@@ -19,6 +19,8 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
#include "types.h"
#include "debug.h"
#include "ntfs.h"
......@@ -242,7 +244,7 @@ int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
* map dictates, into a little endian, 2-byte Unicode string.
*
* This function allocates the string and the caller is responsible for
* calling kmem_cache_free(ntfs_name_cache, @outs); when finished with it.
* calling kmem_cache_free(ntfs_name_cache, *@outs); when finished with it.
*
* On success the function returns the number of Unicode characters written to
* the output string *@outs (>= 0), not counting the terminating Unicode NULL
......@@ -262,37 +264,48 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
wchar_t wc;
int i, o, wc_len;
/* We don't trust outside sources. */
if (ins) {
/* We do not trust outside sources. */
if (likely(ins)) {
ucs = kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS);
if (ucs) {
if (likely(ucs)) {
for (i = o = 0; i < ins_len; i += wc_len) {
wc_len = nls->char2uni(ins + i, ins_len - i,
&wc);
if (wc_len >= 0) {
if (wc) {
if (likely(wc_len >= 0 &&
o < NTFS_MAX_NAME_LEN)) {
if (likely(wc)) {
ucs[o++] = cpu_to_le16(wc);
continue;
} /* else (!wc) */
} /* else if (!wc) */
break;
} /* else (wc_len < 0) */
goto conversion_err;
} /* else if (wc_len < 0 ||
o >= NTFS_MAX_NAME_LEN) */
goto name_err;
}
ucs[o] = 0;
*outs = ucs;
return o;
} /* else (!ucs) */
ntfs_error(vol->sb, "Failed to allocate name from "
"ntfs_name_cache!");
} /* else if (!ucs) */
ntfs_error(vol->sb, "Failed to allocate buffer for converted "
"name from ntfs_name_cache.");
return -ENOMEM;
} /* else (!ins) */
ntfs_error(NULL, "Received NULL pointer.");
} /* else if (!ins) */
ntfs_error(vol->sb, "Received NULL pointer.");
return -EINVAL;
conversion_err:
ntfs_error(vol->sb, "Name using character set %s contains characters "
"that cannot be converted to Unicode.", nls->charset);
name_err:
kmem_cache_free(ntfs_name_cache, ucs);
return -EILSEQ;
if (wc_len < 0) {
ntfs_error(vol->sb, "Name using character set %s contains "
"characters that cannot be converted to "
"Unicode.", nls->charset);
i = -EILSEQ;
} else /* if (o >= NTFS_MAX_NAME_LEN) */ {
ntfs_error(vol->sb, "Name is too long (maximum length for a "
"name on NTFS is %d Unicode characters.",
NTFS_MAX_NAME_LEN);
i = -ENAMETOOLONG;
}
return i;
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment