https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a1d7e9936d8e58bc07ff2cc73a937ce845c7d542
commit a1d7e9936d8e58bc07ff2cc73a937ce845c7d542 Author: Pierre Schweitzer <pie...@reactos.org> AuthorDate: Sun Nov 12 10:47:29 2017 +0100 [EXT2] Upgrade to 0.69 CORE-13980 --- drivers/filesystems/ext2/CMakeLists.txt | 2 + drivers/filesystems/ext2/inc/ext2fs.h | 63 +- drivers/filesystems/ext2/inc/linux/errno.h | 2 + drivers/filesystems/ext2/inc/linux/ext4_xattr.h | 205 ++++ drivers/filesystems/ext2/inc/linux/fs.h | 19 - drivers/filesystems/ext2/inc/linux/module.h | 2 + drivers/filesystems/ext2/src/create.c | 190 +++- drivers/filesystems/ext2/src/dirctl.c | 6 + drivers/filesystems/ext2/src/dispatch.c | 6 + drivers/filesystems/ext2/src/ea.c | 604 ++++++++++ drivers/filesystems/ext2/src/ext3/generic.c | 616 +++++++--- drivers/filesystems/ext2/src/ext3/recover.c | 7 +- drivers/filesystems/ext2/src/ext4/ext4_extents.c | 1 + drivers/filesystems/ext2/src/ext4/ext4_xattr.c | 1295 ++++++++++++++++++++++ drivers/filesystems/ext2/src/fastio.c | 5 + drivers/filesystems/ext2/src/fileinfo.c | 34 +- drivers/filesystems/ext2/src/flush.c | 94 +- drivers/filesystems/ext2/src/fsctl.c | 5 + drivers/filesystems/ext2/src/init.c | 8 + drivers/filesystems/ext2/src/linux.c | 33 +- drivers/filesystems/ext2/src/memory.c | 107 +- drivers/filesystems/ext2/src/volinfo.c | 2 +- drivers/filesystems/ext2/src/write.c | 18 +- media/doc/README.FSD | 2 +- 24 files changed, 3027 insertions(+), 299 deletions(-) diff --git a/drivers/filesystems/ext2/CMakeLists.txt b/drivers/filesystems/ext2/CMakeLists.txt index 4291b27a46..abc1c2489d 100644 --- a/drivers/filesystems/ext2/CMakeLists.txt +++ b/drivers/filesystems/ext2/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND SOURCE src/ext4/ext4_bh.c src/ext4/ext4_extents.c src/ext4/ext4_jbd2.c + src/ext4/ext4_xattr.c src/ext4/extents.c src/jbd/recovery.c src/jbd/replay.c @@ -66,6 +67,7 @@ list(APPEND SOURCE src/devctl.c src/dirctl.c src/dispatch.c + src/ea.c src/except.c src/fastio.c src/fileinfo.c diff --git a/drivers/filesystems/ext2/inc/ext2fs.h b/drivers/filesystems/ext2/inc/ext2fs.h index 7792ed18ac..525a1d1bc9 100644 --- a/drivers/filesystems/ext2/inc/ext2fs.h +++ b/drivers/filesystems/ext2/inc/ext2fs.h @@ -47,7 +47,7 @@ /* STRUCTS & CONSTS******************************************************/ -#define EXT2FSD_VERSION "0.68" +#define EXT2FSD_VERSION "0.69" /* WDK DEFINITIONS ******************************************************/ @@ -720,7 +720,7 @@ typedef struct _EXT2_VCB { // Sector size in bits ULONG SectorBits; - // Aligned size (Page or Block) + // Minimal i/o size: min(PageSize, BlockSize) ULONGLONG IoUnitSize; // Bits of aligned size @@ -783,6 +783,7 @@ typedef struct _EXT2_VCB { #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_GD_LOADED 0x00000100 /* group desc loaded */ #define VCB_BEING_DROPPED 0x00002000 #define VCB_FORCE_WRITING 0x00004000 @@ -929,6 +930,8 @@ struct _EXT2_MCB { // List Link to Vcb->McbList LIST_ENTRY Link; + + struct inode Inode; struct dentry *de; }; @@ -1006,6 +1009,9 @@ typedef struct _EXT2_CCB { /* Open handle control block */ struct file filp; + /* The EA index we are on */ + ULONG EaIndex; + } EXT2_CCB, *PEXT2_CCB; // @@ -1116,6 +1122,10 @@ typedef struct _EXT2_EXTENT { #define FSCTL_GET_RETRIEVAL_POINTER_BASE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 141, METHOD_BUFFERED, FILE_ANY_ACCESS) // RETRIEVAL_POINTER_BASE #endif +#ifndef FILE_SUPPORTS_EXTENDED_ATTRIBUTES +#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 +#endif + // // The following macro is used to determine if an FSD thread can block // for I/O or wait for a resource. It returns TRUE if the thread can @@ -1605,6 +1615,26 @@ Ext2BuildRequest ( IN PIRP Irp ); +// +// ea.c +// + +NTSTATUS +Ext2QueryEa( + IN PEXT2_IRP_CONTEXT IrpContext +); + +BOOLEAN +Ext2IsEaNameValid( + IN OEM_STRING Name +); + +NTSTATUS +Ext2SetEa( + IN PEXT2_IRP_CONTEXT IrpContext +); + + // // Except.c // @@ -1765,15 +1795,24 @@ Ext2RefreshSuper( IN PEXT2_VCB Vcb ); +BOOLEAN +Ext2LoadGroupBH(IN PEXT2_VCB Vcb); + BOOLEAN Ext2LoadGroup(IN PEXT2_VCB Vcb); +VOID +Ext2DropGroupBH(IN PEXT2_VCB Vcb); + VOID Ext2PutGroup(IN PEXT2_VCB Vcb); VOID Ext2DropBH(IN PEXT2_VCB Vcb); +NTSTATUS +Ext2FlushVcb(IN PEXT2_VCB Vcb); + BOOLEAN Ext2SaveGroup( IN PEXT2_IRP_CONTEXT IrpContext, @@ -1814,6 +1853,17 @@ Ext2SaveInode ( IN struct inode *Inode ); +BOOLEAN +Ext2LoadInodeXattr(IN PEXT2_VCB Vcb, + IN struct inode *Inode, + IN PEXT2_INODE InodeXattr); + +BOOLEAN +Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN struct inode *Inode, + IN PEXT2_INODE InodeXattr); + BOOLEAN Ext2LoadBlock ( IN PEXT2_VCB Vcb, @@ -1829,6 +1879,15 @@ Ext2SaveBlock ( IN PVOID Buf ); +BOOLEAN +Ext2LoadBuffer( + IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN LONGLONG Offset, + IN ULONG Size, + IN PVOID Buf +); + BOOLEAN Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext, diff --git a/drivers/filesystems/ext2/inc/linux/errno.h b/drivers/filesystems/ext2/inc/linux/errno.h index 5173d2a6ae..13bcbf4832 100644 --- a/drivers/filesystems/ext2/inc/linux/errno.h +++ b/drivers/filesystems/ext2/inc/linux/errno.h @@ -61,7 +61,9 @@ #define EBFONT 59 /* Bad font file format */ #define ENOSTR 60 /* Device not a stream */ +#endif #define ENODATA 61 /* No data available */ +#ifndef __REACTOS__ #define ETIME 62 /* Timer expired */ #define ENOSR 63 /* Out of streams resources */ #define ENONET 64 /* Machine is not on the network */ diff --git a/drivers/filesystems/ext2/inc/linux/ext4_xattr.h b/drivers/filesystems/ext2/inc/linux/ext4_xattr.h new file mode 100644 index 0000000000..d57949cbea --- /dev/null +++ b/drivers/filesystems/ext2/inc/linux/ext4_xattr.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015 Grzegorz Kostka (kostka.grzeg...@gmail.com) + * Copyright (c) 2015 Kaho Ng (ngkaho1...@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup lwext4 + * @{ + */ +/** + * @file ext4_xattr.h + * @brief Extended Attribute manipulation. + */ + +#ifndef EXT4_XATTR_H_ +#define EXT4_XATTR_H_ + +#include <ext2fs.h> +#include <linux/rbtree.h> + +/* Extended Attribute(EA) */ + +/* Magic value in attribute blocks */ +#define EXT4_XATTR_MAGIC 0xEA020000 + +/* Maximum number of references to one attribute block */ +#define EXT4_XATTR_REFCOUNT_MAX 1024 + +/* Name indexes */ +#define EXT4_XATTR_INDEX_USER 1 +#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3 +#define EXT4_XATTR_INDEX_TRUSTED 4 +#define EXT4_XATTR_INDEX_LUSTRE 5 +#define EXT4_XATTR_INDEX_SECURITY 6 +#define EXT4_XATTR_INDEX_SYSTEM 7 +#define EXT4_XATTR_INDEX_RICHACL 8 +#define EXT4_XATTR_INDEX_ENCRYPTION 9 + +#pragma pack(push, 1) + +struct ext4_xattr_header { + __le32 h_magic; /* magic number for identification */ + __le32 h_refcount; /* reference count */ + __le32 h_blocks; /* number of disk blocks used */ + __le32 h_hash; /* hash value of all attributes */ + __le32 h_checksum; /* crc32c(uuid+id+xattrblock) */ + /* id = inum if refcount=1, blknum otherwise */ + __le32 h_reserved[3]; /* zero right now */ +}; + +struct ext4_xattr_ibody_header { + __le32 h_magic; /* magic number for identification */ +}; + +struct ext4_xattr_entry { + __u8 e_name_len; /* length of name */ + __u8 e_name_index; /* attribute name index */ + __le16 e_value_offs; /* offset in disk block of value */ + __le32 e_value_block; /* disk block attribute is stored on (n/i) */ + __le32 e_value_size; /* size of attribute value */ + __le32 e_hash; /* hash value of name and value */ +}; + +#pragma pack(pop) + +#define EXT4_GOOD_OLD_INODE_SIZE EXT2_GOOD_OLD_INODE_SIZE + +#define EXT4_XATTR_PAD_BITS 2 +#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS) +#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1) +#define EXT4_XATTR_LEN(name_len) \ + (((name_len) + EXT4_XATTR_ROUND + \ + sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND) +#define EXT4_XATTR_NEXT(entry) \ + ((struct ext4_xattr_entry *)( \ + (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len))) +#define EXT4_XATTR_SIZE(size) \ + (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND) +#define EXT4_XATTR_NAME(entry) \ + ((char *)((entry) + 1)) + +#define EXT4_XATTR_IHDR(raw_inode) \ + ((struct ext4_xattr_ibody_header *) \ + ((char *)raw_inode + \ + EXT4_GOOD_OLD_INODE_SIZE + \ + (raw_inode)->i_extra_isize)) +#define EXT4_XATTR_IFIRST(hdr) \ + ((struct ext4_xattr_entry *)((hdr)+1)) + +#define EXT4_XATTR_BHDR(block) \ + ((struct ext4_xattr_header *)((block)->b_data)) +#define EXT4_XATTR_ENTRY(ptr) \ + ((struct ext4_xattr_entry *)(ptr)) +#define EXT4_XATTR_BFIRST(block) \ + EXT4_XATTR_ENTRY(EXT4_XATTR_BHDR(block)+1) +#define EXT4_XATTR_IS_LAST_ENTRY(entry) \ + (*(__le32 *)(entry) == 0) + +#define EXT4_ZERO_XATTR_VALUE ((void *)-1) + + +struct ext4_xattr_item { + /* This attribute should be stored in inode body */ + BOOL in_inode; + BOOL is_data; + + __u8 name_index; + char *name; + size_t name_len; + void *data; + size_t data_size; + + struct rb_node node; + struct list_head list_node; +}; + +struct ext4_xattr_ref { + PEXT2_IRP_CONTEXT IrpContext; + BOOL block_loaded; + struct buffer_head *block_bh; + PEXT2_MCB inode_ref; + + PEXT2_INODE OnDiskInode; + BOOL IsOnDiskInodeDirty; + + BOOL dirty; + size_t ea_size; + size_t inode_size_rem; + size_t block_size_rem; + PEXT2_VCB fs; + + void *iter_arg; + struct ext4_xattr_item *iter_from; + + struct rb_root root; + struct list_head ordered_list; +}; + +#define EXT4_XATTR_ITERATE_CONT 0 +#define EXT4_XATTR_ITERATE_STOP 1 +#define EXT4_XATTR_ITERATE_PAUSE 2 + +int ext4_fs_get_xattr_ref(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB fs, PEXT2_MCB inode_ref, + struct ext4_xattr_ref *ref); + +int ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref); + +int ext4_fs_set_xattr(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size, BOOL replace); + +int ext4_fs_set_xattr_ordered(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size); + +int ext4_fs_remove_xattr(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len); + +int ext4_fs_get_xattr(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, void *buf, + size_t buf_size, size_t *data_size); + +void ext4_fs_xattr_iterate(struct ext4_xattr_ref *ref, + int(*iter)(struct ext4_xattr_ref *ref, + struct ext4_xattr_item *item, + BOOL is_last)); + +void ext4_fs_xattr_iterate_reset(struct ext4_xattr_ref *ref); + +const char *ext4_extract_xattr_name(const char *full_name, size_t full_name_len, + __u8 *name_index, size_t *name_len, + BOOL *found); + +const char *ext4_get_xattr_name_prefix(__u8 name_index, + size_t *ret_prefix_len); + +void ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref); + +#endif +/** + * @} + */ diff --git a/drivers/filesystems/ext2/inc/linux/fs.h b/drivers/filesystems/ext2/inc/linux/fs.h index 52a8b3dc90..5da58f99a8 100644 --- a/drivers/filesystems/ext2/inc/linux/fs.h +++ b/drivers/filesystems/ext2/inc/linux/fs.h @@ -75,25 +75,6 @@ struct super_block { 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 */ diff --git a/drivers/filesystems/ext2/inc/linux/module.h b/drivers/filesystems/ext2/inc/linux/module.h index 141e8fd694..65607b6e2f 100644 --- a/drivers/filesystems/ext2/inc/linux/module.h +++ b/drivers/filesystems/ext2/inc/linux/module.h @@ -864,6 +864,8 @@ struct buffer_head *extents_bread(struct super_block *sb, sector_t block); struct buffer_head *extents_bwrite(struct super_block *sb, sector_t block); void extents_mark_buffer_dirty(struct buffer_head *bh); void extents_brelse(struct buffer_head *bh); +void extents_bforget(struct buffer_head *bh); +void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh); extern int buffer_heads_over_limit; diff --git a/drivers/filesystems/ext2/src/create.c b/drivers/filesystems/ext2/src/create.c index 251343fe1f..01c5cfb0d5 100644 --- a/drivers/filesystems/ext2/src/create.c +++ b/drivers/filesystems/ext2/src/create.c @@ -10,6 +10,7 @@ /* INCLUDES *****************************************************************/ #include "ext2fs.h" +#include <linux/ext4_xattr.h> /* GLOBALS *****************************************************************/ @@ -350,8 +351,9 @@ Ext2LookupFile ( } /* is a directory expected ? */ - if (FullName->Buffer[End - 1] == L'\\') { + while (FullName->Buffer[End - 1] == L'\\') { bDirectory = TRUE; + End -= 1; } /* loop with every sub name */ @@ -674,6 +676,155 @@ errorout: return Ext2WinntError(rc); } +// +// Any call to this routine must have Fcb's MainResource and FcbLock acquired. +// + +NTSTATUS +Ext2OverwriteEa( + PEXT2_IRP_CONTEXT IrpContext, + PEXT2_VCB Vcb, + PEXT2_FCB Fcb, + PIO_STATUS_BLOCK Iosb +) +{ + PEXT2_MCB Mcb = NULL; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + + struct ext4_xattr_ref xattr_ref; + BOOLEAN XattrRefAcquired = FALSE; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + PFILE_FULL_EA_INFORMATION FullEa; + PCHAR EaBuffer; + ULONG EaBufferLength; + + _SEH2_TRY { + + Irp = IrpContext->Irp; + IrpSp = IoGetCurrentIrpStackLocation(Irp); + Mcb = Fcb->Mcb; + + EaBuffer = Irp->AssociatedIrp.SystemBuffer; + EaBufferLength = IrpSp->Parameters.Create.EaLength; + + if (!Mcb) + _SEH2_LEAVE; + + // + // Return peacefully if there is no EaBuffer provided. + // + if (!EaBuffer) { + Status = STATUS_SUCCESS; + _SEH2_LEAVE; + } + + // + // If the caller specifies an EaBuffer, but has no knowledge about Ea, + // we reject the request. + // + if (EaBuffer != NULL && + FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_EA_KNOWLEDGE)) { + Status = STATUS_ACCESS_DENIED; + _SEH2_LEAVE; + } + + // + // Check Ea Buffer validity. + // + Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)EaBuffer, + EaBufferLength, (PULONG)&Iosb->Information); + if (!NT_SUCCESS(Status)) + _SEH2_LEAVE; + + Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref)); + if (!NT_SUCCESS(Status)) { + DbgPrint("ext4_fs_get_xattr_ref() failed!\n"); + _SEH2_LEAVE; + } + + XattrRefAcquired = TRUE; + + // + // Remove all existing EA entries. + // + ext4_xattr_purge_items(&xattr_ref); + xattr_ref.dirty = TRUE; + Status = STATUS_SUCCESS; + + // Iterate the whole EA buffer to do inspection + for (FullEa = (PFILE_FULL_EA_INFORMATION)EaBuffer; + FullEa < (PFILE_FULL_EA_INFORMATION)&EaBuffer[EaBufferLength]; + FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ? + &EaBuffer[EaBufferLength] : + (PCHAR)FullEa + FullEa->NextEntryOffset)) { + + OEM_STRING EaName; + + EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; + EaName.Buffer = &FullEa->EaName[0]; + + // Check if EA's name is valid + if (!Ext2IsEaNameValid(EaName)) { + Status = STATUS_INVALID_EA_NAME; + _SEH2_LEAVE; + } + } + + // Now add EA entries to the inode + for (FullEa = (PFILE_FULL_EA_INFORMATION)EaBuffer; + FullEa < (PFILE_FULL_EA_INFORMATION)&EaBuffer[EaBufferLength]; + FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ? + &EaBuffer[EaBufferLength] : + (PCHAR)FullEa + FullEa->NextEntryOffset)) { + + int ret; + OEM_STRING EaName; + + EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; + EaName.Buffer = &FullEa->EaName[0]; + + Status = Ext2WinntError(ret = + ext4_fs_set_xattr(&xattr_ref, + EXT4_XATTR_INDEX_USER, + EaName.Buffer, + EaName.Length, + &FullEa->EaName[0] + FullEa->EaNameLength + 1, + FullEa->EaValueLength, + TRUE)); + if (!NT_SUCCESS(Status) && ret != -ENODATA) + _SEH2_LEAVE; + + if (ret == -ENODATA) { + Status = Ext2WinntError( + ext4_fs_set_xattr(&xattr_ref, + EXT4_XATTR_INDEX_USER, + EaName.Buffer, + EaName.Length, + &FullEa->EaName[0] + FullEa->EaNameLength + 1, + FullEa->EaValueLength, + FALSE)); + if (!NT_SUCCESS(Status)) + _SEH2_LEAVE; + + } + } + } + _SEH2_FINALLY { + + if (XattrRefAcquired) { + if (!NT_SUCCESS(Status)) { + xattr_ref.dirty = FALSE; + ext4_fs_put_xattr_ref(&xattr_ref); + } else { + Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref)); + } + } + } _SEH2_END; + return Status; +} + NTSTATUS Ext2CreateFile( PEXT2_IRP_CONTEXT IrpContext, @@ -876,13 +1027,17 @@ McbExisting: PathName = FileName; Mcb = NULL; - if (PathName.Buffer[PathName.Length/2 - 1] == L'\\') { - if (DirectoryFile) { - PathName.Length -=2; - PathName.Buffer[PathName.Length/2] = 0; - } else { - DirectoryFile = TRUE; - } + /* here we've found the target file, but it's not matched. */ + if (STATUS_OBJECT_NAME_NOT_FOUND != Status && + STATUS_NO_SUCH_FILE != Status) { + _SEH2_LEAVE; + } + + while (PathName.Length > 0 && + PathName.Buffer[PathName.Length/2 - 1] == L'\\') { + DirectoryFile = TRUE; + PathName.Length -= 2; + PathName.Buffer[PathName.Length / 2] = 0; } if (!ParentMcb) { @@ -922,7 +1077,8 @@ Dissecting: /* quit name resolving loop */ if (!NT_SUCCESS(Status)) { - if (Status == STATUS_NO_SUCH_FILE && RemainName.Length != 0) { + if (Status == STATUS_NO_SUCH_FILE || + Status == STATUS_OBJECT_NAME_NOT_FOUND) { Status = STATUS_OBJECT_PATH_NOT_FOUND; } _SEH2_LEAVE; @@ -1296,6 +1452,12 @@ Openit: // This file is just created. // + Status = Ext2OverwriteEa(IrpContext, Vcb, Fcb, &Irp->IoStatus); + if (!NT_SUCCESS(Status)) { + Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); + _SEH2_LEAVE; + } + if (DirectoryFile) { Status = Ext2AddDotEntries(IrpContext, &ParentMcb->Inode, &Mcb->Inode); @@ -1758,7 +1920,9 @@ Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb) SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED); Vcb->LockFile = IrpSp->FileObject; } else { - if (FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA) ) { + + if (FlagOn(IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) && + FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA) ) { if (!IsVcbReadOnly(Vcb)) { Ext2FlushFiles(IrpContext, Vcb, FALSE); Ext2FlushVolume(IrpContext, Vcb, FALSE); @@ -1888,6 +2052,7 @@ Ext2CreateInode( ULONG iNo; struct inode Inode = { 0 }; struct dentry *Dentry = NULL; + struct ext3_super_block *es = EXT3_SB(&Vcb->sb)->s_es; LARGE_INTEGER SysTime; @@ -1927,6 +2092,8 @@ Ext2CreateInode( } else { DbgBreak(); } + if (le16_to_cpu(es->s_want_extra_isize)) + Inode.i_extra_isize = le16_to_cpu(es->s_want_extra_isize); /* Force using extent */ if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) { @@ -2022,5 +2189,6 @@ Ext2SupersedeOrOverWriteFile( Fcb->Inode->i_mtime = Ext2LinuxTime(CurrentTime); Ext2SaveInode(IrpContext, Vcb, Fcb->Inode); - return STATUS_SUCCESS; + // See if we need to overwrite EA of the file + return Ext2OverwriteEa(IrpContext, Vcb, Fcb, &IrpContext->Irp->IoStatus); } diff --git a/drivers/filesystems/ext2/src/dirctl.c b/drivers/filesystems/ext2/src/dirctl.c index b76385d073..668b9c23f6 100644 --- a/drivers/filesystems/ext2/src/dirctl.c +++ b/drivers/filesystems/ext2/src/dirctl.c @@ -1085,6 +1085,12 @@ Ext2NotifyChangeDirectory ( ASSERT((Ccb->Identifier.Type == EXT2CCB) && (Ccb->Identifier.Size == sizeof(EXT2_CCB))); + /* do nothing if target fie was deleted */ + if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { + Status = STATUS_FILE_DELETED; + _SEH2_LEAVE; + } + if (!IsDirectory(Fcb)) { DbgBreak(); Status = STATUS_INVALID_PARAMETER; diff --git a/drivers/filesystems/ext2/src/dispatch.c b/drivers/filesystems/ext2/src/dispatch.c index 35e4fe2427..3e13af649a 100644 --- a/drivers/filesystems/ext2/src/dispatch.c +++ b/drivers/filesystems/ext2/src/dispatch.c @@ -267,6 +267,12 @@ Ext2DispatchRequest (IN PEXT2_IRP_CONTEXT IrpContext) case IRP_MJ_SHUTDOWN: return Ext2ShutDown(IrpContext); + case IRP_MJ_QUERY_EA: + return Ext2QueryEa(IrpContext); + + case IRP_MJ_SET_EA: + return Ext2SetEa(IrpContext); + #if (_WIN32_WINNT >= 0x0500) case IRP_MJ_PNP: return Ext2Pnp(IrpContext); diff --git a/drivers/filesystems/ext2/src/ea.c b/drivers/filesystems/ext2/src/ea.c new file mode 100644 index 0000000000..2f7d4ce2bf --- /dev/null +++ b/drivers/filesystems/ext2/src/ea.c @@ -0,0 +1,604 @@ +/* +* COPYRIGHT: See COPYRIGHT.TXT +* PROJECT: Ext2 File System Driver for Windows >= NT +* FILE: ea.c +* PROGRAMMER: Matt Wu <mat...@163.com> Kaho Ng <ngkaho1...@gmail.com> +* HOMEPAGE: http://www.ext2fsd.com +* UPDATE HISTORY: +*/ + +/* INCLUDES *****************************************************************/ + +#include "ext2fs.h" +#include <linux/ext4_xattr.h> + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, Ext2QueryEa) +#pragma alloc_text(PAGE, Ext2SetEa) +#pragma alloc_text(PAGE, Ext2IsEaNameValid) +#endif + +// Ea iterator +struct EaIterator { + // Return only an entry + BOOLEAN ReturnSingleEntry; + + // Is the buffer overflowing? + BOOL OverFlow; + + // FILE_FULL_EA_INFORMATION output buffer + PFILE_FULL_EA_INFORMATION FullEa; + PFILE_FULL_EA_INFORMATION LastFullEa; + + // UserBuffer's size + ULONG UserBufferLength; + + // Remaining UserBuffer's size + ULONG RemainingUserBufferLength; + + // Start scanning from this EA + ULONG EaIndex; + + // Next EA index returned by Ext2IterateAllEa + ULONG EaIndexCounter; +}; + +static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last) +{ + struct EaIterator *pEaIterator = xattr_ref->iter_arg; + ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size; + ASSERT(pEaIterator); + if (!is_last && !pEaIterator->ReturnSingleEntry) + EaEntrySize = ALIGN_UP(EaEntrySize, ULONG); + + // Start iteration from index specified + if (pEaIterator->EaIndexCounter < pEaIterator->EaIndex) { + pEaIterator->EaIndexCounter++; + return EXT4_XATTR_ITERATE_CONT; + } + pEaIterator->EaIndexCounter++; + + if (EaEntrySize > pEaIterator->RemainingUserBufferLength) { + pEaIterator->OverFlow = TRUE; + return EXT4_XATTR_ITERATE_STOP; + } + pEaIterator->FullEa->NextEntryOffset = 0; + pEaIterator->FullEa->Flags = 0; + pEaIterator->FullEa->EaNameLength = (UCHAR)item->name_len; + pEaIterator->FullEa->EaValueLength = (USHORT)item->data_size; + RtlCopyMemory(&pEaIterator->FullEa->EaName[0], + item->name, + item->name_len); + RtlCopyMemory(&pEaIterator->FullEa->EaName[0] + item->name_len + 1, + item->data, + item->data_size); + + // Link FullEa and LastFullEa together + if (pEaIterator->LastFullEa) { + pEaIterator->LastFullEa->NextEntryOffset = (ULONG) + ((PCHAR)pEaIterator->FullEa - (PCHAR)pEaIterator->LastFullEa); + } + + pEaIterator->LastFullEa = pEaIterator->FullEa; + pEaIterator->FullEa = (PFILE_FULL_EA_INFORMATION) + ((PCHAR)pEaIterator->FullEa + EaEntrySize); + pEaIterator->RemainingUserBufferLength -= EaEntrySize; + + if (pEaIterator->ReturnSingleEntry) + return EXT4_XATTR_ITERATE_STOP; + + return EXT4_XATTR_ITERATE_CONT; +} + +NTSTATUS +Ext2QueryEa ( + 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; + + PUCHAR UserEaList; + ULONG UserEaListLength; + ULONG UserEaIndex; + + BOOLEAN RestartScan; + BOOLEAN ReturnSingleEntry; + BOOLEAN IndexSpecified; + + BOOLEAN MainResourceAcquired = FALSE; + BOOLEAN XattrRefAcquired = FALSE; + + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + struct ext4_xattr_ref xattr_ref; + PCHAR UserBuffer; + + ULONG UserBufferLength = 0; + ULONG RemainingUserBufferLength = 0; + + PFILE_FULL_EA_INFORMATION FullEa, LastFullEa = 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; + Fcb = IrpContext->Fcb; + Mcb = Fcb->Mcb; + Irp = IrpContext->Irp; + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + Irp->IoStatus.Information = 0; + + // + // Receive input parameter from caller + // + UserBuffer = Ext2GetUserBuffer(Irp); + if (!UserBuffer) { + Status = STATUS_INSUFFICIENT_RESOURCES; + _SEH2_LEAVE; + } + UserBufferLength = IrpSp->Parameters.QueryEa.Length; + RemainingUserBufferLength = UserBufferLength; + UserEaList = IrpSp->Parameters.QueryEa.EaList; + UserEaListLength = IrpSp->Parameters.QueryEa.EaListLength; + UserEaIndex = IrpSp->Parameters.QueryEa.EaIndex; + RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN); + ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); + IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED); + + if (!Mcb) + _SEH2_LEAVE; + + // + // We do not allow multiple instance gaining EA access to the same file + // + if (!ExAcquireResourceExclusiveLite( + &Fcb->MainResource, + IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + Status = STATUS_PENDING; + _SEH2_LEAVE; + } + MainResourceAcquired = TRUE; + + Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref)); + if (!NT_SUCCESS(Status)) { + DbgPrint("ext4_fs_get_xattr_ref() failed!\n"); + _SEH2_LEAVE; + } + + FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer; + + XattrRefAcquired = TRUE; + + if (RemainingUserBufferLength) + RtlZeroMemory(FullEa, RemainingUserBufferLength); + + if (UserEaList != NULL) { + int i = 0; + PFILE_GET_EA_INFORMATION GetEa; + for (GetEa = (PFILE_GET_EA_INFORMATION)&UserEaList[0]; + GetEa < (PFILE_GET_EA_INFORMATION)((PUCHAR)UserEaList + + UserEaListLength); + GetEa = (GetEa->NextEntryOffset == 0 + ? (PFILE_GET_EA_INFORMATION)MAXUINT_PTR + : (PFILE_GET_EA_INFORMATION)((PUCHAR)GetEa + + GetEa->NextEntryOffset))) { + + size_t ItemSize; + OEM_STRING Str; + ULONG EaEntrySize; + BOOL is_last = !GetEa->NextEntryOffset; + + Str.MaximumLength = Str.Length = GetEa->EaNameLength; + Str.Buffer = &GetEa->EaName[0]; + + // + // At the moment we only need to know whether the item exists + // and its size. + // + Status = Ext2WinntError(ext4_fs_get_xattr(&xattr_ref, + EXT4_XATTR_INDEX_USER, + Str.Buffer, + Str.Length, + NULL, + 0, + &ItemSize)); + if (!NT_SUCCESS(Status)) + continue; + + // + // We were not able to locate the name therefore we must + // dummy up a entry for the query. The needed Ea size is + // the size of the name + 4 (next entry offset) + 1 (flags) + // + 1 (name length) + 2 (value length) + the name length + + // 1 (null byte) + Data Size. + // + EaEntrySize = 4 + 1 + 1 + 2 + GetEa->EaNameLength + 1 + ItemSize; + if (!is_last) + EaEntrySize = ALIGN_UP(EaEntrySize, ULONG); + + if (EaEntrySize > RemainingUserBufferLength) { + + Status = i ? STATUS_BUFFER_OVERFLOW : STATUS_BUFFER_TOO_SMALL; + _SEH2_LEAVE; + } + FullEa->NextEntryOffset = 0; + FullEa->Flags = 0; + FullEa->EaNameLength = GetEa->EaNameLength; + FullEa->EaValueLength = (USHORT)ItemSize; + RtlCopyMemory(&FullEa->EaName[0], + &GetEa->EaName[0], + GetEa->EaNameLength); + + // + // This query must succeed, or is guarenteed to succeed + // since we are only looking up + // an EA entry in a in-memory tree structure. + // Otherwise that means someone might be operating on + // the xattr_ref without acquiring Inode lock. + // + ASSERT(NT_SUCCESS(Ext2WinntError( + ext4_fs_get_xattr(&xattr_ref, + EXT4_XATTR_INDEX_USER, + Str.Buffer, + Str.Length, + &FullEa->EaName[0] + FullEa->EaNameLength + 1, + ItemSize, + &ItemSize + )))); + FullEa->EaValueLength = (USHORT)ItemSize; + + // Link FullEa and LastFullEa together + if (LastFullEa) + LastFullEa->NextEntryOffset = (ULONG)((PCHAR)FullEa - + (PCHAR)LastFullEa); + + LastFullEa = FullEa; + FullEa = (PFILE_FULL_EA_INFORMATION) + ((PCHAR)FullEa + EaEntrySize); + RemainingUserBufferLength -= EaEntrySize; + i++; + } + } else if (IndexSpecified) { + struct EaIterator EaIterator; + // + // The user supplied an index into the Ea list. + // + if (RemainingUserBufferLength) + RtlZeroMemory(FullEa, RemainingUserBufferLength); + + EaIterator.OverFlow = FALSE; + EaIterator.RemainingUserBufferLength = UserBufferLength; + // In this case, return only an entry. + EaIterator.ReturnSingleEntry = TRUE; + EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer; + EaIterator.LastFullEa = NULL; + EaIterator.UserBufferLength = UserBufferLength; + EaIterator.EaIndex = UserEaIndex; + EaIterator.EaIndexCounter = 1; + + xattr_ref.iter_arg = &EaIterator; + ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa); + + RemainingUserBufferLength = EaIterator.RemainingUserBufferLength; + + Status = STATUS_SUCCESS; + + // It seems that the item isn't found + if (RemainingUserBufferLength == UserBufferLength) + Status = STATUS_OBJECTID_NOT_FOUND; + + if (EaIterator.OverFlow) { + if (RemainingUserBufferLength == UserBufferLength) + Status = STATUS_BUFFER_TOO_SMALL; + else + Status = STATUS_BUFFER_OVERFLOW; + } + + } else { + struct EaIterator EaIterator; + // + // Else perform a simple scan, taking into account the restart + // flag and the position of the next Ea stored in the Ccb. + // + if (RestartScan) + Ccb->EaIndex = 1; + + if (RemainingUserBufferLength) + RtlZeroMemory(FullEa, RemainingUserBufferLength); + + EaIterator.OverFlow = FALSE; + EaIterator.RemainingUserBufferLength = UserBufferLength; + EaIterator.ReturnSingleEntry = ReturnSingleEntry; + EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer; + EaIterator.LastFullEa = NULL; + EaIterator.UserBufferLength = UserBufferLength; + EaIterator.EaIndex = Ccb->EaIndex; + EaIterator.EaIndexCounter = 1; + + xattr_ref.iter_arg = &EaIterator; + ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa); + + RemainingUserBufferLength = EaIterator.RemainingUserBufferLength; + + if (Ccb->EaIndex < EaIterator.EaIndexCounter) + Ccb->EaIndex = EaIterator.EaIndexCounter; + + Status = STATUS_SUCCESS; + + if (EaIterator.OverFlow) { + if (RemainingUserBufferLength == UserBufferLength) + Status = STATUS_BUFFER_TOO_SMALL; + else + Status = STATUS_BUFFER_OVERFLOW; + } + + } + } + _SEH2_FINALLY { + + if (XattrRefAcquired) { + if (!NT_SUCCESS(Status)) { + xattr_ref.dirty = FALSE; + ext4_fs_put_xattr_ref(&xattr_ref); + } + else + Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref)); + } + + if (MainResourceAcquired) { + ExReleaseResourceLite(&Fcb->MainResource); + } + + if (NT_SUCCESS(Status)) { + Ext2NotifyReportChange( + IrpContext, + Vcb, + Mcb, + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED); + Irp->IoStatus.Information = UserBufferLength - RemainingUserBufferLength; + } + + if (!_SEH2_AbnormalTermination()) { + if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { + Status = Ext2QueueRequest(IrpContext); + } + else { + Ext2CompleteIrpContext(IrpContext, Status); + } + } + } _SEH2_END; + + return Status; +} + +BOOLEAN +Ext2IsEaNameValid( + IN OEM_STRING Name +) +{ + ULONG Index; + UCHAR Char; + + // + // Empty names are not valid + // + + if (Name.Length == 0) + return FALSE; + + // + // Do not allow EA name longer than 255 bytes + // + if (Name.Length > 255) + return FALSE; + + for (Index = 0; Index < (ULONG)Name.Length; Index += 1) { + + Char = Name.Buffer[Index]; + + // + // Skip over and Dbcs chacters + // + if (FsRtlIsLeadDbcsCharacter(Char)) { + + ASSERT(Index != (ULONG)(Name.Length - 1)); + Index += 1; + continue; + } + + // + // Make sure this character is legal, and if a wild card, that + // wild cards are permissible. + // + if (!FsRtlIsAnsiCharacterLegalFat(Char, FALSE)) + return FALSE; + + } + + return TRUE; +} + +NTSTATUS +Ext2SetEa ( + 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; + + BOOLEAN MainResourceAcquired = FALSE; + BOOLEAN FcbLockAcquired = FALSE; + BOOLEAN XattrRefAcquired = FALSE; + + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + struct ext4_xattr_ref xattr_ref; + PCHAR UserBuffer; + ULONG UserBufferLength; + + PFILE_FULL_EA_INFORMATION FullEa; + + _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); + + Irp->IoStatus.Information = 0; + + // + // Receive input parameter from caller + // + UserBufferLength = IrpSp->Parameters.SetEa.Length; + UserBuffer = Irp->UserBuffer; + + // Check if the EA buffer provided is valid + Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)UserBuffer, + UserBufferLength, + (PULONG)&Irp->IoStatus.Information); + if (!NT_SUCCESS(Status)) + _SEH2_LEAVE; + + ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); + FcbLockAcquired = TRUE; + + if (!Mcb) + _SEH2_LEAVE; + + // + // We do not allow multiple instance gaining EA access to the same file + // + if (!ExAcquireResourceExclusiveLite( + &Fcb->MainResource, + IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + Status = STATUS_PENDING; + _SEH2_LEAVE; + } + MainResourceAcquired = TRUE; + + Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref)); + if (!NT_SUCCESS(Status)) { + DbgPrint("ext4_fs_get_xattr_ref() failed!\n"); + _SEH2_LEAVE; + } + + XattrRefAcquired = TRUE; + + // + // Remove all existing EA entries. + // + ext4_xattr_purge_items(&xattr_ref); + xattr_ref.dirty = TRUE; + Status = STATUS_SUCCESS; + + // Iterate the whole EA buffer to do inspection + for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer; + FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength]; + FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ? + &UserBuffer[UserBufferLength] : + (PCHAR)FullEa + FullEa->NextEntryOffset)) { + + OEM_STRING EaName; + + EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; + EaName.Buffer = &FullEa->EaName[0]; + + // Check if EA's name is valid + if (!Ext2IsEaNameValid(EaName)) { + Irp->IoStatus.Information = (PCHAR)FullEa - UserBuffer; + Status = STATUS_INVALID_EA_NAME; + _SEH2_LEAVE; + } + } + + // Now add EA entries to the inode + for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer; + FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength]; + FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ? + &UserBuffer[UserBufferLength] : + (PCHAR)FullEa + FullEa->NextEntryOffset)) { + + int ret; + OEM_STRING EaName; + + EaName.MaximumLength = EaName.Length = FullEa->EaNameLength; + EaName.Buffer = &FullEa->EaName[0]; + + Status = Ext2WinntError(ret = + ext4_fs_set_xattr_ordered(&xattr_ref, + EXT4_XATTR_INDEX_USER, + EaName.Buffer, + EaName.Length, + &FullEa->EaName[0] + FullEa->EaNameLength + 1, + FullEa->EaValueLength)); + if (!NT_SUCCESS(Status)) + _SEH2_LEAVE; + + } + } _SEH2_FINALLY { + + if (XattrRefAcquired) { + if (!NT_SUCCESS(Status)) { + xattr_ref.dirty = FALSE; + ext4_fs_put_xattr_ref(&xattr_ref); + } else + Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref)); + } + + if (FcbLockAcquired) { + ExReleaseResourceLite(&Vcb->FcbLock); + FcbLockAcquired = FALSE; + } + + if (MainResourceAcquired) { + ExReleaseResourceLite(&Fcb->MainResource); + } + + if (NT_SUCCESS(Status)) { + Ext2NotifyReportChange( + IrpContext, + Vcb, + Mcb, + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED); + } + + if (!_SEH2_AbnormalTermination()) { + if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { + Status = Ext2QueueRequest(IrpContext); + } + else { + Ext2CompleteIrpContext(IrpContext, Status); + } + } + } _SEH2_END; + return Status; +} diff --git a/drivers/filesystems/ext2/src/ext3/generic.c b/drivers/filesystems/ext2/src/ext3/generic.c index 4e38352494..377f11f3a8 100644 --- a/drivers/filesystems/ext2/src/ext3/generic.c +++ b/drivers/filesystems/ext2/src/ext3/generic.c @@ -10,7 +10,7 @@ /* INCLUDES *****************************************************************/ #include "ext2fs.h" -#include <linux/ext4.h> +#include "linux/ext4.h" /* GLOBALS ***************************************************************/ @@ -125,23 +125,77 @@ Ext2RefreshSuper ( } VOID -Ext2PutGroup(IN PEXT2_VCB Vcb) +Ext2DropGroupBH(IN PEXT2_VCB Vcb) { struct ext3_sb_info *sbi = &Vcb->sbi; unsigned long i; - if (NULL == Vcb->sbi.s_gd) { return; } for (i = 0; i < Vcb->sbi.s_gdb_count; i++) { - if (Vcb->sbi.s_gd[i].bh) + if (Vcb->sbi.s_gd[i].bh) { fini_bh(&sbi->s_gd[i].bh); + Vcb->sbi.s_gd[i].bh = NULL; + } } +} + +VOID +Ext2PutGroup(IN PEXT2_VCB Vcb) +{ + struct ext3_sb_info *sbi = &Vcb->sbi; + unsigned long i; + + + if (NULL == Vcb->sbi.s_gd) { + return; + } + + Ext2DropGroupBH(Vcb); kfree(Vcb->sbi.s_gd); Vcb->sbi.s_gd = NULL; + + ClearFlag(Vcb->Flags, VCB_GD_LOADED); +} + + +BOOLEAN +Ext2LoadGroupBH(IN PEXT2_VCB Vcb) +{ + struct super_block *sb = &Vcb->sb; + struct ext3_sb_info *sbi = &Vcb->sbi; + unsigned long i; + BOOLEAN rc = FALSE; + + _SEH2_TRY { + + ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); + ASSERT (NULL != sbi->s_gd); + + for (i = 0; i < sbi->s_gdb_count; i++) { + ASSERT (sbi->s_gd[i].block); + if (sbi->s_gd[i].bh) + continue; + sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block); + if (!sbi->s_gd[i].bh) { + DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i)); + DbgBreak(); + _SEH2_LEAVE; + } + sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data; + } + + rc = TRUE; + + } _SEH2_FINALLY { + + ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); + } _SEH2_END; + + return rc; } @@ -177,20 +231,20 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb) DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i)); _SEH2_LEAVE; } - sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block); - if (!sbi->s_gd[i].bh) { - DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i)); - _SEH2_LEAVE; - } - sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data; + } + + if (!Ext2LoadGroupBH(Vcb)) { + DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n")); + _SEH2_LEAVE; } if (!ext4_check_descriptors(sb)) { DbgBreak(); - DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n")); + DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n")); _SEH2_LEAVE; } + SetFlag(Vcb->Flags, VCB_GD_LOADED); rc = TRUE; } _SEH2_FINALLY { @@ -204,13 +258,10 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb) return rc; } - VOID Ext2DropBH(IN PEXT2_VCB Vcb) { struct ext3_sb_info *sbi = &Vcb->sbi; - LARGE_INTEGER timeout; - unsigned long i; /* do nothing if Vcb is not initialized yet */ if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) @@ -222,15 +273,18 @@ Ext2DropBH(IN PEXT2_VCB Vcb) ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE); SetFlag(Vcb->Flags, VCB_BEING_DROPPED); - Ext2PutGroup(Vcb); + Ext2DropGroupBH(Vcb); while (!IsListEmpty(&Vcb->bd.bd_bh_free)) { struct buffer_head *bh; PLIST_ENTRY l; l = RemoveHeadList(&Vcb->bd.bd_bh_free); bh = CONTAINING_RECORD(l, struct buffer_head, b_link); - ASSERT(0 == atomic_read(&bh->b_count)); - free_buffer_head(bh); + InitializeListHead(&bh->b_link); + if (0 == atomic_read(&bh->b_count)) { + buffer_head_remove(&Vcb->bd, bh); + free_buffer_head(bh); + } } } _SEH2_FINALLY { @@ -240,6 +294,90 @@ Ext2DropBH(IN PEXT2_VCB Vcb) ClearFlag(Vcb->Flags, VCB_BEING_DROPPED); } + +VOID +Ext2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e) +{ + ULONG len; + + if (e.QuadPart <= s.QuadPart) + return; + + /* loop per 2G */ + while (s.QuadPart < e.QuadPart) { + if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) { + len = 1024 * 1024 * 1024; + } else { + len = (ULONG) (e.QuadPart - s.QuadPart); + } + CcFlushCache(&Vcb->SectionObject, &s, len, NULL); + s.QuadPart += len; + } +} + +NTSTATUS +Ext2FlushVcb(IN PEXT2_VCB Vcb) +{ + LARGE_INTEGER s = {0}, o; + struct ext3_sb_info *sbi = &Vcb->sbi; + struct rb_node *node; + struct buffer_head *bh; + + if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) { + CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); + goto errorout; + } + + ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource)); + + _SEH2_TRY { + + /* acqurie gd block */ + ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); + + /* acquire bd lock to avoid bh creation */ + ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE); + + /* drop unused bh */ + Ext2DropBH(Vcb); + + /* flush volume with all outstanding bh skipped */ + + node = rb_first(&Vcb->bd.bd_bh_root); + while (node) { + + bh = container_of(node, struct buffer_head, b_rb_node); + node = rb_next(node); + + o.QuadPart = bh->b_blocknr << BLOCK_BITS; + ASSERT(o.QuadPart >= s.QuadPart); + + if (o.QuadPart == s.QuadPart) { + s.QuadPart = s.QuadPart + bh->b_size; + continue; + } + + if (o.QuadPart > s.QuadPart) { + Ext2FlushRange(Vcb, s, o); + s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size; + continue; + } + } + + o = Vcb->PartitionInformation.PartitionLength; + Ext2FlushRange(Vcb, s, o); + + } _SEH2_FINALLY { + + ExReleaseResourceLite(&Vcb->bd.bd_bh_lock); + ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); + } _SEH2_END; + +errorout: + return STATUS_SUCCESS; +} + + BOOLEAN Ext2SaveGroup( IN PEXT2_IRP_CONTEXT IrpContext, @@ -326,8 +464,12 @@ void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src) 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 (EXT3_HAS_RO_COMPAT_FEATURE(dst->i_sb, + EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) + dst->i_extra_isize = src->i_extra_isize; + else + dst->i_extra_isize = 0; } void Ext2EncodeInode(struct ext3_inode *dst, struct inode *src) @@ -352,6 +494,9 @@ void Ext2EncodeInode(struct ext3_inode *dst, struct inode *src) ASSERT(src->i_sb); ext3_inode_blocks_set(dst, src); memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15); + if (EXT3_HAS_RO_COMPAT_FEATURE(src->i_sb, + EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) + dst->i_extra_isize = src->i_extra_isize; } @@ -359,27 +504,15 @@ BOOLEAN Ext2LoadInode (IN PEXT2_VCB Vcb, IN struct inode *Inode) { - struct ext3_inode ext3i; - - IO_STATUS_BLOCK IoStatus; - LONGLONG Offset; + struct ext3_inode ext3i = {0}; + LONGLONG offset; - if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) { - DEBUG(DL_ERR, ( "Ext2LoadInode: error get inode(%xh)'s addr.\n", Inode->i_ino)); + if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset)) { + DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino)); return FALSE; } - if (!CcCopyRead( - Vcb->Volume, - (PLARGE_INTEGER)&Offset, - sizeof(struct ext3_inode), - PIN_WAIT, - (PVOID)&ext3i, - &IoStatus )) { - return FALSE; - } - - if (!NT_SUCCESS(IoStatus.Status)) { + if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) { return FALSE; } @@ -400,7 +533,7 @@ Ext2ClearInode ( rc = Ext2GetInodeLba(Vcb, Inode, &Offset); if (!rc) { - DEBUG(DL_ERR, ( "Ext2SaveInode: error get inode(%xh)'s addr.\n", Inode)); + DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode)); goto errorout; } @@ -416,9 +549,8 @@ Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN struct inode *Inode) { - struct ext3_inode ext3i; + struct ext3_inode ext3i = {0}; - IO_STATUS_BLOCK IoStatus; LONGLONG Offset = 0; ULONG InodeSize = sizeof(ext3i); BOOLEAN rc = 0; @@ -427,24 +559,14 @@ Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext, Inode->i_ino, Inode->i_mode, Inode->i_size)); rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset); if (!rc) { - DEBUG(DL_ERR, ( "Ext2SaveInode: error get inode(%xh)'s addr.\n", Inode->i_ino)); + DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino)); goto errorout; } - if (!CcCopyRead( - Vcb->Volume, - (PLARGE_INTEGER)&Offset, - sizeof(struct ext3_inode), - PIN_WAIT, - (PVOID)&ext3i, - &IoStatus )) { - rc = FALSE; - goto errorout; - } - - if (!NT_SUCCESS(IoStatus.Status)) { - rc = FALSE; - goto errorout; + rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext3i); + if (!rc) { + DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino)); + goto errorout;; } Ext2EncodeInode(&ext3i, Inode); @@ -460,31 +582,111 @@ errorout: return rc; } +BOOLEAN +Ext2LoadInodeXattr(IN PEXT2_VCB Vcb, + IN struct inode *Inode, + IN PEXT2_INODE InodeXattr) +{ + IO_STATUS_BLOCK IoStatus; + LONGLONG Offset; + + if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) { + DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino)); + return FALSE; + } + + if (!CcCopyRead( + Vcb->Volume, + (PLARGE_INTEGER)&Offset, + Vcb->InodeSize, + PIN_WAIT, + (PVOID)InodeXattr, + &IoStatus)) { + return FALSE; + } + + if (!NT_SUCCESS(IoStatus.Status)) { + return FALSE; + } + + Ext2EncodeInode(InodeXattr, Inode); + return TRUE; +} + +BOOLEAN +Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN struct inode *Inode, + IN PEXT2_INODE InodeXattr) +{ + IO_STATUS_BLOCK IoStatus; + LONGLONG Offset = 0; + ULONG InodeSize = Vcb->InodeSize; + BOOLEAN rc = 0; + + /* There is no way to put EA information in such a small inode */ + if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE) + return FALSE; + + DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n", + Inode->i_ino, Inode->i_mode, Inode->i_size)); + rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset); + if (!rc) { + DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino)); + goto errorout; + } + + rc = Ext2SaveBuffer(IrpContext, + Vcb, + Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize, + InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize, + (char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize); + + if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { + Ext2StartFloppyFlushDpc(Vcb, NULL, NULL); + } + +errorout: + return rc; +} + BOOLEAN Ext2LoadBlock (IN PEXT2_VCB Vcb, IN ULONG Index, IN PVOID Buffer ) { - IO_STATUS_BLOCK IoStatus; - LONGLONG Offset; + struct buffer_head *bh = NULL; + BOOLEAN rc = 0; - Offset = (LONGLONG) Index; - Offset = Offset * Vcb->BlockSize; + _SEH2_TRY { - if (!CcCopyRead( - Vcb->Volume, - (PLARGE_INTEGER)&Offset, - Vcb->BlockSize, - PIN_WAIT, - Buffer, - &IoStatus )); + bh = sb_getblk(&Vcb->sb, (sector_t)Index); - if (!NT_SUCCESS(IoStatus.Status)) { - return FALSE; - } + if (!bh) { + DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index)); + DbgBreak(); + _SEH2_LEAVE; + } - return TRUE; + if (!buffer_uptodate(bh)) { + int err = bh_submit_read(bh); + if (err < 0) { + DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err)); + _SEH2_LEAVE; + } + } + + RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE); + rc = TRUE; + + } _SEH2_FINALLY { + + if (bh) + fini_bh(&bh); + } _SEH2_END; + + return rc; } @@ -494,121 +696,231 @@ Ext2SaveBlock ( IN PEXT2_IRP_CONTEXT IrpContext, IN ULONG Index, IN PVOID Buf ) { - LONGLONG Offset; - BOOLEAN rc; + struct buffer_head *bh = NULL; + BOOLEAN rc = 0; - Offset = (LONGLONG) Index; - Offset = Offset * Vcb->BlockSize; + _SEH2_TRY { - rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, Vcb->BlockSize, Buf); + bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index); - if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) { - Ext2StartFloppyFlushDpc(Vcb, NULL, NULL); - } + if (!bh) { + DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index)); + DbgBreak(); + _SEH2_LEAVE; + } + + if (!buffer_uptodate(bh)) { + } + + RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE); + mark_buffer_dirty(bh); + rc = TRUE; + + } _SEH2_FINALLY { + + if (bh) + fini_bh(&bh); + } _SEH2_END; return rc; } BOOLEAN -Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext, +Ext2LoadBuffer( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, - IN LONGLONG Offset, - IN ULONG Size ) + IN LONGLONG offset, + IN ULONG size, + IN PVOID buf ) { - PBCB Bcb; - PVOID Buffer; - BOOLEAN rc; - - if ( !CcPreparePinWrite( - Vcb->Volume, - (PLARGE_INTEGER) (&Offset), - Size, - FALSE, - PIN_WAIT | PIN_EXCLUSIVE, - &Bcb, - &Buffer )) { - - DEBUG(DL_ERR, ( "Ext2SaveBuffer: failed to PinLock offset %I64xh ...\n", Offset)); - return FALSE; - } + struct buffer_head *bh = NULL; + BOOLEAN rc; _SEH2_TRY { - RtlZeroMemory(Buffer, Size); - CcSetDirtyPinnedData(Bcb, NULL ); - SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); + while (size) { - rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Size); - if (!rc) { - DbgBreak(); - Ext2Sleep(100); - rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Size); + sector_t block; + ULONG len = 0, delta = 0; + + block = (sector_t) (offset >> BLOCK_BITS); + delta = (ULONG)offset & (BLOCK_SIZE - 1); + len = BLOCK_SIZE - delta; + if (size < len) + len = size; + + bh = sb_getblk(&Vcb->sb, block); + if (!bh) { + DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block)); + DbgBreak(); + _SEH2_LEAVE; + } + + if (!buffer_uptodate(bh)) { + int err = bh_submit_read(bh); + if (err < 0) { + DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err)); + _SEH2_LEAVE; + } + } + + _SEH2_TRY { + RtlCopyMemory(buf, bh->b_data + delta, len); + } _SEH2_FINALLY { + fini_bh(&bh); + } _SEH2_END; + + buf = (PUCHAR)buf + len; + offset = offset + len; + size = size - len; } + rc = TRUE; + } _SEH2_FINALLY { - CcUnpinData(Bcb); - } _SEH2_END; + if (bh) + fini_bh(&bh); + + } _SEH2_END; return rc; } -#define SIZE_256K 0x40000 BOOLEAN -Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext, +Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, - IN LONGLONG Offset, - IN ULONG Size, - IN PVOID Buf ) + IN LONGLONG offset, + IN ULONG size + ) { - BOOLEAN rc; + struct buffer_head *bh = NULL; + BOOLEAN rc = 0; - while (Size) { + _SEH2_TRY { - PBCB Bcb; - PVOID Buffer; - ULONG Length; + while (size) { - Length = (ULONG)Offset & (SIZE_256K - 1); - Length = SIZE_256K - Length; - if (Size < Length) - Length = Size; + sector_t block; + ULONG len = 0, delta = 0; - if ( !CcPreparePinWrite( - Vcb->Volume, - (PLARGE_INTEGER) (&Offset), - Length, - FALSE, - PIN_WAIT | PIN_EXCLUSIVE, - &Bcb, - &Buffer )) { + block = (sector_t) (offset >> BLOCK_BITS); + delta = (ULONG)offset & (BLOCK_SIZE - 1); + len = BLOCK_SIZE - delta; + if (size < len) + len = size; - DEBUG(DL_ERR, ( "Ext2SaveBuffer: failed to PinLock offset %I64xh ...\n", Offset)); - return FALSE; + if (delta == 0 && len >= BLOCK_SIZE) { + bh = sb_getblk_zero(&Vcb->sb, block); + } else { + bh = sb_getblk(&Vcb->sb, block); + } + + if (!bh) { + DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block)); + DbgBreak(); + _SEH2_LEAVE; + } + + if (!buffer_uptodate(bh)) { + int err = bh_submit_read(bh); + if (err < 0) { + DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err)); + _SEH2_LEAVE; + } + } + + _SEH2_TRY { + if (delta == 0 && len >= BLOCK_SIZE) { + /* bh (cache) was already cleaned as zero */ + } else { + RtlZeroMemory(bh->b_data + delta, len); + } + mark_buffer_dirty(bh); + } _SEH2_FINALLY { + fini_bh(&bh); + } _SEH2_END; + + offset = offset + len; + size = size - len; } - _SEH2_TRY { + rc = TRUE; + + } _SEH2_FINALLY { + + if (bh) + fini_bh(&bh); + + } _SEH2_END; + + return rc; +} + + +BOOLEAN +Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN LONGLONG offset, + IN ULONG size, + IN PVOID buf ) +{ + struct buffer_head *bh = NULL; + BOOLEAN rc = 0; + + _SEH2_TRY { + + while (size) { - RtlCopyMemory(Buffer, Buf, Length); - CcSetDirtyPinnedData(Bcb, NULL ); - SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); + sector_t block; + ULONG len = 0, delta = 0; - rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length); - if (!rc) { + block = (sector_t) (offset >> BLOCK_BITS); + delta = (ULONG)offset & (BLOCK_SIZE - 1); + len = BLOCK_SIZE - delta; + if (size < len) + len = size; + + if (delta == 0 && len >= BLOCK_SIZE) { + bh = sb_getblk_zero(&Vcb->sb, block); + } else { + bh = sb_getblk(&Vcb->sb, block); + } + + if (!bh) { + DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block)); DbgBreak(); - Ext2Sleep(100); - rc = Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)Length); + _SEH2_LEAVE; } - } _SEH2_FINALLY { - CcUnpinData(Bcb); - } _SEH2_END; + if (!buffer_uptodate(bh)) { + int err = bh_submit_read(bh); + if (err < 0) { + DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err)); + _SEH2_LEAVE; + } + } - Buf = (PUCHAR)Buf + Length; - Offset = Offset + Length; - Size = Size - Length; - } + _SEH2_TRY { + RtlCopyMemory(bh->b_data + delta, buf, len); + mark_buffer_dirty(bh); + } _SEH2_FINALLY { + fini_bh(&bh); + } _SEH2_END; + + buf = (PUCHAR)buf + len; + offset = offset + len; + size = size - len; + } + + rc = TRUE; + + } _SEH2_FINALLY { + + if (bh) + fini_bh(&bh); + + } _SEH2_END; return rc; } @@ -1522,7 +1834,7 @@ Ext2AddEntry ( ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE); MainResourceAcquired = TRUE; - _SEH2_TRY { + _SEH2_TRY { Ext2ReferXcb(&Dcb->ReferenceCount); de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName); @@ -1661,7 +1973,7 @@ Ext2RemoveEntry ( ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE); MainResourceAcquired = TRUE; - _SEH2_TRY { + _SEH2_TRY { Ext2ReferXcb(&Dcb->ReferenceCount); @@ -1682,7 +1994,7 @@ Ext2RemoveEntry ( rc = ext3_delete_entry(IrpContext, dir, de, bh); if (rc) { Status = Ext2WinntError(rc); - _SEH2_LEAVE; + _SEH2_LEAVE; } /* if (!inode->i_nlink) @@ -1701,7 +2013,7 @@ Ext2RemoveEntry ( Status = STATUS_SUCCESS; - } _SEH2_FINALLY { + } _SEH2_FINALLY { Ext2DerefXcb(&Dcb->ReferenceCount); @@ -2620,11 +2932,15 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); - if (!sbi->s_gd || !sbi->s_gd[group].block || - !sbi->s_gd[group].bh) { + if (!sbi->s_gd) { if (!Ext2LoadGroup(vcb)) { _SEH2_LEAVE; } + } else if ( !sbi->s_gd[group].block || + !sbi->s_gd[group].bh) { + if (!Ext2LoadGroupBH(vcb)) { + _SEH2_LEAVE; + } } desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd + diff --git a/drivers/filesystems/ext2/src/ext3/recover.c b/drivers/filesystems/ext2/src/ext3/recover.c index 4270c15e60..3ff79bc245 100644 --- a/drivers/filesystems/ext2/src/ext3/recover.c +++ b/drivers/filesystems/ext2/src/ext3/recover.c @@ -108,9 +108,12 @@ Ext2RecoverJournal( journal_t * journal = NULL; struct ext3_super_block *esb; + ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); + /* check journal inode number */ if (!Ext2CheckJournal(Vcb, &jNo)) { - return -1; + rc = -1; + goto errorout; } /* allocate journal Mcb */ @@ -168,5 +171,7 @@ errorout: Ext2FreeMcb(Vcb, jcb); } + ExReleaseResourceLite(&Vcb->MainResource); + return rc; } diff --git a/drivers/filesystems/ext2/src/ext4/ext4_extents.c b/drivers/filesystems/ext2/src/ext4/ext4_extents.c index c23557e382..4ef64b4fd7 100644 --- a/drivers/filesystems/ext2/src/ext4/ext4_extents.c +++ b/drivers/filesystems/ext2/src/ext4/ext4_extents.c @@ -2454,6 +2454,7 @@ int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_f /* allocate new block */ goal = ext4_ext_find_goal(inode, path, iblock); + newblock = ext4_new_meta_blocks(icb, handle, inode, goal, 0, &allocated, &err); if (!newblock) diff --git a/drivers/filesystems/ext2/src/ext4/ext4_xattr.c b/drivers/filesystems/ext2/src/ext4/ext4_xattr.c new file mode 100644 index 0000000000..e1a26e94da --- /dev/null +++ b/drivers/filesystems/ext2/src/ext4/ext4_xattr.c @@ -0,0 +1,1295 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + */ + +#include <ext2fs.h> +#include <linux/module.h> +#include <linux/ext4_xattr.h> + +static ext4_fsblk_t ext4_new_meta_blocks(void *icb, struct inode *inode, + ext4_fsblk_t goal, + unsigned int flags, + unsigned long *count, int *errp) +{ + NTSTATUS status; + ULONG blockcnt = (count) ? *count : 1; + ULONG block = 0; + + status = Ext2NewBlock((PEXT2_IRP_CONTEXT)icb, + inode->i_sb->s_priv, + 0, (ULONG)goal, + &block, + &blockcnt); + if (count) + *count = blockcnt; + + if (!NT_SUCCESS(status)) { + *errp = Ext2LinuxError(status); + return 0; + } + inode->i_blocks += (blockcnt * (inode->i_sb->s_blocksize >> 9)); + return block; +} + +static void ext4_free_blocks(void *icb, struct inode *inode, + ext4_fsblk_t block, int count, int flags) +{ + Ext2FreeBlock((PEXT2_IRP_CONTEXT)icb, inode->i_sb->s_priv, (ULONG)block, count); + inode->i_blocks -= count * (inode->i_sb->s_blocksize >> 9); + return; +} + +static inline ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode) +{ + PEXT2_VCB Vcb; + Vcb = inode->i_sb->s_priv; + return (inode->i_ino - 1) / BLOCKS_PER_GROUP; +} + +#define NAME_HASH_SHIFT 5 +#define VALUE_HASH_SHIFT 16 + +static inline void ext4_xattr_compute_hash(struct ext4_xattr_header *header, + struct ext4_xattr_entry *entry) +{ + __u32 hash = 0; + char *name = EXT4_XATTR_NAME(entry); + int n; + + for (n = 0; n < entry->e_name_len; n++) { + hash = (hash << NAME_HASH_SHIFT) ^ + (hash >> (8 * sizeof(hash) - NAME_HASH_SHIFT)) ^ *name++; + } + + if (entry->e_value_block == 0 && entry->e_value_size != 0) { + __le32 *value = + (__le32 *)((char *)header + le16_to_cpu(entry->e_value_offs)); + for (n = (le32_to_cpu(entry->e_value_size) + EXT4_XATTR_ROUND) >> + EXT4_XATTR_PAD_BITS; + n; n--) { + hash = (hash << VALUE_HASH_SHIFT) ^ + (hash >> (8 * sizeof(hash) - VALUE_HASH_SHIFT)) ^ + le32_to_cpu(*value++); + } + } + entry->e_hash = cpu_to_le32(hash); +} + +#define BLOCK_HASH_SHIFT 16 + +/* + * ext4_xattr_rehash() + * + * Re-compute the extended attribute hash value after an entry has changed. + */ +static void ext4_xattr_rehash(struct ext4_xattr_header *header, + struct ext4_xattr_entry *entry) +{ + struct ext4_xattr_entry *here; + __u32 hash = 0; + + ext4_xattr_compute_hash(header, entry); + here = EXT4_XATTR_ENTRY(header + 1); + while (!EXT4_XATTR_IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + hash = (hash << BLOCK_HASH_SHIFT) ^ + (hash >> (8 * sizeof(hash) - BLOCK_HASH_SHIFT)) ^ + le32_to_cpu(here->e_hash); + here = EXT4_XATTR_NEXT(here); + } + header->h_hash = cpu_to_le32(hash); +} + +#if CONFIG_META_CSUM_ENABLE +static __u32 +ext4_xattr_block_checksum(PEXT2_MCB inode_ref, + ext4_fsblk_t blocknr, + struct ext4_xattr_header *header) +{ + __u32 checksum = 0; + __u64 le64_blocknr = blocknr; + struct ext4_sblock *sb = &inode_ref->fs->sb; + + if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) { + __u32 orig_checksum; + + /* Preparation: temporarily set bg checksum to 0 */ + orig_checksum = header->h_checksum; + header->h_checksum = 0; + /* First calculate crc32 checksum against fs uuid */ + checksum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid, + sizeof(sb->uuid)); + /* Then calculate crc32 checksum block number */ + checksum = ext4_crc32c(checksum, &le64_blocknr, + sizeof(le64_blocknr)); + /* Finally calculate crc32 checksum against + * the entire xattr block */ + checksum = ext4_crc32c(checksum, header, + ext4_sb_get_block_size(sb)); + header->h_checksum = orig_checksum; + } + return checksum; +} +#else +#define ext4_xattr_block_checksum(...) 0 +#endif + +static void +ext4_xattr_set_block_checksum(PEXT2_MCB inode_ref, + ext4_fsblk_t blocknr, + struct ext4_xattr_header *header) +{ + /* TODO: Need METADATA_CSUM supports. */ + header->h_checksum = 0; +} + +static int ext4_xattr_item_cmp(struct rb_node *_a, + struct rb_node *_b) +{ + int result; + struct ext4_xattr_item *a, *b; + a = container_of(_a, struct ext4_xattr_item, node); + a = container_of(_a, struct ext4_xattr_item, node); + b = container_of(_b, struct ext4_xattr_item, node); + + if (a->is_data && !b->is_data) + return -1; + + if (!a->is_data && b->is_data) + return 1; + + result = a->name_index - b->name_index; + if (result) + return result; + + if (a->name_len < b->name_len) + return -1; + + if (a->name_len > b->name_len) + return 1; + + return memcmp(a->name, b->name, a->name_len); +} + +// +// Red-black tree insert routine. +// + +static struct ext4_xattr_item * +ext4_xattr_item_search(struct ext4_xattr_ref *xattr_ref, + struct ext4_xattr_item *name) +{ + struct rb_node *new = xattr_ref->root.rb_node; + + while (new) { + struct ext4_xattr_item *node = + container_of(new, struct ext4_xattr_item, node); + int result = ext4_xattr_item_cmp(&name->node, new); + + if (result < 0) + new = new->rb_left; + else if (result > 0) + new = new->rb_right; + else + return node; + + } + + return NULL; +} + +static void ext4_xattr_item_insert(struct ext4_xattr_ref *xattr_ref, + struct ext4_xattr_item *item) +{ + rb_insert(&xattr_ref->root, &item->node, + ext4_xattr_item_cmp); + list_add_tail(&item->list_node, &xattr_ref->ordered_list); +} + +static void ext4_xattr_item_remove(struct ext4_xattr_ref *xattr_ref, + struct ext4_xattr_item *item) +{ + rb_erase(&item->node, &xattr_ref->root); + list_del_init(&item->list_node); +} + +static struct ext4_xattr_item * +ext4_xattr_item_alloc(__u8 name_index, const char *name, size_t name_len) +{ + struct ext4_xattr_item *item; + item = kzalloc(sizeof(struct ext4_xattr_item) + name_len, GFP_NOFS); + if (!item) + return NULL; + + item->name_index = name_index; + item->name = (char *)(item + 1); + item->name_len = name_len; + item->data = NULL; + item->data_size = 0; + INIT_LIST_HEAD(&item->list_node); + + memcpy(item->name, name, name_len); + + if (name_index == EXT4_XATTR_INDEX_SYSTEM && + name_len == 4 && + !memcmp(name, "data", 4)) + item->is_data = TRUE; + else + item->is_data = FALSE; + + return item; +} + +static int ext4_xattr_item_alloc_data(struct ext4_xattr_item *item, + const void *orig_data, size_t data_size) +{ + void *data = NULL; + ASSERT(!item->data); + data = kmalloc(data_size, GFP_NOFS); + if (!data) + return -ENOMEM; + + if (orig_data) + memcpy(data, orig_data, data_size); + + item->data = data; + item->data_size = data_size; + return 0; +} + +static void ext4_xattr_item_free_data(struct ext4_xattr_item *item) +{ + ASSERT(item->data); + kfree(item->data); + item->data = NULL; + item->data_size = 0; +} + +static int ext4_xattr_item_resize_data(struct ext4_xattr_item *item, + size_t new_data_size) +{ + if (new_data_size != item->data_size) { + void *new_data; + new_data = kmalloc(new_data_size, GFP_NOFS); + if (!new_data) + return -ENOMEM; + + memcpy(new_data, item->data, item->data_size); + kfree(item->data); + + item->data = new_data; + item->data_size = new_data_size; + } + return 0; +} + +static void ext4_xattr_item_free(struct ext4_xattr_item *item) +{ + if (item->data) + ext4_xattr_item_free_data(item); + + kfree(item); +} + +static void *ext4_xattr_entry_data(struct ext4_xattr_ref *xattr_ref, + struct ext4_xattr_entry *entry, + BOOL in_inode) +{ + char *ret; + int block_size; + if (in_inode) { + struct ext4_xattr_ibody_header *header; + struct ext4_xattr_entry *first_entry; + int inode_size = xattr_ref->fs->InodeSize; + header = EXT4_XATTR_IHDR(xattr_ref->OnDiskInode); + first_entry = EXT4_XATTR_IFIRST(header); + + ret = ((char *)first_entry + le16_to_cpu(entry->e_value_offs)); + if (ret + EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) - + (char *)xattr_ref->OnDiskInode > inode_size) + ret = NULL; + + return ret; + + } + block_size = xattr_ref->fs->BlockSize; + ret = ((char *)xattr_ref->block_bh->b_data + le16_to_cpu(entry->e_value_offs)); + if (ret + EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) - + (char *)xattr_ref->block_bh->b_data > block_size) + ret = NULL; + return ret; +} + +static int ext4_xattr_block_fetch(struct ext4_xattr_ref *xattr_ref) +{ + int ret = 0; + size_t size_rem; + void *data; + struct ext4_xattr_entry *entry = NULL; + + ASSERT(xattr_ref->block_bh->b_data); + entry = EXT4_XATTR_BFIRST(xattr_ref->block_bh); + + size_rem = xattr_ref->fs->BlockSize; + for (; size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry); + entry = EXT4_XATTR_NEXT(entry), + size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) { + struct ext4_xattr_item *item; + char *e_name = EXT4_XATTR_NAME(entry); + + data = ext4_xattr_entry_data(xattr_ref, entry, FALSE); + if (!data) { + ret = -EIO; + goto Finish; + } + + item = ext4_xattr_item_alloc(entry->e_name_index, e_name, + (size_t)entry->e_name_len); + if (!item) { + ret = -ENOMEM; + goto Finish; + } + if (ext4_xattr_item_alloc_data( + item, data, le32_to_cpu(entry->e_value_size)) != 0) { + ext4_xattr_item_free(item); + ret = -ENOMEM; + goto Finish; + } + ext4_xattr_item_insert(xattr_ref, item); + xattr_ref->block_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + xattr_ref->ea_size += EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + +Finish: + return ret; +} + +static int ext4_xattr_inode_fetch(struct ext4_xattr_ref *xattr_ref) +{ + void *data; + size_t size_rem; + int ret = 0; + struct ext4_xattr_ibody_header *header = NULL; + struct ext4_xattr_entry *entry = NULL; + int inode_size = xattr_ref->fs->InodeSize; + + header = EXT4_XATTR_IHDR(xattr_ref->OnDiskInode); + entry = EXT4_XATTR_IFIRST(header); + + size_rem = inode_size - EXT4_GOOD_OLD_INODE_SIZE - + xattr_ref->OnDiskInode->i_extra_isize; + for (; size_rem > 0 && !EXT4_XATTR_IS_LAST_ENTRY(entry); + entry = EXT4_XATTR_NEXT(entry), + size_rem -= EXT4_XATTR_LEN(entry->e_name_len)) { + struct ext4_xattr_item *item; + char *e_name = EXT4_XATTR_NAME(entry); + + data = ext4_xattr_entry_data(xattr_ref, entry, TRUE); + if (!data) { + ret = -EIO; + goto Finish; + } + + item = ext4_xattr_item_alloc(entry->e_name_index, e_name, + (size_t)entry->e_name_len); + if (!item) { + ret = -ENOMEM; + goto Finish; + } + if (ext4_xattr_item_alloc_data( + item, data, le32_to_cpu(entry->e_value_size)) != 0) { + ext4_xattr_item_free(item); + ret = -ENOMEM; + goto Finish; + } + item->in_inode = TRUE; + ext4_xattr_item_insert(xattr_ref, item); + xattr_ref->inode_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + xattr_ref->ea_size += EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + +Finish: + return ret; +} + +static __s32 ext4_xattr_inode_space(struct ext4_xattr_ref *xattr_ref) +{ + int inode_size = xattr_ref->fs->InodeSize; + int size_rem = inode_size - EXT4_GOOD_OLD_INODE_SIZE - + xattr_ref->OnDiskInode->i_extra_isize; + return size_rem; +} + +static __s32 ext4_xattr_block_space(struct ext4_xattr_ref *xattr_ref) +{ + return xattr_ref->fs->BlockSize; +} + +static int ext4_xattr_fetch(struct ext4_xattr_ref *xattr_ref) +{ + int ret = 0; + int inode_size = xattr_ref->fs->InodeSize; + if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) { + ret = ext4_xattr_inode_fetch(xattr_ref); + if (ret != 0) + return ret; + } + + if (xattr_ref->block_loaded) + ret = ext4_xattr_block_fetch(xattr_ref); + + xattr_ref->dirty = FALSE; + return ret; +} + +static struct ext4_xattr_item * +ext4_xattr_lookup_item(struct ext4_xattr_ref *xattr_ref, __u8 name_index, + const char *name, size_t name_len) +{ + struct ext4_xattr_item tmp = { + FALSE, + FALSE, + name_index, + (char *)name, /*won't touch this string*/ + name_len, + }; + if (name_index == EXT4_XATTR_INDEX_SYSTEM && + name_len == 4 && + !memcmp(name, "data", 4)) + tmp.is_data = TRUE; + + return ext4_xattr_item_search(xattr_ref, &tmp); +} + +static struct ext4_xattr_item * +ext4_xattr_insert_item(struct ext4_xattr_ref *xattr_ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size, + int *err) +{ + struct ext4_xattr_item *item; + item = ext4_xattr_item_alloc(name_index, name, name_len); + if (!item) { + if (err) + *err = -ENOMEM; + + return NULL; + } + + item->in_inode = TRUE; + if (xattr_ref->inode_size_rem < + EXT4_XATTR_SIZE(data_size) + + EXT4_XATTR_LEN(item->name_len)) { + if (xattr_ref->block_size_rem < + EXT4_XATTR_SIZE(data_size) + + EXT4_XATTR_LEN(item->name_len)) { + if (err) + *err = -ENOSPC; + + return NULL; + } + + item->in_inode = FALSE; + } + if (ext4_xattr_item_alloc_data(item, data, data_size) != 0) { + ext4_xattr_item_free(item); + if (err) + *err = -ENOMEM; + + return NULL; + } + ext4_xattr_item_insert(xattr_ref, item); + xattr_ref->ea_size += + EXT4_XATTR_SIZE(item->data_size) + EXT4_XATTR_LEN(item->name_len); + if (item->in_inode) { + xattr_ref->inode_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } else { + xattr_ref->block_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + xattr_ref->dirty = TRUE; + if (err) + *err = 0; + + return item; +} + +static struct ext4_xattr_item * +ext4_xattr_insert_item_ordered(struct ext4_xattr_ref *xattr_ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size, + int *err) +{ + struct ext4_xattr_item *item, *last_item = NULL; + item = ext4_xattr_item_alloc(name_index, name, name_len); + if (!item) { + if (err) + *err = -ENOMEM; + + return NULL; + } + + if (!list_empty(&xattr_ref->ordered_list)) + last_item = list_entry(xattr_ref->ordered_list.prev, + struct ext4_xattr_item, + list_node); + + item->in_inode = TRUE; + if ((xattr_ref->inode_size_rem < + EXT4_XATTR_SIZE(data_size) + + EXT4_XATTR_LEN(item->name_len)) + || + (last_item && !last_item->in_inode)) { + if (xattr_ref->block_size_rem < + EXT4_XATTR_SIZE(data_size) + + EXT4_XATTR_LEN(item->name_len)) { + if (err) + *err = -ENOSPC; + + return NULL; + } + + item->in_inode = FALSE; + } + if (ext4_xattr_item_alloc_data(item, data, data_size) != 0) { + ext4_xattr_item_free(item); + if (err) + *err = -ENOMEM; + + return NULL; + } + ext4_xattr_item_insert(xattr_ref, item); + xattr_ref->ea_size += + EXT4_XATTR_SIZE(item->data_size) + EXT4_XATTR_LEN(item->name_len); + if (item->in_inode) { + xattr_ref->inode_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + else { + xattr_ref->block_size_rem -= + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + xattr_ref->dirty = TRUE; + if (err) + *err = 0; + + return item; +} + +static int ext4_xattr_remove_item(struct ext4_xattr_ref *xattr_ref, + __u8 name_index, const char *name, + size_t name_len) +{ + int ret = -ENOENT; + struct ext4_xattr_item *item = + ext4_xattr_lookup_item(xattr_ref, name_index, name, name_len); + if (item) { + if (item == xattr_ref->iter_from) { + struct rb_node *next_node; + next_node = rb_next(&item->node); + if (next_node) + xattr_ref->iter_from = + container_of(next_node, + struct ext4_xattr_item, + node); + else + xattr_ref->iter_from = NULL; + } + + xattr_ref->ea_size -= EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + + if (item->in_inode) { + xattr_ref->inode_size_rem += + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } else { + xattr_ref->block_size_rem += + EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + } + + ext4_xattr_item_remove(xattr_ref, item); + ext4_xattr_item_free(item); + xattr_ref->dirty = TRUE; + ret = 0; + } + return ret; +} + +static int ext4_xattr_resize_item(struct ext4_xattr_ref *xattr_ref, + struct ext4_xattr_item *item, + size_t new_data_size) +{ + int ret = 0; + BOOL to_inode = FALSE, to_block = FALSE; + size_t old_data_size = item->data_size; + size_t orig_room_size = item->in_inode ? + xattr_ref->inode_size_rem : + xattr_ref->block_size_rem; + + /* + * Check if we can hold this entry in both in-inode and + * on-block form + * + * More complicated case: we do not allow entries stucking in + * the middle between in-inode space and on-block space, so + * the entry has to stay in either inode space or block space. + */ + if (item->in_inode) { + if (xattr_ref->inode_size_rem + + EXT4_XATTR_SIZE(old_data_size) < + EXT4_XATTR_SIZE(new_data_size)) { + if (xattr_ref->block_size_rem < + EXT4_XATTR_SIZE(new_data_size) + + EXT4_XATTR_LEN(item->name_len)) + return -ENOSPC; + + to_block = TRUE; + } + } else { + if (xattr_ref->block_size_rem + + EXT4_XATTR_SIZE(old_data_size) < + EXT4_XATTR_SIZE(new_data_size)) { + if (xattr_ref->inode_size_rem < + EXT4_XATTR_SIZE(new_data_size) + + EXT4_XATTR_LEN(item->name_len)) + return -ENOSPC; + + to_inode = TRUE; + } + } + ret = ext4_xattr_item_resize_data(item, new_data_size); + if (ret) + return ret; + + xattr_ref->ea_size = + xattr_ref->ea_size - + EXT4_XATTR_SIZE(old_data_size) + + EXT4_XATTR_SIZE(new_data_size); + + /* + * This entry may originally lie in inode space or block space, + * and it is going to be transferred to another place. + */ + if (to_block) { + xattr_ref->inode_size_rem += + EXT4_XATTR_SIZE(old_data_size) + + EXT4_XATTR_LEN(item->name_len); + xattr_ref->block_size_rem -= + EXT4_XATTR_SIZE(new_data_size) + + EXT4_XATTR_LEN(item->name_len); + item->in_inode = FALSE; + } else if (to_inode) { + xattr_ref->block_size_rem += + EXT4_XATTR_SIZE(old_data_size) + + EXT4_XATTR_LEN(item->name_len); + xattr_ref->inode_size_rem -= + EXT4_XATTR_SIZE(new_data_size) + + EXT4_XATTR_LEN(item->name_len); + item->in_inode = TRUE; + } else { + /* + * No need to transfer as there is enough space for the entry + * to stay in inode space or block space it used to be. + */ + orig_room_size += + EXT4_XATTR_SIZE(old_data_size); + orig_room_size -= + EXT4_XATTR_SIZE(new_data_size); + if (item->in_inode) + xattr_ref->inode_size_rem = orig_room_size; + else + xattr_ref->block_size_rem = orig_room_size; + + } + xattr_ref->dirty = TRUE; + return ret; +} + +void ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref) +{ + struct rb_node *first_node; + struct ext4_xattr_item *item = NULL; + first_node = rb_first(&xattr_ref->root); + if (first_node) + item = container_of(first_node, struct ext4_xattr_item, + node); + + while (item) { + struct rb_node *next_node; + struct ext4_xattr_item *next_item = NULL; + next_node = rb_next(&item->node); + if (next_node) + next_item = container_of(next_node, struct ext4_xattr_item, + node); + else + next_item = NULL; + + ext4_xattr_item_remove(xattr_ref, item); + ext4_xattr_item_free(item); + + item = next_item; + } + xattr_ref->ea_size = 0; + if (ext4_xattr_inode_space(xattr_ref) < + sizeof(struct ext4_xattr_ibody_header)) + xattr_ref->inode_size_rem = 0; + else + xattr_ref->inode_size_rem = + ext4_xattr_inode_space(xattr_ref) - + sizeof(struct ext4_xattr_ibody_header); + + xattr_ref->block_size_rem = + ext4_xattr_block_space(xattr_ref) - + sizeof(struct ext4_xattr_header); +} + +static int ext4_xattr_try_alloc_block(struct ext4_xattr_ref *xattr_ref) +{ + int ret = 0; + + ext4_fsblk_t xattr_block = 0; + xattr_block = xattr_ref->inode_ref->Inode.i_file_acl; + if (!xattr_block) { + ext4_fsblk_t goal = + ext4_inode_to_goal_block(&xattr_ref->inode_ref->Inode); + + xattr_block = ext4_new_meta_blocks(xattr_ref->IrpContext, + &xattr_ref->inode_ref->Inode, + goal, 0, NULL, + &ret); + if (ret != 0) + goto Finish; + + xattr_ref->block_bh = extents_bwrite(&xattr_ref->fs->sb, xattr_block); + if (!xattr_ref->block_bh) { + ext4_free_blocks(xattr_ref->IrpContext, &xattr_ref->inode_ref->Inode, + xattr_block, 1, 0); + ret = -ENOMEM; + goto Finish; + } + + xattr_ref->inode_ref->Inode.i_file_acl = xattr_block; + xattr_ref->IsOnDiskInodeDirty = TRUE; + xattr_ref->block_loaded = TRUE; + } + +Finish: + return ret; +} + +static void ext4_xattr_try_free_block(struct ext4_xattr_ref *xattr_ref) +{ + ext4_fsblk_t xattr_block; + xattr_block = xattr_ref->inode_ref->Inode.i_file_acl; + xattr_ref->inode_ref->Inode.i_file_acl = 0; + extents_brelse(xattr_ref->block_bh); + xattr_ref->block_bh = NULL; + ext4_free_blocks(xattr_ref->IrpContext, &xattr_ref->inode_ref->Inode, + xattr_block, 1, 0); + xattr_ref->IsOnDiskInodeDirty = TRUE; + xattr_ref->block_loaded = FALSE; +} + +static void ext4_xattr_set_block_header(struct ext4_xattr_ref *xattr_ref) +{ + struct ext4_xattr_header *block_header = NULL; + block_header = EXT4_XATTR_BHDR(xattr_ref->block_bh); + + memset(block_header, 0, sizeof(struct ext4_xattr_header)); + block_header->h_magic = EXT4_XATTR_MAGIC; + block_header->h_refcount = cpu_to_le32(1); + block_header->h_blocks = cpu_to_le32(1); +} + +static void +ext4_xattr_set_inode_entry(struct ext4_xattr_item *item, + struct ext4_xattr_ibody_header *ibody_header, + struct ext4_xattr_entry *entry, void *ibody_data_ptr) +{ + entry->e_name_len = (__u8)item->name_len; + entry->e_name_index = item->name_index; + entry->e_value_offs = + cpu_to_le16((char *)ibody_data_ptr - (char *)EXT4_XATTR_IFIRST(ibody_header)); + entry->e_value_block = 0; + entry->e_value_size = cpu_to_le32(item->data_size); +} + +static void ext4_xattr_set_block_entry(struct ext4_xattr_item *item, + struct ext4_xattr_header *block_header, + struct ext4_xattr_entry *block_entry, + void *block_data_ptr) +{ + block_entry->e_name_len = (__u8)item->name_len; + block_entry->e_name_index = item->name_index; + block_entry->e_value_offs = + cpu_to_le16((char *)block_data_ptr - (char *)block_header); + block_entry->e_value_block = 0; + block_entry->e_value_size = cpu_to_le32(item->data_size); +} + +static int ext4_xattr_write_to_disk(struct ext4_xattr_ref *xattr_ref) +{ + int ret = 0; + BOOL block_modified = FALSE; + void *ibody_data = NULL; + void *block_data = NULL; + size_t inode_size_rem, block_size_rem; + struct ext4_xattr_ibody_header *ibody_header = NULL; + struct ext4_xattr_header *block_header = NULL; + struct ext4_xattr_entry *entry = NULL; + struct ext4_xattr_entry *block_entry = NULL; + struct ext4_xattr_item *item = NULL; + + inode_size_rem = ext4_xattr_inode_space(xattr_ref); + block_size_rem = ext4_xattr_block_space(xattr_ref); + if (inode_size_rem > sizeof(struct ext4_xattr_ibody_header)) { + ibody_header = EXT4_XATTR_IHDR(xattr_ref->OnDiskInode); + entry = EXT4_XATTR_IFIRST(ibody_header); + } + + if (!xattr_ref->dirty) + goto Finish; + /* If there are enough spaces in the ibody EA table.*/ + if (inode_size_rem > sizeof(struct ext4_xattr_ibody_header)) { + memset(ibody_header, 0, inode_size_rem); + ibody_header->h_magic = EXT4_XATTR_MAGIC; + ibody_data = (char *)ibody_header + inode_size_rem; + inode_size_rem -= sizeof(struct ext4_xattr_ibody_header); + + xattr_ref->IsOnDiskInodeDirty = TRUE; + } + /* If we need an extra block to hold the EA entries*/ + if (xattr_ref->ea_size > inode_size_rem) { + if (!xattr_ref->block_loaded) { + ret = ext4_xattr_try_alloc_block(xattr_ref); + if (ret != 0) + goto Finish; + } + memset(xattr_ref->block_bh->b_data, 0, xattr_ref->fs->BlockSize); + block_header = EXT4_XATTR_BHDR(xattr_ref->block_bh); + block_entry = EXT4_XATTR_BFIRST(xattr_ref->block_bh); + ext4_xattr_set_block_header(xattr_ref); + block_data = (char *)block_header + block_size_rem; + block_size_rem -= sizeof(struct ext4_xattr_header); + + extents_mark_buffer_dirty(xattr_ref->block_bh); + } else { + /* We don't need an extra block.*/ + if (xattr_ref->block_loaded) { + block_header = EXT4_XATTR_BHDR(xattr_ref->block_bh); + le32_add_cpu(&block_header->h_refcount, -1); + if (!block_header->h_refcount) { + ext4_xattr_try_free_block(xattr_ref); + block_header = NULL; + } else { + block_entry = + EXT4_XATTR_BFIRST(xattr_ref->block_bh); + block_data = + (char *)block_header + block_size_rem; + block_size_rem -= + sizeof(struct ext4_xattr_header); + xattr_ref->inode_ref->Inode.i_file_acl = 0; + + xattr_ref->IsOnDiskInodeDirty = TRUE; + extents_mark_buffer_dirty(xattr_ref->block_bh); + } + } + } + + list_for_each_entry(item, &xattr_ref->ordered_list, struct ext4_xattr_item, list_node) { + if (item->in_inode) { + ibody_data = (char *)ibody_data - + EXT4_XATTR_SIZE(item->data_size); + ext4_xattr_set_inode_entry(item, ibody_header, entry, + ibody_data); + memcpy(EXT4_XATTR_NAME(entry), item->name, + item->name_len); + memcpy(ibody_data, item->data, item->data_size); + entry = EXT4_XATTR_NEXT(entry); + inode_size_rem -= EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + + xattr_ref->IsOnDiskInodeDirty = TRUE; + continue; + } + if (EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len) > + block_size_rem) { + ret = -ENOSPC; + DbgPrint("ext4_xattr.c: IMPOSSIBLE -ENOSPC AS WE DID INSPECTION!\n"); + ASSERT(0); + } + block_data = + (char *)block_data - EXT4_XATTR_SIZE(item->data_size); + ext4_xattr_set_block_entry(item, block_header, block_entry, + block_data); + memcpy(EXT4_XATTR_NAME(block_entry), item->name, + item->name_len); + memcpy(block_data, item->data, item->data_size); + ext4_xattr_compute_hash(block_header, block_entry); + block_entry = EXT4_XATTR_NEXT(block_entry); + block_size_rem -= EXT4_XATTR_SIZE(item->data_size) + + EXT4_XATTR_LEN(item->name_len); + + block_modified = TRUE; + } + xattr_ref->dirty = FALSE; + if (block_modified) { + ext4_xattr_rehash(block_header, + EXT4_XATTR_BFIRST(xattr_ref->block_bh)); + ext4_xattr_set_block_checksum(xattr_ref->inode_ref, + xattr_ref->block_bh->b_blocknr, + block_header); + extents_mark_buffer_dirty(xattr_ref->block_bh); + } + +Finish: + return ret; +} + +void ext4_fs_xattr_iterate(struct ext4_xattr_ref *ref, + int (*iter)(struct ext4_xattr_ref *ref, + struct ext4_xattr_item *item, + BOOL is_last)) +{ + struct ext4_xattr_item *item; + if (!ref->iter_from) { + struct list_head *first_node; + first_node = ref->ordered_list.next; + if (first_node && first_node != &ref->ordered_list) { + ref->iter_from = + list_entry(first_node, + struct ext4_xattr_item, + list_node); + } + } + + item = ref->iter_from; + while (item) { + struct list_head *next_node; + struct ext4_xattr_item *next_item; + int ret = EXT4_XATTR_ITERATE_CONT; + next_node = item->list_node.next; + if (next_node && next_node != &ref->ordered_list) + next_item = list_entry(next_node, struct ext4_xattr_item, + list_node); + else + next_item = NULL; + if (iter) + ret = iter(ref, item, !next_item); + + if (ret != EXT4_XATTR_ITERATE_CONT) { + if (ret == EXT4_XATTR_ITERATE_STOP) + ref->iter_from = NULL; + + break; + } + item = next_item; + } +} + +void ext4_fs_xattr_iterate_reset(struct ext4_xattr_ref *ref) +{ + ref->iter_from = NULL; +} + +int ext4_fs_set_xattr(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size, BOOL replace) +{ + int ret = 0; + struct ext4_xattr_item *item = + ext4_xattr_lookup_item(ref, name_index, name, name_len); + if (replace) { + if (!item) { + ret = -ENODATA; + goto Finish; + } + if (item->data_size != data_size) + ret = ext4_xattr_resize_item(ref, item, data_size); + + if (ret != 0) { + goto Finish; + } + memcpy(item->data, data, data_size); + } else { + if (item) { + ret = -EEXIST; + goto Finish; + } + item = ext4_xattr_insert_item(ref, name_index, name, name_len, + data, data_size, &ret); + } +Finish: + return ret; +} + +int ext4_fs_set_xattr_ordered(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, const void *data, + size_t data_size) +{ + int ret = 0; + struct ext4_xattr_item *item = + ext4_xattr_lookup_item(ref, name_index, name, name_len); + if (item) { + ret = -EEXIST; + goto Finish; + } + item = ext4_xattr_insert_item_ordered(ref, name_index, name, name_len, + data, data_size, &ret); +Finish: + return ret; +} + +int ext4_fs_remove_xattr(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len) +{ + return ext4_xattr_remove_item(ref, name_index, name, name_len); +} + +int ext4_fs_get_xattr(struct ext4_xattr_ref *ref, __u8 name_index, + const char *name, size_t name_len, void *buf, + size_t buf_size, size_t *data_size) +{ + int ret = 0; + size_t item_size = 0; + struct ext4_xattr_item *item = + ext4_xattr_lookup_item(ref, name_index, name, name_len); + + if (!item) { + ret = -ENODATA; + goto Finish; + } + item_size = item->data_size; + if (buf_size > item_size) + buf_size = item_size; + + if (buf) + memcpy(buf, item->data, buf_size); + +Finish: + if (data_size) + *data_size = item_size; + + return ret; +} + +int ext4_fs_get_xattr_ref(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB fs, PEXT2_MCB inode_ref, + struct ext4_xattr_ref *ref) +{ + int rc; + ext4_fsblk_t xattr_block; + xattr_block = inode_ref->Inode.i_file_acl; + memset(&ref->root, 0, sizeof(struct rb_root)); + ref->ea_size = 0; + ref->iter_from = NULL; + if (xattr_block) { + ref->block_bh = extents_bread(&fs->sb, xattr_block); + if (!ref->block_bh) + return -EIO; + + ref->block_loaded = TRUE; + } else + ref->block_loaded = FALSE; + + ref->inode_ref = inode_ref; + ref->fs = fs; + INIT_LIST_HEAD(&ref->ordered_list); + + ref->OnDiskInode = Ext2AllocateInode(fs); + if (!ref->OnDiskInode) { + if (xattr_block) { + extents_brelse(ref->block_bh); + ref->block_bh = NULL; + } + return -ENOMEM; + } + if (!Ext2LoadInodeXattr(fs, &inode_ref->Inode, ref->OnDiskInode)) { + if (xattr_block) { + extents_brelse(ref->block_bh); + ref->block_bh = NULL; + } + + Ext2DestroyInode(fs, ref->OnDiskInode); + return -EIO; + } + ref->IsOnDiskInodeDirty = FALSE; + + if (ext4_xattr_inode_space(ref) < + sizeof(struct ext4_xattr_ibody_header) + + sizeof(__u32)) + ref->inode_size_rem = 0; + else { + ref->inode_size_rem = + ext4_xattr_inode_space(ref) - + sizeof(struct ext4_xattr_ibody_header); + } + + ref->block_size_rem = + ext4_xattr_block_space(ref) - + sizeof(struct ext4_xattr_header) - + sizeof(__u32); + + rc = ext4_xattr_fetch(ref); + if (rc != 0) { + ext4_xattr_purge_items(ref); + if (xattr_block) { + extents_brelse(ref->block_bh); + ref->block_bh = NULL; + } + + Ext2DestroyInode(fs, ref->OnDiskInode); + return rc; + } + ref->IrpContext = IrpContext; + return 0; +} + +int ext4_fs_put_xattr_ref(struct ext4_xattr_ref *ref) +{ + int ret; + sector_t orig_file_acl = ref->inode_ref->Inode.i_file_acl; + ret = ext4_xattr_write_to_disk(ref); + if (ref->IsOnDiskInodeDirty) { + ASSERT(ref->fs->InodeSize > EXT4_GOOD_OLD_INODE_SIZE); + + /* As we may do block allocation in ext4_xattr_write_to_disk */ + if (ret) + ref->inode_ref->Inode.i_file_acl = orig_file_acl; + + if (!ret) { + ret = Ext2SaveInode(ref->IrpContext, ref->fs, &ref->inode_ref->Inode) + ? 0 : -EIO; + if (!ret) { + ret = Ext2SaveInodeXattr(ref->IrpContext, + ref->fs, + &ref->inode_ref->Inode, + ref->OnDiskInode) + ? 0 : -EIO; + } + } + ref->IsOnDiskInodeDirty = FALSE; + } + if (ref->block_loaded) { + if (!ret) + extents_brelse(ref->block_bh); + else + extents_bforget(ref->block_bh); + + ref->block_bh = NULL; + ref->block_loaded = FALSE; + } + ext4_xattr_purge_items(ref); + Ext2DestroyInode(ref->fs, ref->OnDiskInode); + ref->OnDiskInode = NULL; + ref->inode_ref = NULL; + ref->fs = NULL; + return ret; +} + +struct xattr_prefix { + const char *prefix; + __u8 name_index; +}; + +static const struct xattr_prefix prefix_tbl[] = { + {"user.", EXT4_XATTR_INDEX_USER}, + {"system.posix_acl_access", EXT4_XATTR_INDEX_POSIX_ACL_ACCESS}, + {"system.posix_acl_default", EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT}, + {"trusted.", EXT4_XATTR_INDEX_TRUSTED}, + {"security.", EXT4_XATTR_INDEX_SECURITY}, + {"system.", EXT4_XATTR_INDEX_SYSTEM}, + {"system.richacl", EXT4_XATTR_INDEX_RICHACL}, + {NULL, 0}, +}; + +const char *ext4_extract_xattr_name(const char *full_name, size_t full_name_len, + __u8 *name_index, size_t *name_len, + BOOL *found) +{ + int i; + ASSERT(name_index); + ASSERT(found); + + *found = FALSE; + + if (!full_name_len) { + if (name_len) + *name_len = 0; + + return NULL; + } + + for (i = 0; prefix_tbl[i].prefix; i++) { + size_t prefix_len = strlen(prefix_tbl[i].prefix); + if (full_name_len >= prefix_len && + !memcmp(full_name, prefix_tbl[i].prefix, prefix_len)) { + BOOL require_name = + prefix_tbl[i].prefix[prefix_len - 1] == '.'; + *name_index = prefix_tbl[i].name_index; + if (name_len) + *name_len = full_name_len - prefix_len; + + if (!(full_name_len - prefix_len) && require_name) + return NULL; + + *found = TRUE; + if (require_name) + return full_name + prefix_len; + + return NULL; + } + } + if (name_len) + *name_len = 0; + + return NULL; +} + +const char *ext4_get_xattr_name_prefix(__u8 name_index, + size_t *ret_prefix_len) +{ + int i; + + for (i = 0; prefix_tbl[i].prefix; i++) { + size_t prefix_len = strlen(prefix_tbl[i].prefix); + if (prefix_tbl[i].name_index == name_index) { + if (ret_prefix_len) + *ret_prefix_len = prefix_len; + + return prefix_tbl[i].prefix; + } + } + if (ret_prefix_len) + *ret_prefix_len = 0; + + return NULL; +} diff --git a/drivers/filesystems/ext2/src/fastio.c b/drivers/filesystems/ext2/src/fastio.c index 70dc2be09b..ea62543bfe 100644 --- a/drivers/filesystems/ext2/src/fastio.c +++ b/drivers/filesystems/ext2/src/fastio.c @@ -93,6 +93,11 @@ Ext2FastIoCheckIfPossible ( ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); + /* do nothing if target fie was deleted */ + if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { + _SEH2_LEAVE; + } + if (IsDirectory(Fcb)) { _SEH2_LEAVE; } diff --git a/drivers/filesystems/ext2/src/fileinfo.c b/drivers/filesystems/ext2/src/fileinfo.c index cfc016bbf8..a9aeb8975a 100644 --- a/drivers/filesystems/ext2/src/fileinfo.c +++ b/drivers/filesystems/ext2/src/fileinfo.c @@ -11,6 +11,7 @@ #include "ext2fs.h" #include <linux/ext4.h> +#include "linux/ext4_xattr.h" /* GLOBALS ***************************************************************/ @@ -29,6 +30,15 @@ extern PEXT2_GLOBAL Ext2Global; #pragma alloc_text(PAGE, Ext2DeleteFile) #endif +static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last) +{ + PULONG EaSize = xattr_ref->iter_arg; + ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size; + + *EaSize += EaEntrySize - 4; + return EXT4_XATTR_ITERATE_CONT; +} + NTSTATUS Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) { @@ -205,6 +215,7 @@ Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) case FileEaInformation: { + struct ext4_xattr_ref xattr_ref; PFILE_EA_INFORMATION FileEaInformation; if (Length < sizeof(FILE_EA_INFORMATION)) { @@ -213,10 +224,19 @@ Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) } FileEaInformation = (PFILE_EA_INFORMATION) Buffer; - - // Romfs doesn't have any extended attributes FileEaInformation->EaSize = 0; + Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref)); + if (!NT_SUCCESS(Status)) + _SEH2_LEAVE; + + xattr_ref.iter_arg = &FileEaInformation->EaSize; + ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa); + ext4_fs_put_xattr_ref(&xattr_ref); + + if (FileEaInformation->EaSize) + FileEaInformation->EaSize += 4; + Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION); Status = STATUS_SUCCESS; } @@ -1936,12 +1956,14 @@ Ext2DeleteFile( ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); bFcbLockAcquired = TRUE; - if (!(Dcb = Mcb->Parent->Fcb)) { - Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent); + /* Mcb->Parent could be NULL when working with layered file systems */ + if (Mcb->Parent) { + Dcb = Mcb->Parent->Fcb; + if (!Dcb) + Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent); } - if (Dcb) { + if (Dcb) Ext2ReferXcb(&Dcb->ReferenceCount); - } if (bFcbLockAcquired) { ExReleaseResourceLite(&Vcb->FcbLock); diff --git a/drivers/filesystems/ext2/src/flush.c b/drivers/filesystems/ext2/src/flush.c index d57a3b1294..c3e3dcd162 100644 --- a/drivers/filesystems/ext2/src/flush.c +++ b/drivers/filesystems/ext2/src/flush.c @@ -35,41 +35,6 @@ Ext2FlushCompletionRoutine ( return STATUS_SUCCESS; } -NTSTATUS -Ext2FlushFiles( - IN PEXT2_IRP_CONTEXT IrpContext, - IN PEXT2_VCB Vcb, - IN BOOLEAN bShutDown -) -{ - IO_STATUS_BLOCK IoStatus; - - PEXT2_FCB Fcb; - PLIST_ENTRY ListEntry; - - if (IsVcbReadOnly(Vcb)) { - return STATUS_SUCCESS; - } - - IoStatus.Status = STATUS_SUCCESS; - - DEBUG(DL_INF, ( "Flushing Files ...\n")); - - // Flush all Fcbs in Vcb list queue. - for (ListEntry = Vcb->FcbList.Flink; - ListEntry != &Vcb->FcbList; - ListEntry = ListEntry->Flink ) { - - Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next); - ExAcquireResourceExclusiveLite( - &Fcb->MainResource, TRUE); - IoStatus.Status = Ext2FlushFile(IrpContext, Fcb, NULL); - ExReleaseResourceLite(&Fcb->MainResource); - } - - return IoStatus.Status; -} - NTSTATUS Ext2FlushVolume ( IN PEXT2_IRP_CONTEXT IrpContext, @@ -77,26 +42,12 @@ Ext2FlushVolume ( IN BOOLEAN bShutDown ) { - IO_STATUS_BLOCK IoStatus; - DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n")); ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); - /* acquire gd lock to avoid gd/bh creation */ - ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); - - /* discard buffer_headers for group_desc */ - Ext2DropBH(Vcb); - - /* do flushing */ - CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus); - - /* release gd lock */ - ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); - - return IoStatus.Status; + return Ext2FlushVcb(Vcb); } NTSTATUS @@ -106,7 +57,7 @@ Ext2FlushFile ( IN PEXT2_CCB Ccb ) { - IO_STATUS_BLOCK IoStatus; + IO_STATUS_BLOCK IoStatus = {0}; ASSERT(Fcb != NULL); ASSERT((Fcb->Identifier.Type == EXT2FCB) && @@ -114,6 +65,12 @@ Ext2FlushFile ( _SEH2_TRY { + /* do nothing if target fie was deleted */ + if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { + IoStatus.Status = STATUS_FILE_DELETED; + _SEH2_LEAVE; + } + /* update timestamp and achieve attribute */ if (Ccb != NULL) { @@ -147,6 +104,41 @@ Ext2FlushFile ( return IoStatus.Status; } +NTSTATUS +Ext2FlushFiles( + IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN BOOLEAN bShutDown +) +{ + IO_STATUS_BLOCK IoStatus; + + PEXT2_FCB Fcb; + PLIST_ENTRY ListEntry; + + if (IsVcbReadOnly(Vcb)) { + return STATUS_SUCCESS; + } + + IoStatus.Status = STATUS_SUCCESS; + + DEBUG(DL_INF, ( "Flushing Files ...\n")); + + // Flush all Fcbs in Vcb list queue. + for (ListEntry = Vcb->FcbList.Flink; + ListEntry != &Vcb->FcbList; + ListEntry = ListEntry->Flink ) { + + Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next); + ExAcquireResourceExclusiveLite( + &Fcb->MainResource, TRUE); + Ext2FlushFile(IrpContext, Fcb, NULL); + ExReleaseResourceLite(&Fcb->MainResource); + } + + return IoStatus.Status; +} + NTSTATUS Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext) diff --git a/drivers/filesystems/ext2/src/fsctl.c b/drivers/filesystems/ext2/src/fsctl.c index 731e018e61..0216528155 100644 --- a/drivers/filesystems/ext2/src/fsctl.c +++ b/drivers/filesystems/ext2/src/fsctl.c @@ -2130,6 +2130,11 @@ Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext) } INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB)); +#ifdef _PNP_POWER_ + /* don't care about power management requests */ + VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE; +#endif + VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); diff --git a/drivers/filesystems/ext2/src/init.c b/drivers/filesystems/ext2/src/init.c index eb0dfc8602..4e968de423 100644 --- a/drivers/filesystems/ext2/src/init.c +++ b/drivers/filesystems/ext2/src/init.c @@ -581,6 +581,11 @@ DriverEntry ( goto errorout; } +#ifdef _PNP_POWER_ + DiskdevObject->DeviceObjectExtension->PowerControlNeeded = FALSE; + CdromdevObject->DeviceObjectExtension->PowerControlNeeded = FALSE; +#endif + /* initializing */ Ext2Global->DiskdevObject = DiskdevObject; Ext2Global->CdromdevObject = CdromdevObject; @@ -604,6 +609,9 @@ DriverEntry ( DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Ext2BuildRequest; DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = Ext2BuildRequest; + DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = Ext2BuildRequest; + DriverObject->MajorFunction[IRP_MJ_SET_EA] = Ext2BuildRequest; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = Ext2BuildRequest; #if (_WIN32_WINNT >= 0x0500) diff --git a/drivers/filesystems/ext2/src/linux.c b/drivers/filesystems/ext2/src/linux.c index f65e0b5e8b..4fb73ff5f8 100644 --- a/drivers/filesystems/ext2/src/linux.c +++ b/drivers/filesystems/ext2/src/linux.c @@ -421,7 +421,7 @@ static void buffer_head_insert(struct block_device *bdev, struct buffer_head *bh rb_insert(&bdev->bd_bh_root, &bh->b_rb_node, buffer_head_blocknr_cmp); } -static void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh) +void buffer_head_remove(struct block_device *bdev, struct buffer_head *bh) { rb_erase(&bh->b_rb_node, &bdev->bd_bh_root); } @@ -469,6 +469,9 @@ get_block_bh_mdl( bh->b_blocknr = block; bh->b_size = size; bh->b_data = NULL; +#ifdef __REACTOS__ + InitializeListHead(&bh->b_link); +#endif again: @@ -476,11 +479,12 @@ again: offset.QuadPart <<= BLOCK_BITS; if (zero) { + /* PIN_EXCLUSIVE disabled, likely to deadlock with volume operations */ if (!CcPreparePinWrite(Vcb->Volume, &offset, bh->b_size, FALSE, - PIN_WAIT | PIN_EXCLUSIVE, + PIN_WAIT /* | PIN_EXCLUSIVE */, &bcb, &ptr)) { Ext2Sleep(100); @@ -563,12 +567,14 @@ int submit_bh_mdl(int rw, struct buffer_head *bh) SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); Offset.QuadPart = ((LONGLONG)bh->b_blocknr) << BLOCK_BITS; + + /* PIN_EXCLUSIVE disabled, likely to deadlock with volume operations */ if (CcPreparePinWrite( Vcb->Volume, &Offset, BLOCK_SIZE, FALSE, - PIN_WAIT | PIN_EXCLUSIVE, + PIN_WAIT /* | PIN_EXCLUSIVE */, &Bcb, &Buffer )) { #if 0 @@ -592,8 +598,6 @@ int submit_bh_mdl(int rw, struct buffer_head *bh) } } else { - - DbgBreak(); } errorout: @@ -644,6 +648,9 @@ get_block_bh_pin( bh->b_blocknr = block; bh->b_size = size; bh->b_data = NULL; +#ifdef __REACTOS__ + InitializeListHead(&bh->b_link); +#endif again: @@ -692,11 +699,11 @@ again: tbh = buffer_head_search(bdev, block); if (tbh) { get_bh(tbh); - ExReleaseResourceLite(&bdev->bd_bh_lock); free_buffer_head(bh); bh = tbh; RemoveEntryList(&bh->b_link); InitializeListHead(&bh->b_link); + ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } else { buffer_head_insert(bdev, bh); @@ -734,7 +741,6 @@ int submit_bh_pin(int rw, struct buffer_head *bh) (ULONG)bh->b_blocknr, (bh->b_size >> BLOCK_BITS)); } else { - DbgBreak(); } errorout: @@ -803,13 +809,6 @@ void __brelse(struct buffer_head *bh) ll_rw_block(WRITE, 1, &bh); } - if (1 == atomic_read(&bh->b_count)) { - } else if (atomic_dec_and_test(&bh->b_count)) { - atomic_inc(&bh->b_count); - } else { - return; - } - ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); if (atomic_dec_and_test(&bh->b_count)) { ASSERT(0 == atomic_read(&bh->b_count)); @@ -817,8 +816,11 @@ void __brelse(struct buffer_head *bh) ExReleaseResourceLite(&bdev->bd_bh_lock); return; } - buffer_head_remove(bdev, bh); KeQuerySystemTime(&bh->b_ts_drop); +#ifdef __REACTOS__ + if (!IsListEmpty(&bh->b_link)) +#endif + RemoveEntryList(&bh->b_link); InsertTailList(&Vcb->bd.bd_bh_free, &bh->b_link); KeClearEvent(&Vcb->bd.bd_bh_notify); ExReleaseResourceLite(&bdev->bd_bh_lock); @@ -924,6 +926,7 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned long size) return __getblk(bdev, block, size); } + // // inode block mapping // diff --git a/drivers/filesystems/ext2/src/memory.c b/drivers/filesystems/ext2/src/memory.c index 6678579a94..8915dfeccb 100644 --- a/drivers/filesystems/ext2/src/memory.c +++ b/drivers/filesystems/ext2/src/memory.c @@ -207,7 +207,7 @@ Ext2UnlinkFcb(IN PEXT2_FCB Fcb) ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE); Mcb = Fcb->Mcb; - DEBUG(DL_ERR, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n", + DEBUG(DL_INF, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n", Fcb, Mcb ? &Mcb->FullName : NULL)); if ((Mcb != NULL) && @@ -2364,6 +2364,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, ExInitializeResourceLite(&Vcb->MetaInode); ExInitializeResourceLite(&Vcb->MetaBlock); ExInitializeResourceLite(&Vcb->McbLock); + ExInitializeResourceLite(&Vcb->FcbLock); ExInitializeResourceLite(&Vcb->sbi.s_gd_lock); #ifndef _WIN2K_TARGET_ ExInitializeFastMutex(&Vcb->Mutex); @@ -2373,7 +2374,6 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, /* initialize Fcb list head */ InitializeListHead(&Vcb->FcbList); - ExInitializeResourceLite(&Vcb->FcbLock); /* initialize Mcb list head */ InitializeListHead(&(Vcb->McbList)); @@ -2401,7 +2401,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, /* initialize inode lookaside list */ ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList), - NULL, NULL, 0, sizeof(EXT2_INODE), + NULL, NULL, 0, Vcb->InodeSize, 'SNIE', 0); InodeLookasideInitialized = TRUE; @@ -2761,6 +2761,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, } if (VcbResourceInitialized) { + ExDeleteResourceLite(&Vcb->FcbLock); ExDeleteResourceLite(&Vcb->McbLock); ExDeleteResourceLite(&Vcb->MetaInode); ExDeleteResourceLite(&Vcb->MetaBlock); @@ -2964,47 +2965,63 @@ Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number) PEXT2_MCB Mcb = NULL; PLIST_ENTRY List = NULL; ULONG i = 0; + LARGE_INTEGER start, now; if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) { return NULL; } + KeQuerySystemTime(&start); + while (Number--) { - if (!IsListEmpty(&Vcb->McbList)) { + BOOLEAN Skip = TRUE; - while (i++ < Vcb->NumOfMcb) { + if (IsListEmpty(&Vcb->McbList)) { + break; + } - List = RemoveHeadList(&Vcb->McbList); - Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link); - ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK)); + while (i++ < Vcb->NumOfMcb) { - if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) && - Mcb->Refercount == 0 && - (Mcb->Child == NULL || IsMcbSymLink(Mcb))) { + KeQuerySystemTime(&now); + if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) { + break; + } - Ext2RemoveMcb(Vcb, Mcb); - ClearLongFlag(Mcb->Flags, MCB_VCB_LINK); - Ext2DerefXcb(&Vcb->NumOfMcb); + List = RemoveHeadList(&Vcb->McbList); + Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link); + ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK)); - /* attach all Mcb into a chain*/ - if (Head) { - ASSERT(Tail != NULL); - Tail->Next = Mcb; - Tail = Mcb; - } else { - Head = Tail = Mcb; - } - Tail->Next = NULL; + if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) && + Mcb->Refercount == 0 && + (Mcb->Child == NULL || IsMcbSymLink(Mcb))) { - } else { + Ext2RemoveMcb(Vcb, Mcb); + ClearLongFlag(Mcb->Flags, MCB_VCB_LINK); + Ext2DerefXcb(&Vcb->NumOfMcb); - InsertTailList(&Vcb->McbList, &Mcb->Link); - Mcb = NULL; + /* attach all Mcb into a chain*/ + if (Head) { + ASSERT(Tail != NULL); + Tail->Next = Mcb; + Tail = Mcb; + } else { + Head = Tail = Mcb; } + Tail->Next = NULL; + Skip = FALSE; + + } else { + + InsertTailList(&Vcb->McbList, &Mcb->Link); + Mcb = NULL; } } + + if (Skip) + break; } + ExReleaseResourceLite(&Vcb->McbLock); return Head; @@ -3119,7 +3136,9 @@ Ext2McbReaperThread( LastState = DidNothing = FALSE; } } - + if (DidNothing) { + KeClearEvent(&Reaper->Wait); + } if (GlobalAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); GlobalAcquired = FALSE; @@ -3145,15 +3164,21 @@ BOOLEAN Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head) { struct buffer_head *bh = NULL; - PLIST_ENTRY next = NULL; - LARGE_INTEGER now; - BOOLEAN wake = FALSE; + PLIST_ENTRY next = NULL; + LARGE_INTEGER start, now; + BOOLEAN wake = FALSE; - KeQuerySystemTime(&now); + KeQuerySystemTime(&start); ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE); while (!IsListEmpty(&Vcb->bd.bd_bh_free)) { + + KeQuerySystemTime(&now); + if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) { + break; + } + next = RemoveHeadList(&Vcb->bd.bd_bh_free); bh = CONTAINING_RECORD(next, struct buffer_head, b_link); if (atomic_read(&bh->b_count)) { @@ -3166,6 +3191,7 @@ Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head) (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart || (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) { InsertTailList(head, &bh->b_link); + buffer_head_remove(&Vcb->bd, bh); } else { InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link); break; @@ -3240,12 +3266,15 @@ Ext2bhReaperThread( Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next); NonWait = Ext2QueryUnusedBH(Vcb, &List); } + DidNothing = IsListEmpty(&List); + if (DidNothing) { + KeClearEvent(&Reaper->Wait); + } if (GlobalAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); GlobalAcquired = FALSE; } - DidNothing = IsListEmpty(&List); while (!IsListEmpty(&List)) { struct buffer_head *bh; Link = RemoveHeadList(&List); @@ -3274,19 +3303,20 @@ Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list) { PEXT2_FCB Fcb; PLIST_ENTRY next = NULL; - LARGE_INTEGER now; + LARGE_INTEGER start, now; ULONG count = 0; ULONG tries = 0; BOOLEAN wake = FALSE; BOOLEAN retry = TRUE; - KeQuerySystemTime(&now); + KeQuerySystemTime(&start); ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); again: + KeQuerySystemTime(&now); while (!IsListEmpty(&Vcb->FcbList)) { next = RemoveHeadList(&Vcb->FcbList); @@ -3312,6 +3342,10 @@ again: } } + if (start.QuadPart + 10*1000*1000 > now.QuadPart) { + retry = FALSE; + } + if (retry) { if (++tries < (Vcb->FcbCount >> 4) ) goto again; @@ -3380,12 +3414,15 @@ Ext2FcbReaperThread( Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next); NonWait = Ext2QueryUnusedFcb(Vcb, &List); } + DidNothing = IsListEmpty(&List); + if (DidNothing) { + KeClearEvent(&Reaper->Wait); + } if (GlobalAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); GlobalAcquired = FALSE; } - DidNothing = IsListEmpty(&List); while (!IsListEmpty(&List)) { PEXT2_FCB Fcb; Link = RemoveHeadList(&List); diff --git a/drivers/filesystems/ext2/src/volinfo.c b/drivers/filesystems/ext2/src/volinfo.c index 8840482787..ce6aad31ed 100644 --- a/drivers/filesystems/ext2/src/volinfo.c +++ b/drivers/filesystems/ext2/src/volinfo.c @@ -188,7 +188,7 @@ Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext) (PFILE_FS_ATTRIBUTE_INFORMATION) Buffer; FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS | FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | - FILE_SUPPORTS_REPARSE_POINTS; + FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_EXTENDED_ATTRIBUTES; if (IsVcbReadOnly(Vcb)) { FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME; } diff --git a/drivers/filesystems/ext2/src/write.c b/drivers/filesystems/ext2/src/write.c index 6dec4c41e3..6f7d51aa9a 100644 --- a/drivers/filesystems/ext2/src/write.c +++ b/drivers/filesystems/ext2/src/write.c @@ -78,23 +78,24 @@ Ext2FloppyFlush(IN PVOID Parameter) if (FileObject) { ASSERT(Fcb == (PEXT2_FCB)FileObject->FsContext); - + ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE); ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Fcb->PagingIoResource); CcFlushCache(&(Fcb->SectionObject), NULL, 0, NULL); + ExReleaseResourceLite(&Fcb->MainResource); ObDereferenceObject(FileObject); } if (Vcb) { + ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); + ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); - ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); - Ext2DropBH(Vcb); - CcFlushCache(&(Vcb->SectionObject), NULL, 0, NULL); - ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); + Ext2FlushVcb(Vcb); + ExReleaseResourceLite(&Vcb->MainResource); } IoSetTopLevelIrp(NULL); @@ -490,7 +491,7 @@ Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext) } Extent->Irp = NULL; - Extent->Lba = DirtyLba; + Extent->Lba = DirtyStart; Extent->Offset = (ULONG)( DirtyStart + Length - RemainLength - DirtyLba ); ASSERT(Extent->Offset <= Length); @@ -503,14 +504,17 @@ Ext2WriteVolume (IN PEXT2_IRP_CONTEXT IrpContext) RemainLength = 0; } else { Extent->Length = (ULONG)(DirtyLength + DirtyLba - DirtyStart); + RemainLength = RemainLength - Extent->Length; +/* RemainLength = (DirtyStart + RemainLength) - (DirtyLba + DirtyLength); +*/ ASSERT(RemainLength <= (LONGLONG)Length); ASSERT(Extent->Length <= Length); } ASSERT(Extent->Length >= SECTOR_SIZE); - DirtyLba = DirtyStart + DirtyLength; + DirtyLba = DirtyStart + Extent->Length; if (List) { List->Next = Extent; diff --git a/media/doc/README.FSD b/media/doc/README.FSD index 14c6d60eca..c2ad019051 100644 --- a/media/doc/README.FSD +++ b/media/doc/README.FSD @@ -9,7 +9,7 @@ reactos/sdk/lib/fslib/btrfslib # Synced to 1.0.1 The following FSD are shared with: http://www.ext2fsd.com/ -reactos/drivers/filesystems/ext2 # Synced to 0.68, with b7657e5, e7c1142, 785943f +reactos/drivers/filesystems/ext2 # Synced to 0.69 The following FSD are shared with: http://www.acc.umu.se/~bosse/