Update the driver to release 0.63.
One notable change is support for ExtX links (hard/sym). They work out of the box due to all the previous work that was done for supporting reparse points on NTFS.
Full changelog available at: http://www.ext2fsd.com/?p=195
CORE-10996 #resolve #comment Commited in r71031
svn path=/trunk/; revision=71031
src/nls/nls_koi8-ru.c
src/nls/nls_koi8-u.c
src/nls/nls_utf8.c
+ src/access.c
src/block.c
src/cleanup.c
src/close.c
* FILE: Ext2fs.h
* PURPOSE: Header file: ext2 structures
* PROGRAMMER: Matt Wu <mattwu@163.com>
- * HOMEPAGE: http://ext2.yeah.net
+ * HOMEPAGE: http://www.ext2fsd.com
* UPDATE HISTORY:
*/
#include <ndk/rtlfuncs.h>
#include <pseh/pseh2.h>
#endif
-#include "stdio.h"
+#include <stdio.h>
+#include <time.h>
#include <string.h>
#include <linux/ext2_fs.h>
#include <linux/ext3_fs.h>
/* STRUCTS & CONSTS******************************************************/
-#define EXT2FSD_VERSION "0.62"
+#define EXT2FSD_VERSION "0.63"
+/* WDK DEFINITIONS ******************************************************/
+
+
+/* COMPILER SWITCH / OPTIONS ********************************************/
+
//
// Ext2Fsd build options
//
#define Ext2SetOwnerReadOnly(m) do {(m) &= ~S_IWUSR;} while(0)
#define Ext2IsOwnerWritable(m) (((m) & S_IWUSR) == S_IWUSR)
-#define Ext2IsOwnerReadOnly(m) (!(Ext2IsOwnerWritable(m)))
+#define Ext2IsOwnerReadable(m) (((m) & S_IRUSR) == S_IRUSR)
+#define Ext2IsOwnerReadOnly(m) (!(Ext2IsOwnerWritable(m)) && Ext2IsOwnerReadable(m))
+
+#define Ext2IsGroupWritable(m) (((m) & S_IWGRP) == S_IWGRP)
+#define Ext2IsGroupReadable(m) (((m) & S_IRGRP) == S_IRGRP)
+#define Ext2IsGroupReadOnly(m) (!(Ext2IsGroupWritable(m)) && Ext2IsGroupReadable(m))
+
+#define Ext2IsOtherWritable(m) (((m) & S_IWOTH) == S_IWOTH)
+#define Ext2IsOtherReadable(m) (((m) & S_IROTH) == S_IROTH)
+#define Ext2IsOtherReadOnly(m) (!(Ext2IsOtherWritable(m)) && Ext2IsOtherReadable(m))
#define Ext2SetReadOnly(m) do {(m) &= ~(S_IWUSR | S_IWGRP | S_IWOTH);} while(0)
+
+#define Ext2FileCanRead (0x1)
+#define Ext2FileCanWrite (0x2)
+#define Ext2FileCanExecute (0x4)
+
+
/*
* We need 8-bytes aligned for all the sturctures
* It's a must for all ERESOURCE allocations
BOOLEAN bHidingSuffix;
CHAR sHidingSuffix[HIDINGPAT_LEN];
+ /* User to impersanate */
+ uid_t uid;
+ gid_t gid;
+
+ /* User to act as */
+ uid_t euid;
+ gid_t egid;
+
/* mountpoint: symlink to DesDevices */
UCHAR DrvLetter;
#define VCB_DISMOUNT_PENDING 0x00000008
#define VCB_NEW_VPB 0x00000010
#define VCB_BEING_CLOSED 0x00000020
+#define VCB_USER_IDS 0x00000040 /* uid/gid specified by user */
+#define VCB_USER_EIDS 0x00000080 /* euid/egid specified by user */
#define VCB_FORCE_WRITING 0x00004000
#define VCB_DEVICE_REMOVED 0x00008000
// Link List Info
PEXT2_MCB Parent; // Parent
- PEXT2_MCB Next; // Brothers
+ PEXT2_MCB Next; // Siblings
union {
PEXT2_MCB Child; // Children Mcb nodes
#define CCB_FROM_POOL 0x00000001
#define CCB_VOLUME_DASD_PURGE 0x00000002
#define CCB_LAST_WRITE_UPDATED 0x00000004
-
+#define CCB_OPEN_REPARSE_POINT 0x00000008
#define CCB_DELETE_ON_CLOSE 0x00000010
#define CCB_ALLOW_EXTENDED_DASD_IO 0x80000000
BOOLEAN efc_single;
} EXT2_FILLDIR_CONTEXT, *PEXT2_FILLDIR_CONTEXT;
+//
+// Access.c
+//
+
+
+int Ext2CheckInodeAccess(PEXT2_VCB Vcb, struct inode *in, int attempt);
+int Ext2CheckFileAccess (PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt);
+
//
// Block.c
//
IN PEXT2_VCB Vcb,
IN PEXT2_MCB Parent,
IN PEXT2_MCB Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
);
NTSTATUS
IN BOOLEAN bDirectory
);
+#define EXT2_LOOKUP_FLAG_MASK (0xFF00000)
+#define EXT2_LOOKUP_NOT_FOLLOW (0x8000000)
+
NTSTATUS
Ext2LookupFile (
IN PEXT2_IRP_CONTEXT IrpContext,
IN PUNICODE_STRING FullName,
IN PEXT2_MCB Parent,
OUT PEXT2_MCB * Ext2Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
);
NTSTATUS
VOID
Ext2PutGroup(IN PEXT2_VCB Vcb);
+VOID
+Ext2DropGroup(IN PEXT2_VCB Vcb);
+
BOOLEAN
Ext2SaveGroup(
IN PEXT2_IRP_CONTEXT IrpContext,
OUT struct dentry **dentry
);
+NTSTATUS
+Ext2SetFileType (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN PEXT2_MCB Mcb
+);
+
NTSTATUS
Ext2RemoveEntry (
IN PEXT2_IRP_CONTEXT IrpContext,
PEXT2_CCB Ccb
);
+NTSTATUS
+Ext2SetLinkInfo(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_FCB Fcb,
+ PEXT2_CCB Ccb
+);
+
ULONG
Ext2InodeType(PEXT2_MCB Mcb);
// Fsctl.c
//
+NTSTATUS
+Ext2ReadSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesRead
+ );
+
+NTSTATUS
+Ext2WriteSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesWritten
+);
+
+NTSTATUS
+Ext2TruncateSymlink(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Mcb,
+ ULONG Size
+);
+
//
// MountPoint process workitem
//
Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb);
PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB SymLink);
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink);
VOID
Ext2FreeMcb (
int s_addr_per_block_bits;
int s_desc_per_block_bits;
- struct buffer_head **s_group_desc;
+ ext3_fsblk_t *s_group_desc;
#if 0
unsigned long s_frag_size; /* Size of a fragment in bytes */
unsigned long max_blocks, struct buffer_head *bh_result,
int create, int flags);
int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode);
-int ext4_ext_remove_space(void *icb, struct inode *inode, unsigned long start);
+int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start);
#endif /* _LINUX_EXT4_EXT */
#include <linux/types.h>
#include <linux/atomic.h>
+#include <linux/rbtree.h>
//
// kdev
void *s_fs_info;
};
+struct xattr_entry {
+ char xe_name_index;
+ char *xe_name;
+ char xe_name_len;
+ char *xe_value;
+ int xe_value_size;
+ int xe_value_buf_size;
+ struct rb_node xe_node;
+};
+
+#define XATTR_FLAG_DIRTY 0x1
+#define XATTR_FLAG_LOADED 0x2
+
+struct xattr_handle {
+ int xh_flags;
+ int xh_total_size;
+ struct rb_root xh_root;
+};
+
struct inode {
__u32 i_ino; /* inode number */
loff_t i_size; /* size */
struct super_block *i_sb; /* super_block */
void *i_priv; /* EXT2_MCB */
+
+ __u16 i_extra_isize; /* extra fields' size */
+ __u64 i_file_acl;
};
//
void iput(struct inode *inode);
ULONGLONG bmap(struct inode *i, ULONGLONG b);
-#endif /*_LINUX_FS_INCLUDE_*/
\ No newline at end of file
+#endif /*_LINUX_FS_INCLUDE_*/
#define journal_oom_retry 1
+#define jbdlock_t FAST_MUTEX
+
+static inline void jbd_lock_init(jbdlock_t *lock)
+{
+ ExInitializeFastMutex(lock);
+}
+
+static inline void jbd_lock(jbdlock_t *lock)
+{
+ ExAcquireFastMutex(lock);
+}
+
+static inline void jbd_unlock(jbdlock_t *lock)
+{
+ ExReleaseFastMutex(lock);
+}
+
+static inline int assert_jbd_locked(jbdlock_t *lock)
+{
+ int rc = 1;
+
+ if (ExTryToAcquireFastMutex(lock)) {
+ ExReleaseFastMutex(lock);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
/*
* Define JBD_PARANIOD_IOFAIL to cause a kernel BUG() if ext3 finds
* certain classes of error which can occur due to failed IOs. Under
/*
* Protects info related to handles
*/
- spinlock_t t_handle_lock;
+ jbdlock_t t_handle_lock;
/*
* Number of outstanding updates running on this transaction
/*
* Protect the various scalars in the journal
*/
- spinlock_t j_state_lock;
+ jbdlock_t j_state_lock;
/*
* Number of processes waiting to create a barrier lock [j_state_lock]
/*
* Protects the buffer lists and internal buffer state.
*/
- spinlock_t j_list_lock;
+ jbdlock_t j_list_lock;
/* Optional inode where we store the journal. If present, all */
/* journal block numbers are mapped into this inode via */
* The revoke table: maintains the list of revoked blocks in the
* current transaction. [j_revoke_lock]
*/
- spinlock_t j_revoke_lock;
+ jbdlock_t j_revoke_lock;
struct jbd_revoke_table_s *j_revoke;
struct jbd_revoke_table_s *j_revoke_table[2];
* FILE: Modules.h
* PURPOSE: Header file: nls structures & linux kernel ...
* PROGRAMMER: Matt Wu <mattwu@163.com>
- * HOMEPAGE: http://ext2.yeah.net
+ * HOMEPAGE: http://www.ext2fsd.com
* UPDATE HISTORY:
*/
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/rbtree.h>
#include <linux/fs.h>
#include <linux/log2.h>
-#include <linux/rbtree.h>
#if _WIN32_WINNT <= 0x500
#define _WIN2K_TARGET_ 1
unsigned long b_state; /* buffer state bitmap (see above) */
struct page *b_page; /* the page this bh is mapped to */
PMDL b_mdl; /* MDL of the locked buffer */
- void *b_bcb; /* BCB of the buffer */
+ void *b_bcb; /* BCB of the buffer */
// kdev_t b_dev; /* device (B_FREE = free) */
struct block_device *b_bdev; /* block device object */
__brelse(bh);
}
+static inline void fini_bh(struct buffer_head **bh)
+{
+ if (bh && *bh) {
+ brelse(*bh);
+ *bh = NULL;
+ }
+}
+
static inline void bforget(struct buffer_head *bh)
{
if (bh)
#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H
-#include <linux/module.h>
-
struct rb_node
{
ULONG_PTR rb_parent_color;
--- /dev/null
+/*
+ * COPYRIGHT: See COPYRIGHT.TXT
+ * PROJECT: Ext2 File System Driver for WinNT/2K/XP
+ * FILE: access.c
+ * PROGRAMMER: Matt Wu <mattwu@163.com>
+ * HOMEPAGE: http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+/* DEFINITIONS *************************************************************/
+
+int Ext2CheckInodeAccess(PEXT2_VCB Vcb, struct inode *in, int attempt)
+{
+ int granted = 0;
+
+ uid_t uid = Vcb->uid;
+ gid_t gid = Vcb->gid;
+
+ if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) {
+ uid = Vcb->euid;
+ gid = Vcb->egid;
+ }
+
+ if (!uid || uid == in->i_uid) {
+ /* grant all access for inode owner or root */
+ granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
+ } else if (gid == in->i_gid) {
+ if (Ext2IsGroupReadOnly(in->i_mode))
+ granted = Ext2FileCanRead | Ext2FileCanExecute;
+ else if (Ext2IsGroupWritable(in->i_mode))
+ granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
+ } else {
+ if (Ext2IsOtherReadOnly(in->i_mode))
+ granted = Ext2FileCanRead | Ext2FileCanExecute;
+ else if (Ext2IsOtherWritable(in->i_mode))
+ granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
+
+ }
+
+ return IsFlagOn(granted, attempt);
+}
+
+int Ext2CheckFileAccess(PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt)
+{
+ return Ext2CheckInodeAccess(Vcb, &Mcb->Inode, attempt);
+}
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_SUCCESS;
- PEXT2_VCB Vcb;
+ PEXT2_VCB Vcb = NULL;
PFILE_OBJECT FileObject;
- PEXT2_FCB Fcb;
- PEXT2_CCB Ccb;
- PIRP Irp;
- PEXT2_MCB Mcb;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PIRP Irp = NULL;
+ PEXT2_MCB Mcb = NULL;
BOOLEAN VcbResourceAcquired = FALSE;
VcbResourceAcquired =
ExAcquireResourceExclusiveLite(
&Vcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
+ TRUE
);
if (Fcb->Identifier.Type == EXT2VCB) {
FcbResourceAcquired =
ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
+ TRUE
);
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) {
if (!INODE_HAS_EXTENT(Fcb->Inode)) {
#if EXT2_PRE_ALLOCATION_SUPPORT
- CcZeroData(FileObject, &Fcb->Header.ValidDataLength,
- &Fcb->Header.AllocationSize, TRUE);
+ _SEH2_TRY {
+ CcZeroData( FileObject,
+ &Fcb->Header.ValidDataLength,
+ &Fcb->Header.AllocationSize,
+ TRUE);
+ } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ } _SEH2_END;
#endif
}
}
FcbResourceAcquired =
ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
+ TRUE
);
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
if (!IsDirectory(Fcb)) {
if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
- (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) &&
+ (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
(Fcb->SectionObject.DataSectionObject != NULL)) {
if (!IsVcbReadOnly(Vcb)) {
ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
}
- if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
- ExReleaseResourceLite(&(Fcb->PagingIoResource));
- }
+ /* purge cache if all remaining openings are non-cached */
+ if (Fcb->NonCachedOpenCount > 0) {
+ if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
+ ExReleaseResourceLite(&(Fcb->PagingIoResource));
+ }
- CcPurgeCacheSection( &Fcb->SectionObject,
- NULL,
- 0,
- FALSE );
+ CcPurgeCacheSection( &Fcb->SectionObject,
+ NULL,
+ 0,
+ FALSE );
+ }
}
CcUninitializeCacheMap(FileObject, NULL, NULL);
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_SUCCESS;
PEXT2_VCB Vcb = NULL;
- BOOLEAN VcbResourceAcquired = FALSE;
PFILE_OBJECT FileObject;
- PEXT2_FCB Fcb;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ BOOLEAN VcbResourceAcquired = FALSE;
BOOLEAN FcbResourceAcquired = FALSE;
- PEXT2_CCB Ccb;
BOOLEAN bDeleteVcb = FALSE;
BOOLEAN bBeingClosed = FALSE;
BOOLEAN bSkipLeave = FALSE;
if (!ExAcquireResourceExclusiveLite(
&Vcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ TRUE )) {
DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
Vcb->OpenHandleCount, Vcb->ReferenceCount));
if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ TRUE )) {
Status = STATUS_PENDING;
_SEH2_LEAVE;
}
if (NT_SUCCESS(Status) && Vcb != NULL && IsVcbInited(Vcb)) {
/* for Ext2Fsd driver open/close, Vcb is NULL */
- if ((!bBeingClosed) && (Vcb->ReferenceCount == 0)&&
+ if ((!bBeingClosed) && (Vcb->ReferenceCount == 0) &&
(!IsMounted(Vcb) || IsDispending(Vcb))) {
bDeleteVcb = TRUE;
}
IN PEXT2_VCB Vcb,
IN PEXT2_MCB Parent,
IN PEXT2_MCB Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
)
{
NTSTATUS Status = STATUS_LINK_FAILED;
/* exit if we jump into a possible symlink forever loop */
if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS ||
- IoGetRemainingStackSize() < 1024) {
+ IoGetRemainingStackSize() < 1024) {
_SEH2_LEAVE;
}
bOemBuffer = TRUE;
RtlZeroMemory(OemName.Buffer, OemName.MaximumLength);
- Status = Ext2ReadInode(
+ Status = Ext2ReadSymlink(
IrpContext,
Vcb,
Mcb,
- (ULONGLONG)0,
OemName.Buffer,
(ULONG)(Mcb->Inode.i_size),
- FALSE,
NULL);
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
if (Target == NULL /* link target doesn't exist */ ||
- Target == Mcb /* symlink points to itself */ ||
- IsMcbSpecialFile(Target) /* target not resolved*/ ||
- IsFileDeleted(Target) /* target deleted */ ) {
+ Target == Mcb /* symlink points to itself */ ||
+ IsMcbSpecialFile(Target) /* target not resolved*/ ||
+ IsFileDeleted(Target) /* target deleted */ ) {
if (Target) {
ASSERT(Target->Refercount > 0);
}
ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
- Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL;
Mcb->Target = NULL;
} else if (IsMcbSymLink(Target)) {
SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ASSERT(Mcb->Target->Refercount > 0);
- Mcb->FileAttr = Target->FileAttr;
-
+
} else {
Mcb->Target = Target;
SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ASSERT(Mcb->Target->Refercount > 0);
- Mcb->FileAttr = Target->FileAttr;
+ }
+
+ /* add directory flag to file attribute */
+ if (Mcb->Target && IsMcbDirectory(Mcb->Target)) {
+ Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY;
}
} _SEH2_FINALLY {
IN PUNICODE_STRING FullName,
IN PEXT2_MCB Parent,
OUT PEXT2_MCB * Ext2Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
)
{
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
BOOLEAN bParent = FALSE;
BOOLEAN bDirectory = FALSE;
BOOLEAN LockAcquired = FALSE;
+ BOOLEAN bNotFollow = FALSE;
_SEH2_TRY {
ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
LockAcquired = TRUE;
+ bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW);
+#ifndef __REACTOS__
+ Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#else
+ ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+#endif
+
*Ext2Mcb = NULL;
DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName));
Parent = Mcb;
if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) &&
- (Mcb->Refercount == 1)) {
+ Mcb->Refercount == 1) {
ASSERT(Mcb->Target);
ASSERT(Mcb->Target->Refercount > 0);
}
/* set inode attribute */
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+ if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY);
}
if (S_ISDIR(Mcb->Inode.i_mode)) {
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
} else {
- SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
- if (!S_ISREG(Mcb->Inode.i_mode) &&
- !S_ISLNK(Mcb->Inode.i_mode)) {
+ if (S_ISREG(Mcb->Inode.i_mode)) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
+ } else if (S_ISLNK(Mcb->Inode.i_mode)) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+ } else {
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
}
}
Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime);
/* process symlink */
- if (S_ISLNK(Mcb->Inode.i_mode)) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) {
Ext2FollowLink( IrpContext,
Vcb,
Parent,
Ext2DerefMcb(Parent);
if (bh)
- brelse(bh);
+ __brelse(bh);
if (!NT_SUCCESS(Status)) {
if (de)
errorout:
if (bh)
- brelse (bh);
+ __brelse (bh);
return Ext2WinntError(rc);
}
BOOLEAN DeleteOnClose;
BOOLEAN TemporaryFile;
BOOLEAN CaseSensitive;
+ BOOLEAN OpenReparsePoint;
ACCESS_MASK DesiredAccess;
ULONG ShareAccess;
+ ULONG CcbFlags = 0;
RtlZeroMemory(&FileName, sizeof(UNICODE_STRING));
NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
+ /* Try to open reparse point (symlink) itself ? */
+ OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT);
+
CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
&FileName,
ParentMcb,
&Mcb,
- 0 );
+ 0 /* always follow link */
+ );
McbExisting:
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(ParentFcb->Mcb->Inode.i_mode)) {
+ if (!Ext2CheckFileAccess(Vcb, ParentMcb, Ext2FileCanWrite)) {
Status = STATUS_ACCESS_DENIED;
_SEH2_LEAVE;
}
if (IsMcbDirectory(Mcb)) {
if ((CreateDisposition != FILE_OPEN) &&
- (CreateDisposition != FILE_OPEN_IF)) {
+ (CreateDisposition != FILE_OPEN_IF)) {
Status = STATUS_OBJECT_NAME_COLLISION;
Ext2DerefMcb(Mcb);
/* refer it's target if it's a symlink, so both refered */
if (IsMcbSymLink(Mcb)) {
- if (IsFileDeleted(Mcb->Target)) {
+
+ if (OpenReparsePoint) {
+ /* set Ccb flag */
+ CcbFlags = CCB_OPEN_REPARSE_POINT;
+ } else if (IsFileDeleted(Mcb->Target)) {
DbgBreak();
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
}
// Check readonly flag
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Mcb->Inode.i_mode)) {
+ if (BooleanFlagOn(DesiredAccess, FILE_GENERIC_READ) &&
+ !Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanRead)) {
+ Status = STATUS_ACCESS_DENIED;
+ _SEH2_LEAVE;
+ }
+ if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
if (BooleanFlagOn(DesiredAccess, FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) {
Status = STATUS_ACCESS_DENIED;
&(Fcb->ShareAccess) );
}
- Ccb = Ext2AllocateCcb(SymLink);
+ Ccb = Ext2AllocateCcb(CcbFlags, SymLink);
if (!Ccb) {
Status = STATUS_INSUFFICIENT_RESOURCES;
DbgBreak();
return STATUS_SHARING_VIOLATION;
}
- Ccb = Ext2AllocateCcb(NULL);
+ Ccb = Ext2AllocateCcb(0, NULL);
if (Ccb == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
Inode.i_sb = &Vcb->sb;
Inode.i_ino = iNo;
Inode.i_ctime = Inode.i_mtime =
- Inode.i_atime = Ext2LinuxTime(SysTime);
- Inode.i_uid = Parent->Inode->i_uid;
- Inode.i_gid = Parent->Inode->i_gid;
+ Inode.i_atime = Ext2LinuxTime(SysTime);
+ Inode.i_uid = Vcb->uid;
+ Inode.i_gid = Vcb->gid;
Inode.i_generation = Parent->Inode->i_generation;
Inode.i_mode = S_IPERMISSION_MASK &
Parent->Inode->i_mode;
/* Force using extent */
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
Inode.i_flags |= EXT2_EXTENTS_FL;
+ ext4_ext_tree_init(IrpContext, NULL, &Inode);
+ /* ext4_ext_tree_init will save inode body */
+ } else {
+ /* save inode body to cache */
+ Ext2SaveInode(IrpContext, Vcb, &Inode);
}
/* add new entry to its parent */
NumberOfBytes = Data[0];
if (Data[1] != NumberOfBytes + 0x20) {
DbgBreak();
+ return;
}
for (i=0x08; i < 0x10; i++) {
if (Buffer[i] != 'S') {
for (i=0; i < 0x10; i++) {
if (Buffer[i + NumberOfBytes + 0x10] != 'E') {
DbgBreak();
+ return;
}
Buffer[i + NumberOfBytes + 0x10] = '-';
}
LONGLONG AllocationSize;
ULONG FileAttributes = 0;
+ BOOLEAN IsEntrySymlink = FALSE;
+
*EntrySize = 0;
NameLength = pName->Length;
ASSERT((UsedLength & 7) == 0);
DEBUG(DL_CP, ("Ext2ProcessDirEntry: %wZ in %wZ\n", pName, &Dcb->Mcb->FullName ));
Mcb = Ext2SearchMcb(Vcb, Dcb->Mcb, pName);
- if (NULL == Mcb) {
+ if (NULL != Mcb) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && NULL == Mcb->Target) {
+ Ext2FollowLink( IrpContext, Vcb, Dcb->Mcb, Mcb, 0);
+ }
+
+ } else {
Inode.i_ino = in;
Inode.i_sb = &Vcb->sb;
} else if (S_ISLNK(Inode.i_mode)) {
DEBUG(DL_RES, ("Ext2ProcessDirEntry: SymLink: %wZ\\%wZ\n",
&Dcb->Mcb->FullName, pName));
- Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb, 0);
+ Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb,0);
if (Mcb && IsMcbSpecialFile(Mcb)) {
Ext2DerefMcb(Mcb);
ASSERT(!IsMcbSymLink(Target));
if (IsMcbDirectory(Target)) {
FileSize = 0;
+ FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
} else {
FileSize = Target->Inode.i_size;
}
}
}
+ if (IsInodeSymLink(&Mcb->Inode)) {
+ IsEntrySymlink = TRUE;
+ }
+
} else {
if (S_ISDIR(Inode.i_mode)) {
if (S_ISDIR(Inode.i_mode)) {
FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+ } else if (S_ISLNK(Inode.i_mode)) {
+ FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT;
+ IsEntrySymlink = TRUE;
} else {
FileAttributes = FILE_ATTRIBUTE_NORMAL;
}
- if (!CanIWrite(Vcb) && Ext2IsOwnerReadOnly(Inode.i_mode)) {
+ if (!Ext2CheckInodeAccess(Vcb, &Inode, Ext2FileCanWrite)) {
SetFlag(FileAttributes, FILE_ATTRIBUTE_READONLY);
}
}
if (FIF) {
FIF->FileId.QuadPart = (LONGLONG) in;
+ if (IsEntrySymlink) {
+ FIF->EaSize = IO_REPARSE_TAG_SYMLINK;
+ }
RtlCopyMemory(&FIF->FileName[0], &pName->Buffer[0], NameLength);
} else if (FFI) {
+ if (IsEntrySymlink) {
+ FFI->EaSize = IO_REPARSE_TAG_SYMLINK;
+ }
RtlCopyMemory(&FFI->FileName[0], &pName->Buffer[0], NameLength);
} else {
RtlCopyMemory(&FDI->FileName[0], &pName->Buffer[0], NameLength);
if (FIB) {
FIB->FileId.QuadPart = (LONGLONG)in;
+ if (IsEntrySymlink) {
+ FIB->EaSize = IO_REPARSE_TAG_SYMLINK;
+ }
RtlCopyMemory(&FIB->FileName[0], &pName->Buffer[0], NameLength);
} else {
RtlCopyMemory(&FBI->FileName[0], &pName->Buffer[0], NameLength);
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PFILE_OBJECT FileObject;
- PEXT2_FCB Fcb;
- PEXT2_MCB Mcb;
- PEXT2_CCB Ccb;
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
+ PEXT2_VCB Vcb = NULL;
+ PFILE_OBJECT FileObject = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_MCB Mcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
ULONG Length;
ULONG FileIndex;
PDEVICE_OBJECT DeviceObject;
BOOLEAN CompleteRequest = TRUE;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PFILE_OBJECT FileObject;
- PEXT2_FCB Fcb;
- PEXT2_CCB Ccb;
- PIRP Irp;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PIRP Irp = NULL;
PIO_STACK_LOCATION IrpSp;
+ PFILE_OBJECT FileObject;
ULONG CompletionFilter;
BOOLEAN WatchTree;
}
return !!ext3_is_dir_empty(IrpContext, &Mcb->Inode);
-}
\ No newline at end of file
+}
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
* FILE: generic.c
* PROGRAMMER: Matt Wu <mattwu@163.com>
- * HOMEPAGE: http://ext2.yeah.net
+ * HOMEPAGE: http://www.ext2fsd.com
* UPDATE HISTORY:
*/
{
struct super_block *sb = &Vcb->sb;
struct ext3_sb_info *sbi = &Vcb->sbi;
+ ext3_fsblk_t sb_block = 1;
unsigned long i;
- ext3_fsblk_t block, sb_block = 1;
if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
}
if (NULL == sbi->s_group_desc) {
- sbi->s_group_desc = kzalloc(sbi->s_gdb_count * sizeof(void *),
+ sbi->s_group_desc = kzalloc(sbi->s_gdb_count * sizeof(ext3_fsblk_t),
GFP_KERNEL);
}
if (sbi->s_group_desc == NULL) {
}
for (i = 0; i < sbi->s_gdb_count; i++) {
- block = descriptor_loc(sb, sb_block, i);
- if (sbi->s_group_desc[i])
- continue;
- sbi->s_group_desc[i] = sb_bread(sb, block);
+ sbi->s_group_desc[i] = descriptor_loc(sb, sb_block, i);
if (!sbi->s_group_desc[i]) {
DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i));
return FALSE;
return TRUE;
}
+
VOID
-Ext2PutGroup(IN PEXT2_VCB Vcb)
+Ext2DropGroup(IN PEXT2_VCB Vcb)
{
struct ext3_sb_info *sbi = &Vcb->sbi;
unsigned long i;
- ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
if (NULL == sbi->s_group_desc) {
- ExReleaseResourceLite(&Vcb->MetaLock);
return;
}
- for (i = 0; i < sbi->s_gdb_count; i++) {
- if (sbi->s_group_desc[i]) {
- brelse(sbi->s_group_desc[i]);
- sbi->s_group_desc[i] = NULL;
- }
- }
-
kfree(sbi->s_group_desc);
sbi->s_group_desc = NULL;
- ExReleaseResourceLite(&Vcb->MetaLock);
}
BOOLEAN
IN ULONG Group
)
{
- struct ext4_group_desc *desc;
- struct buffer_head *bh = NULL;
+ struct ext4_group_desc *gd;
+ struct buffer_head *gb = NULL;
unsigned long i;
- ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
- desc = ext4_get_group_desc(&Vcb->sb, Group, &bh);
- if (bh)
- get_bh(bh);
- ExReleaseResourceLite(&Vcb->MetaLock);
-
- if (!bh)
+ gd = ext4_get_group_desc(&Vcb->sb, Group, &gb);
+ if (!gd)
return 0;
- desc->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, desc);
- mark_buffer_dirty(bh);
- __brelse(bh);
+ gd->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, gd);
+ mark_buffer_dirty(gb);
+ fini_bh(&gb);
return TRUE;
}
)
{
PEXT2_GROUP_DESC gd;
+ struct buffer_head *bh = NULL;
ext4_fsblk_t loc;
int group;
}
group = (inode - 1) / INODES_PER_GROUP ;
- gd = ext4_get_group_desc(&Vcb->sb, group, NULL);
- if (!gd) {
+ gd = ext4_get_group_desc(&Vcb->sb, group, &bh);
+ if (!bh) {
*offset = 0;
DbgBreak();
return FALSE;
loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
*offset = loc;
+ __brelse(bh);
return TRUE;
}
if (S_ISREG(src->i_mode)) {
dst->i_size |= (loff_t)src->i_size_high << 32;
}
+ dst->i_file_acl = src->i_file_acl_lo;
+ dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32;
dst->i_atime = src->i_atime;
dst->i_ctime = src->i_ctime;
dst->i_mtime = src->i_mtime;
dst->i_dtime = src->i_dtime;
dst->i_blocks = ext3_inode_blocks(src, dst);
+ dst->i_extra_isize = src->i_extra_isize;
memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
}
if (S_ISREG(src->i_mode)) {
dst->i_size_high = (__u32)(src->i_size >> 32);
}
+ dst->i_file_acl_lo = (__u32)src->i_file_acl;
+ dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32);
dst->i_atime = src->i_atime;
dst->i_ctime = src->i_ctime;
dst->i_mtime = src->i_mtime;
dst->i_dtime = src->i_dtime;
+ dst->i_extra_isize = src->i_extra_isize;
ASSERT(src->i_sb);
ext3_inode_blocks_set(dst, src);
memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
)
{
struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC group_desc;
- struct buffer_head* bh = NULL;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
ext4_fsblk_t bitmap_blk;
RTL_BITMAP BlockBitmap;
Again:
- if (bh) {
- __brelse(bh);
- bh = NULL;
- }
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
- group_desc = ext4_get_group_desc(sb, Group, NULL);
- if (!group_desc) {
+ gd = ext4_get_group_desc(sb, Group, &gb);
+ if (!gd) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- bitmap_blk = ext4_block_bitmap(sb, group_desc);
+ bitmap_blk = ext4_block_bitmap(sb, gd);
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
bh = sb_getblk_zero(sb, bitmap_blk);
if (!bh) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- group_desc->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, group_desc);
- ext4_init_block_bitmap(sb, bh, Group, group_desc);
+ gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
+ ext4_init_block_bitmap(sb, bh, Group, gd);
set_buffer_uptodate(bh);
- group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
Ext2SaveGroup(IrpContext, Vcb, Group);
} else {
bh = sb_getblk(sb, bitmap_blk);
}
}
- if (ext4_free_blks_count(sb, group_desc)) {
+ if (ext4_free_blks_count(sb, gd)) {
if (Group == Vcb->sbi.s_groups_count - 1) {
RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
/* no blocks found: set bg_free_blocks_count to 0 */
- ext4_free_blks_set(sb, group_desc, 0);
+ ext4_free_blks_set(sb, gd, 0);
Ext2SaveGroup(IrpContext, Vcb, Group);
/* will try next group */
mark_buffer_dirty(bh);
/* update group description */
- ext4_free_blks_set(sb, group_desc, RtlNumberOfClearBits(&BlockBitmap));
+ ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
Ext2SaveGroup(IrpContext, Vcb, Group);
/* update Vcb free blocks */
goto Again;
}
- if (ext4_block_bitmap(sb, group_desc) == *Block ||
- ext4_inode_bitmap(sb, group_desc) == *Block ||
- ext4_inode_table(sb, group_desc) == *Block ) {
+ if (ext4_block_bitmap(sb, gd) == *Block ||
+ ext4_inode_bitmap(sb, gd) == *Block ||
+ ext4_inode_table(sb, gd) == *Block ) {
DbgBreak();
dwHint = 0;
goto Again;
ExReleaseResourceLite(&Vcb->MetaLock);
if (bh)
- __brelse(bh);
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
return Status;
}
)
{
struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC group_desc;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
ext4_fsblk_t bitmap_blk;
RTL_BITMAP BlockBitmap;
Again:
+ if (gb)
+ fini_bh(&gb);
+
if ( Block < EXT2_FIRST_DATA_BLOCK ||
Block >= TOTAL_BLOCKS ||
Group >= Vcb->sbi.s_groups_count) {
} else {
- group_desc = ext4_get_group_desc(sb, Group, NULL);
- if (!group_desc) {
+ gd = ext4_get_group_desc(sb, Group, &gb);
+ if (!gd) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- bitmap_blk = ext4_block_bitmap(sb, group_desc);
+ bitmap_blk = ext4_block_bitmap(sb, gd);
/* check the block is valid or not */
if (bitmap_blk >= TOTAL_BLOCKS) {
RtlClearBits(&BlockBitmap, Index, Count);
/* update group description table */
- ext4_free_blks_set(sb, group_desc, RtlNumberOfClearBits(&BlockBitmap));
+ ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
/* indict the cache range is dirty */
CcSetDirtyPinnedData(BitmapBcb, NULL );
errorout:
+ if (gb)
+ fini_bh(&gb);
+
ExReleaseResourceLite(&Vcb->MetaLock);
return Status;
)
{
struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC group_desc;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
struct buffer_head *bh = NULL;
ext4_fsblk_t bitmap_blk;
repeat:
- if (bh) {
- __brelse(bh);
- bh = NULL;
- }
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
Group = i = 0;
- group_desc = NULL;
+ gd = NULL;
if (Type == EXT2_FT_DIR) {
for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
i = (j + GroupHint) % (Vcb->sbi.s_groups_count);
- group_desc = ext4_get_group_desc(sb, i, NULL);
- if (!group_desc) {
- DbgBreak();
+ gd = ext4_get_group_desc(sb, i, &gb);
+ if (!gd) {
+ DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- if ((group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
- (ext4_used_dirs_count(sb, group_desc) << 8 <
- ext4_free_inodes_count(sb, group_desc)) ) {
+ if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
+ (ext4_used_dirs_count(sb, gd) << 8 <
+ ext4_free_inodes_count(sb, gd)) ) {
Group = i + 1;
break;
}
+ fini_bh(&gb);
}
if (!Group) {
PEXT2_GROUP_DESC desc = NULL;
- group_desc = NULL;
+ gd = NULL;
/* get the group with the biggest vacancy */
for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
- desc = ext4_get_group_desc(sb, j, NULL);
+ struct buffer_head *gt = NULL;
+ desc = ext4_get_group_desc(sb, j, >);
if (!desc) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
/* return the group if it's not initialized yet */
if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
Group = j + 1;
- group_desc = desc;
+ gd = desc;
+
+ if (gb)
+ fini_bh(&gb);
+ gb = gt;
+ gt = NULL;
break;
}
- if (!group_desc) {
+ if (!gd) {
if (ext4_free_inodes_count(sb, desc) > 0) {
Group = j + 1;
- group_desc = desc;
+ gd = desc;
+ if (gb)
+ fini_bh(&gb);
+ gb = gt;
+ gt = NULL;
}
} else {
if (ext4_free_inodes_count(sb, desc) >
- ext4_free_inodes_count(sb, group_desc)) {
+ ext4_free_inodes_count(sb, gd)) {
Group = j + 1;
- group_desc = desc;
+ gd = desc;
+ if (gb)
+ fini_bh(&gb);
+ gb = gt;
+ gt = NULL;
break;
}
}
+ if (gt)
+ fini_bh(>);
}
}
* Try to place the inode in its parent directory (GroupHint)
*/
- group_desc = ext4_get_group_desc(sb, GroupHint, NULL);
- if (!group_desc) {
+ gd = ext4_get_group_desc(sb, GroupHint, &gb);
+ if (!gb) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
- ext4_free_inodes_count(sb, group_desc)) {
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ext4_free_inodes_count(sb, gd)) {
Group = GroupHint + 1;
} else {
+ /* this group is 100% cocucpied */
+ fini_bh(&gb);
+
i = GroupHint;
/*
for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
+
i = (i + j) % Vcb->sbi.s_groups_count;
- group_desc = ext4_get_group_desc(sb, i, NULL);
- if (!group_desc) {
+ gd = ext4_get_group_desc(sb, i, &gb);
+ if (!gd) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
- ext4_free_inodes_count(sb, group_desc)) {
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ext4_free_inodes_count(sb, gd)) {
Group = i + 1;
break;
}
+
+ fini_bh(&gb);
}
}
for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
i = (i + 1) % Vcb->sbi.s_groups_count;
- group_desc = ext4_get_group_desc(sb, i, NULL);
- if (!group_desc) {
+ gd = ext4_get_group_desc(sb, i, &gb);
+ if (!gd) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
- ext4_free_inodes_count(sb, group_desc)) {
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ext4_free_inodes_count(sb, gd)) {
Group = i + 1;
break;
}
+
+ fini_bh(&gb);
}
}
}
- if (group_desc == NULL || Group == 0) {
+ if (gd == NULL || Group == 0) {
goto errorout;
}
/* valid group number starts from 1, not 0 */
Group -= 1;
- ASSERT(group_desc);
- bitmap_blk = ext4_inode_bitmap(sb, group_desc);
+ ASSERT(gd);
+ bitmap_blk = ext4_inode_bitmap(sb, gd);
/* check the block is valid or not */
if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) {
DbgBreak();
goto errorout;
}
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
bh = sb_getblk_zero(sb, bitmap_blk);
if (!bh) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- group_desc->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, group_desc);
- ext4_init_inode_bitmap(sb, bh, Group, group_desc);
+ gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
+ ext4_init_inode_bitmap(sb, bh, Group, gd);
set_buffer_uptodate(bh);
- group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
Ext2SaveGroup(IrpContext, Vcb, Group);
} else {
bh = sb_getblk(sb, bitmap_blk);
if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
- if (ext4_free_inodes_count(sb, group_desc) > 0) {
- ext4_free_inodes_set(sb, group_desc, 0);
+ if (ext4_free_inodes_count(sb, gd) > 0) {
+ ext4_free_inodes_set(sb, gd, 0);
Ext2SaveGroup(IrpContext, Vcb, Group);
}
goto repeat;
__u32 count = 0;
/* update unused inodes count */
- count = ext4_free_inodes_count(sb, group_desc) - 1;
- ext4_free_inodes_set(sb, group_desc, count);
+ count = ext4_free_inodes_count(sb, gd) - 1;
+ ext4_free_inodes_set(sb, gd, count);
RtlSetBits(&InodeBitmap, dwInode, 1);
__u32 free;
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
- group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
/* When marking the block group with
* ~EXT4_BG_INODE_UNINIT we don't want to depend
* on the value of bg_itable_unused even though
free = 0;
} else {
- free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, group_desc);
+ free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd);
}
/*
*
*/
if (dwInode + 1 > free) {
- ext4_itable_unused_set(sb, group_desc,
+ ext4_itable_unused_set(sb, gd,
(EXT3_INODES_PER_GROUP(sb) - 1 - dwInode));
}
/* We may have to initialize the block bitmap if it isn't already */
- if (group_desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
struct buffer_head *block_bitmap_bh = NULL;
/* recheck and clear flag under lock if we still need to */
- block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, group_desc));
+ block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd));
if (block_bitmap_bh) {
- group_desc->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, group_desc);
- free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, group_desc);
+ gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
+ free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd);
set_buffer_uptodate(block_bitmap_bh);
brelse(block_bitmap_bh);
- group_desc->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
- ext4_free_blks_set(sb, group_desc, free);
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+ ext4_free_blks_set(sb, gd, free);
Ext2SaveGroup(IrpContext, Vcb, Group);
}
}
/* update group_desc / super_block */
if (Type == EXT2_FT_DIR) {
- ext4_used_dirs_set(sb, group_desc, ext4_used_dirs_count(sb, group_desc) + 1);
+ ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1);
}
Ext2SaveGroup(IrpContext, Vcb, Group);
Ext2UpdateVcbStat(IrpContext, Vcb);
ExReleaseResourceLite(&Vcb->MetaLock);
- if (bh) {
- brelse(bh);
- }
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
return Status;
}
)
{
struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC group_desc;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
struct buffer_head *bh = NULL;
ext4_fsblk_t bitmap_blk;
goto errorout;
}
- group_desc = ext4_get_group_desc(sb, Group, NULL);
- if (!group_desc) {
+ gd = ext4_get_group_desc(sb, Group, &gb);
+ if (!gd) {
DbgBreak();
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
}
- bitmap_blk = ext4_inode_bitmap(sb, group_desc);
+ bitmap_blk = ext4_inode_bitmap(sb, gd);
bh = sb_getblk(sb, bitmap_blk);
if (!bh) {
DbgBreak();
if (bModified) {
/* update group free inodes */
- ext4_free_inodes_set(sb, group_desc,
+ ext4_free_inodes_set(sb, gd,
RtlNumberOfClearBits(&InodeBitmap));
/* set inode block dirty and add to vcb dirty range */
/* update group_desc and super_block */
if (Type == EXT2_FT_DIR) {
- ext4_used_dirs_set(sb, group_desc,
- ext4_used_dirs_count(sb, group_desc) - 1);
+ ext4_used_dirs_set(sb, gd,
+ ext4_used_dirs_count(sb, gd) - 1);
}
Ext2SaveGroup(IrpContext, Vcb, Group);
Ext2UpdateVcbStat(IrpContext, Vcb);
ExReleaseResourceLite(&Vcb->MetaLock);
- if (bh) {
- brelse(bh);
- }
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
return Status;
}
ext3_inc_count(Inode);
ext3_mark_inode_dirty(IrpContext, Inode);
- *Dentry = de;
- de = NULL;
+ if (Dentry) {
+ *Dentry = de;
+ de = NULL;
+ }
}
} _SEH2_FINALLY {
}
+NTSTATUS
+Ext2SetFileType (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN PEXT2_MCB Mcb
+ )
+{
+ struct inode *dir = Dcb->Inode;
+ struct buffer_head *bh = NULL;
+ struct ext3_dir_entry_2 *de;
+ struct inode *inode;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
+ return STATUS_SUCCESS;
+ }
+
+ if (!IsDirectory(Dcb)) {
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+ MainResourceAcquired = TRUE;
+
+ _SEH2_TRY {
+
+ Ext2ReferXcb(&Dcb->ReferenceCount);
+
+ bh = ext3_find_entry(IrpContext, Mcb->de, &de);
+ if (!bh)
+ _SEH2_LEAVE;
+
+ inode = &Mcb->Inode;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ _SEH2_LEAVE;
+
+ ext3_set_de_type(inode->i_sb, de, inode->i_mode);
+ mark_buffer_dirty(bh);
+
+ //if (!inode->i_nlink)
+ // ext3_orphan_add(handle, inode);
+
+ dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
+ ext3_mark_inode_dirty(IrpContext, dir);
+
+ Status = STATUS_SUCCESS;
+
+ } _SEH2_FINALLY {
+
+ Ext2DerefXcb(&Dcb->ReferenceCount);
+
+ if (MainResourceAcquired)
+ ExReleaseResourceLite(&Dcb->MainResource);
+
+ if (bh)
+ brelse(bh);
+ } _SEH2_END;
+
+ return Status;
+}
+
NTSTATUS
Ext2RemoveEntry (
IN PEXT2_IRP_CONTEXT IrpContext,
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
struct ext4_group_desc *gdp;
- struct buffer_head *bh;
+ struct buffer_head *bh = NULL;
gdp = ext4_get_group_desc(sb, block_group, &bh);
if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
if (!ext4_block_in_group(sb, tmp, block_group))
used_blocks -= 1;
}
+ if (bh)
+ fini_bh(&bh);
}
return used_blocks;
}
struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
ext4_group_t block_group, struct buffer_head **bh)
{
- unsigned int group_desc;
- unsigned int offset;
struct ext4_group_desc *desc = NULL;
+ struct buffer_head *gb = NULL;
struct ext3_sb_info *sbi = EXT3_SB(sb);
PEXT2_VCB vcb = sb->s_priv;
+ unsigned int group;
+ unsigned int offset;
+
+ if (bh)
+ *bh = NULL;
+
if (block_group >= sbi->s_groups_count) {
ext4_error(sb, "ext4_get_group_desc",
"block_group >= groups_count - "
}
smp_rmb();
- group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
+ group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
- ExAcquireResourceExclusiveLite(&vcb->MetaLock, TRUE);
-
- if (!sbi->s_group_desc || !sbi->s_group_desc[group_desc]) {
- if (!Ext2LoadGroup(vcb)) {
- ext4_error(sb, "ext4_get_group_desc",
- "failed to load group desc: "
- "block_group >= groups_count - "
- "block_group = %u, groups_count = %u",
- block_group, sbi->s_groups_count);
- goto errorout;
- }
+ if (!sbi->s_group_desc || !sbi->s_group_desc[group]) {
+ Ext2LoadGroup(vcb);
}
- if (!sbi->s_group_desc[group_desc]) {
+ if (!sbi->s_group_desc[group]) {
ext4_error(sb, "ext4_get_group_desc",
"Group descriptor not loaded - "
- "block_group = %u, group_desc = %u, desc = %u",
- block_group, group_desc, offset);
+ "block_group = %u, group = %u, desc = %u",
+ block_group, group, offset);
goto errorout;
}
- desc = (struct ext4_group_desc *)(
- (__u8 *)sbi->s_group_desc[group_desc]->b_data +
- offset * EXT4_DESC_SIZE(sb));
+ gb = sb_getblk(sb, sbi->s_group_desc[group]);
+ if (!gb) {
+ ext4_error(sb, "ext4_get_group_desc",
+ "failed to load group - "
+ "block_group = %u, group = %u, desc = %u",
+ block_group, group, offset);
+ goto errorout;
+ }
+
+ desc = (struct ext4_group_desc *)(gb->b_data +
+ offset * EXT4_DESC_SIZE(sb));
if (bh)
- *bh = sbi->s_group_desc[group_desc];
+ *bh = gb;
+ else
+ fini_bh(&gb);
errorout:
- ExReleaseResourceLite(&vcb->MetaLock);
-
return desc;
}
{
ext4_fsblk_t desc_count;
struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
ext4_group_t i;
ext4_group_t ngroups = EXT3_SB(sb)->s_groups_count;
desc_count = 0;
smp_rmb();
for (i = 0; i < ngroups; i++) {
- gdp = ext4_get_group_desc(sb, i, NULL);
- if (!gdp)
+ gdp = ext4_get_group_desc(sb, i, &bh);
+ if (!bh)
continue;
desc_count += ext4_free_blks_count(sb, gdp);
+ fini_bh(&bh);
}
return desc_count;
{
unsigned long desc_count;
struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
ext4_group_t i;
desc_count = 0;
for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
- gdp = ext4_get_group_desc(sb, i, NULL);
- if (!gdp)
+ gdp = ext4_get_group_desc(sb, i, &bh);
+ if (!bh)
continue;
desc_count += ext4_free_inodes_count(sb, gdp);
- cond_resched();
+ fini_bh(&bh);
}
return desc_count;
}
/* Called at mount-time, super-block is locked */
unsigned long ext4_count_dirs(struct super_block * sb)
{
+ struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
unsigned long count = 0;
ext4_group_t i;
for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
- struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
- if (!gdp)
+ gdp = ext4_get_group_desc(sb, i, &bh);
+ if (!bh)
continue;
count += ext4_used_dirs_count(sb, gdp);
+ fini_bh(&bh);
}
return count;
}
DEBUG(DL_INF, ("Checking group descriptors"));
for (i = 0; i < sbi->s_groups_count; i++) {
- struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
+
+ struct buffer_head *bh = NULL;
+ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
+
+ if (!bh)
+ continue;
if (i == sbi->s_groups_count - 1 || flexbg_flag)
last_block = ext3_blocks_count(sbi->s_es) - 1;
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
"Block bitmap for group %u not in group "
"(block %llu)!\n", i, block_bitmap);
+ __brelse(bh);
return 0;
}
inode_bitmap = ext4_inode_bitmap(sb, gdp);
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
"Inode bitmap for group %u not in group "
"(block %llu)!\n", i, inode_bitmap);
+ __brelse(bh);
return 0;
}
inode_table = ext4_inode_table(sb, gdp);
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
"Inode table for group %u not in group "
"(block %llu)!\n", i, inode_table);
+ __brelse(bh);
return 0;
}
i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
gdp)), le16_to_cpu(gdp->bg_checksum));
if (!IsVcbReadOnly(Vcb)) {
+ __brelse(bh);
return 0;
}
}
if (!flexbg_flag)
first_block += EXT4_BLOCKS_PER_GROUP(sb);
+
+ __brelse(bh);
}
ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
*err = bh_submit_read(bh);
if (*err) {
- brelse(bh);
+ __brelse(bh);
return NULL;
}
return bh;
while ((char *) de <= top) {
if (!ext3_check_dir_entry("ext3_add_entry", dir, de,
bh, offset)) {
- brelse(bh);
+ __brelse(bh);
return -EIO;
}
if (ext3_match(namelen, name, de)) {
- brelse(bh);
+ __brelse(bh);
return -EEXIST;
}
nlen = EXT3_DIR_REC_LEN(de->name_len);
dir->i_version++;
ext3_mark_inode_dirty(icb, dir);
set_buffer_dirty(bh);
- brelse(bh);
+ __brelse(bh);
return 0;
}
names += stats.names;
space += stats.space;
bcount += stats.bcount;
- brelse (bh);
+ __brelse (bh);
}
if (bcount)
printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ",
ext3_warning(dir->i_sb, __FUNCTION__,
"Unrecognised inode hash code %d",
root->info.hash_version);
- brelse(bh);
+ __brelse(bh);
*err = ERR_BAD_DX_DIR;
goto fail;
}
return NULL;
#ifdef EXT2_HTREE_INDEX
- if (is_dx(dir)) {
+ if (icb->MajorFunction != IRP_MJ_CREATE && is_dx(dir)) {
bh = ext3_dx_find_entry(icb, dentry, res_dir, &err);
/*
* On success, or if the error was file not found,
for (; ra_ptr < ra_max; ra_ptr++)
brelse(bh_use[ra_ptr]);
return ret;
-}
\ No newline at end of file
+}
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
* FILE: recover.c
* PROGRAMMER: Matt Wu <mattwu@163.com>
- * HOMEPAGE: http://ext2.yeah.net
+ * HOMEPAGE: http://www.ext2fsd.com
* UPDATE HISTORY:
*/
{
brelse(bh);
}
+
+/*
+ * extents_bforget: Release the corresponding buffer header.
+ * NOTE: The page owned by @bh will be marked invalidated.
+ *
+ * @bh: The corresponding buffer header that is going to be freed.
+ *
+ * The pages underlying the buffer header will be unlocked.
+ */
+void extents_bforget(struct buffer_head *bh)
+{
+ clear_buffer_uptodate(bh);
+ bforget(bh);
+}
neh = ext_block_hdr(bh);
neh->eh_entries = 0;
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
- neh->eh_magic = EXT4_EXT_MAGIC;
+ neh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
neh->eh_depth = 0;
/* move remainder of path[depth] to the new leaf */
neh = ext_block_hdr(bh);
neh->eh_entries = cpu_to_le16(1);
- neh->eh_magic = EXT4_EXT_MAGIC;
+ neh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
neh->eh_depth = cpu_to_le16(depth - i);
fidx = EXT_FIRST_INDEX(neh);
/* old root could have indexes or leaves
* so calculate e_max right way */
if (ext_depth(inode))
- neh->eh_max = (ext4_ext_space_block_idx(inode, 0));
+ neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
else
- neh->eh_max = (ext4_ext_space_block(inode, 0));
- neh->eh_magic = EXT4_EXT_MAGIC;
+ neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
+ neh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
ext4_extent_block_csum_set(inode, neh);
set_buffer_uptodate(bh);
/* Update top-level index: num,max,pointer */
neh = ext_inode_hdr(inode);
- neh->eh_entries = (1);
+ neh->eh_entries = cpu_to_le16(1);
ext4_idx_store_pblock(EXT_FIRST_INDEX(neh), newblock);
if (neh->eh_depth == 0) {
/* Root extent block becomes index block */
- neh->eh_max = (ext4_ext_space_root_idx(inode, 0));
+ neh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
EXT_FIRST_INDEX(neh)->ei_block =
EXT_FIRST_EXTENT(neh)->ee_block;
}
eh = ext_inode_hdr(inode);
eh->eh_depth = 0;
eh->eh_entries = 0;
- eh->eh_magic = EXT4_EXT_MAGIC;
+ eh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
ext4_mark_inode_dirty(icb, handle, inode);
return 0;
return err ? err : allocated;
}
+int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start)
+{
+ int ret = ext4_ext_remove_space(icb, inode, start);
+
+ /* Save modifications on i_blocks field of the inode. */
+ if (!ret)
+ ret = ext4_mark_inode_dirty(icb, NULL, inode);
+
+ return ret;
+}
+
#ifdef _MSC_VER
#pragma warning(pop)
#endif
)
{
EXT4_EXTENT_HEADER *eh;
- struct buffer_head bh_got;
+ struct buffer_head bh_got = {0};
int flags, rc;
ULONG max_blocks = 0;
flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
max_blocks = EXT_UNWRITTEN_MAX_LEN;
}
+
+ if (Alloc) {
+ if (Number && !*Number) {
+ if (max_blocks > *Number) {
+ max_blocks = *Number;
+ }
+ } else {
+ max_blocks = 1;
+ }
+ }
if ((rc = ext4_ext_get_blocks(
IrpContext,
/* calculate blocks to be freed */
Extra = End - Wanted;
- err = ext4_ext_remove_space(IrpContext, &Mcb->Inode, Wanted);
+ err = ext4_ext_truncate(IrpContext, &Mcb->Inode, Wanted);
if (err == 0) {
if (!Ext2RemoveBlockExtent(Vcb, Mcb, Wanted, Extra)) {
ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS);
}
- /* save inode */
if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart))
Mcb->Inode.i_size = (loff_t)(Size->QuadPart);
+
+ /* Save modifications on i_blocks field and i_size field of the inode. */
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
return Status;
_SEH2_LEAVE;
}
- ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
- Locked = TRUE;
+ if (ExAcquireResourceExclusiveLite(&Fcb->MainResource, Wait))
+ Locked = TRUE;
+ else
+ _SEH2_LEAVE;
if (IsWritingToEof(*FileOffset) ||
- Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart ||
Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) {
Status = FALSE;
- } else {
- ExReleaseResourceLite(&Fcb->MainResource);
- Locked = FALSE;
- Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
- LockKey, Buffer, IoStatus, DeviceObject);
+ _SEH2_LEAVE;
+ }
+
+ Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
+ LockKey, Buffer, IoStatus, DeviceObject);
+ if (Status) {
+ if (IoStatus)
+ Length = (ULONG)IoStatus->Information;
+ if (Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length)
+ Fcb->Header.ValidDataLength.QuadPart = FileOffset->QuadPart + Length;
}
} _SEH2_FINALLY {
IN PDEVICE_OBJECT DeviceObject)
{
PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
BOOLEAN Status = FALSE;
BOOLEAN FcbMainResourceAcquired = FALSE;
IoStatus->Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
-
+ Ccb = (PEXT2_CCB) FileObject->FsContext2;
+ Mcb = Fcb->Mcb;
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
#if EXT2_DEBUG
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
*/
- if (IsRoot(Fcb)) {
- Buffer->CreationTime = Buffer->LastAccessTime =
- Buffer->LastWriteTime = Buffer->ChangeTime = Ext2NtTime(0);
- } else {
- Buffer->CreationTime = Fcb->Mcb->CreationTime;
- Buffer->LastAccessTime = Fcb->Mcb->LastAccessTime;
- Buffer->LastWriteTime = Fcb->Mcb->LastWriteTime;
- Buffer->ChangeTime = Fcb->Mcb->ChangeTime;
- }
-
- Buffer->FileAttributes = Fcb->Mcb->FileAttr;
+ Buffer->CreationTime = Mcb->CreationTime;
+ Buffer->LastAccessTime = Mcb->LastAccessTime;
+ Buffer->LastWriteTime = Mcb->LastWriteTime;
+ Buffer->ChangeTime = Mcb->ChangeTime;
+ Buffer->FileAttributes = Mcb->FileAttr;
if (Buffer->FileAttributes == 0) {
Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
}
{
BOOLEAN Status = FALSE;
- PEXT2_VCB Vcb;
- PEXT2_FCB Fcb;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
BOOLEAN FcbMainResourceAcquired = FALSE;
_SEH2_TRY {
IN PDEVICE_OBJECT DeviceObject
)
{
- BOOLEAN bResult = FALSE;
-
PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+ BOOLEAN bResult = FALSE;
BOOLEAN FcbResourceAcquired = FALSE;
_SEH2_TRY {
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+ Ccb = (PEXT2_CCB) FileObject->FsContext2;
+ Mcb = Fcb->Mcb;
#if EXT2_DEBUG
DEBUG(DL_INF, (
));
#endif
- if (FileObject->FsContext2) {
+ if (!Ccb) {
_SEH2_LEAVE;
}
PFNOI->EndOfFile = Fcb->Header.FileSize;
}
- PFNOI->FileAttributes = Fcb->Mcb->FileAttr;
+ PFNOI->FileAttributes = Mcb->FileAttr;
if (PFNOI->FileAttributes == 0) {
PFNOI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
}
- if (IsRoot(Fcb)) {
- PFNOI->CreationTime =
- PFNOI->LastAccessTime =
- PFNOI->LastWriteTime =
- PFNOI->ChangeTime = Ext2NtTime(0);
- } else {
- PFNOI->CreationTime = Fcb->Mcb->CreationTime;
- PFNOI->LastAccessTime = Fcb->Mcb->LastAccessTime;
- PFNOI->LastWriteTime = Fcb->Mcb->LastWriteTime;
- PFNOI->ChangeTime = Fcb->Mcb->ChangeTime;
- }
+ PFNOI->CreationTime = Mcb->CreationTime;
+ PFNOI->LastAccessTime = Mcb->LastAccessTime;
+ PFNOI->LastWriteTime = Mcb->LastWriteTime;
+ PFNOI->ChangeTime = Mcb->ChangeTime;
bResult = TRUE;
#pragma alloc_text(PAGE, Ext2TruncateFile)
#pragma alloc_text(PAGE, Ext2SetDispositionInfo)
#pragma alloc_text(PAGE, Ext2SetRenameInfo)
+#pragma alloc_text(PAGE, Ext2SetLinkInfo)
#pragma alloc_text(PAGE, Ext2DeleteFile)
#endif
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PFILE_OBJECT FileObject;
- PEXT2_VCB Vcb;
- PEXT2_FCB Fcb;
- PEXT2_MCB Mcb;
- PEXT2_CCB Ccb;
- PIRP Irp;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_MCB Mcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PIRP Irp = NULL;
PIO_STACK_LOCATION IoStackLocation;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG Length;
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PFILE_OBJECT FileObject;
- PEXT2_FCB Fcb;
- PEXT2_CCB Ccb;
- PEXT2_MCB Mcb;
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
+ PEXT2_VCB Vcb = NULL;
+ PFILE_OBJECT FileObject = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG NotifyFilter = 0;
_SEH2_LEAVE;
}
- /* we need grab Vcb in case it's a rename operation */
- if (FileInformationClass == FileRenameInformation) {
+ /* we need grab Vcb in case it's rename or sethardlink */
+ if (FileInformationClass == FileRenameInformation ||
+ FileInformationClass == FileLinkInformation) {
if (!ExAcquireResourceExclusiveLite(
&Vcb->MainResource,
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
}
- /* for renaming, we must not get any Fcb locks here, function
- Ext2SetRenameInfo will get Dcb resource exclusively. */
+ /* for renaming or set link, we must not grab any Fcb locks,
+ and later we will get Dcb or Fcb resources exclusively. */
if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
- FileInformationClass != FileRenameInformation) {
+ FileInformationClass != FileRenameInformation &&
+ FileInformationClass != FileLinkInformation) {
if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
break;
+
+ case FileLinkInformation:
+ {
+ Status = Ext2SetLinkInfo(IrpContext, Vcb, Fcb, Ccb);
+ }
+
+ break;
+
//
// This is the only set file information request supported on read
// only file systems
break;
- case FileLinkInformation:
-
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
-
default:
DEBUG(DL_WRN, ( "Ext2SetInformation: invalid class: %d\n",
FileInformationClass));
return Status;
}
+NTSTATUS
+Ext2SetLinkInfo(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_FCB Fcb,
+ PEXT2_CCB Ccb
+)
+{
+ PEXT2_MCB Mcb = Fcb->Mcb;
+
+ PEXT2_FCB TargetDcb = NULL; /* Dcb of target directory */
+ PEXT2_MCB TargetMcb = NULL;
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ PEXT2_FCB ExistingFcb = NULL; /* Target file Fcb if it exists*/
+ PEXT2_MCB ExistingMcb = NULL;
+ PEXT2_MCB LinkMcb = NULL; /* Mcb for new hardlink */
+
+ UNICODE_STRING FileName;
+
+ NTSTATUS Status;
+
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ PFILE_OBJECT FileObject;
+ PFILE_OBJECT TargetObject;
+
+ BOOLEAN ReplaceIfExists;
+ BOOLEAN bTargetRemoved = FALSE;
+ BOOLEAN bNewTargetDcb = FALSE;
+ BOOLEAN bNewParentDcb = FALSE;
+
+ PFILE_LINK_INFORMATION FLI;
+
+ if (Ccb->SymLink) {
+ Mcb = Ccb->SymLink;
+ }
+
+ if (IsMcbDirectory(Mcb)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto errorout;
+ }
+
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ FileObject = IrpSp->FileObject;
+ TargetObject = IrpSp->Parameters.SetFile.FileObject;
+ ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
+
+ FLI = (PFILE_LINK_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (TargetObject == NULL) {
+
+ UNICODE_STRING NewName;
+
+ NewName.Buffer = FLI->FileName;
+ NewName.MaximumLength = NewName.Length = (USHORT)FLI->FileNameLength;
+
+ while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') {
+ NewName.Buffer[NewName.Length/2 - 1] = 0;
+ NewName.Length -= 2;
+ }
+
+ while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') {
+ NewName.Length -= 2;
+ }
+
+ NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length);
+ NewName.Length = (USHORT)(FLI->FileNameLength - NewName.Length);
+
+ FileName = NewName;
+
+ TargetMcb = Mcb->Parent;
+ if (IsMcbSymLink(TargetMcb)) {
+ TargetMcb = TargetMcb->Target;
+ ASSERT(!IsMcbSymLink(TargetMcb));
+ }
+
+ if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) {
+ Status = STATUS_OBJECT_NAME_INVALID;
+ goto errorout;
+ }
+
+ } else {
+
+ TargetDcb = (PEXT2_FCB)(TargetObject->FsContext);
+ if (!TargetDcb || TargetDcb->Vcb != Vcb) {
+ DbgBreak();
+ Status = STATUS_INVALID_PARAMETER;
+ goto errorout;
+ }
+
+ TargetMcb = TargetDcb->Mcb;
+ FileName = TargetObject->FileName;
+ }
+
+ if (FsRtlDoesNameContainWildCards(&FileName)) {
+ Status = STATUS_OBJECT_NAME_INVALID;
+ goto errorout;
+ }
+
+ if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) {
+ if (FsRtlAreNamesEqual( &FileName,
+ &(Mcb->ShortName),
+ FALSE,
+ NULL )) {
+ Status = STATUS_SUCCESS;
+ goto errorout;
+ }
+ }
+
+ TargetDcb = TargetMcb->Fcb;
+ if (TargetDcb == NULL) {
+ TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
+ if (TargetDcb) {
+ Ext2ReferXcb(&TargetDcb->ReferenceCount);
+ bNewTargetDcb = TRUE;
+ }
+ }
+
+ if (TargetDcb) {
+ SetLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+ }
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+
+ if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) {
+
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ bNewParentDcb = TRUE;
+ }
+ }
+ if (ParentDcb) {
+ SetLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
+ }
+ }
+
+ if (!TargetDcb || !ParentDcb) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ DEBUG(DL_RES, ("Ext2SetLinkInfo: %wZ\\%wZ -> %wZ\n",
+ &TargetMcb->FullName, &FileName, &Mcb->FullName));
+
+ Status = Ext2LookupFile(IrpContext, Vcb, &FileName,
+ TargetMcb, &ExistingMcb, 0);
+ if (NT_SUCCESS(Status) && ExistingMcb != Mcb) {
+
+ if (!ReplaceIfExists) {
+
+ Status = STATUS_OBJECT_NAME_COLLISION;
+ DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n",
+ &ExistingMcb->FullName));
+ goto errorout;
+
+ } else {
+
+ if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) {
+ Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb);
+ if (!NT_SUCCESS(Status)) {
+ DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n",
+ &ExistingMcb->FullName));
+ goto errorout;
+ }
+ }
+
+ Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb);
+ if (!NT_SUCCESS(Status)) {
+ DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n",
+ &FileName, Status));
+
+ goto errorout;
+ }
+ bTargetRemoved = TRUE;
+ }
+ }
+
+ /* add new entry for new target name */
+ Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DEBUG(DL_REN, ("Ext2SetLinkInfo: Failed to add entry for %wZ with status: %xh.\n",
+ &FileName, Status));
+ goto errorout;
+ }
+
+ if (bTargetRemoved) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ ExistingMcb,
+ (IsMcbDirectory(ExistingMcb) ?
+ FILE_NOTIFY_CHANGE_DIR_NAME :
+ FILE_NOTIFY_CHANGE_FILE_NAME ),
+ FILE_ACTION_REMOVED);
+ }
+
+ if (NT_SUCCESS(Status)) {
+
+ Ext2LookupFile(IrpContext, Vcb, &FileName, TargetMcb, &LinkMcb, 0);
+ if (!LinkMcb)
+ goto errorout;
+
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ LinkMcb,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_ACTION_ADDED);
+ }
+
+errorout:
+
+ if (TargetDcb) {
+ if (ParentDcb && ParentDcb->Inode->i_ino != TargetDcb->Inode->i_ino) {
+ ClearLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
+ }
+ ClearLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
+ }
+
+ if (bNewTargetDcb) {
+ ASSERT(TargetDcb != NULL);
+ if (Ext2DerefXcb(&TargetDcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(TargetDcb);
+ TargetDcb = NULL;
+ } else {
+ DEBUG(DL_RES, ( "Ext2SetLinkInfo: TargetDcb is resued by other threads.\n"));
+ }
+ }
+
+ if (bNewParentDcb) {
+ ASSERT(ParentDcb != NULL);
+ if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(ParentDcb);
+ ParentDcb = NULL;
+ } else {
+ DEBUG(DL_RES, ( "Ext2SeLinkInfo: ParentDcb is resued by other threads.\n"));
+ }
+ }
+
+ if (ExistingMcb)
+ Ext2DerefMcb(ExistingMcb);
+
+ if (LinkMcb)
+ Ext2DerefMcb(LinkMcb);
+
+ return Status;
+}
+
ULONG
Ext2InodeType(PEXT2_MCB Mcb)
{
}
}
-
_SEH2_TRY {
Ext2ReferMcb(Mcb);
IN PEXT2_CCB Ccb
)
{
- IO_STATUS_BLOCK IoStatus;
+ IO_STATUS_BLOCK IoStatus;
ASSERT(Fcb != NULL);
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
- /* update timestamp and achieve attribute */
- if (Ccb != NULL) {
+ _SEH2_TRY {
+
+ /* update timestamp and achieve attribute */
+ if (Ccb != NULL) {
- if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
+ if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
- LARGE_INTEGER SysTime;
- KeQuerySystemTime(&SysTime);
+ LARGE_INTEGER SysTime;
+ KeQuerySystemTime(&SysTime);
- Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
- Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
- Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
+ Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
+ Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
+ Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
+ }
}
- }
- if (IsDirectory(Fcb)) {
- return STATUS_SUCCESS;
- }
+ if (IsDirectory(Fcb)) {
+ IoStatus.Status = STATUS_SUCCESS;
+ _SEH2_LEAVE;
+ }
+
+ DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
+ Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
- DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
- Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
+ CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
+ ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+
+ } _SEH2_FINALLY {
- CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
- ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+ /* do cleanup here */
+ } _SEH2_END;
return IoStatus.Status;
}
+
NTSTATUS
Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext)
{
}
MainResourceAcquired =
- ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
-
+ ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE);
ASSERT(MainResourceAcquired);
DEBUG(DL_INF, ("Ext2Flush-pre: total mcb records=%u\n",
FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
} _SEH2_END;
return Status;
-}
\ No newline at end of file
+}
{
PIO_STACK_LOCATION IrpSp;
PDEVICE_OBJECT DeviceObject;
- PEXT2_VCB Vcb;
+ PEXT2_VCB Vcb = NULL;
NTSTATUS Status;
BOOLEAN VcbResourceAcquired = FALSE;
IN PEXT2_IRP_CONTEXT IrpContext
)
{
- PIO_STACK_LOCATION IrpSp;
- PDEVICE_OBJECT DeviceObject;
+ PIO_STACK_LOCATION IrpSp = NULL;
+ PDEVICE_OBJECT DeviceObject = NULL;
+ PEXT2_VCB Vcb = NULL;
NTSTATUS Status;
- PEXT2_VCB Vcb;
BOOLEAN VcbResourceAcquired = FALSE;
_SEH2_TRY {
return Status;
}
+NTSTATUS
+Ext2InspectReparseData(
+ IN PREPARSE_DATA_BUFFER RDB,
+ IN ULONG InputBufferLength
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!RDB) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (InputBufferLength < RDB->ReparseDataLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+ if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
+ > (PUCHAR)RDB + InputBufferLength ) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
+ + RDB->SymbolicLinkReparseBuffer.PrintNameLength
+ > (PUCHAR)RDB + InputBufferLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+out:
+ return Status;
+}
+
+VOID
+Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
+{
+ ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
+ REPARSE_DATA_BUFFER_HEADER_SIZE);
+ RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+ RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+ PathBufferLength * sizeof(WCHAR);
+ RDB->Reserved = 0;
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+ RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
+ RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
+}
+
+NTSTATUS
+Ext2ReadSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesRead
+ )
+{
+ return Ext2ReadInode ( IrpContext,
+ Vcb,
+ Mcb,
+ 0,
+ Buffer,
+ Size,
+ FALSE,
+ BytesRead);
+}
+
+
+
+NTSTATUS
+Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PVOID OutputBuffer;
+ ULONG OutputBufferLength;
+ ULONG BytesRead = 0;
+
+ PREPARSE_DATA_BUFFER RDB;
+
+ UNICODE_STRING UniName;
+ OEM_STRING OemName;
+
+ PCHAR OemNameBuffer = NULL;
+ int OemNameLength = 0, i;
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Mcb = IrpContext->Fcb->Mcb;
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ _SEH2_TRY {
+
+ if (!Mcb || !IsInodeSymLink(&Mcb->Inode)) {
+ Status = STATUS_NOT_A_REPARSE_POINT;
+ _SEH2_LEAVE;
+ }
+
+ OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
+ OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
+ if (!RDB) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+ if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ _SEH2_LEAVE;
+ }
+
+ OemNameLength = (ULONG)Mcb->Inode.i_size;
+ if (OemNameLength > USHRT_MAX) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+ OemName.Length = (USHORT)OemNameLength;
+ OemName.MaximumLength = OemNameLength + 1;
+ OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
+ OemName.MaximumLength,
+ 'NL2E');
+ if (!OemNameBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+
+ Status = Ext2ReadSymlink(IrpContext,
+ Vcb,
+ Mcb,
+ OemNameBuffer,
+ OemNameLength,
+ &BytesRead
+ );
+ OemName.Buffer[OemName.Length] = '\0';
+ for (i = 0;i < OemName.Length;i++) {
+ if (OemName.Buffer[i] == '/') {
+ OemName.Buffer[i] = '\\';
+ }
+ }
+
+ if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
+ UniName.Length = USHRT_MAX;
+ } else {
+ UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
+ }
+ UniName.MaximumLength = UniName.Length;
+ UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
+ Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
+ if (UniName.MaximumLength < 2*UniName.Length) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ _SEH2_LEAVE;
+ }
+
+ Ext2InitializeReparseData(RDB, UniName.Length);
+ UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
+ /*
+ (PWCHAR)((PUCHAR)&
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+ */
+ Ext2OEMToUnicode(Vcb, &UniName, &OemName);
+ RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
+ UniName.Buffer, UniName.Length);
+
+ Status = STATUS_SUCCESS;
+
+ } _SEH2_FINALLY {
+
+ if (OemNameBuffer) {
+ Ext2FreePool(OemNameBuffer, 'NL2E');
+ }
+
+ if (!_SEH2_AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ } _SEH2_END;
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2WriteSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesWritten
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
+
+ if (Size >= EXT2_LINKLEN_IN_INODE) {
+
+ /* initialize inode i_block[] */
+ if (0 == Mcb->Inode.i_blocks) {
+ memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+ ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ }
+
+ Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
+ 0, Buffer, Size,
+ FALSE, BytesWritten);
+ if (!NT_SUCCESS(Status)) {
+ goto out;
+ }
+
+ } else {
+
+ /* free inode blocks before writing in line */
+ if (Mcb->Inode.i_blocks) {
+ LARGE_INTEGER Zero = {0, 0};
+ Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
+ }
+
+ ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+ RtlCopyMemory(Data, Buffer, Size);
+ }
+
+ Mcb->Inode.i_size = Size;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+ if (BytesWritten) {
+ *BytesWritten = Size;
+ }
+
+out:
+ return Status;
+}
+
+
+NTSTATUS
+Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN bNewParentDcb = FALSE;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ ULONG BytesWritten = 0;
+
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ PREPARSE_DATA_BUFFER RDB;
+
+ UNICODE_STRING UniName;
+ OEM_STRING OemName;
+
+ PCHAR OemNameBuffer = NULL;
+ int OemNameLength = 0, i;
+
+
+ _SEH2_TRY {
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Fcb = IrpContext->Fcb;
+ Mcb = Fcb->Mcb;
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ bNewParentDcb = TRUE;
+ }
+ }
+
+ if (!Mcb)
+ _SEH2_LEAVE;
+
+ if (!ExAcquireResourceSharedLite(
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ Status = STATUS_PENDING;
+ _SEH2_LEAVE;
+ }
+ MainResourceAcquired = TRUE;
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+
+ RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
+ Status = Ext2InspectReparseData(RDB, InputBufferLength);
+ if (!NT_SUCCESS(Status)) {
+ _SEH2_LEAVE;
+ }
+
+ UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ UniName.MaximumLength = UniName.Length;
+ UniName.Buffer =
+ (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+
+ OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
+ if (OemNameLength > USHRT_MAX) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
+ OemName.Length = (USHORT)OemNameLength;
+ OemName.MaximumLength = OemNameLength + 1;
+ OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
+ OemName.MaximumLength,
+ 'NL2E');
+ if (!OemNameBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+
+ Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
+ OemName.Buffer[OemName.Length] = '\0';
+ for (i = 0;i < OemName.Length;i++) {
+ if (OemName.Buffer[i] == '\\') {
+ OemName.Buffer[i] = '/';
+ }
+ }
+
+ /* overwrite inode mode as type SYMLINK */
+ Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+
+ Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
+ OemNameLength, &BytesWritten);
+ if (NT_SUCCESS(Status)) {
+ Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+ }
+
+ } _SEH2_FINALLY {
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (OemNameBuffer) {
+ Ext2FreePool(OemNameBuffer, 'NL2E');
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ Mcb,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ FILE_ACTION_MODIFIED );
+ }
+
+ if (bNewParentDcb) {
+ ASSERT(ParentDcb != NULL);
+ if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(ParentDcb);
+ ParentDcb = NULL;
+ } else {
+ DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
+ }
+ }
+
+ if (!_SEH2_AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ } _SEH2_END;
+
+ return Status;
+}
+
+NTSTATUS
+Ext2TruncateSymlink(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Mcb,
+ ULONG Size
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
+ ULONG len = (ULONG)Mcb->Inode.i_size;
+ LARGE_INTEGER NewSize;
+
+ if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
+
+ RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
+ Mcb->Inode.i_size = Size;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+ } else {
+ NewSize.QuadPart = Size;
+ status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
+
+
+/* FIXME: We can only handle one reparse point right now. */
+NTSTATUS
+Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN bNewParentDcb = FALSE;
+ BOOLEAN bFcbAllocated = FALSE;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ _SEH2_TRY {
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Mcb = IrpContext->Fcb->Mcb;
+ Irp = IrpContext->Irp;
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ bNewParentDcb = TRUE;
+ }
+ }
+
+ if (!Mcb) {
+ Status = STATUS_NOT_A_REPARSE_POINT;
+ _SEH2_LEAVE;
+ }
+
+ Fcb = Ext2AllocateFcb (Vcb, Mcb);
+ if (Fcb) {
+ bFcbAllocated = TRUE;
+ } else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+ Ext2ReferXcb(&Fcb->ReferenceCount);
+
+ if (!ExAcquireResourceSharedLite(
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ Status = STATUS_PENDING;
+ _SEH2_LEAVE;
+ }
+ MainResourceAcquired = TRUE;
+
+ Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
+ if (!NT_SUCCESS(Status)) {
+ _SEH2_LEAVE;
+ }
+ if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+ SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ }
+ ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+ ClearFlag(Mcb->Inode.i_flags, S_IFLNK);
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ if (NT_SUCCESS(Status)) {
+ Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+ }
+
+ } _SEH2_FINALLY {
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ Mcb,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ FILE_ACTION_MODIFIED );
+
+ }
+
+ if (bNewParentDcb) {
+ ASSERT(ParentDcb != NULL);
+ if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(ParentDcb);
+ ParentDcb = NULL;
+ } else {
+ DEBUG(DL_RES, ( "Ext2DeleteReparsePoint: ParentDcb is resued.\n"));
+ }
+ }
+
+ if (!_SEH2_AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ if (bFcbAllocated) {
+ if (Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(Fcb);
+ }
+ }
+ } _SEH2_END;
+
+ return Status;
+}
NTSTATUS
Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
Irp = IrpContext->Irp;
-
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
#ifndef _GNU_NTIFS_
switch (FsControlCode) {
+ case FSCTL_GET_REPARSE_POINT:
+ Status = Ext2GetReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_SET_REPARSE_POINT:
+ Status = Ext2SetReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_DELETE_REPARSE_POINT:
+ Status = Ext2DeleteReparsePoint(IrpContext);
+ break;
+
case FSCTL_LOCK_VOLUME:
Status = Ext2LockVolume(IrpContext);
break;
VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
+/*
+ These are for buffer-address alignment requirements.
+ Never do this check, unless you want fail user requests :)
+
if (TargetDeviceObject->AlignmentRequirement >
VolumeDeviceObject->AlignmentRequirement) {
TargetDeviceObject->AlignmentRequirement;
}
+ if (DiskGeometry.BytesPerSector - 1 >
+ VolumeDeviceObject->AlignmentRequirement) {
+ VolumeDeviceObject->AlignmentRequirement =
+ DiskGeometry.BytesPerSector - 1;
+ TargetDeviceObject->AlignmentRequirement =
+ DiskGeometry.BytesPerSector - 1;
+ }
+*/
(IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
VolumeDeviceObject;
Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
+ PEXT2_VCB Vcb = NULL;
BOOLEAN VcbResourceAcquired = FALSE;
_SEH2_TRY {
BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
ULONG UnCleanCount = 0;
- NewVpb = Ext2AllocatePool(NonPagedPool, VPB_SIZE, TAG_VPB);
+ NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
if (NewVpb == NULL) {
DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
return FALSE;
}
+ DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
memset(NewVpb, '_', VPB_SIZE);
RtlZeroMemory(NewVpb, sizeof(VPB));
if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
(IrpContext->RealDevice == Vcb->RealDevice)) {
- UnCleanCount = 3;
- } else {
UnCleanCount = 2;
+ } else {
+ UnCleanCount = 1;
}
IoAcquireVpbSpinLock (&Irql);
DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
+
if (Vpb->ReferenceCount <= UnCleanCount) {
if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
Vpb->DeviceObject = NULL;
}
+ DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
+ Vpb, bDeleted, bTearDown));
+
+
} else if (bForce) {
- DEBUG(DL_DBG, ( "Ext2CheckDismount: NewVpb %p Realdevice = %p\n",
- NewVpb, Vpb->RealDevice));
+ DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
+ NewVpb, Vcb->Vpb, Vpb->RealDevice));
+
+ /* keep vpb president and later we'll free it */
+ SetFlag(Vpb->Flags, VPB_PERSISTENT);
Vcb->Vpb2 = Vcb->Vpb;
NewVpb->Type = IO_TYPE_VPB;
}
if (NewVpb != NULL) {
- DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing Vpb %p\n", NewVpb));
- Ext2FreePool(NewVpb, TAG_VPB);
+ DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
+ ExFreePoolWithTag(NewVpb, TAG_VPB);
DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
}
FlushBeforePurge = FALSE;
}
- Ext2PutGroup(Vcb);
-
FcbListEntry= NULL;
InitializeListHead(&FcbList);
/*
* Ext2Fsd version, building date/time
*/
+
CHAR gVersion[] = EXT2FSD_VERSION;
CHAR gTime[] = __TIME__;
CHAR gDate[] = __DATE__;
+
/* DEFINITIONS ***********************************************************/
NTSTATUS NTAPI
" Free"
#endif
" -- "
- __DATE__" "
- __TIME__".\n");
+ __DATE__ " "
+ __TIME__ ".\n");
DEBUG(DL_FUN, ( "Ext2 DriverEntry ...\n"));
{
int ret;
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
ret = __log_start_commit(journal, tid);
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
return ret;
}
if (journal->j_flags & JFS_ABORT)
return;
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
journal->j_flags |= JFS_ABORT;
transaction = journal->j_running_transaction;
if (transaction)
__log_start_commit(journal, transaction->t_tid);
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
}
/* Soft abort: record the abort error status in the journal superblock,
{
int err;
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
if (journal->j_flags & JFS_ABORT)
err = -EROFS;
else
err = journal->j_errno;
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
return err;
}
{
int err = 0;
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
if (journal->j_flags & JFS_ABORT)
err = -EROFS;
else
journal->j_errno = 0;
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
return err;
}
*/
void journal_ack_err(journal_t *journal)
{
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
if (journal->j_errno)
journal->j_flags |= JFS_ACK_ERR;
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
}
int journal_blocks_per_page(struct inode *inode)
{
unsigned long blocknr;
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
J_ASSERT(journal->j_free > 1);
blocknr = journal->j_head;
journal->j_free--;
if (journal->j_head == journal->j_last)
journal->j_head = journal->j_first;
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
return journal_bmap(journal, blocknr, retp);
}
init_waitqueue_head(&journal->j_wait_updates);
mutex_init(&journal->j_barrier);
mutex_init(&journal->j_checkpoint_mutex);
- spin_lock_init(&journal->j_revoke_lock);
- spin_lock_init(&journal->j_list_lock);
- spin_lock_init(&journal->j_state_lock);
+ jbd_lock_init(&journal->j_revoke_lock);
+ jbd_lock_init(&journal->j_list_lock);
+ jbd_lock_init(&journal->j_state_lock);
journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE);
/* Force any old transactions to disk */
/* Totally anal locking here... */
- spin_lock(&journal->j_list_lock);
+ jbd_lock(&journal->j_list_lock);
while (journal->j_checkpoint_transactions != NULL) {
- spin_unlock(&journal->j_list_lock);
+ jbd_unlock(&journal->j_list_lock);
log_do_checkpoint(journal);
- spin_lock(&journal->j_list_lock);
+ jbd_lock(&journal->j_list_lock);
}
J_ASSERT(journal->j_running_transaction == NULL);
J_ASSERT(journal->j_committing_transaction == NULL);
J_ASSERT(journal->j_checkpoint_transactions == NULL);
- spin_unlock(&journal->j_list_lock);
+ jbd_unlock(&journal->j_list_lock);
/* We can now mark the journal as empty. */
journal->j_tail = 0;
goto out;
}
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
journal->j_tail, journal->j_tail_sequence, journal->j_errno);
sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
sb->s_start = cpu_to_be32(journal->j_tail);
sb->s_errno = cpu_to_be32(journal->j_errno);
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
BUFFER_TRACE(bh, "marking dirty");
mark_buffer_dirty(bh);
* any future commit will have to be careful to update the
* superblock again to re-record the true start of the log. */
- spin_lock(&journal->j_state_lock);
+ jbd_lock(&journal->j_state_lock);
if (sb->s_start)
journal->j_flags &= ~JFS_FLUSHED;
else
journal->j_flags |= JFS_FLUSHED;
- spin_unlock(&journal->j_state_lock);
+ jbd_unlock(&journal->j_state_lock);
}
/*
J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
transaction = jh->b_transaction;
if (transaction)
- assert_spin_locked(&transaction->t_journal->j_list_lock);
+ assert_jbd_locked(&transaction->t_journal->j_list_lock);
J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
if (jh->b_jlist != BJ_None)
void journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
{
jbd_lock_bh_state(jh2bh(jh));
- spin_lock(&journal->j_list_lock);
+ jbd_lock(&journal->j_list_lock);
__journal_unfile_buffer(jh);
- spin_unlock(&journal->j_list_lock);
+ jbd_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(jh2bh(jh));
}
struct buffer_head *bh = jh2bh(jh);
J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
- assert_spin_locked(&transaction->t_journal->j_list_lock);
+ assert_jbd_locked(&transaction->t_journal->j_list_lock);
J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
J_ASSERT_JH(jh, jh->b_transaction == transaction ||
transaction_t *transaction, int jlist)
{
jbd_lock_bh_state(jh2bh(jh));
- spin_lock(&transaction->t_journal->j_list_lock);
+ jbd_lock(&transaction->t_journal->j_list_lock);
__journal_file_buffer(jh, transaction, jlist);
- spin_unlock(&transaction->t_journal->j_list_lock);
+ jbd_unlock(&transaction->t_journal->j_list_lock);
jbd_unlock_bh_state(jh2bh(jh));
}
BUFFER_TRACE(bh, "entry");
jbd_lock_bh_state(bh);
- spin_lock(&journal->j_list_lock);
+ jbd_lock(&journal->j_list_lock);
if (!buffer_jbd(bh))
goto not_jbd;
journal_remove_journal_head(bh);
__brelse(bh);
if (!buffer_jbd(bh)) {
- spin_unlock(&journal->j_list_lock);
+ jbd_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
__bforget(bh);
goto drop;
}
not_jbd:
- spin_unlock(&journal->j_list_lock);
+ jbd_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
__brelse(bh);
drop:
record->sequence = seq;
record->blocknr = blocknr;
hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
- spin_lock(&journal->j_revoke_lock);
+ jbd_lock(&journal->j_revoke_lock);
list_add(&record->hash, hash_list);
- spin_unlock(&journal->j_revoke_lock);
+ jbd_unlock(&journal->j_revoke_lock);
return 0;
oom:
hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
- spin_lock(&journal->j_revoke_lock);
+ jbd_lock(&journal->j_revoke_lock);
record = (struct jbd_revoke_record_s *) hash_list->next;
while (&(record->hash) != hash_list) {
if (record->blocknr == blocknr) {
- spin_unlock(&journal->j_revoke_lock);
+ jbd_unlock(&journal->j_revoke_lock);
return record;
}
record = (struct jbd_revoke_record_s *) record->hash.next;
}
- spin_unlock(&journal->j_revoke_lock);
+ jbd_unlock(&journal->j_revoke_lock);
return NULL;
}
for (tmp = 0; tmp < hash_size; tmp++)
INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
- spin_lock_init(&journal->j_revoke_lock);
+ jbd_lock_init(&journal->j_revoke_lock);
return 0;
}
if (record) {
jbd_debug(4, "cancelled existing revoke on "
"blocknr %llu\n", (u64)bh->b_blocknr);
- spin_lock(&journal->j_revoke_lock);
+ jbd_lock(&journal->j_revoke_lock);
list_del(&record->hash);
- spin_unlock(&journal->j_revoke_lock);
+ jbd_unlock(&journal->j_revoke_lock);
kmem_cache_free(revoke_record_cache, record);
did_revoke = 1;
}
Ext2DestroyMdl(bh->b_mdl);
}
+ if (bh->b_bcb) {
+ CcUnpinDataForThread(bh->b_bcb, (ERESOURCE_THREAD)bh | 0x3);
+ }
+
DEBUG(DL_BH, ("bh=%p freed.\n", bh));
DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head));
kmem_cache_free(g_jbh.bh_cache, bh);
}
struct buffer_head *
-get_block_bh(
+get_block_bh_mdl(
struct block_device * bdev,
sector_t block,
unsigned long size,
return bh;
}
-struct buffer_head *
-__getblk(
- struct block_device * bdev,
- sector_t block,
- unsigned long size
-)
-{
- return get_block_bh(bdev, block, size, 0);
-}
-
-int submit_bh(int rw, struct buffer_head *bh)
+int submit_bh_mdl(int rw, struct buffer_head *bh)
{
struct block_device *bdev = bh->b_bdev;
PEXT2_VCB Vcb = bdev->bd_priv;
return 0;
}
+struct buffer_head *
+get_block_bh(
+ struct block_device * bdev,
+ sector_t block,
+ unsigned long size,
+ int zero
+)
+{
+ PEXT2_VCB Vcb = bdev->bd_priv;
+ LARGE_INTEGER offset;
+
+ KIRQL irql = 0;
+ struct list_head *entry;
+
+ /* allocate buffer_head and initialize it */
+ struct buffer_head *bh = NULL, *tbh = NULL;
+
+ /* check the block is valid or not */
+ if (block >= TOTAL_BLOCKS) {
+ DbgBreak();
+ goto errorout;
+ }
+
+ /* search the bdev bh list */
+ spin_lock_irqsave(&bdev->bd_bh_lock, irql);
+ tbh = buffer_head_search(bdev, block);
+ if (tbh) {
+ bh = tbh;
+ get_bh(bh);
+ spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ goto errorout;
+ }
+ spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+
+ bh = new_buffer_head();
+ if (!bh) {
+ goto errorout;
+ }
+ bh->b_bdev = bdev;
+ bh->b_blocknr = block;
+ bh->b_size = size;
+ bh->b_data = NULL;
+ atomic_inc(&g_jbh.bh_count);
+ atomic_inc(&g_jbh.bh_acount);
+
+again:
+
+ offset.QuadPart = (s64) bh->b_blocknr;
+ offset.QuadPart <<= BLOCK_BITS;
+
+ if (zero) {
+ if (!CcPreparePinWrite(Vcb->Volume,
+ &offset,
+ bh->b_size,
+ FALSE,
+ PIN_WAIT | PIN_EXCLUSIVE,
+ &bh->b_bcb,
+ (PVOID *)&bh->b_data)) {
+ Ext2Sleep(100);
+ goto again;
+ }
+ } else {
+ if (!CcPinRead( Vcb->Volume,
+ &offset,
+ bh->b_size,
+ PIN_WAIT,
+ &bh->b_bcb,
+ (PVOID *)&bh->b_data)) {
+ Ext2Sleep(100);
+ goto again;
+ }
+ set_buffer_uptodate(bh);
+ }
+
+ if (!bh->b_data) {
+ free_buffer_head(bh);
+ bh = NULL;
+ goto errorout;
+ }
+
+ get_bh(bh);
+ CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3));
+
+ DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p ptr=%p.\n",
+ Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_data));
+
+ spin_lock_irqsave(&bdev->bd_bh_lock, irql);
+
+ /* do search again here */
+ tbh = buffer_head_search(bdev, block);
+ if (tbh) {
+ get_bh(tbh);
+ spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ free_buffer_head(bh);
+ bh = tbh;
+ goto errorout;
+ } else {
+ buffer_head_insert(bdev, bh);
+ }
+
+ spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+
+ /* we get it */
+errorout:
+
+ return bh;
+}
+
+int submit_bh(int rw, struct buffer_head *bh)
+{
+ struct block_device *bdev = bh->b_bdev;
+ PEXT2_VCB Vcb = bdev->bd_priv;
+ PVOID Buffer;
+ LARGE_INTEGER Offset;
+
+ ASSERT(Vcb->Identifier.Type == EXT2VCB);
+ ASSERT(bh->b_data && bh->b_bcb);
+
+ if (rw == WRITE) {
+
+ if (IsVcbReadOnly(Vcb)) {
+ goto errorout;
+ }
+
+ SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
+ Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS;
+
+ CcSetDirtyPinnedData(bh->b_bcb, NULL);
+ Ext2AddBlockExtent( Vcb, NULL,
+ (ULONG)bh->b_blocknr,
+ (ULONG)bh->b_blocknr,
+ (bh->b_size >> BLOCK_BITS));
+ } else {
+ DbgBreak();
+ }
+
+errorout:
+
+ unlock_buffer(bh);
+ put_bh(bh);
+ return 0;
+}
+
+struct buffer_head *
+__getblk(
+ struct block_device * bdev,
+ sector_t block,
+ unsigned long size
+)
+{
+ return get_block_bh(bdev, block, size, 0);
+}
+
void __brelse(struct buffer_head *bh)
{
struct block_device *bdev = bh->b_bdev;
atomic_dec(&g_jbh.bh_count);
}
+
void __bforget(struct buffer_head *bh)
{
clear_buffer_dirty(bh);
NTSTATUS
Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext)
{
- PDEVICE_OBJECT DeviceObject;
- PFILE_OBJECT FileObject;
- PEXT2_FCB Fcb;
- PIRP Irp;
+ PDEVICE_OBJECT DeviceObject = NULL;
+ PFILE_OBJECT FileObject = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PIRP Irp = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
BOOLEAN CompleteContext = TRUE;
{
PEXT2_FCB Fcb;
- ASSERT(!IsMcbSymLink(Mcb));
-
Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
&(Ext2Global->Ext2FcbLookasideList));
#endif
if ((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
- (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
+ (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
ASSERT (Fcb->Mcb->Fcb == Fcb);
if (IsMcbSpecialFile(Fcb->Mcb) || IsFileDeleted(Fcb->Mcb)) {
}
PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB SymLink)
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
{
PEXT2_CCB Ccb;
Ccb->Identifier.Type = EXT2CCB;
Ccb->Identifier.Size = sizeof(EXT2_CCB);
+ Ccb->Flags = Flags;
Ccb->SymLink = SymLink;
if (SymLink) {
NTSTATUS Status = STATUS_SUCCESS;
PEXT2_EXTENT Extent = NULL;
- PEXT2_EXTENT List = *Chain;
+ PEXT2_EXTENT List = *Chain = NULL;
if (!IsZoneInited(Mcb)) {
Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
&Mapped
);
if (!NT_SUCCESS(Status)) {
- goto errorout;
+ break;
}
/* skip wrong blocks, in case wrongly treating symlink
Length = Size;
}
+ if (0 == Length) {
+ DbgBreak();
+ break;
+ }
+
Start += Mapped;
Offset = (ULONGLONG)Start << BLOCK_BITS;
Extent = Ext2AllocateExtent();
if (!Extent) {
Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
+ DbgBreak();
+ break;
}
Extent->Lba = Lba;
*Chain = List = Extent;
}
}
+ } else {
+ if (bAlloc) {
+ DbgBreak();
+ }
}
Total += Length;
Size -= Length;
}
-errorout:
-
return Status;
}
BOOLEAN
Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
{
- PEXT2_GROUP_DESC gd;
- ULONG Group, dwBlk, Length;
-
- RTL_BITMAP BlockBitmap;
- PVOID BitmapCache;
- PBCB BitmapBcb;
-
- LARGE_INTEGER Offset;
-
- BOOLEAN bModified = FALSE;
-
-
- Group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
+ ULONG group, dwBlk, Length;
+ RTL_BITMAP bitmap;
+ BOOLEAN bModified = FALSE;
+
+ group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
- gd = ext4_get_group_desc(&Vcb->sb, Group, NULL);
+ gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
if (!gd) {
return FALSE;
}
- Offset.QuadPart = ext4_block_bitmap(&Vcb->sb, gd);
- Offset.QuadPart <<= BLOCK_BITS;
+ bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
- if (Group == Vcb->sbi.s_groups_count - 1) {
+ if (group == Vcb->sbi.s_groups_count - 1) {
Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
/* s_blocks_count is integer multiple of s_blocks_per_group */
Length = BLOCKS_PER_GROUP;
}
- if (dwBlk >= Length)
- return FALSE;
-
- if (!CcPinRead( Vcb->Volume,
- &Offset,
- Vcb->BlockSize,
- PIN_WAIT,
- &BitmapBcb,
- &BitmapCache ) ) {
-
- DEBUG(DL_ERR, ( "Ext2CheckSetBlock: Failed to PinLock block %xh ...\n",
- ext4_block_bitmap(&Vcb->sb, gd)));
+ if (dwBlk >= Length) {
+ fini_bh(&gb);
+ fini_bh(&bh);
return FALSE;
}
- RtlInitializeBitMap( &BlockBitmap,
- BitmapCache,
- Length );
+ RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
- if (RtlCheckBit(&BlockBitmap, dwBlk) == 0) {
+ if (RtlCheckBit(&bitmap, dwBlk) == 0) {
DbgBreak();
- RtlSetBits(&BlockBitmap, dwBlk, 1);
+ RtlSetBits(&bitmap, dwBlk, 1);
bModified = TRUE;
+ mark_buffer_dirty(bh);
}
- if (bModified) {
- CcSetDirtyPinnedData(BitmapBcb, NULL );
- Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE);
- }
-
- {
- CcUnpinData(BitmapBcb);
- BitmapBcb = NULL;
- BitmapCache = NULL;
-
- RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
- }
+ fini_bh(&gb);
+ fini_bh(&bh);
return (!bModified);
}
for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
PEXT2_GROUP_DESC gd;
+ struct buffer_head *bh = NULL;
- gd = ext4_get_group_desc(&Vcb->sb, i, NULL);
+ gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
if (!gd)
continue;
Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
for (j = 0; j < InodeBlocks; j++ )
Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
+
+ fini_bh(&bh);
}
return TRUE;
}
if (ExtentsInitialized) {
- Ext2PutGroup(Vcb);
+ Ext2DropGroup(Vcb);
if (Vcb->bd.bd_bh_cache)
kmem_cache_destroy(Vcb->bd.bd_bh_cache);
FsRtlUninitializeLargeMcb(&(Vcb->Extents));
Ext2CleanupAllMcbs(Vcb);
- Ext2PutGroup(Vcb);
+ Ext2DropGroup(Vcb);
if (Vcb->bd.bd_bh_cache)
kmem_cache_destroy(Vcb->bd.bd_bh_cache);
if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
ASSERT(Vcb->Vpb2 != NULL);
- Ext2FreePool(Vcb->Vpb2, TAG_VPB);
+ DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
+ ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
Vcb->Vpb2 = NULL;
}
case STATUS_HOST_UNREACHABLE:
return (-EHOSTUNREACH);
+ case STATUS_CANT_WAIT:
case STATUS_PENDING:
- case STATUS_DEVICE_NOT_READY:
return (-EAGAIN);
+ case STATUS_DEVICE_NOT_READY:
+ return (-EIO);
+
case STATUS_CANCELLED:
case STATUS_REQUEST_ABORTED:
return (-EINTR);
return STATUS_HOST_UNREACHABLE;
case -EAGAIN:
- return STATUS_DEVICE_NOT_READY;
+ return STATUS_CANT_WAIT;
case -EINTR:
return STATUS_CANCELLED;
{
return (name->Length == 4 && name->Buffer[0] == L'.' &&
name->Buffer[1] == L'.');
-}
\ No newline at end of file
+}
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
- PEXT2_VCB Vcb;
+ PEXT2_VCB Vcb = NULL;
PDEVICE_OBJECT DeviceObject;
_SEH2_TRY {
return Status;
}
-#endif //(_WIN32_WINNT >= 0x0500)
\ No newline at end of file
+#endif //(_WIN32_WINNT >= 0x0500)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PEXT2_CCB Ccb;
- PEXT2_FCBVCB FcbOrVcb;
- PFILE_OBJECT FileObject;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_FCBVCB FcbOrVcb = NULL;
+ PFILE_OBJECT FileObject = NULL;
- PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT DeviceObject = NULL;
PIRP Irp = NULL;
- PIO_STACK_LOCATION IoStackLocation;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
ULONG Length;
LARGE_INTEGER ByteOffset;
/* handle fast symlinks */
- if (S_ISLNK(Mcb->Inode.i_mode) &&
- Mcb->Inode.i_size < EXT2_LINKLEN_IN_INODE) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && 0 == Mcb->Inode.i_blocks) {
PUCHAR Data = (PUCHAR) (&Mcb->Inode.i_block[0]);
-
if (!Buffer) {
Status = STATUS_INSUFFICIENT_RESOURCES;
_SEH2_LEAVE;
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PEXT2_FCB Fcb;
- PEXT2_CCB Ccb;
- PFILE_OBJECT FileObject;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PFILE_OBJECT FileObject = NULL;
- PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT DeviceObject = NULL;
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
ULONG Length;
ULONG ReturnedLength = 0;
DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
&Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
+ if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ _SEH2_LEAVE;
+ }
+
if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ||
IsFileDeleted(Fcb->Mcb)) {
Status = STATUS_FILE_DELETED;
_SEH2_LEAVE;
}
- if (Nocache &&
- (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
- Length & (SECTOR_SIZE - 1))) {
+ if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
+ ByteOffset.HighPart == -1) {
+ ByteOffset = FileObject->CurrentByteOffset;
+ }
+
+ if (Nocache && (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
+ Length & (SECTOR_SIZE - 1))) {
Status = STATUS_INVALID_PARAMETER;
DbgBreak();
_SEH2_LEAVE;
_SEH2_LEAVE;
}
- if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
- CcFlushCache( FileObject->SectionObjectPointer,
- &ByteOffset,
- Length,
- &Irp->IoStatus );
-
- if (!NT_SUCCESS(Irp->IoStatus.Status)) {
- _SEH2_LEAVE;
- }
- }
-
ReturnedLength = Length;
if (PagingIo) {
}
MainResourceAcquired = TRUE;
+ if (FileObject->SectionObjectPointer->DataSectionObject != NULL) {
+ CcFlushCache( FileObject->SectionObjectPointer,
+ &ByteOffset,
+ Length,
+ &Irp->IoStatus );
+ if (!NT_SUCCESS(Irp->IoStatus.Status))
+ _SEH2_LEAVE;
+ }
+
} else {
if (!ExAcquireResourceSharedLite(
Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
{
PDEVICE_OBJECT DeviceObject;
+ PEXT2_VCB Vcb = NULL;
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
+ PVOID Buffer;
+ ULONG Length;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
FS_INFORMATION_CLASS FsInformationClass;
- ULONG Length;
- PVOID Buffer;
BOOLEAN VcbResourceAcquired = FALSE;
_SEH2_TRY {
FsAttrInfo =
(PFILE_FS_ATTRIBUTE_INFORMATION) Buffer;
- FsAttrInfo->FileSystemAttributes =
- FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+ FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS |
+ FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
+ FILE_SUPPORTS_REPARSE_POINTS;
if (IsVcbReadOnly(Vcb)) {
FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
}
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
+ PEXT2_VCB Vcb = NULL;
PIRP Irp;
PIO_STACK_LOCATION IoStackLocation;
FS_INFORMATION_CLASS FsInformationClass;
} _SEH2_END;
return Status;
-}
\ No newline at end of file
+}
PBCB Bcb;
PVOID Ptr;
ULONG Size;
-#ifndef __REACTOS__
BOOLEAN rc = TRUE;
-#endif
+
ASSERT (End && Start && End->QuadPart > Start->QuadPart);
Fcb = (PEXT2_FCB) FileObject->FsContext;
}
/* clear data in range [Start, End) */
- return CcZeroData(FileObject, Start, End, Ext2CanIWait());
+ _SEH2_TRY {
+ rc = CcZeroData(FileObject, Start, End, Ext2CanIWait());
+ } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ } _SEH2_END;
+
+ return rc;
}
VOID
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb;
- PEXT2_CCB Ccb;
- PEXT2_FCBVCB FcbOrVcb;
- PFILE_OBJECT FileObject;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_FCBVCB FcbOrVcb = NULL;
+ PFILE_OBJECT FileObject = NULL;
- PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT DeviceObject = NULL;
PIRP Irp = NULL;
- PIO_STACK_LOCATION IoStackLocation;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
ULONG Length;
LARGE_INTEGER ByteOffset;
IN ULONG Size,
IN BOOLEAN bDirectIo,
OUT PULONG BytesWritten
-)
+ )
{
PEXT2_EXTENT Chain = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
Mcb,
Offset,
Size,
- IsMcbDirectory(Mcb) ? FALSE : TRUE,
+ S_ISDIR(Mcb->Inode.i_mode) ? FALSE : TRUE,
&Chain
);
return Status;
}
+
NTSTATUS
Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
{
- PEXT2_VCB Vcb;
- PEXT2_FCB Fcb;
- PEXT2_CCB Ccb;
- PFILE_OBJECT FileObject;
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PFILE_OBJECT FileObject = NULL;
- PDEVICE_OBJECT DeviceObject;
+ PDEVICE_OBJECT DeviceObject = NULL;
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
- PUCHAR Buffer;
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IoStackLocation = NULL;
+ PUCHAR Buffer = NULL;
LARGE_INTEGER ByteOffset;
ULONG ReturnedLength = 0;
DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
&Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
- if (IsSpecialFile(Fcb)) {
+ if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
_SEH2_LEAVE;
}
- if (Nocache && ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
- (Length & (SECTOR_SIZE - 1))) ) {
+ if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
+ ByteOffset.HighPart == -1) {
+ ByteOffset = FileObject->CurrentByteOffset;
+ } else if (IsWritingToEof(ByteOffset)) {
+ ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
+ }
+
+ if (Nocache && !PagingIo &&
+ ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
+ (Length & (SECTOR_SIZE - 1))) ) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
}
}
- if (IsWritingToEof(ByteOffset)) {
- ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
- }
-
if (IsDirectory(Fcb) && !PagingIo) {
Status = STATUS_INVALID_DEVICE_REQUEST;
_SEH2_LEAVE;
}
PagingIoResourceAcquired = TRUE;
- if ( (ByteOffset.QuadPart + Length) > Fcb->Header.AllocationSize.QuadPart) {
+ if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {
- if ( ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
+ if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
- Status = STATUS_END_OF_FILE;
+ Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
_SEH2_LEAVE;
} else {
- Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
+ ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
+ if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart)
+ Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
}
+
+ } else {
+
+ ReturnedLength = Length;
}
} else {
&Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
Fcb->Header.AllocationSize.QuadPart));
}
- }
- ReturnedLength = Length;
+ ReturnedLength = Length;
+ }
if (!Nocache) {
} else {
if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
- if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
- if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
-
- /* let this irp wait, since it has to be synchronous */
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
- rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
- &Fcb->Header.ValidDataLength,
- &ByteOffset);
- if (!rc) {
- Status = STATUS_PENDING;
- DbgBreak();
- _SEH2_LEAVE;
- }
+ if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
+
+ /* let this irp wait, since it has to be synchronous */
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+ rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
+ &Fcb->Header.ValidDataLength,
+ &ByteOffset);
+ if (!rc) {
+ Status = STATUS_PENDING;
+ DbgBreak();
+ _SEH2_LEAVE;
}
}
}
Irp = IrpContext->Irp;
- if (NT_SUCCESS(Status) && !PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
+ if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {
FileSizesChanged = TRUE;
if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
+ if (!PagingIo)
+ Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length;
Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
} else {
if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
}
- if (CcIsFileCached(FileObject)) {
+ if (!PagingIo && CcIsFileCached(FileObject)) {
CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
}
/*
* in case we got excpetions, we need revert MajorFunction
- * back to IRP_MJ_WRITE. The reason we do this, if to tell
+ * back to IRP_MJ_WRITE. The reason we do this, is to tell
* Ext2ExpandFile to allocate unwritten extent or don't add
* new blocks for indirect files.
*/