NTFS: Stamp the transaction log ($UsnJrnl), aka user space journal, if it

is active on the volume and we are mounting read-write or remounting
      from read-only to read-write.

Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
This commit is contained in:
Anton Altaparmakov 2005-06-25 15:28:56 +01:00
parent 38b22b6e9f
commit 3f2faef00c
8 changed files with 566 additions and 21 deletions

View File

@ -1,6 +1,5 @@
ToDo/Notes:
- Find and fix bugs.
- Checkpoint or disable the user space journal ($UsnJrnl).
- In between ntfs_prepare/commit_write, need exclusion between
simultaneous file extensions. This is given to us by holding i_sem
on the inode. The only places in the kernel when a file is resized
@ -119,6 +118,9 @@ ToDo/Notes:
- Use C99 style structure initialization after memory allocation where
possible (fs/ntfs/{attrib.c,index.c,super.c}). Thanks to Al Viro and
Pekka Enberg.
- Stamp the transaction log ($UsnJrnl), aka user space journal, if it
is active on the volume and we are mounting read-write or remounting
from read-only to read-write.
2.1.22 - Many bug and race fixes and error handling improvements.

View File

@ -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

View File

@ -936,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
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. */
/* 64*/ USN usn; /* Last update sequence number
of the file. This is a direct index into the
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;
@ -1912,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;

View File

@ -34,6 +34,7 @@
#include "sysctl.h"
#include "logfile.h"
#include "quota.h"
#include "usnjrnl.h"
#include "dir.h"
#include "debug.h"
#include "index.h"
@ -497,6 +498,12 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
NVolSetErrors(vol);
return -EROFS;
}
if (!ntfs_stamp_usnjrnl(vol)) {
ntfs_error(sb, "Failed to stamp transation log "
"($UsnJrnl)%s", es);
NVolSetErrors(vol);
return -EROFS;
}
} else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
/* Remounting read-only. */
if (!NVolErrors(vol)) {
@ -1218,6 +1225,167 @@ static BOOL load_and_init_quota(ntfs_volume *vol)
return TRUE;
}
/**
* load_and_init_usnjrnl - load and setup the transaction log if present
* @vol: ntfs super block describing device whose usnjrnl file to load
*
* Return TRUE on success or FALSE on error.
*
* If $UsnJrnl is not present or in the process of being disabled, we set
* NVolUsnJrnlStamped() and return success.
*
* If the $UsnJrnl $DATA/$J attribute has a size equal to the lowest valid usn,
* i.e. transaction logging has only just been enabled or the journal has been
* stamped and nothing has been logged since, we also set NVolUsnJrnlStamped()
* and return success.
*/
static BOOL load_and_init_usnjrnl(ntfs_volume *vol)
{
MFT_REF mref;
struct inode *tmp_ino;
ntfs_inode *tmp_ni;
struct page *page;
ntfs_name *name = NULL;
USN_HEADER *uh;
static const ntfschar UsnJrnl[9] = { const_cpu_to_le16('$'),
const_cpu_to_le16('U'), const_cpu_to_le16('s'),
const_cpu_to_le16('n'), const_cpu_to_le16('J'),
const_cpu_to_le16('r'), const_cpu_to_le16('n'),
const_cpu_to_le16('l'), 0 };
static ntfschar Max[5] = { const_cpu_to_le16('$'),
const_cpu_to_le16('M'), const_cpu_to_le16('a'),
const_cpu_to_le16('x'), 0 };
static ntfschar J[3] = { const_cpu_to_le16('$'),
const_cpu_to_le16('J'), 0 };
ntfs_debug("Entering.");
/*
* Find the inode number for the transaction log file by looking up the
* filename $UsnJrnl in the extended system files directory $Extend.
*/
down(&vol->extend_ino->i_sem);
mref = ntfs_lookup_inode_by_name(NTFS_I(vol->extend_ino), UsnJrnl, 8,
&name);
up(&vol->extend_ino->i_sem);
if (IS_ERR_MREF(mref)) {
/*
* If the file does not exist, transaction logging is disabled,
* just return success.
*/
if (MREF_ERR(mref) == -ENOENT) {
ntfs_debug("$UsnJrnl not present. Volume does not "
"have transaction logging enabled.");
not_enabled:
/*
* No need to try to stamp the transaction log if
* transaction logging is not enabled.
*/
NVolSetUsnJrnlStamped(vol);
return TRUE;
}
/* A real error occured. */
ntfs_error(vol->sb, "Failed to find inode number for "
"$UsnJrnl.");
return FALSE;
}
/* We do not care for the type of match that was found. */
kfree(name);
/* Get the inode. */
tmp_ino = ntfs_iget(vol->sb, MREF(mref));
if (unlikely(IS_ERR(tmp_ino) || is_bad_inode(tmp_ino))) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(vol->sb, "Failed to load $UsnJrnl.");
return FALSE;
}
vol->usnjrnl_ino = tmp_ino;
/*
* If the transaction log is in the process of being deleted, we can
* ignore it.
*/
if (unlikely(vol->vol_flags & VOLUME_DELETE_USN_UNDERWAY)) {
ntfs_debug("$UsnJrnl in the process of being disabled. "
"Volume does not have transaction logging "
"enabled.");
goto not_enabled;
}
/* Get the $DATA/$Max attribute. */
tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, Max, 4);
if (IS_ERR(tmp_ino)) {
ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$Max "
"attribute.");
return FALSE;
}
vol->usnjrnl_max_ino = tmp_ino;
if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) {
ntfs_error(vol->sb, "Found corrupt $UsnJrnl/$DATA/$Max "
"attribute (size is 0x%llx but should be at "
"least 0x%x bytes).", i_size_read(tmp_ino),
sizeof(USN_HEADER));
return FALSE;
}
/* Get the $DATA/$J attribute. */
tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, J, 2);
if (IS_ERR(tmp_ino)) {
ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$J "
"attribute.");
return FALSE;
}
vol->usnjrnl_j_ino = tmp_ino;
/* Verify $J is non-resident and sparse. */
tmp_ni = NTFS_I(vol->usnjrnl_j_ino);
if (unlikely(!NInoNonResident(tmp_ni) || !NInoSparse(tmp_ni))) {
ntfs_error(vol->sb, "$UsnJrnl/$DATA/$J attribute is resident "
"and/or not sparse.");
return FALSE;
}
/* Read the USN_HEADER from $DATA/$Max. */
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);
/* Sanity check the $Max. */
if (unlikely(sle64_to_cpu(uh->allocation_delta) >
sle64_to_cpu(uh->maximum_size))) {
ntfs_error(vol->sb, "Allocation delta (0x%llx) exceeds "
"maximum size (0x%llx). $UsnJrnl is corrupt.",
(long long)sle64_to_cpu(uh->allocation_delta),
(long long)sle64_to_cpu(uh->maximum_size));
ntfs_unmap_page(page);
return FALSE;
}
/*
* If the transaction log has been stamped and nothing has been written
* to it since, we do not need to stamp it.
*/
if (unlikely(sle64_to_cpu(uh->lowest_valid_usn) >=
i_size_read(vol->usnjrnl_j_ino))) {
if (likely(sle64_to_cpu(uh->lowest_valid_usn) ==
i_size_read(vol->usnjrnl_j_ino))) {
ntfs_unmap_page(page);
ntfs_debug("$UsnJrnl is enabled but nothing has been "
"logged since it was last stamped. "
"Treating this as if the volume does "
"not have transaction logging "
"enabled.");
goto not_enabled;
}
ntfs_error(vol->sb, "$UsnJrnl has lowest valid usn (0x%llx) "
"which is out of bounds (0x%llx). $UsnJrnl "
"is corrupt.",
(long long)sle64_to_cpu(uh->lowest_valid_usn),
i_size_read(vol->usnjrnl_j_ino));
ntfs_unmap_page(page);
return FALSE;
}
ntfs_unmap_page(page);
ntfs_debug("Done.");
return TRUE;
}
/**
* load_and_init_attrdef - load the attribute definitions table for a volume
* @vol: ntfs super block describing device whose attrdef to load
@ -1653,7 +1821,7 @@ static BOOL load_system_files(ntfs_volume *vol)
goto iput_logfile_err_out;
}
/* If on NTFS versions before 3.0, we are done. */
if (vol->major_ver < 3)
if (unlikely(vol->major_ver < 3))
return TRUE;
/* NTFS 3.0+ specific initialization. */
/* Get the security descriptors inode. */
@ -1664,7 +1832,7 @@ static BOOL load_system_files(ntfs_volume *vol)
ntfs_error(sb, "Failed to load $Secure.");
goto iput_root_err_out;
}
// FIXME: Initialize security.
// TODO: Initialize security.
/* Get the extended system files' directory inode. */
vol->extend_ino = ntfs_iget(sb, FILE_Extend);
if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino)) {
@ -1715,10 +1883,60 @@ static BOOL load_system_files(ntfs_volume *vol)
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
NVolSetErrors(vol);
}
// TODO: Delete or checkpoint the $UsnJrnl if it exists.
/*
* Find the transaction log file ($UsnJrnl), load it if present, check
* it, and set it up.
*/
if (!load_and_init_usnjrnl(vol)) {
static const char *es1 = "Failed to load $UsnJrnl";
static const char *es2 = ". Run chkdsk.";
/* If a read-write mount, convert it to a read-only mount. */
if (!(sb->s_flags & MS_RDONLY)) {
if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
ON_ERRORS_CONTINUE))) {
ntfs_error(sb, "%s and neither on_errors="
"continue nor on_errors="
"remount-ro was specified%s",
es1, es2);
goto iput_usnjrnl_err_out;
}
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
ntfs_error(sb, "%s. Mounting read-only%s", es1, es2);
} else
ntfs_warning(sb, "%s. Will not be able to remount "
"read-write%s", es1, es2);
/* This will prevent a read-write remount. */
NVolSetErrors(vol);
}
/* If (still) a read-write mount, stamp the transaction log. */
if (!(sb->s_flags & MS_RDONLY) && !ntfs_stamp_usnjrnl(vol)) {
static const char *es1 = "Failed to stamp transaction log "
"($UsnJrnl)";
static const char *es2 = ". Run chkdsk.";
/* Convert to a read-only mount. */
if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
ON_ERRORS_CONTINUE))) {
ntfs_error(sb, "%s and neither on_errors=continue nor "
"on_errors=remount-ro was specified%s",
es1, es2);
goto iput_usnjrnl_err_out;
}
ntfs_error(sb, "%s. Mounting read-only%s", es1, es2);
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
NVolSetErrors(vol);
}
#endif /* NTFS_RW */
return TRUE;
#ifdef NTFS_RW
iput_usnjrnl_err_out:
if (vol->usnjrnl_j_ino)
iput(vol->usnjrnl_j_ino);
if (vol->usnjrnl_max_ino)
iput(vol->usnjrnl_max_ino);
if (vol->usnjrnl_ino)
iput(vol->usnjrnl_ino);
iput_quota_err_out:
if (vol->quota_q_ino)
iput(vol->quota_q_ino);
@ -1792,6 +2010,12 @@ static void ntfs_put_super(struct super_block *sb)
/* NTFS 3.0+ specific. */
if (vol->major_ver >= 3) {
if (vol->usnjrnl_j_ino)
ntfs_commit_inode(vol->usnjrnl_j_ino);
if (vol->usnjrnl_max_ino)
ntfs_commit_inode(vol->usnjrnl_max_ino);
if (vol->usnjrnl_ino)
ntfs_commit_inode(vol->usnjrnl_ino);
if (vol->quota_q_ino)
ntfs_commit_inode(vol->quota_q_ino);
if (vol->quota_ino)
@ -1847,6 +2071,18 @@ static void ntfs_put_super(struct super_block *sb)
/* NTFS 3.0+ specific clean up. */
if (vol->major_ver >= 3) {
#ifdef NTFS_RW
if (vol->usnjrnl_j_ino) {
iput(vol->usnjrnl_j_ino);
vol->usnjrnl_j_ino = NULL;
}
if (vol->usnjrnl_max_ino) {
iput(vol->usnjrnl_max_ino);
vol->usnjrnl_max_ino = NULL;
}
if (vol->usnjrnl_ino) {
iput(vol->usnjrnl_ino);
vol->usnjrnl_ino = NULL;
}
if (vol->quota_q_ino) {
iput(vol->quota_q_ino);
vol->quota_q_ino = NULL;
@ -2463,6 +2699,18 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
/* NTFS 3.0+ specific clean up. */
if (vol->major_ver >= 3) {
#ifdef NTFS_RW
if (vol->usnjrnl_j_ino) {
iput(vol->usnjrnl_j_ino);
vol->usnjrnl_j_ino = NULL;
}
if (vol->usnjrnl_max_ino) {
iput(vol->usnjrnl_max_ino);
vol->usnjrnl_max_ino = NULL;
}
if (vol->usnjrnl_ino) {
iput(vol->usnjrnl_ino);
vol->usnjrnl_ino = NULL;
}
if (vol->quota_q_ino) {
iput(vol->quota_q_ino);
vol->quota_q_ino = NULL;

View File

@ -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

84
fs/ntfs/usnjrnl.c Normal file
View File

@ -0,0 +1,84 @@
/*
* 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 */

205
fs/ntfs/usnjrnl.h Normal file
View File

@ -0,0 +1,205 @@
/*
* 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 */

View File

@ -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,7 @@ 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;
@ -168,6 +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 */