Commit af6ea9ca authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/aia21/ntfs-2.6

parents 1fa4aad4 c5147207
......@@ -21,7 +21,7 @@ Overview
========
Linux-NTFS comes with a number of user-space programs known as ntfsprogs.
These include mkntfs, a full-featured ntfs file system format utility,
These include mkntfs, a full-featured ntfs filesystem format utility,
ntfsundelete used for recovering files that were unintentionally deleted
from an NTFS volume and ntfsresize which is used to resize an NTFS partition.
See the web site for more information.
......@@ -149,7 +149,14 @@ case_sensitive=<BOOL> If case_sensitive is specified, treat all file names as
name, if it exists. If case_sensitive, you will need
to provide the correct case of the short file name.
errors=opt What to do when critical file system errors are found.
disable_sparse=<BOOL> If disable_sparse is specified, creation of sparse
regions, i.e. holes, inside files is disabled for the
volume (for the duration of this mount only). By
default, creation of sparse regions is enabled, which
is consistent with the behaviour of traditional Unix
filesystems.
errors=opt What to do when critical filesystem errors are found.
Following values can be used for "opt":
continue: DEFAULT, try to clean-up as much as
possible, e.g. marking a corrupt inode as
......@@ -432,6 +439,24 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.23:
- Stamp the user space journal, aka transaction log, aka $UsnJrnl, if
it is present and active thus telling Windows and applications using
the transaction log that changes can have happened on the volume
which are not recorded in $UsnJrnl.
- Detect the case when Windows has been hibernated (suspended to disk)
and if this is the case do not allow (re)mounting read-write to
prevent data corruption when you boot back into the suspended
Windows session.
- Implement extension of resident files using the normal file write
code paths, i.e. most very small files can be extended to be a little
bit bigger but not by much.
- Add new mount option "disable_sparse". (See list of mount options
above for details.)
- Improve handling of ntfs volumes with errors and strange boot sectors
in particular.
- Fix various bugs including a nasty deadlock that appeared in recent
kernels (around 2.6.11-2.6.12 timeframe).
2.1.22:
- Improve handling of ntfs volumes with errors.
- Fix various bugs and race conditions.
......
This diff is collapsed.
......@@ -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.22\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.23\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......@@ -15,5 +15,5 @@ endif
ifeq ($(CONFIG_NTFS_RW),y)
EXTRA_CFLAGS += -DNTFS_RW
ntfs-objs += bitmap.o lcnalloc.o logfile.o quota.o
ntfs-objs += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
endif
This diff is collapsed.
This diff is collapsed.
......@@ -2,7 +2,7 @@
* attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -60,10 +60,14 @@ typedef struct {
ATTR_RECORD *base_attr;
} ntfs_attr_search_ctx;
extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn);
extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
extern runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn,
const BOOL need_write);
extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
const BOOL write_locked);
extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
const VCN vcn, const BOOL write_locked);
int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
const u32 name_len, const IGNORE_CASE_BOOL ic,
......@@ -85,6 +89,8 @@ extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
MFT_RECORD *mrec);
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
#ifdef NTFS_RW
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
const ATTR_TYPE type, const s64 size);
extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
......@@ -94,7 +100,11 @@ extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
extern int ntfs_attr_make_non_resident(ntfs_inode *ni);
extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt,
const u8 val);
#endif /* NTFS_RW */
#endif /* _LINUX_NTFS_ATTRIB_H */
......@@ -96,13 +96,14 @@ void free_compression_buffers(void)
/**
* zero_partial_compressed_page - zero out of bounds compressed page region
*/
static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
static void zero_partial_compressed_page(struct page *page,
const s64 initialized_size)
{
u8 *kp = page_address(page);
unsigned int kp_ofs;
ntfs_debug("Zeroing page region outside initialized size.");
if (((s64)page->index << PAGE_CACHE_SHIFT) >= ni->initialized_size) {
if (((s64)page->index << PAGE_CACHE_SHIFT) >= initialized_size) {
/*
* FIXME: Using clear_page() will become wrong when we get
* PAGE_CACHE_SIZE != PAGE_SIZE but for now there is no problem.
......@@ -110,7 +111,7 @@ static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
clear_page(kp);
return;
}
kp_ofs = ni->initialized_size & ~PAGE_CACHE_MASK;
kp_ofs = initialized_size & ~PAGE_CACHE_MASK;
memset(kp + kp_ofs, 0, PAGE_CACHE_SIZE - kp_ofs);
return;
}
......@@ -118,12 +119,12 @@ static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
/**
* handle_bounds_compressed_page - test for&handle out of bounds compressed page
*/
static inline void handle_bounds_compressed_page(ntfs_inode *ni,
struct page *page)
static inline void handle_bounds_compressed_page(struct page *page,
const loff_t i_size, const s64 initialized_size)
{
if ((page->index >= (ni->initialized_size >> PAGE_CACHE_SHIFT)) &&
(ni->initialized_size < VFS_I(ni)->i_size))
zero_partial_compressed_page(ni, page);
if ((page->index >= (initialized_size >> PAGE_CACHE_SHIFT)) &&
(initialized_size < i_size))
zero_partial_compressed_page(page, initialized_size);
return;
}
......@@ -138,6 +139,8 @@ static inline void handle_bounds_compressed_page(ntfs_inode *ni,
* @xpage_done: set to 1 if xpage was completed successfully (IN/OUT)
* @cb_start: compression block to decompress (IN)
* @cb_size: size of compression block @cb_start in bytes (IN)
* @i_size: file size when we started the read (IN)
* @initialized_size: initialized file size when we started the read (IN)
*
* The caller must have disabled preemption. ntfs_decompress() reenables it when
* the critical section is finished.
......@@ -165,7 +168,8 @@ static inline void handle_bounds_compressed_page(ntfs_inode *ni,
static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
int *dest_ofs, const int dest_max_index, const int dest_max_ofs,
const int xpage, char *xpage_done, u8 *const cb_start,
const u32 cb_size)
const u32 cb_size, const loff_t i_size,
const s64 initialized_size)
{
/*
* Pointers into the compressed data, i.e. the compression block (cb),
......@@ -219,9 +223,6 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
spin_unlock(&ntfs_cb_lock);
/* Second stage: finalize completed pages. */
if (nr_completed_pages > 0) {
struct page *page = dest_pages[completed_pages[0]];
ntfs_inode *ni = NTFS_I(page->mapping->host);
for (i = 0; i < nr_completed_pages; i++) {
int di = completed_pages[i];
......@@ -230,7 +231,8 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
* If we are outside the initialized size, zero
* the out of bounds page range.
*/
handle_bounds_compressed_page(ni, dp);
handle_bounds_compressed_page(dp, i_size,
initialized_size);
flush_dcache_page(dp);
kunmap(dp);
SetPageUptodate(dp);
......@@ -478,12 +480,14 @@ static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
*/
int ntfs_read_compressed_block(struct page *page)
{
loff_t i_size;
s64 initialized_size;
struct address_space *mapping = page->mapping;
ntfs_inode *ni = NTFS_I(mapping->host);
ntfs_volume *vol = ni->vol;
struct super_block *sb = vol->sb;
runlist_element *rl;
unsigned long block_size = sb->s_blocksize;
unsigned long flags, block_size = sb->s_blocksize;
unsigned char block_size_bits = sb->s_blocksize_bits;
u8 *cb, *cb_pos, *cb_end;
struct buffer_head **bhs;
......@@ -552,8 +556,12 @@ int ntfs_read_compressed_block(struct page *page)
* The remaining pages need to be allocated and inserted into the page
* cache, alignment guarantees keep all the below much simpler. (-8
*/
max_page = ((VFS_I(ni)->i_size + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT) - offset;
read_lock_irqsave(&ni->size_lock, flags);
i_size = i_size_read(VFS_I(ni));
initialized_size = ni->initialized_size;
read_unlock_irqrestore(&ni->size_lock, flags);
max_page = ((i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -
offset;
if (nr_pages < max_page)
max_page = nr_pages;
for (i = 0; i < max_page; i++, offset++) {
......@@ -824,7 +832,8 @@ int ntfs_read_compressed_block(struct page *page)
* If we are outside the initialized size, zero
* the out of bounds page range.
*/
handle_bounds_compressed_page(ni, page);
handle_bounds_compressed_page(page, i_size,
initialized_size);
flush_dcache_page(page);
kunmap(page);
SetPageUptodate(page);
......@@ -847,7 +856,8 @@ int ntfs_read_compressed_block(struct page *page)
ntfs_debug("Found compressed compression block.");
err = ntfs_decompress(pages, &cur_page, &cur_ofs,
cb_max_page, cb_max_ofs, xpage, &xpage_done,
cb_pos, cb_size - (cb_pos - cb));
cb_pos, cb_size - (cb_pos - cb), i_size,
initialized_size);
/*
* We can sleep from now on, lock already dropped by
* ntfs_decompress().
......
......@@ -164,14 +164,17 @@ void ntfs_debug_dump_runlist(const runlist_element *rl)
if (index > -LCN_ENOENT - 1)
index = 3;
printk(KERN_DEBUG "%-16Lx %s %-16Lx%s\n",
(rl + i)->vcn, lcn_str[index],
(rl + i)->length, (rl + i)->length ?
"" : " (runlist end)");
(long long)(rl + i)->vcn, lcn_str[index],
(long long)(rl + i)->length,
(rl + i)->length ? "" :
" (runlist end)");
} else
printk(KERN_DEBUG "%-16Lx %-16Lx %-16Lx%s\n",
(rl + i)->vcn, (rl + i)->lcn,
(rl + i)->length, (rl + i)->length ?
"" : " (runlist end)");
(long long)(rl + i)->vcn,
(long long)(rl + i)->lcn,
(long long)(rl + i)->length,
(rl + i)->length ? "" :
" (runlist end)");
if (!(rl + i)->length)
break;
}
......
/**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -183,7 +183,6 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
name->len = 0;
*res = name;
} else {
if (name)
kfree(name);
*res = NULL;
}
......@@ -444,7 +443,6 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
name->len = 0;
*res = name;
} else {
if (name)
kfree(name);
*res = NULL;
}
......@@ -610,7 +608,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
// TODO: (AIA)
// The algorithm embedded in this code will be required for the time when we
// want to support adding of entries to directories, where we require correct
// collation of file names in order not to cause corruption of the file system.
// collation of file names in order not to cause corruption of the filesystem.
/**
* ntfs_lookup_inode_by_name - find an inode in a directory given its name
......@@ -1101,7 +1099,7 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos,
static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
loff_t fpos;
loff_t fpos, i_size;
struct inode *bmp_vi, *vdir = filp->f_dentry->d_inode;
struct super_block *sb = vdir->i_sb;
ntfs_inode *ndir = NTFS_I(vdir);
......@@ -1122,7 +1120,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
vdir->i_ino, fpos);
rc = err = 0;
/* Are we at end of dir yet? */
if (fpos >= vdir->i_size + vol->mft_record_size)
i_size = i_size_read(vdir);
if (fpos >= i_size + vol->mft_record_size)
goto done;
/* Emulate . and .. for all directories. */
if (!fpos) {
......@@ -1264,7 +1263,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
bmp_mapping = bmp_vi->i_mapping;
/* Get the starting bitmap bit position and sanity check it. */
bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
if (unlikely(bmp_pos >> 3 >= bmp_vi->i_size)) {
if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
ntfs_error(sb, "Current index allocation position exceeds "
"index bitmap size.");
goto err_out;
......@@ -1301,7 +1300,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
goto get_next_bmp_page;
}
/* If we have reached the end of the bitmap, we are done. */
if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= vdir->i_size))
if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size))
goto unm_EOD;
ia_pos = (bmp_pos + cur_bmp_pos) <<
ndir->itype.index.block_size_bits;
......@@ -1309,7 +1308,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
ntfs_debug("Handling index buffer 0x%llx.",
(unsigned long long)bmp_pos + cur_bmp_pos);
/* If the current index buffer is in the same page we reuse the page. */
if ((prev_ia_pos & PAGE_CACHE_MASK) != (ia_pos & PAGE_CACHE_MASK)) {
if ((prev_ia_pos & (s64)PAGE_CACHE_MASK) !=
(ia_pos & (s64)PAGE_CACHE_MASK)) {
prev_ia_pos = ia_pos;
if (likely(ia_page != NULL)) {
unlock_page(ia_page);
......@@ -1441,7 +1441,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
ntfs_unmap_page(bmp_page);
EOD:
/* We are finished, set fpos to EOD. */
fpos = vdir->i_size + vol->mft_record_size;
fpos = i_size + vol->mft_record_size;
abort:
kfree(name);
done:
......@@ -1461,9 +1461,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
unlock_page(ia_page);
ntfs_unmap_page(ia_page);
}
if (ir)
kfree(ir);
if (name)
kfree(name);
if (ctx)
ntfs_attr_put_search_ctx(ctx);
......@@ -1495,7 +1493,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int ntfs_dir_open(struct inode *vi, struct file *filp)
{
if (sizeof(unsigned long) < 8) {
if (vi->i_size > MAX_LFS_FILESIZE)
if (i_size_read(vi) > MAX_LFS_FILESIZE)
return -EFBIG;
}
return 0;
......
......@@ -47,7 +47,7 @@
static int ntfs_file_open(struct inode *vi, struct file *filp)
{
if (sizeof(unsigned long) < 8) {
if (vi->i_size > MAX_LFS_FILESIZE)
if (i_size_read(vi) > MAX_LFS_FILESIZE)
return -EFBIG;
}
return generic_file_open(vi, filp);
......
/*
* index.c - NTFS kernel index handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2004-2005 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
......@@ -39,18 +39,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni)
ntfs_index_context *ictx;
ictx = kmem_cache_alloc(ntfs_index_ctx_cache, SLAB_NOFS);
if (ictx) {
ictx->idx_ni = idx_ni;
ictx->entry = NULL;
ictx->data = NULL;
ictx->data_len = 0;
ictx->is_in_root = 0;
ictx->ir = NULL;
ictx->actx = NULL;
ictx->base_ni = NULL;
ictx->ia = NULL;
ictx->page = NULL;
}
if (ictx)
*ictx = (ntfs_index_context){ .idx_ni = idx_ni };
return ictx;
}
......
This diff is collapsed.
......@@ -2,7 +2,7 @@
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
* the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -44,6 +44,7 @@ typedef struct _ntfs_inode ntfs_inode;
* fields already provided in the VFS inode.
*/
struct _ntfs_inode {
rwlock_t size_lock; /* Lock serializing access to inode sizes. */
s64 initialized_size; /* Copy from the attribute record. */
s64 allocated_size; /* Copy from the attribute record. */
unsigned long state; /* NTFS specific flags describing this inode.
......@@ -109,7 +110,7 @@ struct _ntfs_inode {
u8 block_size_bits; /* Log2 of the above. */
u8 vcn_size_bits; /* Log2 of the above. */
} index;
struct { /* It is a compressed file or an attribute inode. */
struct { /* It is a compressed/sparse file/attribute inode. */
s64 size; /* Copy of compressed_size from
$DATA. */
u32 block_size; /* Size of a compression block
......@@ -165,6 +166,7 @@ typedef enum {
NI_Sparse, /* 1: Unnamed data attr is sparse (f).
1: Create sparse files by default (d).
1: Attribute is sparse (a). */
NI_SparseDisabled, /* 1: May not create sparse regions. */
NI_TruncateFailed, /* 1: Last ntfs_truncate() call failed. */
} ntfs_inode_state_bits;
......@@ -217,6 +219,7 @@ NINO_FNS(IndexAllocPresent)
NINO_FNS(Compressed)
NINO_FNS(Encrypted)
NINO_FNS(Sparse)
NINO_FNS(SparseDisabled)
NINO_FNS(TruncateFailed)
/*
......
......@@ -2,7 +2,7 @@
* layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -547,26 +547,44 @@ enum {
COLLATION_NTOFS_ULONG = const_cpu_to_le32(0x10),
COLLATION_NTOFS_SID = const_cpu_to_le32(0x11),
COLLATION_NTOFS_SECURITY_HASH = const_cpu_to_le32(0x12),
COLLATION_NTOFS_ULONGS = const_cpu_to_le32(0x13)
COLLATION_NTOFS_ULONGS = const_cpu_to_le32(0x13),
};
typedef le32 COLLATION_RULE;
/*
* The flags (32-bit) describing attribute properties in the attribute
* definition structure. FIXME: This information is from Regis's information
* and, according to him, it is not certain and probably incomplete.
* The INDEXABLE flag is fairly certainly correct as only the file name
* attribute has this flag set and this is the only attribute indexed in NT4.
* definition structure. FIXME: This information is based on Regis's
* information and, according to him, it is not certain and probably
* incomplete. The INDEXABLE flag is fairly certainly correct as only the file
* name attribute has this flag set and this is the only attribute indexed in
* NT4.
*/
enum {
INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be
ATTR_DEF_INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be
indexed. */
NEED_TO_REGENERATE = const_cpu_to_le32(0x40), /* Need to regenerate
during regeneration
phase. */
CAN_BE_NON_RESIDENT = const_cpu_to_le32(0x80), /* Attribute can be
non-resident. */
ATTR_DEF_MULTIPLE = const_cpu_to_le32(0x04), /* Attribute type
can be present multiple times in the
mft records of an inode. */
ATTR_DEF_NOT_ZERO = const_cpu_to_le32(0x08), /* Attribute value
must contain at least one non-zero
byte. */
ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be
indexed and the attribute value must be
unique for the attribute type in all of
the mft records of an inode. */
ATTR_DEF_NAMED_UNIQUE = const_cpu_to_le32(0x20), /* Attribute must be
named and the name must be unique for
the attribute type in all of the mft
records of an inode. */
ATTR_DEF_RESIDENT = const_cpu_to_le32(0x40), /* Attribute must be
resident. */
ATTR_DEF_ALWAYS_LOG = const_cpu_to_le32(0x80), /* Always log
modifications to this attribute,
regardless of whether it is resident or
non-resident. Without this, only log
modifications if the attribute is
resident. */
};
typedef le32 ATTR_DEF_FLAGS;
......@@ -752,7 +770,8 @@ typedef struct {
clusters in a compression unit. 0 means not
compressed. (This effectively limits the
compression unit size to be a power of two
clusters.) WinNT4 only uses a value of 4. */
clusters.) WinNT4 only uses a value of 4.
Sparse files also have this set to 4. */
/* 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.*/
......@@ -773,9 +792,9 @@ typedef struct {
/* sizeof(uncompressed attr) = 64*/
/* 64*/ sle64 compressed_size; /* Byte size of the attribute
value after compression. Only present when
compressed. Always is a multiple of the
cluster size. Represents the actual amount of
disk space being used on the disk. */
compressed or sparse. Always is a multiple of
the cluster size. Represents the actual amount
of disk space being used on the disk. */
/* sizeof(compressed attr) = 72*/
} __attribute__ ((__packed__)) non_resident;
} __attribute__ ((__packed__)) data;
......@@ -834,7 +853,7 @@ enum {
/* 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
index, quota index, one of the security indexes or the encrypting
file system related indexes). */
filesystem related indexes). */
};
typedef le32 FILE_ATTR_FLAGS;
......@@ -917,20 +936,12 @@ typedef struct {
/* 56*/ le64 quota_charged; /* Byte size of the charge to
the quota for all streams of the file. Note: Is
zero if quotas are disabled. */
/* 64*/ le64 usn; /* Last update sequence number
/* 64*/ leUSN usn; /* Last update sequence number
of the file. This is a direct index into the
change (aka usn) journal file. It is zero if
the usn journal is disabled.
NOTE: To disable the journal need to delete
the journal file itself and to then walk the
whole mft and set all Usn entries in all mft
records to zero! (This can take a while!)
The journal is FILE_Extend/$UsnJrnl. Win2k
will recreate the journal and initiate
logging if necessary when mounting the
partition. This, in contrast to disabling the
journal is a very fast process, so the user
won't even notice it. */
transaction log file ($UsnJrnl). It is zero if
the usn journal is disabled or this file has
not been subject to logging yet. See usnjrnl.h
for details. */
} __attribute__ ((__packed__)) v3;
/* sizeof() = 72 bytes (NTFS 3.x) */
} __attribute__ ((__packed__)) ver;
......@@ -1893,7 +1904,7 @@ enum {
VOLUME_FLAGS_MASK = const_cpu_to_le16(0x803f),
/* To make our life easier when checking if we must mount read-only. */
VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8037),
VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8027),
} __attribute__ ((__packed__));
typedef le16 VOLUME_FLAGS;
......
/*
* lcnalloc.c - Cluster (de)allocation code. Part of the Linux-NTFS project.
*
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2004-2005 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
......@@ -60,7 +60,7 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
if (rl->lcn < 0)
continue;
err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length);
if (unlikely(err && (!ret || ret == ENOMEM) && ret != err))
if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err))
ret = err;
}
ntfs_debug("Done.");
......@@ -140,6 +140,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
s64 clusters;
loff_t i_size;
struct inode *lcnbmp_vi;
runlist_element *rl = NULL;
struct address_space *mapping;
......@@ -249,6 +250,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
clusters = count;
rlpos = rlsize = 0;
mapping = lcnbmp_vi->i_mapping;
i_size = i_size_read(lcnbmp_vi);
while (1) {
ntfs_debug("Start of outer while loop: done_zones 0x%x, "
"search_zone %i, pass %i, zone_start 0x%llx, "
......@@ -263,7 +265,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
last_read_pos = bmp_pos >> 3;
ntfs_debug("last_read_pos 0x%llx.",
(unsigned long long)last_read_pos);
if (last_read_pos > lcnbmp_vi->i_size) {
if (last_read_pos > i_size) {
ntfs_debug("End of attribute reached. "
"Skipping to zone_pass_done.");
goto zone_pass_done;
......@@ -287,11 +289,11 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
buf_size = last_read_pos & ~PAGE_CACHE_MASK;
buf = page_address(page) + buf_size;
buf_size = PAGE_CACHE_SIZE - buf_size;
if (unlikely(last_read_pos + buf_size > lcnbmp_vi->i_size))
buf_size = lcnbmp_vi->i_size - last_read_pos;
if (unlikely(last_read_pos + buf_size > i_size))
buf_size = i_size - last_read_pos;
buf_size <<= 3;
lcn = bmp_pos & 7;
bmp_pos &= ~7;
bmp_pos &= ~(LCN)7;
ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, "
"bmp_pos 0x%llx, need_writeback %i.", buf_size,
(unsigned long long)lcn,
......@@ -309,7 +311,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
(unsigned int)*byte);
/* Skip full bytes. */
if (*byte == 0xff) {
lcn = (lcn + 8) & ~7;
lcn = (lcn + 8) & ~(LCN)7;
ntfs_debug("Continuing while loop 1.");
continue;
}
......@@ -691,7 +693,7 @@ switch_to_data1_zone: search_zone = 2;
if (zone == MFT_ZONE || mft_zone_size <= 0) {
ntfs_debug("No free clusters left, going to out.");
/* Really no more space left on device. */
err = ENOSPC;
err = -ENOSPC;
goto out;
} /* zone == DATA_ZONE && mft_zone_size > 0 */
ntfs_debug("Shrinking mft zone.");
......@@ -755,13 +757,13 @@ switch_to_data1_zone: search_zone = 2;
if (rl) {
int err2;
if (err == ENOSPC)
if (err == -ENOSPC)
ntfs_debug("Not enough space to complete allocation, "
"err ENOSPC, first free lcn 0x%llx, "
"err -ENOSPC, first free lcn 0x%llx, "
"could allocate up to 0x%llx "
"clusters.",
(unsigned long long)rl[0].lcn,
(unsigned long long)count - clusters);
(unsigned long long)(count - clusters));
/* Deallocate all allocated clusters. */
ntfs_debug("Attempting rollback...");
err2 = ntfs_cluster_free_from_rl_nolock(vol, rl);
......@@ -773,10 +775,10 @@ switch_to_data1_zone: search_zone = 2;
}
/* Free the runlist. */
ntfs_free(rl);
} else if (err == ENOSPC)
ntfs_debug("No space left at all, err = ENOSPC, "
"first free lcn = 0x%llx.",
(unsigned long long)vol->data1_zone_pos);
} else if (err == -ENOSPC)
ntfs_debug("No space left at all, err = -ENOSPC, first free "
"lcn = 0x%llx.",
(long long)vol->data1_zone_pos);
up_write(&vol->lcnbmp_lock);
return ERR_PTR(err);
}
......@@ -846,8 +848,8 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
total_freed = real_freed = 0;
/* This returns with ni->runlist locked for reading on success. */
rl = ntfs_find_vcn(ni, start_vcn, FALSE);
down_read(&ni->runlist.lock);
rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, FALSE);
if (IS_ERR(rl)) {
if (!is_rollback)
ntfs_error(vol->sb, "Failed to find first runlist "
......@@ -861,7 +863,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
ntfs_error(vol->sb, "First runlist element has "
"invalid lcn, aborting.");
err = -EIO;
goto unl_err_out;
goto err_out;
}
/* Find the starting cluster inside the run that needs freeing. */
delta = start_vcn - rl->vcn;
......@@ -879,7 +881,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
if (!is_rollback)
ntfs_error(vol->sb, "Failed to clear first run "
"(error %i), aborting.", err);
goto unl_err_out;
goto err_out;
}
/* We have freed @to_free real clusters. */
real_freed = to_free;
......@@ -899,30 +901,15 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
if (unlikely(rl->lcn < LCN_HOLE)) {
VCN vcn;
/*
* Attempt to map runlist, dropping runlist lock for
* the duration.
*/
/* Attempt to map runlist. */
vcn = rl->vcn;
up_read(&ni->runlist.lock);
err = ntfs_map_runlist(ni, vcn);
if (err) {
if (!is_rollback)
ntfs_error(vol->sb, "Failed to map "
"runlist fragment.");
if (err == -EINVAL || err == -ENOENT)
err = -EIO;
goto err_out;
}
/*
* This returns with ni->runlist locked for reading on
* success.
*/
rl = ntfs_find_vcn(ni, vcn, FALSE);
rl = ntfs_attr_find_vcn_nolock(ni, vcn, FALSE);
if (IS_ERR(rl)) {
err = PTR_ERR(rl);
if (!is_rollback)
ntfs_error(vol->sb, "Failed to find "
ntfs_error(vol->sb, "Failed to map "
"runlist fragment or "
"failed to find "
"subsequent runlist "
"element.");
goto err_out;
......@@ -935,7 +922,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
(unsigned long long)
rl->lcn);
err = -EIO;
goto unl_err_out;
goto err_out;
}
}
/* The number of clusters in this run that need freeing. */
......@@ -951,7 +938,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
if (!is_rollback)
ntfs_error(vol->sb, "Failed to clear "
"subsequent run.");
goto unl_err_out;
goto err_out;
}
/* We have freed @to_free real clusters. */
real_freed += to_free;
......@@ -972,9 +959,8 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
/* We are done. Return the number of actually freed clusters. */
ntfs_debug("Done.");
return real_freed;
unl_err_out:
up_read(&ni->runlist.lock);
err_out:
up_read(&ni->runlist.lock);
if (is_rollback)
return err;
/* If no real clusters were freed, no need to rollback. */
......
/*
* logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2004 Anton Altaparmakov
* Copyright (c) 2002-2005 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
......@@ -410,7 +410,7 @@ static BOOL ntfs_check_and_load_restart_page(struct inode *vi,
}
/**
* ntfs_ckeck_logfile - check in the journal if the volume is consistent
* ntfs_check_logfile - check the journal for consistency
* @log_vi: struct inode of loaded journal $LogFile to check
*
* Check the $LogFile journal for consistency and return TRUE if it is
......@@ -443,7 +443,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi)
/* An empty $LogFile must have been clean before it got emptied. */
if (NVolLogFileEmpty(vol))
goto is_empty;
size = log_vi->i_size;
size = i_size_read(log_vi);
/* Make sure the file doesn't exceed the maximum allowed size. */
if (size > MaxLogFileSize)
size = MaxLogFileSize;
......@@ -464,7 +464,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi)
* optimize log_page_size and log_page_bits into constants.
*/
log_page_bits = generic_ffs(log_page_size) - 1;
size &= ~(log_page_size - 1);
size &= ~(s64)(log_page_size - 1);
/*
* Ensure the log file is big enough to store at least the two restart
* pages and the minimum number of log record pages.
......@@ -689,7 +689,8 @@ BOOL ntfs_empty_logfile(struct inode *log_vi)
if (!NVolLogFileEmpty(vol)) {
int err;
err = ntfs_attr_set(NTFS_I(log_vi), 0, log_vi->i_size, 0xff);
err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi),
0xff);
if (unlikely(err)) {
ntfs_error(vol->sb, "Failed to fill $LogFile with "
"0xff bytes (error code %i).", err);
......
This diff is collapsed.
......@@ -153,7 +153,6 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
"error code %li.", dent_ino,
PTR_ERR(dent_inode));
if (name)
kfree(name);
/* Return the error code. */
return (struct dentry *)dent_inode;
......@@ -380,7 +379,7 @@ struct inode_operations ntfs_dir_inode_ops = {
* Return the dentry of the parent directory on success or the error code on
* error (IS_ERR() is true).
*/
struct dentry *ntfs_get_parent(struct dentry *child_dent)
static struct dentry *ntfs_get_parent(struct dentry *child_dent)
{
struct inode *vi = child_dent->d_inode;
ntfs_inode *ni = NTFS_I(vi);
......@@ -465,7 +464,7 @@ struct dentry *ntfs_get_parent(struct dentry *child_dent)
*
* Return the dentry on success or the error code on error (IS_ERR() is true).
*/
struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
static struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
{
struct inode *vi;
struct dentry *dent;
......@@ -496,3 +495,30 @@ struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen);
return dent;
}
/**
* Export operations allowing NFS exporting of mounted NTFS partitions.
*
* We use the default ->decode_fh() and ->encode_fh() for now. Note that they
* use 32 bits to store the inode number which is an unsigned long so on 64-bit
* architectures is usually 64 bits so it would all fail horribly on huge
* volumes. I guess we need to define our own encode and decode fh functions
* that store 64-bit inode numbers at some point but for now we will ignore the
* problem...
*
* We also use the default ->get_name() helper (used by ->decode_fh() via
* fs/exportfs/expfs.c::find_exported_dentry()) as that is completely fs
* independent.
*
* The default ->get_parent() just returns -EACCES so we have to provide our
* own and the default ->get_dentry() is incompatible with NTFS due to not
* allowing the inode number 0 which is used in NTFS for the system file $MFT
* and due to using iget() whereas NTFS needs ntfs_iget().
*/
struct export_operations ntfs_export_ops = {
.get_parent = ntfs_get_parent, /* Find the parent of a given
directory. */
.get_dentry = ntfs_get_dentry, /* Find a dentry for the inode
given a file handle
sub-fragment. */
};
......@@ -2,7 +2,7 @@
* ntfs.h - Defines for NTFS Linux kernel driver. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (C) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -31,6 +31,7 @@
#include <linux/fs.h>
#include <linux/nls.h>
#include <linux/smp.h>
#include <linux/pagemap.h>
#include "types.h"
#include "volume.h"
......@@ -41,6 +42,9 @@ typedef enum {
NTFS_BLOCK_SIZE_BITS = 9,
NTFS_SB_MAGIC = 0x5346544e, /* 'NTFS' */
NTFS_MAX_NAME_LEN = 255,
NTFS_MAX_ATTR_NAME_LEN = 255,
NTFS_MAX_CLUSTER_SIZE = 64 * 1024, /* 64kiB */
NTFS_MAX_PAGES_PER_CLUSTER = NTFS_MAX_CLUSTER_SIZE / PAGE_CACHE_SIZE,
} NTFS_CONSTANTS;
/* Global variables. */
......@@ -65,6 +69,8 @@ extern struct inode_operations ntfs_dir_inode_ops;
extern struct file_operations ntfs_empty_file_ops;
extern struct inode_operations ntfs_empty_inode_ops;
extern struct export_operations ntfs_export_ops;
/**
* NTFS_SB - return the ntfs volume given a vfs super block
* @sb: VFS super block
......
This diff is collapsed.
......@@ -2,7 +2,7 @@
* runlist.h - Defines for runlist handling in NTFS Linux kernel driver.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -66,6 +66,8 @@ typedef enum {
LCN_HOLE = -1, /* Keep this as highest value or die! */
LCN_RL_NOT_MAPPED = -2,
LCN_ENOENT = -3,
LCN_ENOMEM = -4,
LCN_EIO = -5,
} LCN_SPECIAL_VALUES;
extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
......@@ -76,14 +78,22 @@ extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);
#ifdef NTFS_RW
extern runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl,
const VCN vcn);
extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
const runlist_element *rl, const VCN start_vcn);
const runlist_element *rl, const VCN first_vcn,
const VCN last_vcn);
extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
const int dst_len, const runlist_element *rl,
const VCN start_vcn, VCN *const stop_vcn);
const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn);
extern int ntfs_rl_truncate_nolock(const ntfs_volume *vol,
runlist *const runlist, const s64 new_length);
#endif /* NTFS_RW */
#endif /* _LINUX_NTFS_RUNLIST_H */
This diff is collapsed.
......@@ -3,7 +3,7 @@
* the Linux-NTFS project. Adapted from the old NTFS driver,
* Copyright (C) 1997 Martin von Lwis, Rgis Duchesne
*
* Copyright (c) 2002-2004 Anton Altaparmakov
* Copyright (c) 2002-2005 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
......@@ -67,7 +67,7 @@ int ntfs_sysctl(int add)
return -ENOMEM;
#ifdef CONFIG_PROC_FS
/*
* If the proc file system is in use and we are a module, need
* If the proc filesystem is in use and we are a module, need
* to set the owner of our proc entry to our module. In the
* non-modular case, THIS_MODULE is NULL, so this is ok.
*/
......
/*
* time.h - NTFS time conversion functions. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 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
......@@ -87,7 +87,7 @@ static inline struct timespec ntfs2utc(const sle64 time)
struct timespec ts;
/* Subtract the NTFS time offset. */
s64 t = sle64_to_cpu(time) - NTFS_TIME_OFFSET;
u64 t = (u64)(sle64_to_cpu(time) - NTFS_TIME_OFFSET);
/*
* Convert the time to 1-second intervals and the remainder to
* 1-nano-second intervals.
......
......@@ -2,7 +2,7 @@
* types.h - Defines for NTFS Linux kernel driver specific types.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 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
......@@ -53,6 +53,14 @@ typedef sle64 leLCN;
typedef s64 LSN;
typedef sle64 leLSN;
/*
* The NTFS transaction log $UsnJrnl uses usn which are signed 64-bit values.
* We define our own type USN, to allow for type checking and better code
* readability.
*/
typedef s64 USN;
typedef sle64 leUSN;
typedef enum {
FALSE = 0,
TRUE = 1
......
......@@ -264,7 +264,7 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
/* We don't trust outside sources. */
if (ins) {
ucs = (ntfschar*)kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS);
ucs = kmem_cache_alloc(ntfs_name_cache, SLAB_NOFS);
if (ucs) {
for (i = o = 0; i < ins_len; i += wc_len) {
wc_len = nls->char2uni(ins + i, ins_len - i,
......
/*
* usnjrnl.h - NTFS kernel transaction log ($UsnJrnl) handling. Part of the
* Linux-NTFS project.
*
* Copyright (c) 2005 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
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef NTFS_RW
#include <linux/fs.h>
#include <linux/highmem.h>
#include <linux/mm.h>
#include "aops.h"
#include "debug.h"
#include "endian.h"
#include "time.h"
#include "types.h"
#include "usnjrnl.h"
#include "volume.h"
/**
* ntfs_stamp_usnjrnl - stamp the transaction log ($UsnJrnl) on an ntfs volume
* @vol: ntfs volume on which to stamp the transaction log
*
* Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
* TRUE on success and FALSE on error.
*
* This function assumes that the transaction log has already been loaded and
* consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
*/
BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol)
{
ntfs_debug("Entering.");
if (likely(!NVolUsnJrnlStamped(vol))) {
sle64 stamp;
struct page *page;
USN_HEADER *uh;
page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read from "
"$UsnJrnl/$DATA/$Max attribute.");
return FALSE;
}
uh = (USN_HEADER*)page_address(page);
stamp = get_current_ntfs_time();
ntfs_debug("Stamping transaction log ($UsnJrnl): old "
"journal_id 0x%llx, old lowest_valid_usn "
"0x%llx, new journal_id 0x%llx, new "
"lowest_valid_usn 0x%llx.",
(long long)sle64_to_cpu(uh->journal_id),
(long long)sle64_to_cpu(uh->lowest_valid_usn),
(long long)sle64_to_cpu(stamp),
i_size_read(vol->usnjrnl_j_ino));
uh->lowest_valid_usn =
cpu_to_sle64(i_size_read(vol->usnjrnl_j_ino));
uh->journal_id = stamp;
flush_dcache_page(page);
set_page_dirty(page);
ntfs_unmap_page(page);
/* Set the flag so we do not have to do it again on remount. */
NVolSetUsnJrnlStamped(vol);
}
ntfs_debug("Done.");
return TRUE;
}
#endif /* NTFS_RW */
/*
* usnjrnl.h - Defines for NTFS kernel transaction log ($UsnJrnl) handling.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2005 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
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LINUX_NTFS_USNJRNL_H
#define _LINUX_NTFS_USNJRNL_H
#ifdef NTFS_RW
#include "types.h"
#include "endian.h"
#include "layout.h"
#include "volume.h"
/*
* Transaction log ($UsnJrnl) organization:
*
* The transaction log records whenever a file is modified in any way. So for
* example it will record that file "blah" was written to at a particular time
* but not what was written. If will record that a file was deleted or
* created, that a file was truncated, etc. See below for all the reason
* codes used.
*
* The transaction log is in the $Extend directory which is in the root
* directory of each volume. If it is not present it means transaction
* logging is disabled. If it is present it means transaction logging is
* either enabled or in the process of being disabled in which case we can
* ignore it as it will go away as soon as Windows gets its hands on it.
*
* To determine whether the transaction logging is enabled or in the process
* of being disabled, need to check the volume flags in the
* $VOLUME_INFORMATION attribute in the $Volume system file (which is present
* in the root directory and has a fixed mft record number, see layout.h).
* If the flag VOLUME_DELETE_USN_UNDERWAY is set it means the transaction log
* is in the process of being disabled and if this flag is clear it means the
* transaction log is enabled.
*
* The transaction log consists of two parts; the $DATA/$Max attribute as well
* as the $DATA/$J attribute. $Max is a header describing the transaction
* log whilst $J is the transaction log data itself as a sequence of variable
* sized USN_RECORDs (see below for all the structures).
*
* We do not care about transaction logging at this point in time but we still
* need to let windows know that the transaction log is out of date. To do
* this we need to stamp the transaction log. This involves setting the
* lowest_valid_usn field in the $DATA/$Max attribute to the usn to be used
* for the next added USN_RECORD to the $DATA/$J attribute as well as
* generating a new journal_id in $DATA/$Max.
*
* The journal_id is as of the current version (2.0) of the transaction log
* simply the 64-bit timestamp of when the journal was either created or last
* stamped.
*
* To determine the next usn there are two ways. The first is to parse
* $DATA/$J and to find the last USN_RECORD in it and to add its record_length
* to its usn (which is the byte offset in the $DATA/$J attribute). The
* second is simply to take the data size of the attribute. Since the usns
* are simply byte offsets into $DATA/$J, this is exactly the next usn. For
* obvious reasons we use the second method as it is much simpler and faster.
*
* As an aside, note that to actually disable the transaction log, one would
* need to set the VOLUME_DELETE_USN_UNDERWAY flag (see above), then go
* through all the mft records on the volume and set the usn field in their
* $STANDARD_INFORMATION attribute to zero. Once that is done, one would need
* to delete the transaction log file, i.e. \$Extent\$UsnJrnl, and finally,
* one would need to clear the VOLUME_DELETE_USN_UNDERWAY flag.
*
* Note that if a volume is unmounted whilst the transaction log is being
* disabled, the process will continue the next time the volume is mounted.
* This is why we can safely mount read-write when we see a transaction log
* in the process of being deleted.
*/
/* Some $UsnJrnl related constants. */
#define UsnJrnlMajorVer 2
#define UsnJrnlMinorVer 0
/*
* $DATA/$Max attribute. This is (always?) resident and has a fixed size of
* 32 bytes. It contains the header describing the transaction log.
*/
typedef struct {
/*Ofs*/
/* 0*/sle64 maximum_size; /* The maximum on-disk size of the $DATA/$J
attribute. */
/* 8*/sle64 allocation_delta; /* Number of bytes by which to increase the
size of the $DATA/$J attribute. */
/*0x10*/sle64 journal_id; /* Current id of the transaction log. */
/*0x18*/leUSN lowest_valid_usn; /* Lowest valid usn in $DATA/$J for the
current journal_id. */
/* sizeof() = 32 (0x20) bytes */
} __attribute__ ((__packed__)) USN_HEADER;
/*
* Reason flags (32-bit). Cumulative flags describing the change(s) to the
* file since it was last opened. I think the names speak for themselves but
* if you disagree check out the descriptions in the Linux NTFS project NTFS
* documentation: http://linux-ntfs.sourceforge.net/ntfs/files/usnjrnl.html
*/
enum {
USN_REASON_DATA_OVERWRITE = const_cpu_to_le32(0x00000001),
USN_REASON_DATA_EXTEND = const_cpu_to_le32(0x00000002),
USN_REASON_DATA_TRUNCATION = const_cpu_to_le32(0x00000004),
USN_REASON_NAMED_DATA_OVERWRITE = const_cpu_to_le32(0x00000010),
USN_REASON_NAMED_DATA_EXTEND = const_cpu_to_le32(0x00000020),
USN_REASON_NAMED_DATA_TRUNCATION= const_cpu_to_le32(0x00000040),
USN_REASON_FILE_CREATE = const_cpu_to_le32(0x00000100),
USN_REASON_FILE_DELETE = const_cpu_to_le32(0x00000200),
USN_REASON_EA_CHANGE = const_cpu_to_le32(0x00000400),
USN_REASON_SECURITY_CHANGE = const_cpu_to_le32(0x00000800),
USN_REASON_RENAME_OLD_NAME = const_cpu_to_le32(0x00001000),
USN_REASON_RENAME_NEW_NAME = const_cpu_to_le32(0x00002000),
USN_REASON_INDEXABLE_CHANGE = const_cpu_to_le32(0x00004000),
USN_REASON_BASIC_INFO_CHANGE = const_cpu_to_le32(0x00008000),
USN_REASON_HARD_LINK_CHANGE = const_cpu_to_le32(0x00010000),
USN_REASON_COMPRESSION_CHANGE = const_cpu_to_le32(0x00020000),
USN_REASON_ENCRYPTION_CHANGE = const_cpu_to_le32(0x00040000),
USN_REASON_OBJECT_ID_CHANGE = const_cpu_to_le32(0x00080000),
USN_REASON_REPARSE_POINT_CHANGE = const_cpu_to_le32(0x00100000),
USN_REASON_STREAM_CHANGE = const_cpu_to_le32(0x00200000),
USN_REASON_CLOSE = const_cpu_to_le32(0x80000000),
};
typedef le32 USN_REASON_FLAGS;
/*
* Source info flags (32-bit). Information about the source of the change(s)
* to the file. For detailed descriptions of what these mean, see the Linux
* NTFS project NTFS documentation:
* http://linux-ntfs.sourceforge.net/ntfs/files/usnjrnl.html
*/
enum {
USN_SOURCE_DATA_MANAGEMENT = const_cpu_to_le32(0x00000001),
USN_SOURCE_AUXILIARY_DATA = const_cpu_to_le32(0x00000002),
USN_SOURCE_REPLICATION_MANAGEMENT = const_cpu_to_le32(0x00000004),
};
typedef le32 USN_SOURCE_INFO_FLAGS;
/*
* $DATA/$J attribute. This is always non-resident, is marked as sparse, and
* is of variabled size. It consists of a sequence of variable size
* USN_RECORDS. The minimum allocated_size is allocation_delta as
* specified in $DATA/$Max. When the maximum_size specified in $DATA/$Max is
* exceeded by more than allocation_delta bytes, allocation_delta bytes are
* allocated and appended to the $DATA/$J attribute and an equal number of
* bytes at the beginning of the attribute are freed and made sparse. Note the
* making sparse only happens at volume checkpoints and hence the actual
* $DATA/$J size can exceed maximum_size + allocation_delta temporarily.
*/
typedef struct {
/*Ofs*/
/* 0*/le32 length; /* Byte size of this record (8-byte
aligned). */
/* 4*/le16 major_ver; /* Major version of the transaction log used
for this record. */
/* 6*/le16 minor_ver; /* Minor version of the transaction log used
for this record. */
/* 8*/leMFT_REF mft_reference;/* The mft reference of the file (or
directory) described by this record. */
/*0x10*/leMFT_REF parent_directory;/* The mft reference of the parent
directory of the file described by this
record. */
/*0x18*/leUSN usn; /* The usn of this record. Equals the offset
within the $DATA/$J attribute. */
/*0x20*/sle64 time; /* Time when this record was created. */
/*0x28*/USN_REASON_FLAGS reason;/* Reason flags (see above). */
/*0x2c*/USN_SOURCE_INFO_FLAGS source_info;/* Source info flags (see above). */
/*0x30*/le32 security_id; /* File security_id copied from
$STANDARD_INFORMATION. */
/*0x34*/FILE_ATTR_FLAGS file_attributes; /* File attributes copied from
$STANDARD_INFORMATION or $FILE_NAME (not
sure which). */
/*0x38*/le16 file_name_size; /* Size of the file name in bytes. */
/*0x3a*/le16 file_name_offset; /* Offset to the file name in bytes from the
start of this record. */
/*0x3c*/ntfschar file_name[0]; /* Use when creating only. When reading use
file_name_offset to determine the location
of the name. */
/* sizeof() = 60 (0x3c) bytes */
} __attribute__ ((__packed__)) USN_RECORD;
extern BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol);
#endif /* NTFS_RW */
#endif /* _LINUX_NTFS_USNJRNL_H */
......@@ -2,7 +2,7 @@
* volume.h - Defines for volume structures in NTFS Linux kernel driver. Part
* of the Linux-NTFS project.
*
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -54,7 +54,7 @@ typedef struct {
mode_t dmask; /* The mask for directory
permissions. */
u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
u8 on_errors; /* What to do on file system errors. */
u8 on_errors; /* What to do on filesystem errors. */
/* NTFS bootsector provided information. */
u16 sector_size; /* in bytes */
u8 sector_size_bits; /* log2(sector_size) */
......@@ -125,6 +125,10 @@ typedef struct {
/* $Quota stuff is NTFS3.0+ specific. Unused/NULL otherwise. */
struct inode *quota_ino; /* The VFS inode of $Quota. */
struct inode *quota_q_ino; /* Attribute inode for $Quota/$Q. */
/* $UsnJrnl stuff is NTFS3.0+ specific. Unused/NULL otherwise. */
struct inode *usnjrnl_ino; /* The VFS inode of $UsnJrnl. */
struct inode *usnjrnl_max_ino; /* Attribute inode for $UsnJrnl/$Max. */
struct inode *usnjrnl_j_ino; /* Attribute inode for $UsnJrnl/$J. */
#endif /* NTFS_RW */
struct nls_table *nls_map;
} ntfs_volume;
......@@ -141,6 +145,8 @@ typedef enum {
file names in WIN32 namespace. */
NV_LogFileEmpty, /* 1: $LogFile journal is empty. */
NV_QuotaOutOfDate, /* 1: $Quota is out of date. */
NV_UsnJrnlStamped, /* 1: $UsnJrnl has been stamped. */
NV_SparseEnabled, /* 1: May create sparse files. */
} ntfs_volume_flags;
/*
......@@ -167,5 +173,7 @@ NVOL_FNS(ShowSystemFiles)
NVOL_FNS(CaseSensitive)
NVOL_FNS(LogFileEmpty)
NVOL_FNS(QuotaOutOfDate)
NVOL_FNS(UsnJrnlStamped)
NVOL_FNS(SparseEnabled)
#endif /* _LINUX_NTFS_VOLUME_H */
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