mirror of
https://github.com/bobranten/Ext4Fsd.git
synced 2025-10-29 13:18:30 -05:00
converted some files from UNIX to DOS line endings
This commit is contained in:
@@ -1 +1 @@
|
||||
DIRS = nls ext3 ext4 jbd2 sys
|
||||
DIRS = nls ext3 ext4 jbd2 sys
|
||||
|
||||
108
Ext4Fsd/access.c
108
Ext4Fsd/access.c
@@ -1,54 +1,54 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: access.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
int Ext2CheckInodeAccess(PEXT2_VCB Vcb, struct inode *in, int attempt)
|
||||
{
|
||||
int granted = 0;
|
||||
|
||||
uid_t uid = Vcb->uid;
|
||||
gid_t gid = Vcb->gid;
|
||||
|
||||
if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) {
|
||||
uid = Vcb->euid;
|
||||
gid = Vcb->egid;
|
||||
}
|
||||
|
||||
if (!uid || uid == in->i_uid) {
|
||||
/* grant all access for inode owner or root */
|
||||
granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
|
||||
} else if (gid == in->i_gid) {
|
||||
if (Ext2IsGroupReadOnly(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanExecute;
|
||||
else if (Ext2IsGroupWritable(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
|
||||
} else {
|
||||
if (Ext2IsOtherReadOnly(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanExecute;
|
||||
else if (Ext2IsOtherWritable(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
|
||||
|
||||
}
|
||||
|
||||
return IsFlagOn(granted, attempt);
|
||||
}
|
||||
|
||||
int Ext2CheckFileAccess(PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt)
|
||||
{
|
||||
return Ext2CheckInodeAccess(Vcb, &Mcb->Inode, attempt);
|
||||
}
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: access.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
int Ext2CheckInodeAccess(PEXT2_VCB Vcb, struct inode *in, int attempt)
|
||||
{
|
||||
int granted = 0;
|
||||
|
||||
uid_t uid = Vcb->uid;
|
||||
gid_t gid = Vcb->gid;
|
||||
|
||||
if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) {
|
||||
uid = Vcb->euid;
|
||||
gid = Vcb->egid;
|
||||
}
|
||||
|
||||
if (!uid || uid == in->i_uid) {
|
||||
/* grant all access for inode owner or root */
|
||||
granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
|
||||
} else if (gid == in->i_gid) {
|
||||
if (Ext2IsGroupReadOnly(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanExecute;
|
||||
else if (Ext2IsGroupWritable(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
|
||||
} else {
|
||||
if (Ext2IsOtherReadOnly(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanExecute;
|
||||
else if (Ext2IsOtherWritable(in->i_mode))
|
||||
granted = Ext2FileCanRead | Ext2FileCanWrite | Ext2FileCanExecute;
|
||||
|
||||
}
|
||||
|
||||
return IsFlagOn(granted, attempt);
|
||||
}
|
||||
|
||||
int Ext2CheckFileAccess(PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt)
|
||||
{
|
||||
return Ext2CheckInodeAccess(Vcb, &Mcb->Inode, attempt);
|
||||
}
|
||||
|
||||
1518
Ext4Fsd/block.c
1518
Ext4Fsd/block.c
File diff suppressed because it is too large
Load Diff
@@ -1,399 +1,399 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: cleanup.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PFILE_OBJECT FileObject;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PEXT2_CCB Ccb = NULL;
|
||||
PIRP Irp = NULL;
|
||||
PEXT2_MCB Mcb = NULL;
|
||||
|
||||
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbPagingIoResourceAcquired = FALSE;
|
||||
BOOLEAN SymLinkDelete = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
if (!IsVcbInited(Vcb)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
||||
if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
|
||||
Fcb->Identifier.Type != EXT2FCB)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
Mcb = Fcb->Mcb;
|
||||
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
||||
|
||||
if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (Fcb->Identifier.Type == EXT2VCB) {
|
||||
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE);
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
|
||||
Vcb->LockFile == FileObject ){
|
||||
|
||||
ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
||||
Vcb->LockFile = NULL;
|
||||
Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
||||
}
|
||||
|
||||
if (Ccb) {
|
||||
Ext2DerefXcb(&Vcb->OpenHandleCount);
|
||||
Ext2DerefXcb(&Vcb->OpenVolumeCount);
|
||||
}
|
||||
|
||||
IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
FcbResourceAcquired =
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Fcb->MainResource,
|
||||
TRUE
|
||||
);
|
||||
|
||||
if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
||||
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
|
||||
IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
|
||||
!IsVcbReadOnly(Vcb) ) {
|
||||
Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
|
||||
}
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (Ccb == NULL) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (IsDirectory(Fcb)) {
|
||||
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
|
||||
SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
|
||||
|
||||
FsRtlNotifyFullChangeDirectory(
|
||||
Vcb->NotifySync,
|
||||
&Vcb->NotifyList,
|
||||
Ccb,
|
||||
NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL );
|
||||
}
|
||||
|
||||
FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);
|
||||
}
|
||||
|
||||
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
||||
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
||||
|
||||
Ext2DerefXcb(&Vcb->OpenHandleCount);
|
||||
Ext2DerefXcb(&Fcb->OpenHandleCount);
|
||||
|
||||
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
|
||||
Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
if (IsDirectory(Fcb)) {
|
||||
|
||||
ext3_release_dir(Fcb->Inode, &Ccb->filp);
|
||||
|
||||
} else {
|
||||
|
||||
if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
|
||||
!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
|
||||
|
||||
LARGE_INTEGER SysTime;
|
||||
KeQuerySystemTime(&SysTime);
|
||||
|
||||
Fcb->Inode->i_atime =
|
||||
Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
|
||||
Fcb->Mcb->LastAccessTime =
|
||||
Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime);
|
||||
|
||||
Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
|
||||
|
||||
Ext2NotifyReportChange(
|
||||
IrpContext,
|
||||
Vcb,
|
||||
Fcb->Mcb,
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
FILE_NOTIFY_CHANGE_LAST_ACCESS,
|
||||
FILE_ACTION_MODIFIED );
|
||||
}
|
||||
|
||||
FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
|
||||
|
||||
if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) {
|
||||
Fcb->NonCachedOpenCount--;
|
||||
}
|
||||
|
||||
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
|
||||
if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
|
||||
SymLinkDelete = TRUE;
|
||||
} else {
|
||||
SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Drop any byte range locks this process may have on the file.
|
||||
//
|
||||
|
||||
FsRtlFastUnlockAll(
|
||||
&Fcb->FileLockAnchor,
|
||||
FileObject,
|
||||
IoGetRequestorProcess(Irp),
|
||||
NULL );
|
||||
|
||||
//
|
||||
// If there are no byte range locks owned by other processes on the
|
||||
// file the fast I/O read/write functions doesn't have to check for
|
||||
// locks so we set IsFastIoPossible to FastIoIsPossible again.
|
||||
//
|
||||
if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) {
|
||||
if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) {
|
||||
#if EXT2_DEBUG
|
||||
DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n",
|
||||
Ext2GetCurrentProcessName(),
|
||||
"FastIoIsPossible",
|
||||
&Fcb->Mcb->FullName
|
||||
));
|
||||
#endif
|
||||
|
||||
Fcb->Header.IsFastIoPossible = FastIoIsPossible;
|
||||
}
|
||||
}
|
||||
|
||||
if (Fcb->OpenHandleCount == 0 && FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE |
|
||||
FCB_ALLOC_IN_SETINFO) ){
|
||||
|
||||
if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_SETINFO)) {
|
||||
if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) {
|
||||
if (!INODE_HAS_EXTENT(Fcb->Inode)) {
|
||||
#if EXT2_PRE_ALLOCATION_SUPPORT
|
||||
__try {
|
||||
CcZeroData( FileObject,
|
||||
&Fcb->Header.ValidDataLength,
|
||||
&Fcb->Header.AllocationSize,
|
||||
TRUE);
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
DbgBreak();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
|
||||
|
||||
LARGE_INTEGER Size;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
|
||||
FcbPagingIoResourceAcquired = TRUE;
|
||||
|
||||
Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
|
||||
(ULONGLONG)Fcb->Mcb->Inode.i_size,
|
||||
(ULONGLONG)BLOCK_SIZE);
|
||||
if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
||||
|
||||
Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
|
||||
Fcb->Header.AllocationSize = Size;
|
||||
Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
|
||||
if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart)
|
||||
Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
|
||||
if (CcIsFileCached(FileObject)) {
|
||||
CcSetFileSizes(FileObject,
|
||||
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
|
||||
}
|
||||
}
|
||||
ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE|FCB_ALLOC_IN_SETINFO);
|
||||
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
||||
FcbPagingIoResourceAcquired = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
|
||||
|
||||
if (!IsDirectory(Fcb)) {
|
||||
|
||||
if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
|
||||
(Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
|
||||
(Fcb->SectionObject.DataSectionObject != NULL)) {
|
||||
|
||||
if (!IsVcbReadOnly(Vcb)) {
|
||||
CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
|
||||
ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
||||
}
|
||||
|
||||
/* purge cache if all remaining openings are non-cached */
|
||||
if (Fcb->NonCachedOpenCount > 0 ||
|
||||
IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
||||
if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
|
||||
ExReleaseResourceLite(&(Fcb->PagingIoResource));
|
||||
}
|
||||
|
||||
/* CcPurge could generate recursive IRP_MJ_CLOSE request */
|
||||
CcPurgeCacheSection( &Fcb->SectionObject,
|
||||
NULL,
|
||||
0,
|
||||
FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
CcUninitializeCacheMap(FileObject, NULL, NULL);
|
||||
}
|
||||
|
||||
if (SymLinkDelete ||
|
||||
(IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) &&
|
||||
Fcb->OpenHandleCount == 0) ) {
|
||||
|
||||
//
|
||||
// Ext2DeleteFile will acquire these lock inside
|
||||
//
|
||||
|
||||
if (FcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
FcbResourceAcquired = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// this file is to be deleted ...
|
||||
//
|
||||
if (Ccb->SymLink) {
|
||||
Mcb = Ccb->SymLink;
|
||||
FileObject->DeletePending = FALSE;
|
||||
}
|
||||
|
||||
Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (IsMcbDirectory(Mcb)) {
|
||||
Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME,
|
||||
FILE_ACTION_REMOVED );
|
||||
} else {
|
||||
Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||
FILE_ACTION_REMOVED );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// re-acquire the main resource lock
|
||||
//
|
||||
|
||||
FcbResourceAcquired =
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Fcb->MainResource,
|
||||
TRUE
|
||||
);
|
||||
if (!SymLinkDelete) {
|
||||
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||
if (CcIsFileCached(FileObject)) {
|
||||
CcSetFileSizes(FileObject,
|
||||
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
|
||||
Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
if (FileObject) {
|
||||
SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (FcbPagingIoResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
||||
}
|
||||
|
||||
if (FcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
}
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: cleanup.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PFILE_OBJECT FileObject;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PEXT2_CCB Ccb = NULL;
|
||||
PIRP Irp = NULL;
|
||||
PEXT2_MCB Mcb = NULL;
|
||||
|
||||
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbPagingIoResourceAcquired = FALSE;
|
||||
BOOLEAN SymLinkDelete = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
if (!IsVcbInited(Vcb)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
||||
if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
|
||||
Fcb->Identifier.Type != EXT2FCB)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
Mcb = Fcb->Mcb;
|
||||
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
||||
|
||||
if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (Fcb->Identifier.Type == EXT2VCB) {
|
||||
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE);
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
|
||||
Vcb->LockFile == FileObject ){
|
||||
|
||||
ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
||||
Vcb->LockFile = NULL;
|
||||
Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
||||
}
|
||||
|
||||
if (Ccb) {
|
||||
Ext2DerefXcb(&Vcb->OpenHandleCount);
|
||||
Ext2DerefXcb(&Vcb->OpenVolumeCount);
|
||||
}
|
||||
|
||||
IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
FcbResourceAcquired =
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Fcb->MainResource,
|
||||
TRUE
|
||||
);
|
||||
|
||||
if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
||||
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
|
||||
IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
|
||||
!IsVcbReadOnly(Vcb) ) {
|
||||
Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
|
||||
}
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (Ccb == NULL) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (IsDirectory(Fcb)) {
|
||||
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
|
||||
SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
|
||||
|
||||
FsRtlNotifyFullChangeDirectory(
|
||||
Vcb->NotifySync,
|
||||
&Vcb->NotifyList,
|
||||
Ccb,
|
||||
NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL );
|
||||
}
|
||||
|
||||
FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);
|
||||
}
|
||||
|
||||
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
||||
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
||||
|
||||
Ext2DerefXcb(&Vcb->OpenHandleCount);
|
||||
Ext2DerefXcb(&Fcb->OpenHandleCount);
|
||||
|
||||
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
|
||||
Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
if (IsDirectory(Fcb)) {
|
||||
|
||||
ext3_release_dir(Fcb->Inode, &Ccb->filp);
|
||||
|
||||
} else {
|
||||
|
||||
if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
|
||||
!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
|
||||
|
||||
LARGE_INTEGER SysTime;
|
||||
KeQuerySystemTime(&SysTime);
|
||||
|
||||
Fcb->Inode->i_atime =
|
||||
Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
|
||||
Fcb->Mcb->LastAccessTime =
|
||||
Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime);
|
||||
|
||||
Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
|
||||
|
||||
Ext2NotifyReportChange(
|
||||
IrpContext,
|
||||
Vcb,
|
||||
Fcb->Mcb,
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
FILE_NOTIFY_CHANGE_LAST_ACCESS,
|
||||
FILE_ACTION_MODIFIED );
|
||||
}
|
||||
|
||||
FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
|
||||
|
||||
if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) {
|
||||
Fcb->NonCachedOpenCount--;
|
||||
}
|
||||
|
||||
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
|
||||
if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
|
||||
SymLinkDelete = TRUE;
|
||||
} else {
|
||||
SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Drop any byte range locks this process may have on the file.
|
||||
//
|
||||
|
||||
FsRtlFastUnlockAll(
|
||||
&Fcb->FileLockAnchor,
|
||||
FileObject,
|
||||
IoGetRequestorProcess(Irp),
|
||||
NULL );
|
||||
|
||||
//
|
||||
// If there are no byte range locks owned by other processes on the
|
||||
// file the fast I/O read/write functions doesn't have to check for
|
||||
// locks so we set IsFastIoPossible to FastIoIsPossible again.
|
||||
//
|
||||
if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) {
|
||||
if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) {
|
||||
#if EXT2_DEBUG
|
||||
DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n",
|
||||
Ext2GetCurrentProcessName(),
|
||||
"FastIoIsPossible",
|
||||
&Fcb->Mcb->FullName
|
||||
));
|
||||
#endif
|
||||
|
||||
Fcb->Header.IsFastIoPossible = FastIoIsPossible;
|
||||
}
|
||||
}
|
||||
|
||||
if (Fcb->OpenHandleCount == 0 && FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE |
|
||||
FCB_ALLOC_IN_SETINFO) ){
|
||||
|
||||
if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_SETINFO)) {
|
||||
if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) {
|
||||
if (!INODE_HAS_EXTENT(Fcb->Inode)) {
|
||||
#if EXT2_PRE_ALLOCATION_SUPPORT
|
||||
__try {
|
||||
CcZeroData( FileObject,
|
||||
&Fcb->Header.ValidDataLength,
|
||||
&Fcb->Header.AllocationSize,
|
||||
TRUE);
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
DbgBreak();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
|
||||
|
||||
LARGE_INTEGER Size;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
|
||||
FcbPagingIoResourceAcquired = TRUE;
|
||||
|
||||
Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
|
||||
(ULONGLONG)Fcb->Mcb->Inode.i_size,
|
||||
(ULONGLONG)BLOCK_SIZE);
|
||||
if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
||||
|
||||
Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
|
||||
Fcb->Header.AllocationSize = Size;
|
||||
Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
|
||||
if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart)
|
||||
Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
|
||||
if (CcIsFileCached(FileObject)) {
|
||||
CcSetFileSizes(FileObject,
|
||||
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
|
||||
}
|
||||
}
|
||||
ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE|FCB_ALLOC_IN_SETINFO);
|
||||
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
||||
FcbPagingIoResourceAcquired = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
|
||||
|
||||
if (!IsDirectory(Fcb)) {
|
||||
|
||||
if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
|
||||
(Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
|
||||
(Fcb->SectionObject.DataSectionObject != NULL)) {
|
||||
|
||||
if (!IsVcbReadOnly(Vcb)) {
|
||||
CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
|
||||
ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
||||
}
|
||||
|
||||
/* purge cache if all remaining openings are non-cached */
|
||||
if (Fcb->NonCachedOpenCount > 0 ||
|
||||
IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
||||
if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
|
||||
ExReleaseResourceLite(&(Fcb->PagingIoResource));
|
||||
}
|
||||
|
||||
/* CcPurge could generate recursive IRP_MJ_CLOSE request */
|
||||
CcPurgeCacheSection( &Fcb->SectionObject,
|
||||
NULL,
|
||||
0,
|
||||
FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
CcUninitializeCacheMap(FileObject, NULL, NULL);
|
||||
}
|
||||
|
||||
if (SymLinkDelete ||
|
||||
(IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) &&
|
||||
Fcb->OpenHandleCount == 0) ) {
|
||||
|
||||
//
|
||||
// Ext2DeleteFile will acquire these lock inside
|
||||
//
|
||||
|
||||
if (FcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
FcbResourceAcquired = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// this file is to be deleted ...
|
||||
//
|
||||
if (Ccb->SymLink) {
|
||||
Mcb = Ccb->SymLink;
|
||||
FileObject->DeletePending = FALSE;
|
||||
}
|
||||
|
||||
Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (IsMcbDirectory(Mcb)) {
|
||||
Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME,
|
||||
FILE_ACTION_REMOVED );
|
||||
} else {
|
||||
Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||
FILE_ACTION_REMOVED );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// re-acquire the main resource lock
|
||||
//
|
||||
|
||||
FcbResourceAcquired =
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Fcb->MainResource,
|
||||
TRUE
|
||||
);
|
||||
if (!SymLinkDelete) {
|
||||
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||
if (CcIsFileCached(FileObject)) {
|
||||
CcSetFileSizes(FileObject,
|
||||
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
|
||||
Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
if (FileObject) {
|
||||
SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (FcbPagingIoResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
||||
}
|
||||
|
||||
if (FcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
}
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
494
Ext4Fsd/close.c
494
Ext4Fsd/close.c
@@ -1,247 +1,247 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: close.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2QueueCloseRequest)
|
||||
#pragma alloc_text(PAGE, Ext2DeQueueCloseRequest)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PFILE_OBJECT FileObject;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PEXT2_CCB Ccb = NULL;
|
||||
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbDerefDeferred = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
Vcb = NULL;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
|
||||
|
||||
FileObject = NULL;
|
||||
Fcb = IrpContext->Fcb;
|
||||
Ccb = IrpContext->Ccb;
|
||||
|
||||
} else {
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
||||
if (!Fcb) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
ASSERT(Fcb != NULL);
|
||||
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2Close: (VCB) Vcb = %p ReferCount = %d\n",
|
||||
Vcb, Vcb->ReferenceCount));
|
||||
|
||||
/*
|
||||
* WARNING: don't release Vcb resource lock here.
|
||||
*
|
||||
* CcPurgeCacheSection will lead a recursive irp: IRP_MJ_CLOSE
|
||||
* which would cause revrese order of lock acquirision:
|
||||
* 1) IRP_MJ_CLEANUP: a) Vcb lock -> b) Fcb lock
|
||||
* 2) IRP_MJ_CLOSE: c) Vcb lock -> d) Fcb lock
|
||||
*/
|
||||
|
||||
if (Fcb->Identifier.Type == EXT2VCB) {
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource,
|
||||
TRUE )) {
|
||||
DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
|
||||
Vcb->OpenHandleCount, Vcb->ReferenceCount));
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
if (Ccb) {
|
||||
|
||||
Ext2DerefXcb(&Vcb->ReferenceCount);
|
||||
Ext2FreeCcb(Vcb, Ccb);
|
||||
|
||||
if (FileObject) {
|
||||
FileObject->FsContext2 = Ccb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if ( Fcb->Identifier.Type != EXT2FCB ||
|
||||
Fcb->Identifier.Size != sizeof(EXT2_FCB)) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Fcb->MainResource,
|
||||
TRUE )) {
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
FcbResourceAcquired = TRUE;
|
||||
|
||||
Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
|
||||
|
||||
if (Ccb == NULL ||
|
||||
Ccb->Identifier.Type != EXT2CCB ||
|
||||
Ccb->Identifier.Size != sizeof(EXT2_CCB)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2Close: Fcb = %p OpenHandleCount= %u ReferenceCount=%u NonCachedCount=%u %wZ\n",
|
||||
Fcb, Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName ));
|
||||
|
||||
Ext2FreeCcb(Vcb, Ccb);
|
||||
if (FileObject) {
|
||||
FileObject->FsContext2 = Ccb = NULL;
|
||||
}
|
||||
|
||||
/* only deref fcb, Ext2ReleaseFcb might lead deadlock */
|
||||
FcbDerefDeferred = TRUE;
|
||||
if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
|
||||
NULL == Fcb->Mcb ||
|
||||
IsFileDeleted(Fcb->Mcb)) {
|
||||
Fcb->TsDrop.QuadPart = 0;
|
||||
} else {
|
||||
KeQuerySystemTime(&Fcb->TsDrop);
|
||||
}
|
||||
Ext2DerefXcb(&Vcb->ReferenceCount);
|
||||
|
||||
if (FileObject) {
|
||||
FileObject->FsContext = NULL;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
} __finally {
|
||||
|
||||
if (FcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
}
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
Ext2QueueCloseRequest(IrpContext);
|
||||
|
||||
} else {
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
|
||||
if (FcbDerefDeferred)
|
||||
Ext2DerefXcb(&Fcb->ReferenceCount);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2QueueCloseRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ASSERT(IrpContext);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
|
||||
|
||||
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_FILE_BUSY)) {
|
||||
Ext2Sleep(500); /* 0.5 sec*/
|
||||
} else {
|
||||
Ext2Sleep(50); /* 0.05 sec*/
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE);
|
||||
|
||||
IrpContext->Fcb = (PEXT2_FCB) IrpContext->FileObject->FsContext;
|
||||
IrpContext->Ccb = (PEXT2_CCB) IrpContext->FileObject->FsContext2;
|
||||
}
|
||||
|
||||
ExInitializeWorkItem(
|
||||
&IrpContext->WorkQueueItem,
|
||||
Ext2DeQueueCloseRequest,
|
||||
IrpContext);
|
||||
|
||||
ExQueueWorkItem(&IrpContext->WorkQueueItem, DelayedWorkQueue);
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2DeQueueCloseRequest (IN PVOID Context)
|
||||
{
|
||||
PEXT2_IRP_CONTEXT IrpContext;
|
||||
|
||||
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
||||
ASSERT(IrpContext);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
__try {
|
||||
|
||||
__try {
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
Ext2Close(IrpContext);
|
||||
|
||||
} __except (Ext2ExceptionFilter(IrpContext, GetExceptionInformation())) {
|
||||
|
||||
Ext2ExceptionHandler(IrpContext);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: close.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2QueueCloseRequest)
|
||||
#pragma alloc_text(PAGE, Ext2DeQueueCloseRequest)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
Ext2Close (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PFILE_OBJECT FileObject;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PEXT2_CCB Ccb = NULL;
|
||||
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbResourceAcquired = FALSE;
|
||||
BOOLEAN FcbDerefDeferred = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
Vcb = NULL;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
|
||||
|
||||
FileObject = NULL;
|
||||
Fcb = IrpContext->Fcb;
|
||||
Ccb = IrpContext->Ccb;
|
||||
|
||||
} else {
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
||||
if (!Fcb) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
ASSERT(Fcb != NULL);
|
||||
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2Close: (VCB) Vcb = %p ReferCount = %d\n",
|
||||
Vcb, Vcb->ReferenceCount));
|
||||
|
||||
/*
|
||||
* WARNING: don't release Vcb resource lock here.
|
||||
*
|
||||
* CcPurgeCacheSection will lead a recursive irp: IRP_MJ_CLOSE
|
||||
* which would cause revrese order of lock acquirision:
|
||||
* 1) IRP_MJ_CLEANUP: a) Vcb lock -> b) Fcb lock
|
||||
* 2) IRP_MJ_CLOSE: c) Vcb lock -> d) Fcb lock
|
||||
*/
|
||||
|
||||
if (Fcb->Identifier.Type == EXT2VCB) {
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource,
|
||||
TRUE )) {
|
||||
DEBUG(DL_INF, ("Ext2Close: PENDING ... Vcb: %xh/%xh\n",
|
||||
Vcb->OpenHandleCount, Vcb->ReferenceCount));
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
if (Ccb) {
|
||||
|
||||
Ext2DerefXcb(&Vcb->ReferenceCount);
|
||||
Ext2FreeCcb(Vcb, Ccb);
|
||||
|
||||
if (FileObject) {
|
||||
FileObject->FsContext2 = Ccb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if ( Fcb->Identifier.Type != EXT2FCB ||
|
||||
Fcb->Identifier.Size != sizeof(EXT2_FCB)) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Fcb->MainResource,
|
||||
TRUE )) {
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
FcbResourceAcquired = TRUE;
|
||||
|
||||
Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
|
||||
|
||||
if (Ccb == NULL ||
|
||||
Ccb->Identifier.Type != EXT2CCB ||
|
||||
Ccb->Identifier.Size != sizeof(EXT2_CCB)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2Close: Fcb = %p OpenHandleCount= %u ReferenceCount=%u NonCachedCount=%u %wZ\n",
|
||||
Fcb, Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName ));
|
||||
|
||||
Ext2FreeCcb(Vcb, Ccb);
|
||||
if (FileObject) {
|
||||
FileObject->FsContext2 = Ccb = NULL;
|
||||
}
|
||||
|
||||
/* only deref fcb, Ext2ReleaseFcb might lead deadlock */
|
||||
FcbDerefDeferred = TRUE;
|
||||
if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
|
||||
NULL == Fcb->Mcb ||
|
||||
IsFileDeleted(Fcb->Mcb)) {
|
||||
Fcb->TsDrop.QuadPart = 0;
|
||||
} else {
|
||||
KeQuerySystemTime(&Fcb->TsDrop);
|
||||
}
|
||||
Ext2DerefXcb(&Vcb->ReferenceCount);
|
||||
|
||||
if (FileObject) {
|
||||
FileObject->FsContext = NULL;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
} __finally {
|
||||
|
||||
if (FcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
}
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
Ext2QueueCloseRequest(IrpContext);
|
||||
|
||||
} else {
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
|
||||
if (FcbDerefDeferred)
|
||||
Ext2DerefXcb(&Fcb->ReferenceCount);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2QueueCloseRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ASSERT(IrpContext);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE)) {
|
||||
|
||||
if (IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_FILE_BUSY)) {
|
||||
Ext2Sleep(500); /* 0.5 sec*/
|
||||
} else {
|
||||
Ext2Sleep(50); /* 0.05 sec*/
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DELAY_CLOSE);
|
||||
|
||||
IrpContext->Fcb = (PEXT2_FCB) IrpContext->FileObject->FsContext;
|
||||
IrpContext->Ccb = (PEXT2_CCB) IrpContext->FileObject->FsContext2;
|
||||
}
|
||||
|
||||
ExInitializeWorkItem(
|
||||
&IrpContext->WorkQueueItem,
|
||||
Ext2DeQueueCloseRequest,
|
||||
IrpContext);
|
||||
|
||||
ExQueueWorkItem(&IrpContext->WorkQueueItem, DelayedWorkQueue);
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2DeQueueCloseRequest (IN PVOID Context)
|
||||
{
|
||||
PEXT2_IRP_CONTEXT IrpContext;
|
||||
|
||||
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
||||
ASSERT(IrpContext);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
__try {
|
||||
|
||||
__try {
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
Ext2Close(IrpContext);
|
||||
|
||||
} __except (Ext2ExceptionFilter(IrpContext, GetExceptionInformation())) {
|
||||
|
||||
Ext2ExceptionHandler(IrpContext);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
276
Ext4Fsd/cmcb.c
276
Ext4Fsd/cmcb.c
@@ -1,138 +1,138 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: cmcb.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#define CMCB_DEBUG_LEVEL DL_NVR
|
||||
|
||||
BOOLEAN
|
||||
Ext2AcquireForLazyWrite (
|
||||
IN PVOID Context,
|
||||
IN BOOLEAN Wait)
|
||||
{
|
||||
//
|
||||
// On a readonly filesystem this function still has to exist but it
|
||||
// doesn't need to do anything.
|
||||
|
||||
PEXT2_FCB Fcb;
|
||||
|
||||
Fcb = (PEXT2_FCB) Context;
|
||||
ASSERT(Fcb != NULL);
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
#if EXT2_DEBUG
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForLazyWrite: %s %s Fcb=%p\n",
|
||||
Ext2GetCurrentProcessName(), "ACQUIRE_FOR_LAZY_WRITE", Fcb));
|
||||
#endif
|
||||
if (!ExAcquireResourceExclusiveLite(Fcb->Header.Resource, Wait)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT(Fcb->LazyWriterThread == NULL);
|
||||
Fcb->LazyWriterThread = PsGetCurrentThread();
|
||||
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2ReleaseFromLazyWrite (IN PVOID Context)
|
||||
{
|
||||
//
|
||||
// On a readonly filesystem this function still has to exist but it
|
||||
// doesn't need to do anything.
|
||||
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
#if EXT2_DEBUG
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ( "Ext2ReleaseFromLazyWrite: %s %s Fcb=%p\n",
|
||||
Ext2GetCurrentProcessName(), "RELEASE_FROM_LAZY_WRITE", Fcb));
|
||||
#endif
|
||||
ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread());
|
||||
Fcb->LazyWriterThread = NULL;
|
||||
|
||||
ExReleaseResourceLite(Fcb->Header.Resource);
|
||||
|
||||
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
IoSetTopLevelIrp( NULL );
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Ext2AcquireForReadAhead (IN PVOID Context,
|
||||
IN BOOLEAN Wait)
|
||||
{
|
||||
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForReadAhead: i=%xh Fcb=%p\n",
|
||||
Fcb->Mcb->Inode.i_ino, Fcb));
|
||||
|
||||
if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait))
|
||||
return FALSE;
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2ReleaseFromReadAhead (IN PVOID Context)
|
||||
{
|
||||
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFromReadAhead: i=%xh Fcb=%p\n",
|
||||
Fcb->Mcb->Inode.i_ino, Fcb));
|
||||
|
||||
IoSetTopLevelIrp(NULL);
|
||||
ExReleaseResourceLite(Fcb->Header.Resource);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Ext2NoOpAcquire (
|
||||
IN PVOID Fcb,
|
||||
IN BOOLEAN Wait
|
||||
)
|
||||
{
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2NoOpRelease (
|
||||
IN PVOID Fcb
|
||||
)
|
||||
{
|
||||
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
IoSetTopLevelIrp( NULL );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: cmcb.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#define CMCB_DEBUG_LEVEL DL_NVR
|
||||
|
||||
BOOLEAN
|
||||
Ext2AcquireForLazyWrite (
|
||||
IN PVOID Context,
|
||||
IN BOOLEAN Wait)
|
||||
{
|
||||
//
|
||||
// On a readonly filesystem this function still has to exist but it
|
||||
// doesn't need to do anything.
|
||||
|
||||
PEXT2_FCB Fcb;
|
||||
|
||||
Fcb = (PEXT2_FCB) Context;
|
||||
ASSERT(Fcb != NULL);
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
#if EXT2_DEBUG
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForLazyWrite: %s %s Fcb=%p\n",
|
||||
Ext2GetCurrentProcessName(), "ACQUIRE_FOR_LAZY_WRITE", Fcb));
|
||||
#endif
|
||||
if (!ExAcquireResourceExclusiveLite(Fcb->Header.Resource, Wait)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT(Fcb->LazyWriterThread == NULL);
|
||||
Fcb->LazyWriterThread = PsGetCurrentThread();
|
||||
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2ReleaseFromLazyWrite (IN PVOID Context)
|
||||
{
|
||||
//
|
||||
// On a readonly filesystem this function still has to exist but it
|
||||
// doesn't need to do anything.
|
||||
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
#if EXT2_DEBUG
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ( "Ext2ReleaseFromLazyWrite: %s %s Fcb=%p\n",
|
||||
Ext2GetCurrentProcessName(), "RELEASE_FROM_LAZY_WRITE", Fcb));
|
||||
#endif
|
||||
ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread());
|
||||
Fcb->LazyWriterThread = NULL;
|
||||
|
||||
ExReleaseResourceLite(Fcb->Header.Resource);
|
||||
|
||||
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
IoSetTopLevelIrp( NULL );
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Ext2AcquireForReadAhead (IN PVOID Context,
|
||||
IN BOOLEAN Wait)
|
||||
{
|
||||
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForReadAhead: i=%xh Fcb=%p\n",
|
||||
Fcb->Mcb->Inode.i_ino, Fcb));
|
||||
|
||||
if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait))
|
||||
return FALSE;
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2ReleaseFromReadAhead (IN PVOID Context)
|
||||
{
|
||||
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFromReadAhead: i=%xh Fcb=%p\n",
|
||||
Fcb->Mcb->Inode.i_ino, Fcb));
|
||||
|
||||
IoSetTopLevelIrp(NULL);
|
||||
ExReleaseResourceLite(Fcb->Header.Resource);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
Ext2NoOpAcquire (
|
||||
IN PVOID Fcb,
|
||||
IN BOOLEAN Wait
|
||||
)
|
||||
{
|
||||
ASSERT(IoGetTopLevelIrp() == NULL);
|
||||
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
Ext2NoOpRelease (
|
||||
IN PVOID Fcb
|
||||
)
|
||||
{
|
||||
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
||||
IoSetTopLevelIrp( NULL );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
5410
Ext4Fsd/debug.c
5410
Ext4Fsd/debug.c
File diff suppressed because it is too large
Load Diff
1624
Ext4Fsd/devctl.c
1624
Ext4Fsd/devctl.c
File diff suppressed because it is too large
Load Diff
2548
Ext4Fsd/dirctl.c
2548
Ext4Fsd/dirctl.c
File diff suppressed because it is too large
Load Diff
@@ -1,354 +1,354 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: dispatch.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2QueueRequest)
|
||||
#pragma alloc_text(PAGE, Ext2DeQueueRequest)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ext2OplockComplete
|
||||
*
|
||||
* callback routine of FsRtlCheckOplock when an oplock break has
|
||||
* completed, allowing an Irp to resume execution.
|
||||
*
|
||||
* Arguments:
|
||||
*
|
||||
* Context: the IrpContext to be queued
|
||||
* Irp: the I/O request packet
|
||||
*
|
||||
* Return Value:
|
||||
* N/A
|
||||
*/
|
||||
|
||||
VOID
|
||||
Ext2OplockComplete (
|
||||
IN PVOID Context,
|
||||
IN PIRP Irp
|
||||
)
|
||||
{
|
||||
//
|
||||
// Check on the return value in the Irp.
|
||||
//
|
||||
|
||||
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
|
||||
|
||||
//
|
||||
// queue the Irp context in the workqueue.
|
||||
//
|
||||
|
||||
Ext2QueueRequest((PEXT2_IRP_CONTEXT)Context);
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// complete the request in case of failure
|
||||
//
|
||||
|
||||
Ext2CompleteIrpContext( (PEXT2_IRP_CONTEXT) Context,
|
||||
Irp->IoStatus.Status );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ext2LockIrp
|
||||
*
|
||||
* performs buffer locking if we need pend the process of the Irp
|
||||
*
|
||||
* Arguments:
|
||||
* Context: the irp context
|
||||
* Irp: the I/O request packet.
|
||||
*
|
||||
* Return Value:
|
||||
* N/A
|
||||
*/
|
||||
|
||||
VOID
|
||||
Ext2LockIrp (
|
||||
IN PVOID Context,
|
||||
IN PIRP Irp
|
||||
)
|
||||
{
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
PEXT2_IRP_CONTEXT IrpContext;
|
||||
|
||||
if (Irp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
||||
|
||||
if ( IrpContext->MajorFunction == IRP_MJ_READ ||
|
||||
IrpContext->MajorFunction == IRP_MJ_WRITE ) {
|
||||
|
||||
//
|
||||
// lock the user's buffer to MDL, if the I/O is bufferred
|
||||
//
|
||||
|
||||
if (!IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
|
||||
|
||||
Ext2LockUserBuffer( Irp, IrpSp->Parameters.Write.Length,
|
||||
(IrpContext->MajorFunction == IRP_MJ_READ) ?
|
||||
IoWriteAccess : IoReadAccess );
|
||||
}
|
||||
|
||||
} else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
|
||||
&& IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
|
||||
|
||||
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryDirectory.Length;
|
||||
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
|
||||
} else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
|
||||
|
||||
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryEa.Length;
|
||||
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
|
||||
} else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
|
||||
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.SetEa.Length;
|
||||
Ext2LockUserBuffer(Irp, Length, IoReadAccess);
|
||||
|
||||
} else if ( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
|
||||
(IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) ) {
|
||||
PEXTENDED_IO_STACK_LOCATION EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
||||
if ( (EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
|
||||
(EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS) ||
|
||||
(EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTER_BASE) ) {
|
||||
ULONG Length = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the request as pending status
|
||||
|
||||
IoMarkIrpPending( Irp );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2QueueRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
/* set the flags of "can wait" and "queued" */
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
|
||||
|
||||
/* make sure the buffer is kept valid in system context */
|
||||
Ext2LockIrp(IrpContext, IrpContext->Irp);
|
||||
|
||||
/* initialize workite*/
|
||||
ExInitializeWorkItem(
|
||||
&IrpContext->WorkQueueItem,
|
||||
Ext2DeQueueRequest,
|
||||
IrpContext );
|
||||
|
||||
/* dispatch it */
|
||||
ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
Ext2DeQueueRequest (IN PVOID Context)
|
||||
{
|
||||
PEXT2_IRP_CONTEXT IrpContext;
|
||||
|
||||
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
||||
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
__try {
|
||||
|
||||
__try {
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
if (!IrpContext->IsTopLevel) {
|
||||
IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP);
|
||||
}
|
||||
|
||||
Ext2DispatchRequest(IrpContext);
|
||||
|
||||
} __except (Ext2ExceptionFilter(IrpContext, GetExceptionInformation())) {
|
||||
|
||||
Ext2ExceptionHandler(IrpContext);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2DispatchRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
switch (IrpContext->MajorFunction) {
|
||||
|
||||
case IRP_MJ_CREATE:
|
||||
return Ext2Create(IrpContext);
|
||||
|
||||
case IRP_MJ_CLOSE:
|
||||
return Ext2Close(IrpContext);
|
||||
|
||||
case IRP_MJ_READ:
|
||||
return Ext2Read(IrpContext);
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
return Ext2Write(IrpContext);
|
||||
|
||||
case IRP_MJ_FLUSH_BUFFERS:
|
||||
return Ext2Flush(IrpContext);
|
||||
|
||||
case IRP_MJ_QUERY_INFORMATION:
|
||||
return Ext2QueryFileInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_SET_INFORMATION:
|
||||
return Ext2SetFileInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
||||
return Ext2QueryVolumeInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_SET_VOLUME_INFORMATION:
|
||||
return Ext2SetVolumeInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL:
|
||||
return Ext2DirectoryControl(IrpContext);
|
||||
|
||||
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
||||
return Ext2FileSystemControl(IrpContext);
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
return Ext2DeviceControl(IrpContext);
|
||||
|
||||
case IRP_MJ_LOCK_CONTROL:
|
||||
return Ext2LockControl(IrpContext);
|
||||
|
||||
case IRP_MJ_CLEANUP:
|
||||
return Ext2Cleanup(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);
|
||||
#endif //(_WIN32_WINNT >= 0x0500)
|
||||
default:
|
||||
DEBUG(DL_ERR, ( "Ext2DispatchRequest: Unexpected major function: %xh\n",
|
||||
IrpContext->MajorFunction));
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, STATUS_DRIVER_INTERNAL_ERROR);
|
||||
|
||||
return STATUS_DRIVER_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2BuildRequest (PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
BOOLEAN AtIrqlPassiveLevel = FALSE;
|
||||
BOOLEAN IsTopLevelIrp = FALSE;
|
||||
PEXT2_IRP_CONTEXT IrpContext = NULL;
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
|
||||
__try {
|
||||
|
||||
__try {
|
||||
|
||||
#if EXT2_DEBUG
|
||||
Ext2DbgPrintCall(DeviceObject, Irp);
|
||||
#endif
|
||||
|
||||
AtIrqlPassiveLevel = (KeGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
if (AtIrqlPassiveLevel) {
|
||||
FsRtlEnterFileSystem();
|
||||
}
|
||||
|
||||
if (!IoGetTopLevelIrp()) {
|
||||
IsTopLevelIrp = TRUE;
|
||||
IoSetTopLevelIrp(Irp);
|
||||
}
|
||||
|
||||
IrpContext = Ext2AllocateIrpContext(DeviceObject, Irp);
|
||||
|
||||
if (!IrpContext) {
|
||||
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
Ext2CompleteRequest(Irp, TRUE, IO_NO_INCREMENT);
|
||||
|
||||
} else {
|
||||
|
||||
if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
||||
!AtIrqlPassiveLevel) {
|
||||
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
Status = Ext2DispatchRequest(IrpContext);
|
||||
}
|
||||
} __except (Ext2ExceptionFilter(IrpContext, GetExceptionInformation())) {
|
||||
|
||||
Status = Ext2ExceptionHandler(IrpContext);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (IsTopLevelIrp) {
|
||||
IoSetTopLevelIrp(NULL);
|
||||
}
|
||||
|
||||
if (AtIrqlPassiveLevel) {
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: dispatch.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2QueueRequest)
|
||||
#pragma alloc_text(PAGE, Ext2DeQueueRequest)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Ext2OplockComplete
|
||||
*
|
||||
* callback routine of FsRtlCheckOplock when an oplock break has
|
||||
* completed, allowing an Irp to resume execution.
|
||||
*
|
||||
* Arguments:
|
||||
*
|
||||
* Context: the IrpContext to be queued
|
||||
* Irp: the I/O request packet
|
||||
*
|
||||
* Return Value:
|
||||
* N/A
|
||||
*/
|
||||
|
||||
VOID
|
||||
Ext2OplockComplete (
|
||||
IN PVOID Context,
|
||||
IN PIRP Irp
|
||||
)
|
||||
{
|
||||
//
|
||||
// Check on the return value in the Irp.
|
||||
//
|
||||
|
||||
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
|
||||
|
||||
//
|
||||
// queue the Irp context in the workqueue.
|
||||
//
|
||||
|
||||
Ext2QueueRequest((PEXT2_IRP_CONTEXT)Context);
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// complete the request in case of failure
|
||||
//
|
||||
|
||||
Ext2CompleteIrpContext( (PEXT2_IRP_CONTEXT) Context,
|
||||
Irp->IoStatus.Status );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Ext2LockIrp
|
||||
*
|
||||
* performs buffer locking if we need pend the process of the Irp
|
||||
*
|
||||
* Arguments:
|
||||
* Context: the irp context
|
||||
* Irp: the I/O request packet.
|
||||
*
|
||||
* Return Value:
|
||||
* N/A
|
||||
*/
|
||||
|
||||
VOID
|
||||
Ext2LockIrp (
|
||||
IN PVOID Context,
|
||||
IN PIRP Irp
|
||||
)
|
||||
{
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
PEXT2_IRP_CONTEXT IrpContext;
|
||||
|
||||
if (Irp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
||||
|
||||
if ( IrpContext->MajorFunction == IRP_MJ_READ ||
|
||||
IrpContext->MajorFunction == IRP_MJ_WRITE ) {
|
||||
|
||||
//
|
||||
// lock the user's buffer to MDL, if the I/O is bufferred
|
||||
//
|
||||
|
||||
if (!IsFlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
|
||||
|
||||
Ext2LockUserBuffer( Irp, IrpSp->Parameters.Write.Length,
|
||||
(IrpContext->MajorFunction == IRP_MJ_READ) ?
|
||||
IoWriteAccess : IoReadAccess );
|
||||
}
|
||||
|
||||
} else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
|
||||
&& IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
|
||||
|
||||
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryDirectory.Length;
|
||||
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
|
||||
} else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
|
||||
|
||||
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.QueryEa.Length;
|
||||
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
|
||||
} else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
|
||||
ULONG Length = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.SetEa.Length;
|
||||
Ext2LockUserBuffer(Irp, Length, IoReadAccess);
|
||||
|
||||
} else if ( (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
|
||||
(IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) ) {
|
||||
PEXTENDED_IO_STACK_LOCATION EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
|
||||
if ( (EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
|
||||
(EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS) ||
|
||||
(EIrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTER_BASE) ) {
|
||||
ULONG Length = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
Ext2LockUserBuffer(Irp, Length, IoWriteAccess);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the request as pending status
|
||||
|
||||
IoMarkIrpPending( Irp );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2QueueRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
/* set the flags of "can wait" and "queued" */
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);
|
||||
|
||||
/* make sure the buffer is kept valid in system context */
|
||||
Ext2LockIrp(IrpContext, IrpContext->Irp);
|
||||
|
||||
/* initialize workite*/
|
||||
ExInitializeWorkItem(
|
||||
&IrpContext->WorkQueueItem,
|
||||
Ext2DeQueueRequest,
|
||||
IrpContext );
|
||||
|
||||
/* dispatch it */
|
||||
ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
Ext2DeQueueRequest (IN PVOID Context)
|
||||
{
|
||||
PEXT2_IRP_CONTEXT IrpContext;
|
||||
|
||||
IrpContext = (PEXT2_IRP_CONTEXT) Context;
|
||||
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
__try {
|
||||
|
||||
__try {
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
if (!IrpContext->IsTopLevel) {
|
||||
IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP);
|
||||
}
|
||||
|
||||
Ext2DispatchRequest(IrpContext);
|
||||
|
||||
} __except (Ext2ExceptionFilter(IrpContext, GetExceptionInformation())) {
|
||||
|
||||
Ext2ExceptionHandler(IrpContext);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2DispatchRequest (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
switch (IrpContext->MajorFunction) {
|
||||
|
||||
case IRP_MJ_CREATE:
|
||||
return Ext2Create(IrpContext);
|
||||
|
||||
case IRP_MJ_CLOSE:
|
||||
return Ext2Close(IrpContext);
|
||||
|
||||
case IRP_MJ_READ:
|
||||
return Ext2Read(IrpContext);
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
return Ext2Write(IrpContext);
|
||||
|
||||
case IRP_MJ_FLUSH_BUFFERS:
|
||||
return Ext2Flush(IrpContext);
|
||||
|
||||
case IRP_MJ_QUERY_INFORMATION:
|
||||
return Ext2QueryFileInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_SET_INFORMATION:
|
||||
return Ext2SetFileInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_QUERY_VOLUME_INFORMATION:
|
||||
return Ext2QueryVolumeInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_SET_VOLUME_INFORMATION:
|
||||
return Ext2SetVolumeInformation(IrpContext);
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL:
|
||||
return Ext2DirectoryControl(IrpContext);
|
||||
|
||||
case IRP_MJ_FILE_SYSTEM_CONTROL:
|
||||
return Ext2FileSystemControl(IrpContext);
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
return Ext2DeviceControl(IrpContext);
|
||||
|
||||
case IRP_MJ_LOCK_CONTROL:
|
||||
return Ext2LockControl(IrpContext);
|
||||
|
||||
case IRP_MJ_CLEANUP:
|
||||
return Ext2Cleanup(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);
|
||||
#endif //(_WIN32_WINNT >= 0x0500)
|
||||
default:
|
||||
DEBUG(DL_ERR, ( "Ext2DispatchRequest: Unexpected major function: %xh\n",
|
||||
IrpContext->MajorFunction));
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, STATUS_DRIVER_INTERNAL_ERROR);
|
||||
|
||||
return STATUS_DRIVER_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2BuildRequest (PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
BOOLEAN AtIrqlPassiveLevel = FALSE;
|
||||
BOOLEAN IsTopLevelIrp = FALSE;
|
||||
PEXT2_IRP_CONTEXT IrpContext = NULL;
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
|
||||
__try {
|
||||
|
||||
__try {
|
||||
|
||||
#if EXT2_DEBUG
|
||||
Ext2DbgPrintCall(DeviceObject, Irp);
|
||||
#endif
|
||||
|
||||
AtIrqlPassiveLevel = (KeGetCurrentIrql() == PASSIVE_LEVEL);
|
||||
|
||||
if (AtIrqlPassiveLevel) {
|
||||
FsRtlEnterFileSystem();
|
||||
}
|
||||
|
||||
if (!IoGetTopLevelIrp()) {
|
||||
IsTopLevelIrp = TRUE;
|
||||
IoSetTopLevelIrp(Irp);
|
||||
}
|
||||
|
||||
IrpContext = Ext2AllocateIrpContext(DeviceObject, Irp);
|
||||
|
||||
if (!IrpContext) {
|
||||
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
Ext2CompleteRequest(Irp, TRUE, IO_NO_INCREMENT);
|
||||
|
||||
} else {
|
||||
|
||||
if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
||||
!AtIrqlPassiveLevel) {
|
||||
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
Status = Ext2DispatchRequest(IrpContext);
|
||||
}
|
||||
} __except (Ext2ExceptionFilter(IrpContext, GetExceptionInformation())) {
|
||||
|
||||
Status = Ext2ExceptionHandler(IrpContext);
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (IsTopLevelIrp) {
|
||||
IoSetTopLevelIrp(NULL);
|
||||
}
|
||||
|
||||
if (AtIrqlPassiveLevel) {
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
1208
Ext4Fsd/ea.c
1208
Ext4Fsd/ea.c
File diff suppressed because it is too large
Load Diff
546
Ext4Fsd/except.c
546
Ext4Fsd/except.c
@@ -1,273 +1,273 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: except.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
Ext2ExceptionFilter (
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXCEPTION_POINTERS ExceptionPointer
|
||||
)
|
||||
{
|
||||
NTSTATUS Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
NTSTATUS ExceptionCode;
|
||||
PEXCEPTION_RECORD ExceptRecord;
|
||||
|
||||
ExceptRecord = ExceptionPointer->ExceptionRecord;
|
||||
ExceptionCode = ExceptRecord->ExceptionCode;
|
||||
|
||||
DbgPrint("-------------------------------------------------------------\n");
|
||||
DbgPrint("Exception happends in Ext2Fsd (code %xh):\n", ExceptionCode);
|
||||
DbgPrint(".exr %p;.cxr %p;\n", ExceptionPointer->ExceptionRecord,
|
||||
ExceptionPointer->ContextRecord);
|
||||
DbgPrint("-------------------------------------------------------------\n");
|
||||
|
||||
DbgBreak();
|
||||
|
||||
//
|
||||
// Check IrpContext is valid or not
|
||||
//
|
||||
|
||||
if (IrpContext) {
|
||||
if ((IrpContext->Identifier.Type != EXT2ICX) ||
|
||||
(IrpContext->Identifier.Size != sizeof(EXT2_IRP_CONTEXT))) {
|
||||
DbgBreak();
|
||||
IrpContext = NULL;
|
||||
} else if (IrpContext->DeviceObject) {
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
Vcb = (PEXT2_VCB) IrpContext->DeviceObject->DeviceExtension;
|
||||
if (NULL == Vcb) {
|
||||
Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
} else {
|
||||
if (Vcb->Identifier.Type == EXT2VCB && !IsMounted(Vcb)) {
|
||||
Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (FsRtlIsNtstatusExpected(ExceptionCode)) {
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
} else {
|
||||
Ext2BugCheck( EXT2_BUGCHK_EXCEPT, (ULONG_PTR)ExceptRecord,
|
||||
(ULONG_PTR)ExceptionPointer->ContextRecord,
|
||||
(ULONG_PTR)ExceptRecord->ExceptionAddress );
|
||||
}
|
||||
}
|
||||
|
||||
if (IrpContext) {
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
}
|
||||
|
||||
if ( Status == EXCEPTION_EXECUTE_HANDLER ||
|
||||
FsRtlIsNtstatusExpected(ExceptionCode)) {
|
||||
//
|
||||
// If the exception is expected execute our handler
|
||||
//
|
||||
|
||||
DEBUG(DL_ERR, ( "Ext2ExceptionFilter: Catching exception %xh\n",
|
||||
ExceptionCode));
|
||||
|
||||
Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
|
||||
if (IrpContext) {
|
||||
IrpContext->ExceptionInProgress = TRUE;
|
||||
IrpContext->ExceptionCode = ExceptionCode;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Continue search for an higher level exception handler
|
||||
//
|
||||
|
||||
DEBUG(DL_ERR, ( "Ext2ExceptionFilter: Passing on exception %#x\n",
|
||||
ExceptionCode));
|
||||
|
||||
Status = EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
if (IrpContext) {
|
||||
Ext2FreeIrpContext(IrpContext);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2ExceptionHandler (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
if (IrpContext) {
|
||||
|
||||
if ( (IrpContext->Identifier.Type != EXT2ICX) ||
|
||||
(IrpContext->Identifier.Size != sizeof(EXT2_IRP_CONTEXT))) {
|
||||
DbgBreak();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
Status = IrpContext->ExceptionCode;
|
||||
|
||||
if (IrpContext->Irp) {
|
||||
|
||||
//
|
||||
// Check if this error is a result of user actions
|
||||
//
|
||||
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PIRP Irp = IrpContext->Irp;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
Vcb = (PEXT2_VCB) IrpContext->DeviceObject->DeviceExtension;
|
||||
|
||||
if (NULL == Vcb) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
} else if (Vcb->Identifier.Type != EXT2VCB) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
} else if (!IsMounted(Vcb)) {
|
||||
if (IsFlagOn(Vcb->Flags, VCB_DEVICE_REMOVED)) {
|
||||
Status = STATUS_NO_SUCH_DEVICE;
|
||||
} else {
|
||||
Status = STATUS_VOLUME_DISMOUNTED;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* queue it again if our request is at top level */
|
||||
if (IrpContext->IsTopLevel &&
|
||||
((Status == STATUS_CANT_WAIT) ||
|
||||
((Status == STATUS_VERIFY_REQUIRED) &&
|
||||
(KeGetCurrentIrql() >= APC_LEVEL)))) {
|
||||
|
||||
Status = Ext2QueueRequest(IrpContext);
|
||||
}
|
||||
}
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
if (IoIsErrorUserInduced(Status)) {
|
||||
|
||||
//
|
||||
// Now we will generate a pop-up to user
|
||||
//
|
||||
|
||||
PDEVICE_OBJECT RealDevice;
|
||||
PVPB Vpb = NULL;
|
||||
PETHREAD Thread;
|
||||
|
||||
if (IrpSp->FileObject != NULL) {
|
||||
Vpb = IrpSp->FileObject->Vpb;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the initial thread
|
||||
//
|
||||
|
||||
Thread = Irp->Tail.Overlay.Thread;
|
||||
RealDevice = IoGetDeviceToVerify( Thread );
|
||||
|
||||
if (RealDevice == NULL) {
|
||||
//
|
||||
// Get current thread
|
||||
//
|
||||
|
||||
Thread = PsGetCurrentThread();
|
||||
RealDevice = IoGetDeviceToVerify( Thread );
|
||||
|
||||
ASSERT( RealDevice != NULL );
|
||||
}
|
||||
|
||||
Status = IrpContext->ExceptionCode;
|
||||
|
||||
if (RealDevice != NULL) {
|
||||
|
||||
if (IrpContext->ExceptionCode == STATUS_VERIFY_REQUIRED) {
|
||||
|
||||
Status = IoVerifyVolume (RealDevice, FALSE);
|
||||
|
||||
ExAcquireResourceSharedLite(&Vcb->MainResource, TRUE);
|
||||
if (NT_SUCCESS(Status) && (!IsMounted(Vcb) ||
|
||||
IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))) {
|
||||
Status = STATUS_WRONG_VOLUME;
|
||||
}
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
if (Ext2CheckDismount(IrpContext, Vcb, FALSE)) {
|
||||
Ext2CompleteIrpContext( IrpContext, STATUS_VOLUME_DISMOUNTED);
|
||||
Status = STATUS_VOLUME_DISMOUNTED;
|
||||
Irp = NULL;
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
if ( (IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
||||
(IrpContext->FileObject->RelatedFileObject == NULL) &&
|
||||
((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) {
|
||||
|
||||
Irp->IoStatus.Information = IO_REMOUNT;
|
||||
|
||||
Ext2CompleteIrpContext( IrpContext, STATUS_REPARSE);
|
||||
Status = STATUS_REPARSE;
|
||||
Irp = NULL;
|
||||
}
|
||||
|
||||
if (Irp) {
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
IoSetHardErrorOrVerifyDevice(Irp, RealDevice);
|
||||
ASSERT (STATUS_VERIFY_REQUIRED != Status);
|
||||
Ext2NormalizeAndRaiseStatus(IrpContext, Status);
|
||||
}
|
||||
|
||||
Status = Ext2QueueRequest(IrpContext);
|
||||
}
|
||||
|
||||
goto errorout;
|
||||
|
||||
} else {
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
|
||||
IoMarkIrpPending( Irp );
|
||||
IoRaiseHardError( Irp, Vpb, RealDevice );
|
||||
IoSetDeviceToVerify( Thread, NULL );
|
||||
goto release_context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ext2CompleteRequest(Irp, FALSE, IO_NO_INCREMENT);
|
||||
}
|
||||
|
||||
release_context:
|
||||
|
||||
Ext2FreeIrpContext(IrpContext);
|
||||
|
||||
} else {
|
||||
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
errorout:
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: except.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
Ext2ExceptionFilter (
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXCEPTION_POINTERS ExceptionPointer
|
||||
)
|
||||
{
|
||||
NTSTATUS Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
NTSTATUS ExceptionCode;
|
||||
PEXCEPTION_RECORD ExceptRecord;
|
||||
|
||||
ExceptRecord = ExceptionPointer->ExceptionRecord;
|
||||
ExceptionCode = ExceptRecord->ExceptionCode;
|
||||
|
||||
DbgPrint("-------------------------------------------------------------\n");
|
||||
DbgPrint("Exception happends in Ext2Fsd (code %xh):\n", ExceptionCode);
|
||||
DbgPrint(".exr %p;.cxr %p;\n", ExceptionPointer->ExceptionRecord,
|
||||
ExceptionPointer->ContextRecord);
|
||||
DbgPrint("-------------------------------------------------------------\n");
|
||||
|
||||
DbgBreak();
|
||||
|
||||
//
|
||||
// Check IrpContext is valid or not
|
||||
//
|
||||
|
||||
if (IrpContext) {
|
||||
if ((IrpContext->Identifier.Type != EXT2ICX) ||
|
||||
(IrpContext->Identifier.Size != sizeof(EXT2_IRP_CONTEXT))) {
|
||||
DbgBreak();
|
||||
IrpContext = NULL;
|
||||
} else if (IrpContext->DeviceObject) {
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
Vcb = (PEXT2_VCB) IrpContext->DeviceObject->DeviceExtension;
|
||||
if (NULL == Vcb) {
|
||||
Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
} else {
|
||||
if (Vcb->Identifier.Type == EXT2VCB && !IsMounted(Vcb)) {
|
||||
Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (FsRtlIsNtstatusExpected(ExceptionCode)) {
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
} else {
|
||||
Ext2BugCheck( EXT2_BUGCHK_EXCEPT, (ULONG_PTR)ExceptRecord,
|
||||
(ULONG_PTR)ExceptionPointer->ContextRecord,
|
||||
(ULONG_PTR)ExceptRecord->ExceptionAddress );
|
||||
}
|
||||
}
|
||||
|
||||
if (IrpContext) {
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
}
|
||||
|
||||
if ( Status == EXCEPTION_EXECUTE_HANDLER ||
|
||||
FsRtlIsNtstatusExpected(ExceptionCode)) {
|
||||
//
|
||||
// If the exception is expected execute our handler
|
||||
//
|
||||
|
||||
DEBUG(DL_ERR, ( "Ext2ExceptionFilter: Catching exception %xh\n",
|
||||
ExceptionCode));
|
||||
|
||||
Status = EXCEPTION_EXECUTE_HANDLER;
|
||||
|
||||
if (IrpContext) {
|
||||
IrpContext->ExceptionInProgress = TRUE;
|
||||
IrpContext->ExceptionCode = ExceptionCode;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Continue search for an higher level exception handler
|
||||
//
|
||||
|
||||
DEBUG(DL_ERR, ( "Ext2ExceptionFilter: Passing on exception %#x\n",
|
||||
ExceptionCode));
|
||||
|
||||
Status = EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
if (IrpContext) {
|
||||
Ext2FreeIrpContext(IrpContext);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2ExceptionHandler (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
if (IrpContext) {
|
||||
|
||||
if ( (IrpContext->Identifier.Type != EXT2ICX) ||
|
||||
(IrpContext->Identifier.Size != sizeof(EXT2_IRP_CONTEXT))) {
|
||||
DbgBreak();
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
Status = IrpContext->ExceptionCode;
|
||||
|
||||
if (IrpContext->Irp) {
|
||||
|
||||
//
|
||||
// Check if this error is a result of user actions
|
||||
//
|
||||
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PIRP Irp = IrpContext->Irp;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
Vcb = (PEXT2_VCB) IrpContext->DeviceObject->DeviceExtension;
|
||||
|
||||
if (NULL == Vcb) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
} else if (Vcb->Identifier.Type != EXT2VCB) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
} else if (!IsMounted(Vcb)) {
|
||||
if (IsFlagOn(Vcb->Flags, VCB_DEVICE_REMOVED)) {
|
||||
Status = STATUS_NO_SUCH_DEVICE;
|
||||
} else {
|
||||
Status = STATUS_VOLUME_DISMOUNTED;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* queue it again if our request is at top level */
|
||||
if (IrpContext->IsTopLevel &&
|
||||
((Status == STATUS_CANT_WAIT) ||
|
||||
((Status == STATUS_VERIFY_REQUIRED) &&
|
||||
(KeGetCurrentIrql() >= APC_LEVEL)))) {
|
||||
|
||||
Status = Ext2QueueRequest(IrpContext);
|
||||
}
|
||||
}
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
if (IoIsErrorUserInduced(Status)) {
|
||||
|
||||
//
|
||||
// Now we will generate a pop-up to user
|
||||
//
|
||||
|
||||
PDEVICE_OBJECT RealDevice;
|
||||
PVPB Vpb = NULL;
|
||||
PETHREAD Thread;
|
||||
|
||||
if (IrpSp->FileObject != NULL) {
|
||||
Vpb = IrpSp->FileObject->Vpb;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the initial thread
|
||||
//
|
||||
|
||||
Thread = Irp->Tail.Overlay.Thread;
|
||||
RealDevice = IoGetDeviceToVerify( Thread );
|
||||
|
||||
if (RealDevice == NULL) {
|
||||
//
|
||||
// Get current thread
|
||||
//
|
||||
|
||||
Thread = PsGetCurrentThread();
|
||||
RealDevice = IoGetDeviceToVerify( Thread );
|
||||
|
||||
ASSERT( RealDevice != NULL );
|
||||
}
|
||||
|
||||
Status = IrpContext->ExceptionCode;
|
||||
|
||||
if (RealDevice != NULL) {
|
||||
|
||||
if (IrpContext->ExceptionCode == STATUS_VERIFY_REQUIRED) {
|
||||
|
||||
Status = IoVerifyVolume (RealDevice, FALSE);
|
||||
|
||||
ExAcquireResourceSharedLite(&Vcb->MainResource, TRUE);
|
||||
if (NT_SUCCESS(Status) && (!IsMounted(Vcb) ||
|
||||
IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))) {
|
||||
Status = STATUS_WRONG_VOLUME;
|
||||
}
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
if (Ext2CheckDismount(IrpContext, Vcb, FALSE)) {
|
||||
Ext2CompleteIrpContext( IrpContext, STATUS_VOLUME_DISMOUNTED);
|
||||
Status = STATUS_VOLUME_DISMOUNTED;
|
||||
Irp = NULL;
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
if ( (IrpContext->MajorFunction == IRP_MJ_CREATE) &&
|
||||
(IrpContext->FileObject->RelatedFileObject == NULL) &&
|
||||
((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) {
|
||||
|
||||
Irp->IoStatus.Information = IO_REMOUNT;
|
||||
|
||||
Ext2CompleteIrpContext( IrpContext, STATUS_REPARSE);
|
||||
Status = STATUS_REPARSE;
|
||||
Irp = NULL;
|
||||
}
|
||||
|
||||
if (Irp) {
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
IoSetHardErrorOrVerifyDevice(Irp, RealDevice);
|
||||
ASSERT (STATUS_VERIFY_REQUIRED != Status);
|
||||
Ext2NormalizeAndRaiseStatus(IrpContext, Status);
|
||||
}
|
||||
|
||||
Status = Ext2QueueRequest(IrpContext);
|
||||
}
|
||||
|
||||
goto errorout;
|
||||
|
||||
} else {
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
|
||||
IoMarkIrpPending( Irp );
|
||||
IoRaiseHardError( Irp, Vpb, RealDevice );
|
||||
IoSetDeviceToVerify( Thread, NULL );
|
||||
goto release_context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ext2CompleteRequest(Irp, FALSE, IO_NO_INCREMENT);
|
||||
}
|
||||
|
||||
release_context:
|
||||
|
||||
Ext2FreeIrpContext(IrpContext);
|
||||
|
||||
} else {
|
||||
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
errorout:
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,68 +1,68 @@
|
||||
#include <ext2fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
/*
|
||||
* extents_bread: This function is a wrapper of CcPinRead routine.
|
||||
*
|
||||
* @sb: the device we need to undergo buffered IO on.
|
||||
* @block: the block we want to read from.
|
||||
*
|
||||
* If the call to this routine succeeds, the pages underlying the buffer header
|
||||
* will be locked into memory, so that the buffer header returned for use is safe.
|
||||
*/
|
||||
struct buffer_head *
|
||||
extents_bread(struct super_block *sb, sector_t block)
|
||||
{
|
||||
return sb_getblk(sb, block);
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_bwrite: This function is a wrapper of CcPreparePinWrite routine.
|
||||
*
|
||||
* @sb: the device we need to undergo buffered IO on.
|
||||
* @block: the block we want to write to.
|
||||
*/
|
||||
struct buffer_head *
|
||||
extents_bwrite(struct super_block *sb, sector_t block)
|
||||
{
|
||||
return sb_getblk_zero(sb, block);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_mark_buffer_dirty: Mark the buffer dirtied and so
|
||||
* that changes will be written back.
|
||||
*
|
||||
* @bh: The corresponding buffer header that is modified.
|
||||
*/
|
||||
void extents_mark_buffer_dirty(struct buffer_head *bh)
|
||||
{
|
||||
set_buffer_dirty(bh);
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_brelse: Release the corresponding buffer header.
|
||||
*
|
||||
* @bh: The corresponding buffer header that is going to be freed.
|
||||
*
|
||||
* The pages underlying the buffer header will be unlocked.
|
||||
*/
|
||||
void extents_brelse(struct buffer_head *bh)
|
||||
{
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_bforget: Release the corresponding buffer header.
|
||||
* NOTE: The page owned by @bh will be marked invalidated.
|
||||
*
|
||||
* @bh: The corresponding buffer header that is going to be freed.
|
||||
*
|
||||
* The pages underlying the buffer header will be unlocked.
|
||||
*/
|
||||
void extents_bforget(struct buffer_head *bh)
|
||||
{
|
||||
clear_buffer_uptodate(bh);
|
||||
bforget(bh);
|
||||
}
|
||||
#include <ext2fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
/*
|
||||
* extents_bread: This function is a wrapper of CcPinRead routine.
|
||||
*
|
||||
* @sb: the device we need to undergo buffered IO on.
|
||||
* @block: the block we want to read from.
|
||||
*
|
||||
* If the call to this routine succeeds, the pages underlying the buffer header
|
||||
* will be locked into memory, so that the buffer header returned for use is safe.
|
||||
*/
|
||||
struct buffer_head *
|
||||
extents_bread(struct super_block *sb, sector_t block)
|
||||
{
|
||||
return sb_getblk(sb, block);
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_bwrite: This function is a wrapper of CcPreparePinWrite routine.
|
||||
*
|
||||
* @sb: the device we need to undergo buffered IO on.
|
||||
* @block: the block we want to write to.
|
||||
*/
|
||||
struct buffer_head *
|
||||
extents_bwrite(struct super_block *sb, sector_t block)
|
||||
{
|
||||
return sb_getblk_zero(sb, block);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_mark_buffer_dirty: Mark the buffer dirtied and so
|
||||
* that changes will be written back.
|
||||
*
|
||||
* @bh: The corresponding buffer header that is modified.
|
||||
*/
|
||||
void extents_mark_buffer_dirty(struct buffer_head *bh)
|
||||
{
|
||||
set_buffer_dirty(bh);
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_brelse: Release the corresponding buffer header.
|
||||
*
|
||||
* @bh: The corresponding buffer header that is going to be freed.
|
||||
*
|
||||
* The pages underlying the buffer header will be unlocked.
|
||||
*/
|
||||
void extents_brelse(struct buffer_head *bh)
|
||||
{
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
/*
|
||||
* extents_bforget: Release the corresponding buffer header.
|
||||
* NOTE: The page owned by @bh will be marked invalidated.
|
||||
*
|
||||
* @bh: The corresponding buffer header that is going to be freed.
|
||||
*
|
||||
* The pages underlying the buffer header will be unlocked.
|
||||
*/
|
||||
void extents_bforget(struct buffer_head *bh)
|
||||
{
|
||||
clear_buffer_uptodate(bh);
|
||||
bforget(bh);
|
||||
}
|
||||
|
||||
@@ -1,244 +1,244 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: extents.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS *****************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2MapExtent(
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_VCB Vcb,
|
||||
IN PEXT2_MCB Mcb,
|
||||
IN ULONG Index,
|
||||
IN BOOLEAN Alloc,
|
||||
OUT PULONG Block,
|
||||
OUT PULONG Number
|
||||
)
|
||||
{
|
||||
EXT4_EXTENT_HEADER *eh;
|
||||
struct buffer_head bh_got = {0};
|
||||
int flags, rc;
|
||||
ULONG max_blocks = 0;
|
||||
|
||||
memset(&bh_got, 0, sizeof(struct buffer_head));
|
||||
eh = get_ext4_header(&Mcb->Inode);
|
||||
|
||||
if (eh->eh_magic != EXT4_EXT_MAGIC) {
|
||||
if (Alloc) {
|
||||
/* now initialize inode extent root node */
|
||||
ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
|
||||
} else {
|
||||
/* return empty-mapping when inode extent isn't initialized */
|
||||
if (Block)
|
||||
*Block = 0;
|
||||
if (Number) {
|
||||
LONGLONG _len = _len = Mcb->Inode.i_size;
|
||||
if (Mcb->Fcb)
|
||||
_len = Mcb->Fcb->Header.AllocationSize.QuadPart;
|
||||
*Number = (ULONG)((_len + BLOCK_SIZE - 1) >> BLOCK_BITS);
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* IrpContext is NULL when called during journal initialization */
|
||||
if (IsMcbDirectory(Mcb) || IrpContext == NULL ||
|
||||
IrpContext->MajorFunction == IRP_MJ_WRITE || !Alloc){
|
||||
flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
|
||||
max_blocks = EXT_INIT_MAX_LEN;
|
||||
} else {
|
||||
flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
|
||||
max_blocks = EXT_UNWRITTEN_MAX_LEN;
|
||||
}
|
||||
|
||||
if (Alloc) {
|
||||
if (Number && !*Number) {
|
||||
if (max_blocks > *Number) {
|
||||
max_blocks = *Number;
|
||||
}
|
||||
} else {
|
||||
max_blocks = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = ext4_ext_get_blocks(
|
||||
IrpContext,
|
||||
NULL,
|
||||
&Mcb->Inode,
|
||||
Index,
|
||||
max_blocks,
|
||||
&bh_got,
|
||||
Alloc,
|
||||
flags)) < 0) {
|
||||
DEBUG(DL_ERR, ("Block insufficient resources, err: %d\n", rc));
|
||||
return Ext2WinntError(rc);
|
||||
}
|
||||
if (Alloc)
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
if (Number)
|
||||
*Number = rc ? rc : 1;
|
||||
if (Block)
|
||||
*Block = (ULONG)bh_got.b_blocknr;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2DoExtentExpand(
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_VCB Vcb,
|
||||
IN PEXT2_MCB Mcb,
|
||||
IN ULONG Index,
|
||||
IN OUT PULONG Block,
|
||||
IN OUT PULONG Number
|
||||
)
|
||||
{
|
||||
EXT4_EXTENT_HEADER *eh;
|
||||
struct buffer_head bh_got;
|
||||
int rc, flags;
|
||||
|
||||
if (IsMcbDirectory(Mcb) || IrpContext->MajorFunction == IRP_MJ_WRITE) {
|
||||
flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
|
||||
} else {
|
||||
flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
|
||||
}
|
||||
|
||||
memset(&bh_got, 0, sizeof(struct buffer_head));
|
||||
eh = get_ext4_header(&Mcb->Inode);
|
||||
|
||||
if (eh->eh_magic != EXT4_EXT_MAGIC) {
|
||||
ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
|
||||
}
|
||||
|
||||
if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index,
|
||||
*Number, &bh_got, 1, flags)) < 0) {
|
||||
DEBUG(DL_ERR, ("Expand Block insufficient resources, Number: %u,"
|
||||
" err: %d\n", *Number, rc));
|
||||
DbgBreak();
|
||||
return Ext2WinntError(rc);
|
||||
}
|
||||
|
||||
if (Number)
|
||||
*Number = rc ? rc : 1;
|
||||
if (Block)
|
||||
*Block = (ULONG)bh_got.b_blocknr;
|
||||
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2ExpandExtent(
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb,
|
||||
PEXT2_MCB Mcb,
|
||||
ULONG Start,
|
||||
ULONG End,
|
||||
PLARGE_INTEGER Size
|
||||
)
|
||||
{
|
||||
ULONG Count = 0, Number = 0, Block = 0;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
if (End <= Start)
|
||||
return Status;
|
||||
|
||||
while (End > Start + Count) {
|
||||
|
||||
Number = End - Start - Count;
|
||||
Status = Ext2DoExtentExpand(IrpContext, Vcb, Mcb, Start + Count,
|
||||
&Block, &Number);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
if (Number == 0) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Block && IsZoneInited(Mcb)) {
|
||||
if (!Ext2AddBlockExtent(Vcb, Mcb, Start + Count, Block, Number)) {
|
||||
DbgBreak();
|
||||
ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
|
||||
Ext2ClearAllExtents(&Mcb->Extents);
|
||||
}
|
||||
}
|
||||
Count += Number;
|
||||
}
|
||||
|
||||
Size->QuadPart = ((LONGLONG)(Start + Count)) << BLOCK_BITS;
|
||||
|
||||
/* save inode whatever it succeeds to expand or not */
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2TruncateExtent(
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb,
|
||||
PEXT2_MCB Mcb,
|
||||
PLARGE_INTEGER Size
|
||||
)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
ULONG Extra = 0;
|
||||
ULONG Wanted = 0;
|
||||
ULONG End;
|
||||
ULONG Removed;
|
||||
int err;
|
||||
|
||||
/* translate file size to block */
|
||||
End = Vcb->max_data_blocks;
|
||||
Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
|
||||
|
||||
/* calculate blocks to be freed */
|
||||
Extra = End - Wanted;
|
||||
|
||||
err = ext4_ext_truncate(IrpContext, &Mcb->Inode, Wanted);
|
||||
if (err == 0) {
|
||||
if (!Ext2RemoveBlockExtent(Vcb, Mcb, Wanted, Extra)) {
|
||||
ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
|
||||
Ext2ClearAllExtents(&Mcb->Extents);
|
||||
}
|
||||
Extra = 0;
|
||||
} else {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS);
|
||||
}
|
||||
|
||||
if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart))
|
||||
Mcb->Inode.i_size = (loff_t)(Size->QuadPart);
|
||||
|
||||
/* Save modifications on i_blocks field and i_size field of the inode. */
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
|
||||
return Status;
|
||||
}
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: extents.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS *****************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2MapExtent(
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_VCB Vcb,
|
||||
IN PEXT2_MCB Mcb,
|
||||
IN ULONG Index,
|
||||
IN BOOLEAN Alloc,
|
||||
OUT PULONG Block,
|
||||
OUT PULONG Number
|
||||
)
|
||||
{
|
||||
EXT4_EXTENT_HEADER *eh;
|
||||
struct buffer_head bh_got = {0};
|
||||
int flags, rc;
|
||||
ULONG max_blocks = 0;
|
||||
|
||||
memset(&bh_got, 0, sizeof(struct buffer_head));
|
||||
eh = get_ext4_header(&Mcb->Inode);
|
||||
|
||||
if (eh->eh_magic != EXT4_EXT_MAGIC) {
|
||||
if (Alloc) {
|
||||
/* now initialize inode extent root node */
|
||||
ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
|
||||
} else {
|
||||
/* return empty-mapping when inode extent isn't initialized */
|
||||
if (Block)
|
||||
*Block = 0;
|
||||
if (Number) {
|
||||
LONGLONG _len = _len = Mcb->Inode.i_size;
|
||||
if (Mcb->Fcb)
|
||||
_len = Mcb->Fcb->Header.AllocationSize.QuadPart;
|
||||
*Number = (ULONG)((_len + BLOCK_SIZE - 1) >> BLOCK_BITS);
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* IrpContext is NULL when called during journal initialization */
|
||||
if (IsMcbDirectory(Mcb) || IrpContext == NULL ||
|
||||
IrpContext->MajorFunction == IRP_MJ_WRITE || !Alloc){
|
||||
flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
|
||||
max_blocks = EXT_INIT_MAX_LEN;
|
||||
} else {
|
||||
flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
|
||||
max_blocks = EXT_UNWRITTEN_MAX_LEN;
|
||||
}
|
||||
|
||||
if (Alloc) {
|
||||
if (Number && !*Number) {
|
||||
if (max_blocks > *Number) {
|
||||
max_blocks = *Number;
|
||||
}
|
||||
} else {
|
||||
max_blocks = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rc = ext4_ext_get_blocks(
|
||||
IrpContext,
|
||||
NULL,
|
||||
&Mcb->Inode,
|
||||
Index,
|
||||
max_blocks,
|
||||
&bh_got,
|
||||
Alloc,
|
||||
flags)) < 0) {
|
||||
DEBUG(DL_ERR, ("Block insufficient resources, err: %d\n", rc));
|
||||
return Ext2WinntError(rc);
|
||||
}
|
||||
if (Alloc)
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
if (Number)
|
||||
*Number = rc ? rc : 1;
|
||||
if (Block)
|
||||
*Block = (ULONG)bh_got.b_blocknr;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2DoExtentExpand(
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_VCB Vcb,
|
||||
IN PEXT2_MCB Mcb,
|
||||
IN ULONG Index,
|
||||
IN OUT PULONG Block,
|
||||
IN OUT PULONG Number
|
||||
)
|
||||
{
|
||||
EXT4_EXTENT_HEADER *eh;
|
||||
struct buffer_head bh_got;
|
||||
int rc, flags;
|
||||
|
||||
if (IsMcbDirectory(Mcb) || IrpContext->MajorFunction == IRP_MJ_WRITE) {
|
||||
flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
|
||||
} else {
|
||||
flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
|
||||
}
|
||||
|
||||
memset(&bh_got, 0, sizeof(struct buffer_head));
|
||||
eh = get_ext4_header(&Mcb->Inode);
|
||||
|
||||
if (eh->eh_magic != EXT4_EXT_MAGIC) {
|
||||
ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
|
||||
}
|
||||
|
||||
if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index,
|
||||
*Number, &bh_got, 1, flags)) < 0) {
|
||||
DEBUG(DL_ERR, ("Expand Block insufficient resources, Number: %u,"
|
||||
" err: %d\n", *Number, rc));
|
||||
DbgBreak();
|
||||
return Ext2WinntError(rc);
|
||||
}
|
||||
|
||||
if (Number)
|
||||
*Number = rc ? rc : 1;
|
||||
if (Block)
|
||||
*Block = (ULONG)bh_got.b_blocknr;
|
||||
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2ExpandExtent(
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb,
|
||||
PEXT2_MCB Mcb,
|
||||
ULONG Start,
|
||||
ULONG End,
|
||||
PLARGE_INTEGER Size
|
||||
)
|
||||
{
|
||||
ULONG Count = 0, Number = 0, Block = 0;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
if (End <= Start)
|
||||
return Status;
|
||||
|
||||
while (End > Start + Count) {
|
||||
|
||||
Number = End - Start - Count;
|
||||
Status = Ext2DoExtentExpand(IrpContext, Vcb, Mcb, Start + Count,
|
||||
&Block, &Number);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
if (Number == 0) {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Block && IsZoneInited(Mcb)) {
|
||||
if (!Ext2AddBlockExtent(Vcb, Mcb, Start + Count, Block, Number)) {
|
||||
DbgBreak();
|
||||
ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
|
||||
Ext2ClearAllExtents(&Mcb->Extents);
|
||||
}
|
||||
}
|
||||
Count += Number;
|
||||
}
|
||||
|
||||
Size->QuadPart = ((LONGLONG)(Start + Count)) << BLOCK_BITS;
|
||||
|
||||
/* save inode whatever it succeeds to expand or not */
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2TruncateExtent(
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb,
|
||||
PEXT2_MCB Mcb,
|
||||
PLARGE_INTEGER Size
|
||||
)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
ULONG Extra = 0;
|
||||
ULONG Wanted = 0;
|
||||
ULONG End;
|
||||
ULONG Removed;
|
||||
int err;
|
||||
|
||||
/* translate file size to block */
|
||||
End = Vcb->max_data_blocks;
|
||||
Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
|
||||
|
||||
/* calculate blocks to be freed */
|
||||
Extra = End - Wanted;
|
||||
|
||||
err = ext4_ext_truncate(IrpContext, &Mcb->Inode, Wanted);
|
||||
if (err == 0) {
|
||||
if (!Ext2RemoveBlockExtent(Vcb, Mcb, Wanted, Extra)) {
|
||||
ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
|
||||
Ext2ClearAllExtents(&Mcb->Extents);
|
||||
}
|
||||
Extra = 0;
|
||||
} else {
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS);
|
||||
}
|
||||
|
||||
if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart))
|
||||
Mcb->Inode.i_size = (loff_t)(Size->QuadPart);
|
||||
|
||||
/* Save modifications on i_blocks field and i_size field of the inode. */
|
||||
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
2250
Ext4Fsd/fastio.c
2250
Ext4Fsd/fastio.c
File diff suppressed because it is too large
Load Diff
4178
Ext4Fsd/fileinfo.c
4178
Ext4Fsd/fileinfo.c
File diff suppressed because it is too large
Load Diff
552
Ext4Fsd/flush.c
552
Ext4Fsd/flush.c
@@ -1,277 +1,277 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: flush.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2FlushCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context )
|
||||
|
||||
{
|
||||
if (Irp->PendingReturned)
|
||||
IoMarkIrpPending( Irp );
|
||||
|
||||
|
||||
if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST)
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2FlushVolume (
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_VCB Vcb,
|
||||
IN BOOLEAN bShutDown
|
||||
)
|
||||
{
|
||||
DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
|
||||
|
||||
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
|
||||
ExReleaseResourceLite(&Vcb->PagingIoResource);
|
||||
|
||||
return Ext2FlushVcb(Vcb);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2FlushFile (
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_FCB Fcb,
|
||||
IN PEXT2_CCB Ccb
|
||||
)
|
||||
{
|
||||
IO_STATUS_BLOCK IoStatus = {0};
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
__try {
|
||||
|
||||
/* do nothing if target fie was deleted */
|
||||
if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
||||
IoStatus.Status = STATUS_FILE_DELETED;
|
||||
__leave;
|
||||
}
|
||||
|
||||
/* update timestamp and achieve attribute */
|
||||
if (Ccb != NULL) {
|
||||
|
||||
if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
|
||||
|
||||
LARGE_INTEGER SysTime;
|
||||
KeQuerySystemTime(&SysTime);
|
||||
|
||||
Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
|
||||
Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
|
||||
Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsDirectory(Fcb)) {
|
||||
IoStatus.Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
|
||||
Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
|
||||
|
||||
CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
|
||||
ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
||||
|
||||
} __finally {
|
||||
|
||||
/* do cleanup here */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PIRP Irp = NULL;
|
||||
PIO_STACK_LOCATION IrpSp = NULL;
|
||||
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PEXT2_FCBVCB FcbOrVcb = NULL;
|
||||
PEXT2_CCB Ccb = NULL;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
|
||||
PDEVICE_OBJECT DeviceObject = NULL;
|
||||
|
||||
BOOLEAN MainResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
//
|
||||
// This request is not allowed on the main device object
|
||||
//
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
ASSERT(IsMounted(Vcb));
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
|
||||
ASSERT(FcbOrVcb != NULL);
|
||||
|
||||
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
||||
if (Ccb == NULL) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
MainResourceAcquired =
|
||||
ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE);
|
||||
ASSERT(MainResourceAcquired);
|
||||
DEBUG(DL_INF, ("Ext2Flush-pre: total mcb records=%u\n",
|
||||
FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
|
||||
|
||||
if (FcbOrVcb->Identifier.Type == EXT2VCB) {
|
||||
|
||||
Ext2VerifyVcb(IrpContext, Vcb);
|
||||
Status = Ext2FlushFiles(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
Status = Ext2FlushVolume(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
|
||||
|
||||
if (NT_SUCCESS(Status) && IsFlagOn(Vcb->Volume->Flags, FO_FILE_MODIFIED)) {
|
||||
ClearFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
|
||||
}
|
||||
|
||||
} else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
|
||||
|
||||
Fcb = (PEXT2_FCB)(FcbOrVcb);
|
||||
|
||||
Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
|
||||
Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
ClearFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ("Ext2Flush-post: total mcb records=%u\n",
|
||||
FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
|
||||
|
||||
|
||||
} __finally {
|
||||
|
||||
if (MainResourceAcquired) {
|
||||
ExReleaseResourceLite(&FcbOrVcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
|
||||
if (Vcb && Irp && IrpSp && !IsVcbReadOnly(Vcb)) {
|
||||
|
||||
// Call the disk driver to flush the physial media.
|
||||
NTSTATUS DriverStatus;
|
||||
PIO_STACK_LOCATION NextIrpSp;
|
||||
|
||||
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
||||
|
||||
*NextIrpSp = *IrpSp;
|
||||
|
||||
IoSetCompletionRoutine( Irp,
|
||||
Ext2FlushCompletionRoutine,
|
||||
NULL,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
|
||||
Status : DriverStatus;
|
||||
|
||||
IrpContext->Irp = Irp = NULL;
|
||||
}
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: flush.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2FlushCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context )
|
||||
|
||||
{
|
||||
if (Irp->PendingReturned)
|
||||
IoMarkIrpPending( Irp );
|
||||
|
||||
|
||||
if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST)
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2FlushVolume (
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_VCB Vcb,
|
||||
IN BOOLEAN bShutDown
|
||||
)
|
||||
{
|
||||
DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
|
||||
|
||||
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
|
||||
ExReleaseResourceLite(&Vcb->PagingIoResource);
|
||||
|
||||
return Ext2FlushVcb(Vcb);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2FlushFile (
|
||||
IN PEXT2_IRP_CONTEXT IrpContext,
|
||||
IN PEXT2_FCB Fcb,
|
||||
IN PEXT2_CCB Ccb
|
||||
)
|
||||
{
|
||||
IO_STATUS_BLOCK IoStatus = {0};
|
||||
|
||||
ASSERT(Fcb != NULL);
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
__try {
|
||||
|
||||
/* do nothing if target fie was deleted */
|
||||
if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
||||
IoStatus.Status = STATUS_FILE_DELETED;
|
||||
__leave;
|
||||
}
|
||||
|
||||
/* update timestamp and achieve attribute */
|
||||
if (Ccb != NULL) {
|
||||
|
||||
if (!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
|
||||
|
||||
LARGE_INTEGER SysTime;
|
||||
KeQuerySystemTime(&SysTime);
|
||||
|
||||
Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
|
||||
Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_mtime);
|
||||
Ext2SaveInode(IrpContext, Fcb->Vcb, Fcb->Inode);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsDirectory(Fcb)) {
|
||||
IoStatus.Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ( "Ext2FlushFile: Flushing File Inode=%xh %S ...\n",
|
||||
Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer));
|
||||
|
||||
CcFlushCache(&(Fcb->SectionObject), NULL, 0, &IoStatus);
|
||||
ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
||||
|
||||
} __finally {
|
||||
|
||||
/* do cleanup here */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PIRP Irp = NULL;
|
||||
PIO_STACK_LOCATION IrpSp = NULL;
|
||||
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PEXT2_FCBVCB FcbOrVcb = NULL;
|
||||
PEXT2_CCB Ccb = NULL;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
|
||||
PDEVICE_OBJECT DeviceObject = NULL;
|
||||
|
||||
BOOLEAN MainResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
//
|
||||
// This request is not allowed on the main device object
|
||||
//
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
ASSERT(IsMounted(Vcb));
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext;
|
||||
ASSERT(FcbOrVcb != NULL);
|
||||
|
||||
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
||||
if (Ccb == NULL) {
|
||||
Status = STATUS_SUCCESS;
|
||||
__leave;
|
||||
}
|
||||
|
||||
MainResourceAcquired =
|
||||
ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE);
|
||||
ASSERT(MainResourceAcquired);
|
||||
DEBUG(DL_INF, ("Ext2Flush-pre: total mcb records=%u\n",
|
||||
FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
|
||||
|
||||
if (FcbOrVcb->Identifier.Type == EXT2VCB) {
|
||||
|
||||
Ext2VerifyVcb(IrpContext, Vcb);
|
||||
Status = Ext2FlushFiles(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
Status = Ext2FlushVolume(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE);
|
||||
|
||||
if (NT_SUCCESS(Status) && IsFlagOn(Vcb->Volume->Flags, FO_FILE_MODIFIED)) {
|
||||
ClearFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED);
|
||||
}
|
||||
|
||||
} else if (FcbOrVcb->Identifier.Type == EXT2FCB) {
|
||||
|
||||
Fcb = (PEXT2_FCB)(FcbOrVcb);
|
||||
|
||||
Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
|
||||
Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
ClearFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(DL_INF, ("Ext2Flush-post: total mcb records=%u\n",
|
||||
FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
|
||||
|
||||
|
||||
} __finally {
|
||||
|
||||
if (MainResourceAcquired) {
|
||||
ExReleaseResourceLite(&FcbOrVcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
|
||||
if (Vcb && Irp && IrpSp && !IsVcbReadOnly(Vcb)) {
|
||||
|
||||
// Call the disk driver to flush the physial media.
|
||||
NTSTATUS DriverStatus;
|
||||
PIO_STACK_LOCATION NextIrpSp;
|
||||
|
||||
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
||||
|
||||
*NextIrpSp = *IrpSp;
|
||||
|
||||
IoSetCompletionRoutine( Irp,
|
||||
Ext2FlushCompletionRoutine,
|
||||
NULL,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
|
||||
Status : DriverStatus;
|
||||
|
||||
IrpContext->Irp = Irp = NULL;
|
||||
}
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
@@ -1,261 +1,261 @@
|
||||
#ifndef _EXT2_COMMON_INCLUDE_
|
||||
#define _EXT2_COMMON_INCLUDE_
|
||||
|
||||
/* global ioctl */
|
||||
#define IOCTL_APP_VOLUME_PROPERTY \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2000, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_APP_QUERY_PERFSTAT \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2001, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_APP_MOUNT_POINT \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
|
||||
/* performance / memory allocaiton statistics */
|
||||
#define PS_IRP_CONTEXT 0x00
|
||||
#define PS_VCB 0x01
|
||||
#define PS_FCB 0x02
|
||||
#define PS_CCB 0x03
|
||||
#define PS_MCB 0x04
|
||||
#define PS_EXTENT 0x05
|
||||
#define PS_RW_CONTEXT 0x06
|
||||
#define PS_VPB 0x07
|
||||
#define PS_FILE_NAME 0x08
|
||||
#define PS_MCB_NAME 0x09
|
||||
#define PS_INODE_NAME 0x0A
|
||||
#define PS_DIR_ENTRY 0x0B
|
||||
#define PS_DIR_PATTERN 0x0C
|
||||
#define PS_DISK_EVENT 0x0D
|
||||
#define PS_DISK_BUFFER 0x0E
|
||||
#define PS_BLOCK_DATA 0x0F
|
||||
|
||||
#define PS_EXT2_INODE 0x10
|
||||
#define PS_DENTRY 0x11
|
||||
#define PS_BUFF_HEAD 0x12
|
||||
|
||||
#define PS_MAX_TYPE_V1 (0x10)
|
||||
#define PS_MAX_TYPE_V2 (0x30)
|
||||
|
||||
typedef union {
|
||||
|
||||
ULONG Slot[PS_MAX_TYPE_V1];
|
||||
|
||||
struct {
|
||||
ULONG IrpContext;
|
||||
ULONG Vcb;
|
||||
ULONG Fcb;
|
||||
ULONG Ccb;
|
||||
ULONG Mcb;
|
||||
ULONG Extent;
|
||||
ULONG RwContext; /* rw context */
|
||||
ULONG Vpb;
|
||||
ULONG FileName;
|
||||
ULONG McbName;
|
||||
ULONG InodeName;
|
||||
ULONG DirEntry; /* pDir */
|
||||
ULONG DirPattern; /* Ccb-> in Ext2QeuryDir */
|
||||
ULONG ReadDiskEvent;
|
||||
ULONG ReadDiskBuffer;
|
||||
ULONG BlockData; /* Ext2Expand&TruncateFile*/
|
||||
};
|
||||
|
||||
} EXT2_STAT_ARRAY_V1;
|
||||
|
||||
typedef union {
|
||||
|
||||
ULONG Slot[PS_MAX_TYPE_V2];
|
||||
|
||||
struct {
|
||||
ULONG IrpContext;
|
||||
ULONG Vcb;
|
||||
ULONG Fcb;
|
||||
ULONG Ccb;
|
||||
ULONG Mcb;
|
||||
ULONG Extent;
|
||||
ULONG RwContext; /* rw context */
|
||||
ULONG Vpb;
|
||||
ULONG FileName;
|
||||
ULONG McbName;
|
||||
ULONG InodeName;
|
||||
ULONG DirEntry; /* pDir */
|
||||
ULONG DirPattern; /* Ccb-> in Ext2QeuryDir */
|
||||
ULONG ReadDiskEvent;
|
||||
ULONG ReadDiskBuffer;
|
||||
ULONG BlockData; /* Ext2Expand&TruncateFile*/
|
||||
ULONG Inodes; /* inodes */
|
||||
ULONG NameEntries; /* name dentry */
|
||||
ULONG BufferHead; /* Buffer Header allocations */
|
||||
};
|
||||
|
||||
} EXT2_STAT_ARRAY_V2;
|
||||
|
||||
typedef struct _EXT2_PERF_STATISTICS_V1 {
|
||||
|
||||
/* totoal number of processed/being processed requests */
|
||||
struct {
|
||||
ULONG Processed;
|
||||
ULONG Current;
|
||||
} Irps [IRP_MJ_MAXIMUM_FUNCTION + 1];
|
||||
|
||||
/* structure size */
|
||||
EXT2_STAT_ARRAY_V1 Unit;
|
||||
|
||||
/* current memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V1 Current;
|
||||
|
||||
/* memory allocated in bytes */
|
||||
EXT2_STAT_ARRAY_V1 Size;
|
||||
|
||||
/* totoal memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V1 Total;
|
||||
|
||||
} EXT2_PERF_STATISTICS_V1, *PEXT2_PERF_STATISTICS_V1;
|
||||
|
||||
#define EXT2_PERF_STAT_MAGIC '2SPE'
|
||||
#define EXT2_PERF_STAT_VER2 2
|
||||
|
||||
typedef struct _EXT2_PERF_STATISTICS_V2 {
|
||||
|
||||
ULONG Magic; /* EPS2 */
|
||||
USHORT Version; /* 02 */
|
||||
USHORT Length; /* sizeof(EXT2_PERF_STATISTICS_V2) */
|
||||
|
||||
/* totoal number of processed/being processed requests */
|
||||
struct {
|
||||
ULONG Processed;
|
||||
ULONG Current;
|
||||
} Irps [IRP_MJ_MAXIMUM_FUNCTION + 1];
|
||||
|
||||
/* structure size */
|
||||
EXT2_STAT_ARRAY_V2 Unit;
|
||||
|
||||
/* current memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V2 Current;
|
||||
|
||||
/* memory allocated in bytes */
|
||||
EXT2_STAT_ARRAY_V2 Size;
|
||||
|
||||
/* totoal memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V2 Total;
|
||||
|
||||
} EXT2_PERF_STATISTICS_V2, *PEXT2_PERF_STATISTICS_V2;
|
||||
|
||||
/* volume property ... */
|
||||
|
||||
#define EXT2_VOLUME_PROPERTY_MAGIC 'EVPM'
|
||||
|
||||
#define EXT2_FLAG_VP_SET_GLOBAL 0x00000001
|
||||
|
||||
#define APP_CMD_QUERY_VERSION 0x00000000 /* with global flag set */
|
||||
#define APP_CMD_QUERY_CODEPAGES 0x00000001
|
||||
#define APP_CMD_QUERY_PROPERTY 0x00000002
|
||||
#define APP_CMD_SET_PROPERTY 0x00000003
|
||||
#define APP_CMD_QUERY_PROPERTY2 0x00000004
|
||||
#define APP_CMD_SET_PROPERTY2 0x00000005
|
||||
#define APP_CMD_QUERY_PROPERTY3 0x00000006
|
||||
#define APP_CMD_SET_PROPERTY3 0x00000007
|
||||
|
||||
#define CODEPAGE_MAXLEN 0x20
|
||||
#define HIDINGPAT_LEN 0x20
|
||||
|
||||
typedef struct _EXT2_VOLUME_PROPERTY {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Command;
|
||||
BOOLEAN bReadonly;
|
||||
BOOLEAN bExt3Writable;
|
||||
BOOLEAN bExt2;
|
||||
BOOLEAN bExt3;
|
||||
CHAR Codepage[CODEPAGE_MAXLEN];
|
||||
} EXT2_VOLUME_PROPERTY, *PEXT2_VOLUME_PROPERTY;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY2:EXT2_VOLUME_PROPERTY {
|
||||
#else // __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY2 {
|
||||
EXT2_VOLUME_PROPERTY ;
|
||||
#endif // __cplusplus
|
||||
|
||||
/* new volume properties added after version 0.35 */
|
||||
|
||||
/* volume uuid */
|
||||
__u8 UUID[16];
|
||||
|
||||
/* mount point: driver letter only */
|
||||
UCHAR DrvLetter;
|
||||
|
||||
/* checking bitmap */
|
||||
BOOLEAN bCheckBitmap;
|
||||
|
||||
/* global hiding patterns */
|
||||
BOOLEAN bHidingPrefix;
|
||||
BOOLEAN bHidingSuffix;
|
||||
CHAR sHidingPrefix[HIDINGPAT_LEN];
|
||||
CHAR sHidingSuffix[HIDINGPAT_LEN];
|
||||
|
||||
} EXT2_VOLUME_PROPERTY2, *PEXT2_VOLUME_PROPERTY2;
|
||||
|
||||
#define EXT2_VPROP3_AUTOMOUNT (1ui64 << 0)
|
||||
#define EXT2_VPROP3_USERIDS (1ui64 << 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY3:EXT2_VOLUME_PROPERTY2 {
|
||||
#else // __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY3 {
|
||||
EXT2_VOLUME_PROPERTY2 ;
|
||||
#endif // __cplusplus
|
||||
unsigned __int64 Flags2;
|
||||
ULONG AutoMount:1;
|
||||
ULONG EIDS:1;
|
||||
ULONG Reserved1:30;
|
||||
USHORT uid;
|
||||
USHORT gid;
|
||||
USHORT euid;
|
||||
USHORT egid;
|
||||
ULONG Reserved2[29];
|
||||
} EXT2_VOLUME_PROPERTY3, *PEXT2_VOLUME_PROPERTY3;
|
||||
|
||||
/* Ext2Fsd driver version and built time */
|
||||
typedef struct _EXT2_VOLUME_PROPERTY_VERSION {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Command;
|
||||
CHAR Version[0x1C];
|
||||
CHAR Time[0x20];
|
||||
CHAR Date[0x20];
|
||||
} EXT2_VOLUME_PROPERTY_VERSION, *PEXT2_VOLUME_PROPERTY_VERSION;
|
||||
|
||||
/* performance statistics */
|
||||
#define EXT2_QUERY_PERFSTAT_MAGIC 'EVPM'
|
||||
#define EXT2_QUERY_PERFSTAT_VER2 0x8000000
|
||||
|
||||
typedef struct _EXT2_QUERY_PERFSTAT {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Command;
|
||||
union {
|
||||
EXT2_PERF_STATISTICS_V1 PerfStatV1;
|
||||
EXT2_PERF_STATISTICS_V2 PerfStatV2;
|
||||
};
|
||||
} EXT2_QUERY_PERFSTAT, *PEXT2_QUERY_PERFSTAT;
|
||||
|
||||
#define EXT2_QUERY_PERFSTAT_SZV1 (FIELD_OFFSET(EXT2_QUERY_PERFSTAT, PerfStatV1) + sizeof(EXT2_PERF_STATISTICS_V1))
|
||||
#define EXT2_QUERY_PERFSTAT_SZV2 (FIELD_OFFSET(EXT2_QUERY_PERFSTAT, PerfStatV1) + sizeof(EXT2_PERF_STATISTICS_V2))
|
||||
|
||||
/* mountpoint management */
|
||||
#define EXT2_APP_MOUNTPOINT_MAGIC 'EAMM'
|
||||
typedef struct _EXT2_MOUNT_POINT {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Size;
|
||||
ULONG Command;
|
||||
USHORT Link[256];
|
||||
USHORT Name[256];
|
||||
} EXT2_MOUNT_POINT, *PEXT2_MOUNT_POINT;
|
||||
|
||||
#define APP_CMD_ADD_DOS_SYMLINK 0x00000001
|
||||
#define APP_CMD_DEL_DOS_SYMLINK 0x00000002
|
||||
|
||||
|
||||
#endif /* _EXT2_COMMON_INCLUDE_ */
|
||||
#ifndef _EXT2_COMMON_INCLUDE_
|
||||
#define _EXT2_COMMON_INCLUDE_
|
||||
|
||||
/* global ioctl */
|
||||
#define IOCTL_APP_VOLUME_PROPERTY \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2000, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_APP_QUERY_PERFSTAT \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2001, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_APP_MOUNT_POINT \
|
||||
CTL_CODE(FILE_DEVICE_UNKNOWN, 2002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
|
||||
/* performance / memory allocaiton statistics */
|
||||
#define PS_IRP_CONTEXT 0x00
|
||||
#define PS_VCB 0x01
|
||||
#define PS_FCB 0x02
|
||||
#define PS_CCB 0x03
|
||||
#define PS_MCB 0x04
|
||||
#define PS_EXTENT 0x05
|
||||
#define PS_RW_CONTEXT 0x06
|
||||
#define PS_VPB 0x07
|
||||
#define PS_FILE_NAME 0x08
|
||||
#define PS_MCB_NAME 0x09
|
||||
#define PS_INODE_NAME 0x0A
|
||||
#define PS_DIR_ENTRY 0x0B
|
||||
#define PS_DIR_PATTERN 0x0C
|
||||
#define PS_DISK_EVENT 0x0D
|
||||
#define PS_DISK_BUFFER 0x0E
|
||||
#define PS_BLOCK_DATA 0x0F
|
||||
|
||||
#define PS_EXT2_INODE 0x10
|
||||
#define PS_DENTRY 0x11
|
||||
#define PS_BUFF_HEAD 0x12
|
||||
|
||||
#define PS_MAX_TYPE_V1 (0x10)
|
||||
#define PS_MAX_TYPE_V2 (0x30)
|
||||
|
||||
typedef union {
|
||||
|
||||
ULONG Slot[PS_MAX_TYPE_V1];
|
||||
|
||||
struct {
|
||||
ULONG IrpContext;
|
||||
ULONG Vcb;
|
||||
ULONG Fcb;
|
||||
ULONG Ccb;
|
||||
ULONG Mcb;
|
||||
ULONG Extent;
|
||||
ULONG RwContext; /* rw context */
|
||||
ULONG Vpb;
|
||||
ULONG FileName;
|
||||
ULONG McbName;
|
||||
ULONG InodeName;
|
||||
ULONG DirEntry; /* pDir */
|
||||
ULONG DirPattern; /* Ccb-> in Ext2QeuryDir */
|
||||
ULONG ReadDiskEvent;
|
||||
ULONG ReadDiskBuffer;
|
||||
ULONG BlockData; /* Ext2Expand&TruncateFile*/
|
||||
};
|
||||
|
||||
} EXT2_STAT_ARRAY_V1;
|
||||
|
||||
typedef union {
|
||||
|
||||
ULONG Slot[PS_MAX_TYPE_V2];
|
||||
|
||||
struct {
|
||||
ULONG IrpContext;
|
||||
ULONG Vcb;
|
||||
ULONG Fcb;
|
||||
ULONG Ccb;
|
||||
ULONG Mcb;
|
||||
ULONG Extent;
|
||||
ULONG RwContext; /* rw context */
|
||||
ULONG Vpb;
|
||||
ULONG FileName;
|
||||
ULONG McbName;
|
||||
ULONG InodeName;
|
||||
ULONG DirEntry; /* pDir */
|
||||
ULONG DirPattern; /* Ccb-> in Ext2QeuryDir */
|
||||
ULONG ReadDiskEvent;
|
||||
ULONG ReadDiskBuffer;
|
||||
ULONG BlockData; /* Ext2Expand&TruncateFile*/
|
||||
ULONG Inodes; /* inodes */
|
||||
ULONG NameEntries; /* name dentry */
|
||||
ULONG BufferHead; /* Buffer Header allocations */
|
||||
};
|
||||
|
||||
} EXT2_STAT_ARRAY_V2;
|
||||
|
||||
typedef struct _EXT2_PERF_STATISTICS_V1 {
|
||||
|
||||
/* totoal number of processed/being processed requests */
|
||||
struct {
|
||||
ULONG Processed;
|
||||
ULONG Current;
|
||||
} Irps [IRP_MJ_MAXIMUM_FUNCTION + 1];
|
||||
|
||||
/* structure size */
|
||||
EXT2_STAT_ARRAY_V1 Unit;
|
||||
|
||||
/* current memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V1 Current;
|
||||
|
||||
/* memory allocated in bytes */
|
||||
EXT2_STAT_ARRAY_V1 Size;
|
||||
|
||||
/* totoal memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V1 Total;
|
||||
|
||||
} EXT2_PERF_STATISTICS_V1, *PEXT2_PERF_STATISTICS_V1;
|
||||
|
||||
#define EXT2_PERF_STAT_MAGIC '2SPE'
|
||||
#define EXT2_PERF_STAT_VER2 2
|
||||
|
||||
typedef struct _EXT2_PERF_STATISTICS_V2 {
|
||||
|
||||
ULONG Magic; /* EPS2 */
|
||||
USHORT Version; /* 02 */
|
||||
USHORT Length; /* sizeof(EXT2_PERF_STATISTICS_V2) */
|
||||
|
||||
/* totoal number of processed/being processed requests */
|
||||
struct {
|
||||
ULONG Processed;
|
||||
ULONG Current;
|
||||
} Irps [IRP_MJ_MAXIMUM_FUNCTION + 1];
|
||||
|
||||
/* structure size */
|
||||
EXT2_STAT_ARRAY_V2 Unit;
|
||||
|
||||
/* current memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V2 Current;
|
||||
|
||||
/* memory allocated in bytes */
|
||||
EXT2_STAT_ARRAY_V2 Size;
|
||||
|
||||
/* totoal memory allocation statistics */
|
||||
EXT2_STAT_ARRAY_V2 Total;
|
||||
|
||||
} EXT2_PERF_STATISTICS_V2, *PEXT2_PERF_STATISTICS_V2;
|
||||
|
||||
/* volume property ... */
|
||||
|
||||
#define EXT2_VOLUME_PROPERTY_MAGIC 'EVPM'
|
||||
|
||||
#define EXT2_FLAG_VP_SET_GLOBAL 0x00000001
|
||||
|
||||
#define APP_CMD_QUERY_VERSION 0x00000000 /* with global flag set */
|
||||
#define APP_CMD_QUERY_CODEPAGES 0x00000001
|
||||
#define APP_CMD_QUERY_PROPERTY 0x00000002
|
||||
#define APP_CMD_SET_PROPERTY 0x00000003
|
||||
#define APP_CMD_QUERY_PROPERTY2 0x00000004
|
||||
#define APP_CMD_SET_PROPERTY2 0x00000005
|
||||
#define APP_CMD_QUERY_PROPERTY3 0x00000006
|
||||
#define APP_CMD_SET_PROPERTY3 0x00000007
|
||||
|
||||
#define CODEPAGE_MAXLEN 0x20
|
||||
#define HIDINGPAT_LEN 0x20
|
||||
|
||||
typedef struct _EXT2_VOLUME_PROPERTY {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Command;
|
||||
BOOLEAN bReadonly;
|
||||
BOOLEAN bExt3Writable;
|
||||
BOOLEAN bExt2;
|
||||
BOOLEAN bExt3;
|
||||
CHAR Codepage[CODEPAGE_MAXLEN];
|
||||
} EXT2_VOLUME_PROPERTY, *PEXT2_VOLUME_PROPERTY;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY2:EXT2_VOLUME_PROPERTY {
|
||||
#else // __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY2 {
|
||||
EXT2_VOLUME_PROPERTY ;
|
||||
#endif // __cplusplus
|
||||
|
||||
/* new volume properties added after version 0.35 */
|
||||
|
||||
/* volume uuid */
|
||||
__u8 UUID[16];
|
||||
|
||||
/* mount point: driver letter only */
|
||||
UCHAR DrvLetter;
|
||||
|
||||
/* checking bitmap */
|
||||
BOOLEAN bCheckBitmap;
|
||||
|
||||
/* global hiding patterns */
|
||||
BOOLEAN bHidingPrefix;
|
||||
BOOLEAN bHidingSuffix;
|
||||
CHAR sHidingPrefix[HIDINGPAT_LEN];
|
||||
CHAR sHidingSuffix[HIDINGPAT_LEN];
|
||||
|
||||
} EXT2_VOLUME_PROPERTY2, *PEXT2_VOLUME_PROPERTY2;
|
||||
|
||||
#define EXT2_VPROP3_AUTOMOUNT (1ui64 << 0)
|
||||
#define EXT2_VPROP3_USERIDS (1ui64 << 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY3:EXT2_VOLUME_PROPERTY2 {
|
||||
#else // __cplusplus
|
||||
typedef struct _EXT2_VOLUME_PROPERTY3 {
|
||||
EXT2_VOLUME_PROPERTY2 ;
|
||||
#endif // __cplusplus
|
||||
unsigned __int64 Flags2;
|
||||
ULONG AutoMount:1;
|
||||
ULONG EIDS:1;
|
||||
ULONG Reserved1:30;
|
||||
USHORT uid;
|
||||
USHORT gid;
|
||||
USHORT euid;
|
||||
USHORT egid;
|
||||
ULONG Reserved2[29];
|
||||
} EXT2_VOLUME_PROPERTY3, *PEXT2_VOLUME_PROPERTY3;
|
||||
|
||||
/* Ext2Fsd driver version and built time */
|
||||
typedef struct _EXT2_VOLUME_PROPERTY_VERSION {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Command;
|
||||
CHAR Version[0x1C];
|
||||
CHAR Time[0x20];
|
||||
CHAR Date[0x20];
|
||||
} EXT2_VOLUME_PROPERTY_VERSION, *PEXT2_VOLUME_PROPERTY_VERSION;
|
||||
|
||||
/* performance statistics */
|
||||
#define EXT2_QUERY_PERFSTAT_MAGIC 'EVPM'
|
||||
#define EXT2_QUERY_PERFSTAT_VER2 0x8000000
|
||||
|
||||
typedef struct _EXT2_QUERY_PERFSTAT {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Command;
|
||||
union {
|
||||
EXT2_PERF_STATISTICS_V1 PerfStatV1;
|
||||
EXT2_PERF_STATISTICS_V2 PerfStatV2;
|
||||
};
|
||||
} EXT2_QUERY_PERFSTAT, *PEXT2_QUERY_PERFSTAT;
|
||||
|
||||
#define EXT2_QUERY_PERFSTAT_SZV1 (FIELD_OFFSET(EXT2_QUERY_PERFSTAT, PerfStatV1) + sizeof(EXT2_PERF_STATISTICS_V1))
|
||||
#define EXT2_QUERY_PERFSTAT_SZV2 (FIELD_OFFSET(EXT2_QUERY_PERFSTAT, PerfStatV1) + sizeof(EXT2_PERF_STATISTICS_V2))
|
||||
|
||||
/* mountpoint management */
|
||||
#define EXT2_APP_MOUNTPOINT_MAGIC 'EAMM'
|
||||
typedef struct _EXT2_MOUNT_POINT {
|
||||
ULONG Magic;
|
||||
ULONG Flags;
|
||||
ULONG Size;
|
||||
ULONG Command;
|
||||
USHORT Link[256];
|
||||
USHORT Name[256];
|
||||
} EXT2_MOUNT_POINT, *PEXT2_MOUNT_POINT;
|
||||
|
||||
#define APP_CMD_ADD_DOS_SYMLINK 0x00000001
|
||||
#define APP_CMD_DEL_DOS_SYMLINK 0x00000002
|
||||
|
||||
|
||||
#endif /* _EXT2_COMMON_INCLUDE_ */
|
||||
|
||||
@@ -1,155 +1,155 @@
|
||||
#ifndef _LINUX_ATOMIC_H
|
||||
#define _LINUX_ATOMIC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
//
|
||||
// atomic
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
volatile LONG counter;
|
||||
} atomic_t;
|
||||
|
||||
#define ATOMIC_INIT(i) (i)
|
||||
|
||||
/**
|
||||
* atomic_read - read atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically reads the value of @v. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
#define atomic_read(v) ((v)->counter)
|
||||
|
||||
/**
|
||||
* atomic_set - set atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
* @i: required value
|
||||
*
|
||||
* Atomically sets the value of @v to @i. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
#define atomic_set(v,i) InterlockedExchange((PLONG)(&(v)->counter), (LONG)(i))
|
||||
|
||||
/**
|
||||
* atomic_add - add integer to atomic variable
|
||||
* @i: integer value to add
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically adds @i to @v. Note that the guaranteed useful range
|
||||
* of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_add(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_sub - subtract the atomic variable
|
||||
* @i: integer value to subtract
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically subtracts @i from @v. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_sub(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) (-1*i));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_sub_and_test - subtract value from variable and test result
|
||||
* @i: integer value to subtract
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically subtracts @i from @v and returns
|
||||
* true if the result is zero, or false for all
|
||||
* other cases. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_sub_and_test(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
int counter, result;
|
||||
|
||||
do {
|
||||
|
||||
counter = v->counter;
|
||||
result = counter - i;
|
||||
|
||||
} while ( InterlockedCompareExchange(
|
||||
(PLONG) (&v->counter),
|
||||
(LONG) result,
|
||||
(LONG) counter) != counter);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_inc - increment atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically increments @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_inc(atomic_t volatile *v)
|
||||
{
|
||||
InterlockedIncrement((PLONG)(&v->counter));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_dec - decrement atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically decrements @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_dec(atomic_t volatile *v)
|
||||
{
|
||||
InterlockedDecrement((PLONG)(&v->counter));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_dec_and_test - decrement and test
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically decrements @v by 1 and
|
||||
* returns true if the result is 0, or false for all other
|
||||
* cases. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_dec_and_test(atomic_t volatile *v)
|
||||
{
|
||||
return (0 == InterlockedDecrement((PLONG)(&v->counter)));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_inc_and_test - increment and test
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically increments @v by 1
|
||||
* and returns true if the result is zero, or false for all
|
||||
* other cases. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_inc_and_test(atomic_t volatile *v)
|
||||
{
|
||||
return (0 == InterlockedIncrement((PLONG)(&v->counter)));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_add_negative - add and test if negative
|
||||
* @v: pointer of type atomic_t
|
||||
* @i: integer value to add
|
||||
*
|
||||
* Atomically adds @i to @v and returns true
|
||||
* if the result is negative, or false when
|
||||
* result is greater than or equal to zero. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_add_negative(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
return (InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i) + i);
|
||||
}
|
||||
|
||||
#ifndef _LINUX_ATOMIC_H
|
||||
#define _LINUX_ATOMIC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
//
|
||||
// atomic
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
volatile LONG counter;
|
||||
} atomic_t;
|
||||
|
||||
#define ATOMIC_INIT(i) (i)
|
||||
|
||||
/**
|
||||
* atomic_read - read atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically reads the value of @v. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
#define atomic_read(v) ((v)->counter)
|
||||
|
||||
/**
|
||||
* atomic_set - set atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
* @i: required value
|
||||
*
|
||||
* Atomically sets the value of @v to @i. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
#define atomic_set(v,i) InterlockedExchange((PLONG)(&(v)->counter), (LONG)(i))
|
||||
|
||||
/**
|
||||
* atomic_add - add integer to atomic variable
|
||||
* @i: integer value to add
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically adds @i to @v. Note that the guaranteed useful range
|
||||
* of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_add(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_sub - subtract the atomic variable
|
||||
* @i: integer value to subtract
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically subtracts @i from @v. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_sub(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) (-1*i));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_sub_and_test - subtract value from variable and test result
|
||||
* @i: integer value to subtract
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically subtracts @i from @v and returns
|
||||
* true if the result is zero, or false for all
|
||||
* other cases. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_sub_and_test(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
int counter, result;
|
||||
|
||||
do {
|
||||
|
||||
counter = v->counter;
|
||||
result = counter - i;
|
||||
|
||||
} while ( InterlockedCompareExchange(
|
||||
(PLONG) (&v->counter),
|
||||
(LONG) result,
|
||||
(LONG) counter) != counter);
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_inc - increment atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically increments @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_inc(atomic_t volatile *v)
|
||||
{
|
||||
InterlockedIncrement((PLONG)(&v->counter));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_dec - decrement atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically decrements @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline void atomic_dec(atomic_t volatile *v)
|
||||
{
|
||||
InterlockedDecrement((PLONG)(&v->counter));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_dec_and_test - decrement and test
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically decrements @v by 1 and
|
||||
* returns true if the result is 0, or false for all other
|
||||
* cases. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_dec_and_test(atomic_t volatile *v)
|
||||
{
|
||||
return (0 == InterlockedDecrement((PLONG)(&v->counter)));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_inc_and_test - increment and test
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically increments @v by 1
|
||||
* and returns true if the result is zero, or false for all
|
||||
* other cases. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_inc_and_test(atomic_t volatile *v)
|
||||
{
|
||||
return (0 == InterlockedIncrement((PLONG)(&v->counter)));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_add_negative - add and test if negative
|
||||
* @v: pointer of type atomic_t
|
||||
* @i: integer value to add
|
||||
*
|
||||
* Atomically adds @i to @v and returns true
|
||||
* if the result is negative, or false when
|
||||
* result is greater than or equal to zero. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static inline int atomic_add_negative(int volatile i, atomic_t volatile *v)
|
||||
{
|
||||
return (InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i) + i);
|
||||
}
|
||||
|
||||
#endif /* LINUX_ATOMIC_H */
|
||||
@@ -1,95 +1,95 @@
|
||||
#ifndef __LINUX_BIT_SPINLOCK_H
|
||||
#define __LINUX_BIT_SPINLOCK_H
|
||||
|
||||
/*
|
||||
* bit-based spin_lock()
|
||||
*
|
||||
* Don't use this unless you really need to: spin_lock() and spin_unlock()
|
||||
* are significantly faster.
|
||||
*/
|
||||
static inline void bit_spin_lock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
/*
|
||||
* Assuming the lock is uncontended, this never enters
|
||||
* the body of the outer loop. If it is contended, then
|
||||
* within the inner loop a non-atomic test is used to
|
||||
* busywait with less bus contention for a good time to
|
||||
* attempt to acquire the lock bit.
|
||||
*/
|
||||
preempt_disable();
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
|
||||
while (test_bit(bitnum, addr)) {
|
||||
preempt_enable();
|
||||
cpu_relax();
|
||||
preempt_disable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
__acquire(bitlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if it was acquired
|
||||
*/
|
||||
static inline int bit_spin_trylock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
preempt_disable();
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
if (unlikely(test_and_set_bit_lock(bitnum, addr))) {
|
||||
preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
__acquire(bitlock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* bit-based spin_unlock()
|
||||
*/
|
||||
static inline void bit_spin_unlock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
||||
BUG_ON(!test_bit(bitnum, addr));
|
||||
#endif
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
clear_bit_unlock(bitnum, addr);
|
||||
#endif
|
||||
preempt_enable();
|
||||
__release(bitlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* bit-based spin_unlock()
|
||||
* non-atomic version, which can be used eg. if the bit lock itself is
|
||||
* protecting the rest of the flags in the word.
|
||||
*/
|
||||
static inline void __bit_spin_unlock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
||||
BUG_ON(!test_bit(bitnum, addr));
|
||||
#endif
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
__clear_bit_unlock(bitnum, addr);
|
||||
#endif
|
||||
preempt_enable();
|
||||
__release(bitlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the lock is held.
|
||||
*/
|
||||
static inline int bit_spin_is_locked(int bitnum, unsigned long *addr)
|
||||
{
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
return test_bit(bitnum, addr);
|
||||
#elif defined CONFIG_PREEMPT
|
||||
return preempt_count();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __LINUX_BIT_SPINLOCK_H */
|
||||
|
||||
#ifndef __LINUX_BIT_SPINLOCK_H
|
||||
#define __LINUX_BIT_SPINLOCK_H
|
||||
|
||||
/*
|
||||
* bit-based spin_lock()
|
||||
*
|
||||
* Don't use this unless you really need to: spin_lock() and spin_unlock()
|
||||
* are significantly faster.
|
||||
*/
|
||||
static inline void bit_spin_lock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
/*
|
||||
* Assuming the lock is uncontended, this never enters
|
||||
* the body of the outer loop. If it is contended, then
|
||||
* within the inner loop a non-atomic test is used to
|
||||
* busywait with less bus contention for a good time to
|
||||
* attempt to acquire the lock bit.
|
||||
*/
|
||||
preempt_disable();
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
|
||||
while (test_bit(bitnum, addr)) {
|
||||
preempt_enable();
|
||||
cpu_relax();
|
||||
preempt_disable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
__acquire(bitlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if it was acquired
|
||||
*/
|
||||
static inline int bit_spin_trylock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
preempt_disable();
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
if (unlikely(test_and_set_bit_lock(bitnum, addr))) {
|
||||
preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
__acquire(bitlock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* bit-based spin_unlock()
|
||||
*/
|
||||
static inline void bit_spin_unlock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
||||
BUG_ON(!test_bit(bitnum, addr));
|
||||
#endif
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
clear_bit_unlock(bitnum, addr);
|
||||
#endif
|
||||
preempt_enable();
|
||||
__release(bitlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* bit-based spin_unlock()
|
||||
* non-atomic version, which can be used eg. if the bit lock itself is
|
||||
* protecting the rest of the flags in the word.
|
||||
*/
|
||||
static inline void __bit_spin_unlock(int bitnum, unsigned long *addr)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
||||
BUG_ON(!test_bit(bitnum, addr));
|
||||
#endif
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
__clear_bit_unlock(bitnum, addr);
|
||||
#endif
|
||||
preempt_enable();
|
||||
__release(bitlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the lock is held.
|
||||
*/
|
||||
static inline int bit_spin_is_locked(int bitnum, unsigned long *addr)
|
||||
{
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
return test_bit(bitnum, addr);
|
||||
#elif defined CONFIG_PREEMPT
|
||||
return preempt_count();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __LINUX_BIT_SPINLOCK_H */
|
||||
|
||||
|
||||
@@ -1,280 +1,280 @@
|
||||
#ifndef _LINUX_BITOPS_H
|
||||
#define _LINUX_BITOPS_H
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define BIT(nr) (1 << (nr))
|
||||
#define BIT_MASK(nr) (1 << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG)
|
||||
#define BITS_PER_BYTE 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Include this here because some architectures need generic_ffs/fls in
|
||||
* scope
|
||||
*/
|
||||
|
||||
/**
|
||||
* find_first_zero_bit - find the first zero bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first zero bit, not the number of the byte
|
||||
* containing a bit.
|
||||
*/
|
||||
#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
|
||||
|
||||
/**
|
||||
* find_next_zero_bit - find the first zero bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
* @offset: The bit number to start searching at
|
||||
* @size: The maximum size to search
|
||||
*/
|
||||
int find_next_zero_bit(const unsigned long *addr, int size, int offset);
|
||||
|
||||
/**
|
||||
* __ffs - find first bit in word.
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static inline unsigned long __ffs(unsigned long word)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
if ((word & 0xffffffff) == 0) {
|
||||
num += 32;
|
||||
word >>= 32;
|
||||
}
|
||||
#endif
|
||||
if ((word & 0xffff) == 0) {
|
||||
num += 16;
|
||||
word >>= 16;
|
||||
}
|
||||
if ((word & 0xff) == 0) {
|
||||
num += 8;
|
||||
word >>= 8;
|
||||
}
|
||||
if ((word & 0xf) == 0) {
|
||||
num += 4;
|
||||
word >>= 4;
|
||||
}
|
||||
if ((word & 0x3) == 0) {
|
||||
num += 2;
|
||||
word >>= 2;
|
||||
}
|
||||
if ((word & 0x1) == 0)
|
||||
num += 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_first_bit - find the first set bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first set bit, not the number of the byte
|
||||
* containing a bit.
|
||||
*/
|
||||
static inline unsigned find_first_bit(const unsigned long *addr, unsigned size)
|
||||
{
|
||||
unsigned x = 0;
|
||||
|
||||
while (x < size) {
|
||||
unsigned long val = *addr++;
|
||||
if (val)
|
||||
return __ffs(val) + x;
|
||||
x += (sizeof(*addr)<<3);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_next_bit - find the next set bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
* @offset: The bitnumber to start searching at
|
||||
* @size: The maximum size to search
|
||||
*/
|
||||
|
||||
/*
|
||||
* ffz - find first zero in word.
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||
*/
|
||||
#define ffz(x) __ffs(~(x))
|
||||
|
||||
|
||||
/**
|
||||
* ffs - find first bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as
|
||||
* the libc and compiler builtin ffs routines, therefore
|
||||
* differs in spirit from the above ffz (man ffs).
|
||||
*/
|
||||
static inline int ffs(int x)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fls - find last (most-significant) bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as ffs.
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
|
||||
static inline int fls(int x)
|
||||
{
|
||||
int r = 32;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff0000u)) {
|
||||
x <<= 16;
|
||||
r -= 16;
|
||||
}
|
||||
if (!(x & 0xff000000u)) {
|
||||
x <<= 8;
|
||||
r -= 8;
|
||||
}
|
||||
if (!(x & 0xf0000000u)) {
|
||||
x <<= 4;
|
||||
r -= 4;
|
||||
}
|
||||
if (!(x & 0xc0000000u)) {
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int fls64(__u64 x)
|
||||
{
|
||||
__u32 h = (__u32) (x >> 32);
|
||||
if (h)
|
||||
return fls(h) + 32;
|
||||
return fls((int)x);
|
||||
}
|
||||
|
||||
#define for_each_bit(bit, addr, size) \
|
||||
for ((bit) = find_first_bit((addr), (size)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_bit((addr), (size), (bit) + 1))
|
||||
|
||||
|
||||
static __inline int get_bitmask_order(unsigned int count)
|
||||
{
|
||||
int order;
|
||||
|
||||
order = fls(count);
|
||||
return order; /* We could be slightly more clever with -1 here... */
|
||||
}
|
||||
|
||||
static __inline int get_count_order(unsigned int count)
|
||||
{
|
||||
int order;
|
||||
|
||||
order = fls(count) - 1;
|
||||
if (count & (count - 1))
|
||||
order++;
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rol32 - rotate a 32-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline __u32 rol32(__u32 word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> (32 - shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror32 - rotate a 32-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline __u32 ror32(__u32 word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (32 - shift));
|
||||
}
|
||||
|
||||
static inline unsigned fls_long(unsigned long l)
|
||||
{
|
||||
if (sizeof(l) == 4)
|
||||
return fls(l);
|
||||
return fls64(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* hweightN: returns the hamming weight (i.e. the number
|
||||
* of bits set) of a N-bit word
|
||||
*/
|
||||
|
||||
static inline unsigned long hweight32(unsigned long w)
|
||||
{
|
||||
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
|
||||
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
|
||||
res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
|
||||
res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
|
||||
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
static inline unsigned long hweight64(__u64 w)
|
||||
{
|
||||
#if BITS_PER_LONG < 64
|
||||
return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
|
||||
#else
|
||||
u64 res;
|
||||
res = (w & 0x5555555555555555U) + ((w >> 1) & 0x5555555555555555U);
|
||||
res = (res & 0x3333333333333333U) + ((res >> 2) & 0x3333333333333333U);
|
||||
res = (res & 0x0F0F0F0F0F0F0F0FU) + ((res >> 4) & 0x0F0F0F0F0F0F0F0FU);
|
||||
res = (res & 0x00FF00FF00FF00FFU) + ((res >> 8) & 0x00FF00FF00FF00FFU);
|
||||
res = (res & 0x0000FFFF0000FFFFU) + ((res >> 16) & 0x0000FFFF0000FFFFU);
|
||||
return (res & 0x00000000FFFFFFFFU) + ((res >> 32) & 0x00000000FFFFFFFFU);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long hweight_long(unsigned long w)
|
||||
{
|
||||
return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef _LINUX_BITOPS_H
|
||||
#define _LINUX_BITOPS_H
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define BIT(nr) (1 << (nr))
|
||||
#define BIT_MASK(nr) (1 << ((nr) % BITS_PER_LONG))
|
||||
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG)
|
||||
#define BITS_PER_BYTE 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Include this here because some architectures need generic_ffs/fls in
|
||||
* scope
|
||||
*/
|
||||
|
||||
/**
|
||||
* find_first_zero_bit - find the first zero bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first zero bit, not the number of the byte
|
||||
* containing a bit.
|
||||
*/
|
||||
#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
|
||||
|
||||
/**
|
||||
* find_next_zero_bit - find the first zero bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
* @offset: The bit number to start searching at
|
||||
* @size: The maximum size to search
|
||||
*/
|
||||
int find_next_zero_bit(const unsigned long *addr, int size, int offset);
|
||||
|
||||
/**
|
||||
* __ffs - find first bit in word.
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static inline unsigned long __ffs(unsigned long word)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
if ((word & 0xffffffff) == 0) {
|
||||
num += 32;
|
||||
word >>= 32;
|
||||
}
|
||||
#endif
|
||||
if ((word & 0xffff) == 0) {
|
||||
num += 16;
|
||||
word >>= 16;
|
||||
}
|
||||
if ((word & 0xff) == 0) {
|
||||
num += 8;
|
||||
word >>= 8;
|
||||
}
|
||||
if ((word & 0xf) == 0) {
|
||||
num += 4;
|
||||
word >>= 4;
|
||||
}
|
||||
if ((word & 0x3) == 0) {
|
||||
num += 2;
|
||||
word >>= 2;
|
||||
}
|
||||
if ((word & 0x1) == 0)
|
||||
num += 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_first_bit - find the first set bit in a memory region
|
||||
* @addr: The address to start the search at
|
||||
* @size: The maximum size to search
|
||||
*
|
||||
* Returns the bit number of the first set bit, not the number of the byte
|
||||
* containing a bit.
|
||||
*/
|
||||
static inline unsigned find_first_bit(const unsigned long *addr, unsigned size)
|
||||
{
|
||||
unsigned x = 0;
|
||||
|
||||
while (x < size) {
|
||||
unsigned long val = *addr++;
|
||||
if (val)
|
||||
return __ffs(val) + x;
|
||||
x += (sizeof(*addr)<<3);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_next_bit - find the next set bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
* @offset: The bitnumber to start searching at
|
||||
* @size: The maximum size to search
|
||||
*/
|
||||
|
||||
/*
|
||||
* ffz - find first zero in word.
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||
*/
|
||||
#define ffz(x) __ffs(~(x))
|
||||
|
||||
|
||||
/**
|
||||
* ffs - find first bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as
|
||||
* the libc and compiler builtin ffs routines, therefore
|
||||
* differs in spirit from the above ffz (man ffs).
|
||||
*/
|
||||
static inline int ffs(int x)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* fls - find last (most-significant) bit set
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as ffs.
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
|
||||
static inline int fls(int x)
|
||||
{
|
||||
int r = 32;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff0000u)) {
|
||||
x <<= 16;
|
||||
r -= 16;
|
||||
}
|
||||
if (!(x & 0xff000000u)) {
|
||||
x <<= 8;
|
||||
r -= 8;
|
||||
}
|
||||
if (!(x & 0xf0000000u)) {
|
||||
x <<= 4;
|
||||
r -= 4;
|
||||
}
|
||||
if (!(x & 0xc0000000u)) {
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int fls64(__u64 x)
|
||||
{
|
||||
__u32 h = (__u32) (x >> 32);
|
||||
if (h)
|
||||
return fls(h) + 32;
|
||||
return fls((int)x);
|
||||
}
|
||||
|
||||
#define for_each_bit(bit, addr, size) \
|
||||
for ((bit) = find_first_bit((addr), (size)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_bit((addr), (size), (bit) + 1))
|
||||
|
||||
|
||||
static __inline int get_bitmask_order(unsigned int count)
|
||||
{
|
||||
int order;
|
||||
|
||||
order = fls(count);
|
||||
return order; /* We could be slightly more clever with -1 here... */
|
||||
}
|
||||
|
||||
static __inline int get_count_order(unsigned int count)
|
||||
{
|
||||
int order;
|
||||
|
||||
order = fls(count) - 1;
|
||||
if (count & (count - 1))
|
||||
order++;
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rol32 - rotate a 32-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline __u32 rol32(__u32 word, unsigned int shift)
|
||||
{
|
||||
return (word << shift) | (word >> (32 - shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror32 - rotate a 32-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline __u32 ror32(__u32 word, unsigned int shift)
|
||||
{
|
||||
return (word >> shift) | (word << (32 - shift));
|
||||
}
|
||||
|
||||
static inline unsigned fls_long(unsigned long l)
|
||||
{
|
||||
if (sizeof(l) == 4)
|
||||
return fls(l);
|
||||
return fls64(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* hweightN: returns the hamming weight (i.e. the number
|
||||
* of bits set) of a N-bit word
|
||||
*/
|
||||
|
||||
static inline unsigned long hweight32(unsigned long w)
|
||||
{
|
||||
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
|
||||
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
|
||||
res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
|
||||
res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
|
||||
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
static inline unsigned long hweight64(__u64 w)
|
||||
{
|
||||
#if BITS_PER_LONG < 64
|
||||
return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
|
||||
#else
|
||||
u64 res;
|
||||
res = (w & 0x5555555555555555U) + ((w >> 1) & 0x5555555555555555U);
|
||||
res = (res & 0x3333333333333333U) + ((res >> 2) & 0x3333333333333333U);
|
||||
res = (res & 0x0F0F0F0F0F0F0F0FU) + ((res >> 4) & 0x0F0F0F0F0F0F0F0FU);
|
||||
res = (res & 0x00FF00FF00FF00FFU) + ((res >> 8) & 0x00FF00FF00FF00FFU);
|
||||
res = (res & 0x0000FFFF0000FFFFU) + ((res >> 16) & 0x0000FFFF0000FFFFU);
|
||||
return (res & 0x00000000FFFFFFFFU) + ((res >> 32) & 0x00000000FFFFFFFFU);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long hweight_long(unsigned long w)
|
||||
{
|
||||
return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef LINUX_CONFIG_H
|
||||
#define LINUX_CONFIG_H
|
||||
|
||||
#define EXT2_HTREE_INDEX 1
|
||||
//#undef EXT2_HTREE_INDEX
|
||||
|
||||
#ifndef LINUX_CONFIG_H
|
||||
#define LINUX_CONFIG_H
|
||||
|
||||
#define EXT2_HTREE_INDEX 1
|
||||
//#undef EXT2_HTREE_INDEX
|
||||
|
||||
#endif /* LINUX_CONFIG_H */
|
||||
@@ -1,147 +1,147 @@
|
||||
#ifndef _I386_ERRNO_H
|
||||
#define _I386_ERRNO_H
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Arg list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
#define ENOMSG 42 /* No message of desired type */
|
||||
#define EIDRM 43 /* Identifier removed */
|
||||
#define ECHRNG 44 /* Channel number out of range */
|
||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||
#define EL3HLT 46 /* Level 3 halted */
|
||||
#define EL3RST 47 /* Level 3 reset */
|
||||
#define ELNRNG 48 /* Link number out of range */
|
||||
#define EUNATCH 49 /* Protocol driver not attached */
|
||||
#define ENOCSI 50 /* No CSI structure available */
|
||||
#define EL2HLT 51 /* Level 2 halted */
|
||||
#define EBADE 52 /* Invalid exchange */
|
||||
#define EBADR 53 /* Invalid request descriptor */
|
||||
#define EXFULL 54 /* Exchange full */
|
||||
#define ENOANO 55 /* No anode */
|
||||
#define EBADRQC 56 /* Invalid request code */
|
||||
#define EBADSLT 57 /* Invalid slot */
|
||||
|
||||
#define EDEADLOCK EDEADLK
|
||||
|
||||
#define EBFONT 59 /* Bad font file format */
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data available */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* Object is remote */
|
||||
#define ENOLINK 67 /* Link has been severed */
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 72 /* Multihop attempted */
|
||||
#define EDOTDOT 73 /* RFS specific error */
|
||||
#define EBADMSG 74 /* Not a data message */
|
||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EREMCHG 78 /* Remote address changed */
|
||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||
#define ESTRPIPE 86 /* Streams pipe error */
|
||||
#define EUSERS 87 /* Too many users */
|
||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||
#define EDESTADDRREQ 89 /* Destination address required */
|
||||
#define EMSGSIZE 90 /* Message too long */
|
||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||
#define EADDRINUSE 98 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#define ENETDOWN 100 /* Network is down */
|
||||
#define ENETUNREACH 101 /* Network is unreachable */
|
||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||
#define ETIMEDOUT 110 /* Connection timed out */
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EHOSTDOWN 112 /* Host is down */
|
||||
#define EHOSTUNREACH 113 /* No route to host */
|
||||
#define EALREADY 114 /* Operation already in progress */
|
||||
#define EINPROGRESS 115 /* Operation now in progress */
|
||||
#define ESTALE 116 /* Stale NFS file handle */
|
||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||
#define EISNAM 120 /* Is a named type file */
|
||||
#define EREMOTEIO 121 /* Remote I/O error */
|
||||
#define EDQUOT 122 /* Quota exceeded */
|
||||
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
|
||||
/* Should never be seen by user programs */
|
||||
#define ERESTARTSYS 512
|
||||
#define ERESTARTNOINTR 513
|
||||
#define ERESTARTNOHAND 514 /* restart if no handler.. */
|
||||
#define ENOIOCTLCMD 515 /* No ioctl command */
|
||||
|
||||
/* Defined for the NFSv3 protocol */
|
||||
#define EBADHANDLE 521 /* Illegal NFS file handle */
|
||||
#define ENOTSYNC 522 /* Update synchronization mismatch */
|
||||
#define EBADCOOKIE 523 /* Cookie is stale */
|
||||
#define ENOTSUPP 524 /* Operation is not supported */
|
||||
#define ETOOSMALL 525 /* Buffer or request is too small */
|
||||
#define ESERVERFAULT 526 /* An untranslatable error occurred */
|
||||
#define EBADTYPE 527 /* Type not supported by server */
|
||||
#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
|
||||
#if _MSC_VER > 1900
|
||||
#define ENAMETOOLONG 1024;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#ifndef _I386_ERRNO_H
|
||||
#define _I386_ERRNO_H
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Arg list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
#define ENOMSG 42 /* No message of desired type */
|
||||
#define EIDRM 43 /* Identifier removed */
|
||||
#define ECHRNG 44 /* Channel number out of range */
|
||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||
#define EL3HLT 46 /* Level 3 halted */
|
||||
#define EL3RST 47 /* Level 3 reset */
|
||||
#define ELNRNG 48 /* Link number out of range */
|
||||
#define EUNATCH 49 /* Protocol driver not attached */
|
||||
#define ENOCSI 50 /* No CSI structure available */
|
||||
#define EL2HLT 51 /* Level 2 halted */
|
||||
#define EBADE 52 /* Invalid exchange */
|
||||
#define EBADR 53 /* Invalid request descriptor */
|
||||
#define EXFULL 54 /* Exchange full */
|
||||
#define ENOANO 55 /* No anode */
|
||||
#define EBADRQC 56 /* Invalid request code */
|
||||
#define EBADSLT 57 /* Invalid slot */
|
||||
|
||||
#define EDEADLOCK EDEADLK
|
||||
|
||||
#define EBFONT 59 /* Bad font file format */
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data available */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* Object is remote */
|
||||
#define ENOLINK 67 /* Link has been severed */
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 72 /* Multihop attempted */
|
||||
#define EDOTDOT 73 /* RFS specific error */
|
||||
#define EBADMSG 74 /* Not a data message */
|
||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EREMCHG 78 /* Remote address changed */
|
||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||
#define ESTRPIPE 86 /* Streams pipe error */
|
||||
#define EUSERS 87 /* Too many users */
|
||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||
#define EDESTADDRREQ 89 /* Destination address required */
|
||||
#define EMSGSIZE 90 /* Message too long */
|
||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||
#define EADDRINUSE 98 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#define ENETDOWN 100 /* Network is down */
|
||||
#define ENETUNREACH 101 /* Network is unreachable */
|
||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||
#define ETIMEDOUT 110 /* Connection timed out */
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EHOSTDOWN 112 /* Host is down */
|
||||
#define EHOSTUNREACH 113 /* No route to host */
|
||||
#define EALREADY 114 /* Operation already in progress */
|
||||
#define EINPROGRESS 115 /* Operation now in progress */
|
||||
#define ESTALE 116 /* Stale NFS file handle */
|
||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||
#define EISNAM 120 /* Is a named type file */
|
||||
#define EREMOTEIO 121 /* Remote I/O error */
|
||||
#define EDQUOT 122 /* Quota exceeded */
|
||||
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
|
||||
/* Should never be seen by user programs */
|
||||
#define ERESTARTSYS 512
|
||||
#define ERESTARTNOINTR 513
|
||||
#define ERESTARTNOHAND 514 /* restart if no handler.. */
|
||||
#define ENOIOCTLCMD 515 /* No ioctl command */
|
||||
|
||||
/* Defined for the NFSv3 protocol */
|
||||
#define EBADHANDLE 521 /* Illegal NFS file handle */
|
||||
#define ENOTSYNC 522 /* Update synchronization mismatch */
|
||||
#define EBADCOOKIE 523 /* Cookie is stale */
|
||||
#define ENOTSUPP 524 /* Operation is not supported */
|
||||
#define ETOOSMALL 525 /* Buffer or request is too small */
|
||||
#define ESERVERFAULT 526 /* An untranslatable error occurred */
|
||||
#define EBADTYPE 527 /* Type not supported by server */
|
||||
#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */
|
||||
#if _MSC_VER > 1900
|
||||
#define ENAMETOOLONG 1024;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,257 +1,257 @@
|
||||
#ifndef _LINUX_EXT4_EXT
|
||||
#define _LINUX_EXT4_EXT
|
||||
|
||||
/*
|
||||
* This is the extent tail on-disk structure.
|
||||
* All other extent structures are 12 bytes long. It turns out that
|
||||
* block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
|
||||
* covers all valid ext4 block sizes. Therefore, this tail structure can be
|
||||
* crammed into the end of the block without having to rebalance the tree.
|
||||
*/
|
||||
struct ext4_extent_tail {
|
||||
uint32_t et_checksum; /* crc32c(uuid+inum+extent_block) */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the extent on-disk structure.
|
||||
* It's used at the bottom of the tree.
|
||||
*/
|
||||
typedef struct ext4_extent {
|
||||
uint32_t ee_block; /* first logical block extent covers */
|
||||
uint16_t ee_len; /* number of blocks covered by extent */
|
||||
uint16_t ee_start_hi; /* high 16 bits of physical block */
|
||||
uint32_t ee_start_lo; /* low 32 bits of physical block */
|
||||
} __attribute__ ((__packed__)) EXT4_EXTENT;
|
||||
|
||||
/*
|
||||
* This is index on-disk structure.
|
||||
* It's used at all the levels except the bottom.
|
||||
*/
|
||||
typedef struct ext4_extent_idx {
|
||||
uint32_t ei_block; /* index covers logical blocks from 'block' */
|
||||
uint32_t ei_leaf_lo; /* pointer to the physical block of the next *
|
||||
* level. leaf or next index could be there */
|
||||
uint16_t ei_leaf_hi; /* high 16 bits of physical block */
|
||||
uint16_t ei_unused;
|
||||
}__attribute__ ((__packed__)) EXT4_EXTENT_IDX;
|
||||
|
||||
/*
|
||||
* Each block (leaves and indexes), even inode-stored has header.
|
||||
*/
|
||||
typedef struct ext4_extent_header {
|
||||
uint16_t eh_magic; /* probably will support different formats */
|
||||
uint16_t eh_entries; /* number of valid entries */
|
||||
uint16_t eh_max; /* capacity of store in entries */
|
||||
uint16_t eh_depth; /* has tree real underlying blocks? */
|
||||
uint32_t eh_generation; /* generation of the tree */
|
||||
}__attribute__ ((__packed__)) EXT4_EXTENT_HEADER;
|
||||
|
||||
|
||||
#define EXT4_EXT_MAGIC 0xf30a
|
||||
#define get_ext4_header(i) ((struct ext4_extent_header *) (i)->i_block)
|
||||
|
||||
#define EXT4_EXTENT_TAIL_OFFSET(hdr) \
|
||||
(sizeof(struct ext4_extent_header) + \
|
||||
(sizeof(struct ext4_extent) * (hdr)->eh_max))
|
||||
|
||||
static inline struct ext4_extent_tail *
|
||||
find_ext4_extent_tail(struct ext4_extent_header *eh)
|
||||
{
|
||||
return (struct ext4_extent_tail *)(((char *)eh) +
|
||||
EXT4_EXTENT_TAIL_OFFSET(eh));
|
||||
}
|
||||
|
||||
/*
|
||||
* Array of ext4_ext_path contains path to some extent.
|
||||
* Creation/lookup routines use it for traversal/splitting/etc.
|
||||
* Truncate uses it to simulate recursive walking.
|
||||
*/
|
||||
struct ext4_ext_path
|
||||
{
|
||||
ext4_fsblk_t p_block;
|
||||
int p_depth;
|
||||
int p_maxdepth;
|
||||
struct ext4_extent *p_ext;
|
||||
struct ext4_extent_idx *p_idx;
|
||||
struct ext4_extent_header *p_hdr;
|
||||
struct buffer_head *p_bh;
|
||||
};
|
||||
|
||||
/*
|
||||
* structure for external API
|
||||
*/
|
||||
|
||||
/*
|
||||
* EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
* initialized extent. This is 2^15 and not (2^16 - 1), since we use the
|
||||
* MSB of ee_len field in the extent datastructure to signify if this
|
||||
* particular extent is an initialized extent or an uninitialized (i.e.
|
||||
* preallocated).
|
||||
* EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
* uninitialized extent.
|
||||
* If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
|
||||
* uninitialized one. In other words, if MSB of ee_len is set, it is an
|
||||
* uninitialized extent with only one special scenario when ee_len = 0x8000.
|
||||
* In this case we can not have an uninitialized extent of zero length and
|
||||
* thus we make it as a special case of initialized extent with 0x8000 length.
|
||||
* This way we get better extent-to-group alignment for initialized extents.
|
||||
* Hence, the maximum number of blocks we can have in an *initialized*
|
||||
* extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
|
||||
*/
|
||||
#define EXT_INIT_MAX_LEN (1UL << 15)
|
||||
#define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1)
|
||||
|
||||
#define EXT_EXTENT_SIZE sizeof(struct ext4_extent)
|
||||
#define EXT_INDEX_SIZE sizeof(struct ext4_extent_idx)
|
||||
|
||||
#define EXT_FIRST_EXTENT(__hdr__) \
|
||||
((struct ext4_extent *)(((char *)(__hdr__)) + \
|
||||
sizeof(struct ext4_extent_header)))
|
||||
#define EXT_FIRST_INDEX(__hdr__) \
|
||||
((struct ext4_extent_idx *)(((char *)(__hdr__)) + \
|
||||
sizeof(struct ext4_extent_header)))
|
||||
#define EXT_HAS_FREE_INDEX(__path__) \
|
||||
((__path__)->p_hdr->eh_entries < (__path__)->p_hdr->eh_max)
|
||||
#define EXT_LAST_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_entries - 1)
|
||||
#define EXT_LAST_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_entries - 1)
|
||||
#define EXT_MAX_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_max - 1)
|
||||
#define EXT_MAX_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_max - 1)
|
||||
|
||||
static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
|
||||
{
|
||||
return get_ext4_header(inode);
|
||||
}
|
||||
|
||||
static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh)
|
||||
{
|
||||
return (struct ext4_extent_header *)bh->b_data;
|
||||
}
|
||||
|
||||
static inline unsigned short ext_depth(struct inode *inode)
|
||||
{
|
||||
return ext_inode_hdr(inode)->eh_depth;
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
|
||||
{
|
||||
/* We can not have an uninitialized extent of zero length! */
|
||||
ext->ee_len |= EXT_INIT_MAX_LEN;
|
||||
}
|
||||
|
||||
static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
|
||||
{
|
||||
/* Extent with ee_len of 0x8000 is treated as an initialized extent */
|
||||
return (ext->ee_len > EXT_INIT_MAX_LEN);
|
||||
}
|
||||
|
||||
static inline uint16_t ext4_ext_get_actual_len(struct ext4_extent *ext)
|
||||
{
|
||||
return (ext->ee_len <= EXT_INIT_MAX_LEN
|
||||
? ext->ee_len
|
||||
: (ext->ee_len - EXT_INIT_MAX_LEN));
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_initialized(struct ext4_extent *ext)
|
||||
{
|
||||
ext->ee_len = ext4_ext_get_actual_len(ext);
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext)
|
||||
{
|
||||
/* We can not have an unwritten extent of zero length! */
|
||||
ext->ee_len |= EXT_INIT_MAX_LEN;
|
||||
}
|
||||
|
||||
static inline int ext4_ext_is_unwritten(struct ext4_extent *ext)
|
||||
{
|
||||
/* Extent with ee_len of 0x8000 is treated as an initialized extent */
|
||||
return (ext->ee_len > EXT_INIT_MAX_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_pblock:
|
||||
* combine low and high parts of physical block number into ext4_fsblk_t
|
||||
*/
|
||||
static inline ext4_fsblk_t ext4_ext_pblock(struct ext4_extent *ex)
|
||||
{
|
||||
ext4_fsblk_t block;
|
||||
|
||||
block = ex->ee_start_lo;
|
||||
block |= ((ext4_fsblk_t)ex->ee_start_hi << 31) << 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_idx_pblock:
|
||||
* combine low and high parts of a leaf physical block number into ext4_fsblk_t
|
||||
*/
|
||||
static inline ext4_fsblk_t ext4_idx_pblock(struct ext4_extent_idx *ix)
|
||||
{
|
||||
ext4_fsblk_t block;
|
||||
|
||||
block = ix->ei_leaf_lo;
|
||||
block |= ((ext4_fsblk_t)ix->ei_leaf_hi << 31) << 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_store_pblock:
|
||||
* stores a large physical block number into an extent struct,
|
||||
* breaking it into parts
|
||||
*/
|
||||
static inline void ext4_ext_store_pblock(struct ext4_extent *ex,
|
||||
ext4_fsblk_t pb)
|
||||
{
|
||||
ex->ee_start_lo = (uint32_t)(pb & 0xffffffff);
|
||||
ex->ee_start_hi = (uint16_t)((pb >> 31) >> 1) & 0xffff;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_idx_store_pblock:
|
||||
* stores a large physical block number into an index struct,
|
||||
* breaking it into parts
|
||||
*/
|
||||
static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix,
|
||||
ext4_fsblk_t pb)
|
||||
{
|
||||
ix->ei_leaf_lo = (uint32_t)(pb & 0xffffffff);
|
||||
ix->ei_leaf_hi = (uint16_t)((pb >> 31) >> 1) & 0xffff;
|
||||
}
|
||||
|
||||
#define ext4_ext_dirty(icb, handle, inode, path) \
|
||||
__ext4_ext_dirty("", __LINE__, (icb), (handle), (inode), (path))
|
||||
|
||||
#define INODE_HAS_EXTENT(i) ((i)->i_flags & EXT2_EXTENTS_FL)
|
||||
|
||||
static inline uint64_t ext_to_block(EXT4_EXTENT *extent)
|
||||
{
|
||||
uint64_t block;
|
||||
|
||||
block = (uint64_t)extent->ee_start_lo;
|
||||
block |= ((uint64_t) extent->ee_start_hi << 31) << 1;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static inline uint64_t idx_to_block(EXT4_EXTENT_IDX *idx)
|
||||
{
|
||||
uint64_t block;
|
||||
|
||||
block = (uint64_t)idx->ei_leaf_lo;
|
||||
block |= ((uint64_t) idx->ei_leaf_hi << 31) << 1;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_fsblk_t iblock,
|
||||
unsigned long max_blocks, struct buffer_head *bh_result,
|
||||
int create, int flags);
|
||||
int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode);
|
||||
int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start);
|
||||
|
||||
#endif /* _LINUX_EXT4_EXT */
|
||||
#ifndef _LINUX_EXT4_EXT
|
||||
#define _LINUX_EXT4_EXT
|
||||
|
||||
/*
|
||||
* This is the extent tail on-disk structure.
|
||||
* All other extent structures are 12 bytes long. It turns out that
|
||||
* block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
|
||||
* covers all valid ext4 block sizes. Therefore, this tail structure can be
|
||||
* crammed into the end of the block without having to rebalance the tree.
|
||||
*/
|
||||
struct ext4_extent_tail {
|
||||
uint32_t et_checksum; /* crc32c(uuid+inum+extent_block) */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the extent on-disk structure.
|
||||
* It's used at the bottom of the tree.
|
||||
*/
|
||||
typedef struct ext4_extent {
|
||||
uint32_t ee_block; /* first logical block extent covers */
|
||||
uint16_t ee_len; /* number of blocks covered by extent */
|
||||
uint16_t ee_start_hi; /* high 16 bits of physical block */
|
||||
uint32_t ee_start_lo; /* low 32 bits of physical block */
|
||||
} __attribute__ ((__packed__)) EXT4_EXTENT;
|
||||
|
||||
/*
|
||||
* This is index on-disk structure.
|
||||
* It's used at all the levels except the bottom.
|
||||
*/
|
||||
typedef struct ext4_extent_idx {
|
||||
uint32_t ei_block; /* index covers logical blocks from 'block' */
|
||||
uint32_t ei_leaf_lo; /* pointer to the physical block of the next *
|
||||
* level. leaf or next index could be there */
|
||||
uint16_t ei_leaf_hi; /* high 16 bits of physical block */
|
||||
uint16_t ei_unused;
|
||||
}__attribute__ ((__packed__)) EXT4_EXTENT_IDX;
|
||||
|
||||
/*
|
||||
* Each block (leaves and indexes), even inode-stored has header.
|
||||
*/
|
||||
typedef struct ext4_extent_header {
|
||||
uint16_t eh_magic; /* probably will support different formats */
|
||||
uint16_t eh_entries; /* number of valid entries */
|
||||
uint16_t eh_max; /* capacity of store in entries */
|
||||
uint16_t eh_depth; /* has tree real underlying blocks? */
|
||||
uint32_t eh_generation; /* generation of the tree */
|
||||
}__attribute__ ((__packed__)) EXT4_EXTENT_HEADER;
|
||||
|
||||
|
||||
#define EXT4_EXT_MAGIC 0xf30a
|
||||
#define get_ext4_header(i) ((struct ext4_extent_header *) (i)->i_block)
|
||||
|
||||
#define EXT4_EXTENT_TAIL_OFFSET(hdr) \
|
||||
(sizeof(struct ext4_extent_header) + \
|
||||
(sizeof(struct ext4_extent) * (hdr)->eh_max))
|
||||
|
||||
static inline struct ext4_extent_tail *
|
||||
find_ext4_extent_tail(struct ext4_extent_header *eh)
|
||||
{
|
||||
return (struct ext4_extent_tail *)(((char *)eh) +
|
||||
EXT4_EXTENT_TAIL_OFFSET(eh));
|
||||
}
|
||||
|
||||
/*
|
||||
* Array of ext4_ext_path contains path to some extent.
|
||||
* Creation/lookup routines use it for traversal/splitting/etc.
|
||||
* Truncate uses it to simulate recursive walking.
|
||||
*/
|
||||
struct ext4_ext_path
|
||||
{
|
||||
ext4_fsblk_t p_block;
|
||||
int p_depth;
|
||||
int p_maxdepth;
|
||||
struct ext4_extent *p_ext;
|
||||
struct ext4_extent_idx *p_idx;
|
||||
struct ext4_extent_header *p_hdr;
|
||||
struct buffer_head *p_bh;
|
||||
};
|
||||
|
||||
/*
|
||||
* structure for external API
|
||||
*/
|
||||
|
||||
/*
|
||||
* EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
* initialized extent. This is 2^15 and not (2^16 - 1), since we use the
|
||||
* MSB of ee_len field in the extent datastructure to signify if this
|
||||
* particular extent is an initialized extent or an uninitialized (i.e.
|
||||
* preallocated).
|
||||
* EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
|
||||
* uninitialized extent.
|
||||
* If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
|
||||
* uninitialized one. In other words, if MSB of ee_len is set, it is an
|
||||
* uninitialized extent with only one special scenario when ee_len = 0x8000.
|
||||
* In this case we can not have an uninitialized extent of zero length and
|
||||
* thus we make it as a special case of initialized extent with 0x8000 length.
|
||||
* This way we get better extent-to-group alignment for initialized extents.
|
||||
* Hence, the maximum number of blocks we can have in an *initialized*
|
||||
* extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
|
||||
*/
|
||||
#define EXT_INIT_MAX_LEN (1UL << 15)
|
||||
#define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1)
|
||||
|
||||
#define EXT_EXTENT_SIZE sizeof(struct ext4_extent)
|
||||
#define EXT_INDEX_SIZE sizeof(struct ext4_extent_idx)
|
||||
|
||||
#define EXT_FIRST_EXTENT(__hdr__) \
|
||||
((struct ext4_extent *)(((char *)(__hdr__)) + \
|
||||
sizeof(struct ext4_extent_header)))
|
||||
#define EXT_FIRST_INDEX(__hdr__) \
|
||||
((struct ext4_extent_idx *)(((char *)(__hdr__)) + \
|
||||
sizeof(struct ext4_extent_header)))
|
||||
#define EXT_HAS_FREE_INDEX(__path__) \
|
||||
((__path__)->p_hdr->eh_entries < (__path__)->p_hdr->eh_max)
|
||||
#define EXT_LAST_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_entries - 1)
|
||||
#define EXT_LAST_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_entries - 1)
|
||||
#define EXT_MAX_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + (__hdr__)->eh_max - 1)
|
||||
#define EXT_MAX_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + (__hdr__)->eh_max - 1)
|
||||
|
||||
static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
|
||||
{
|
||||
return get_ext4_header(inode);
|
||||
}
|
||||
|
||||
static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh)
|
||||
{
|
||||
return (struct ext4_extent_header *)bh->b_data;
|
||||
}
|
||||
|
||||
static inline unsigned short ext_depth(struct inode *inode)
|
||||
{
|
||||
return ext_inode_hdr(inode)->eh_depth;
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
|
||||
{
|
||||
/* We can not have an uninitialized extent of zero length! */
|
||||
ext->ee_len |= EXT_INIT_MAX_LEN;
|
||||
}
|
||||
|
||||
static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
|
||||
{
|
||||
/* Extent with ee_len of 0x8000 is treated as an initialized extent */
|
||||
return (ext->ee_len > EXT_INIT_MAX_LEN);
|
||||
}
|
||||
|
||||
static inline uint16_t ext4_ext_get_actual_len(struct ext4_extent *ext)
|
||||
{
|
||||
return (ext->ee_len <= EXT_INIT_MAX_LEN
|
||||
? ext->ee_len
|
||||
: (ext->ee_len - EXT_INIT_MAX_LEN));
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_initialized(struct ext4_extent *ext)
|
||||
{
|
||||
ext->ee_len = ext4_ext_get_actual_len(ext);
|
||||
}
|
||||
|
||||
static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext)
|
||||
{
|
||||
/* We can not have an unwritten extent of zero length! */
|
||||
ext->ee_len |= EXT_INIT_MAX_LEN;
|
||||
}
|
||||
|
||||
static inline int ext4_ext_is_unwritten(struct ext4_extent *ext)
|
||||
{
|
||||
/* Extent with ee_len of 0x8000 is treated as an initialized extent */
|
||||
return (ext->ee_len > EXT_INIT_MAX_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_pblock:
|
||||
* combine low and high parts of physical block number into ext4_fsblk_t
|
||||
*/
|
||||
static inline ext4_fsblk_t ext4_ext_pblock(struct ext4_extent *ex)
|
||||
{
|
||||
ext4_fsblk_t block;
|
||||
|
||||
block = ex->ee_start_lo;
|
||||
block |= ((ext4_fsblk_t)ex->ee_start_hi << 31) << 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_idx_pblock:
|
||||
* combine low and high parts of a leaf physical block number into ext4_fsblk_t
|
||||
*/
|
||||
static inline ext4_fsblk_t ext4_idx_pblock(struct ext4_extent_idx *ix)
|
||||
{
|
||||
ext4_fsblk_t block;
|
||||
|
||||
block = ix->ei_leaf_lo;
|
||||
block |= ((ext4_fsblk_t)ix->ei_leaf_hi << 31) << 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_ext_store_pblock:
|
||||
* stores a large physical block number into an extent struct,
|
||||
* breaking it into parts
|
||||
*/
|
||||
static inline void ext4_ext_store_pblock(struct ext4_extent *ex,
|
||||
ext4_fsblk_t pb)
|
||||
{
|
||||
ex->ee_start_lo = (uint32_t)(pb & 0xffffffff);
|
||||
ex->ee_start_hi = (uint16_t)((pb >> 31) >> 1) & 0xffff;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext4_idx_store_pblock:
|
||||
* stores a large physical block number into an index struct,
|
||||
* breaking it into parts
|
||||
*/
|
||||
static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix,
|
||||
ext4_fsblk_t pb)
|
||||
{
|
||||
ix->ei_leaf_lo = (uint32_t)(pb & 0xffffffff);
|
||||
ix->ei_leaf_hi = (uint16_t)((pb >> 31) >> 1) & 0xffff;
|
||||
}
|
||||
|
||||
#define ext4_ext_dirty(icb, handle, inode, path) \
|
||||
__ext4_ext_dirty("", __LINE__, (icb), (handle), (inode), (path))
|
||||
|
||||
#define INODE_HAS_EXTENT(i) ((i)->i_flags & EXT2_EXTENTS_FL)
|
||||
|
||||
static inline uint64_t ext_to_block(EXT4_EXTENT *extent)
|
||||
{
|
||||
uint64_t block;
|
||||
|
||||
block = (uint64_t)extent->ee_start_lo;
|
||||
block |= ((uint64_t) extent->ee_start_hi << 31) << 1;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static inline uint64_t idx_to_block(EXT4_EXTENT_IDX *idx)
|
||||
{
|
||||
uint64_t block;
|
||||
|
||||
block = (uint64_t)idx->ei_leaf_lo;
|
||||
block |= ((uint64_t) idx->ei_leaf_hi << 31) << 1;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_fsblk_t iblock,
|
||||
unsigned long max_blocks, struct buffer_head *bh_result,
|
||||
int create, int flags);
|
||||
int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode);
|
||||
int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start);
|
||||
|
||||
#endif /* _LINUX_EXT4_EXT */
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
#ifndef _EXT4_JBD2_H
|
||||
#define _EXT4_JBD2_H
|
||||
|
||||
/*
|
||||
* Wrapper functions with which ext4 calls into JBD.
|
||||
*/
|
||||
void ext4_journal_abort_handle(const char *caller, unsigned int line,
|
||||
const char *err_fn, struct buffer_head *bh,
|
||||
handle_t *handle, int err);
|
||||
|
||||
int __ext4_handle_dirty_super(const char *where, unsigned int line,
|
||||
handle_t *handle, struct super_block *sb);
|
||||
|
||||
int __ext4_journal_get_write_access(const char *where, unsigned int line,
|
||||
void *icb, handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_forget(const char *where, unsigned int line, void *icb, handle_t *handle,
|
||||
int is_metadata, struct inode *inode,
|
||||
struct buffer_head *bh, ext4_fsblk_t blocknr);
|
||||
|
||||
int __ext4_journal_get_create_access(const char *where, unsigned int line,
|
||||
void *icb, handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
||||
void *icb, handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh);
|
||||
|
||||
#define ext4_journal_get_write_access(handle, icb, bh) \
|
||||
__ext4_journal_get_write_access("", __LINE__, (icb), (handle), (bh))
|
||||
#define ext4_forget(handle, icb, is_metadata, inode, bh, block_nr) \
|
||||
__ext4_forget("", __LINE__, (icb), (handle), (is_metadata), (inode), \
|
||||
(bh), (block_nr))
|
||||
#define ext4_journal_get_create_access(handle, icb, bh) \
|
||||
__ext4_journal_get_create_access("", __LINE__, (icb), (handle), (bh))
|
||||
#define ext4_handle_dirty_metadata(handle, icb, inode, bh) \
|
||||
__ext4_handle_dirty_metadata("", __LINE__, (icb), (handle), (inode), \
|
||||
(bh))
|
||||
|
||||
handle_t *__ext4_journal_start_sb(void *icb, struct super_block *sb, unsigned int line,
|
||||
int type, int blocks, int rsv_blocks);
|
||||
int __ext4_journal_stop(const char *where, unsigned int line, void *icb, handle_t *handle);
|
||||
|
||||
#define ext4_journal_start_sb(icb, sb, type, nblocks) \
|
||||
__ext4_journal_start_sb((icb), (sb), __LINE__, (type), (nblocks), 0)
|
||||
|
||||
#define ext4_journal_start(icb, inode, type, nblocks) \
|
||||
__ext4_journal_start((icb), (inode), __LINE__, (type), (nblocks), 0)
|
||||
|
||||
static inline handle_t *__ext4_journal_start(void *icb, struct inode *inode,
|
||||
unsigned int line, int type,
|
||||
int blocks, int rsv_blocks)
|
||||
{
|
||||
return __ext4_journal_start_sb(icb, inode->i_sb, line, type, blocks,
|
||||
rsv_blocks);
|
||||
}
|
||||
|
||||
#define ext4_journal_stop(icb, handle) \
|
||||
__ext4_journal_stop("", __LINE__, (icb), (handle))
|
||||
|
||||
static inline int ext4_journal_extend(void *icb, handle_t *handle, int nblocks)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef _EXT4_JBD2_H
|
||||
#define _EXT4_JBD2_H
|
||||
|
||||
/*
|
||||
* Wrapper functions with which ext4 calls into JBD.
|
||||
*/
|
||||
void ext4_journal_abort_handle(const char *caller, unsigned int line,
|
||||
const char *err_fn, struct buffer_head *bh,
|
||||
handle_t *handle, int err);
|
||||
|
||||
int __ext4_handle_dirty_super(const char *where, unsigned int line,
|
||||
handle_t *handle, struct super_block *sb);
|
||||
|
||||
int __ext4_journal_get_write_access(const char *where, unsigned int line,
|
||||
void *icb, handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_forget(const char *where, unsigned int line, void *icb, handle_t *handle,
|
||||
int is_metadata, struct inode *inode,
|
||||
struct buffer_head *bh, ext4_fsblk_t blocknr);
|
||||
|
||||
int __ext4_journal_get_create_access(const char *where, unsigned int line,
|
||||
void *icb, handle_t *handle, struct buffer_head *bh);
|
||||
|
||||
int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
||||
void *icb, handle_t *handle, struct inode *inode,
|
||||
struct buffer_head *bh);
|
||||
|
||||
#define ext4_journal_get_write_access(handle, icb, bh) \
|
||||
__ext4_journal_get_write_access("", __LINE__, (icb), (handle), (bh))
|
||||
#define ext4_forget(handle, icb, is_metadata, inode, bh, block_nr) \
|
||||
__ext4_forget("", __LINE__, (icb), (handle), (is_metadata), (inode), \
|
||||
(bh), (block_nr))
|
||||
#define ext4_journal_get_create_access(handle, icb, bh) \
|
||||
__ext4_journal_get_create_access("", __LINE__, (icb), (handle), (bh))
|
||||
#define ext4_handle_dirty_metadata(handle, icb, inode, bh) \
|
||||
__ext4_handle_dirty_metadata("", __LINE__, (icb), (handle), (inode), \
|
||||
(bh))
|
||||
|
||||
handle_t *__ext4_journal_start_sb(void *icb, struct super_block *sb, unsigned int line,
|
||||
int type, int blocks, int rsv_blocks);
|
||||
int __ext4_journal_stop(const char *where, unsigned int line, void *icb, handle_t *handle);
|
||||
|
||||
#define ext4_journal_start_sb(icb, sb, type, nblocks) \
|
||||
__ext4_journal_start_sb((icb), (sb), __LINE__, (type), (nblocks), 0)
|
||||
|
||||
#define ext4_journal_start(icb, inode, type, nblocks) \
|
||||
__ext4_journal_start((icb), (inode), __LINE__, (type), (nblocks), 0)
|
||||
|
||||
static inline handle_t *__ext4_journal_start(void *icb, struct inode *inode,
|
||||
unsigned int line, int type,
|
||||
int blocks, int rsv_blocks)
|
||||
{
|
||||
return __ext4_journal_start_sb(icb, inode->i_sb, line, type, blocks,
|
||||
rsv_blocks);
|
||||
}
|
||||
|
||||
#define ext4_journal_stop(icb, handle) \
|
||||
__ext4_journal_stop("", __LINE__, (icb), (handle))
|
||||
|
||||
static inline int ext4_journal_extend(void *icb, handle_t *handle, int nblocks)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,205 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Grzegorz Kostka (kostka.grzegorz@gmail.com)
|
||||
* Copyright (c) 2015 Kaho Ng (ngkaho1234@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
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2015 Grzegorz Kostka (kostka.grzegorz@gmail.com)
|
||||
* Copyright (c) 2015 Kaho Ng (ngkaho1234@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
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -1,160 +1,160 @@
|
||||
#ifndef _LINUX_FS_INCLUDE_
|
||||
#define _LINUX_FS_INCLUDE_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
//
|
||||
// kdev
|
||||
//
|
||||
|
||||
#define NODEV 0
|
||||
|
||||
typedef struct block_device * kdev_t;
|
||||
|
||||
#define MINORBITS 8
|
||||
#define MINORMASK ((1U << MINORBITS) - 1)
|
||||
|
||||
#define MAJOR(dev) ((unsigned int)((int)(dev) >> MINORBITS))
|
||||
#define MINOR(dev) ((unsigned int)((int)(dev) & MINORMASK))
|
||||
|
||||
static inline unsigned int kdev_t_to_nr(kdev_t dev) {
|
||||
/*return (unsigned int)(MAJOR(dev)<<8) | MINOR(dev);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NODEV 0
|
||||
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
|
||||
|
||||
static inline kdev_t to_kdev_t(int dev)
|
||||
{
|
||||
#if 0
|
||||
int major, minor;
|
||||
#if 0
|
||||
major = (dev >> 16);
|
||||
if (!major) {
|
||||
major = (dev >> 8);
|
||||
minor = (dev & 0xff);
|
||||
} else
|
||||
minor = (dev & 0xffff);
|
||||
#else
|
||||
major = (dev >> 8);
|
||||
minor = (dev & 0xff);
|
||||
#endif
|
||||
return (kdev_t) MKDEV(major, minor);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// file system specific structures
|
||||
//
|
||||
|
||||
/*
|
||||
* Kernel pointers have redundant information, so we can use a
|
||||
* scheme where we can return either an error code or a dentry
|
||||
* pointer with the same return value.
|
||||
*
|
||||
* This should be a per-architecture thing, to allow different
|
||||
* error and pointer decisions.
|
||||
*/
|
||||
|
||||
struct super_block {
|
||||
unsigned long s_magic;
|
||||
unsigned long s_flags;
|
||||
unsigned long s_blocksize; /* blocksize */
|
||||
unsigned long long s_maxbytes;
|
||||
unsigned char s_blocksize_bits; /* bits of blocksize */
|
||||
unsigned char s_dirt; /* any thing */
|
||||
char s_id[30]; /* id string */
|
||||
kdev_t s_bdev; /* block_device */
|
||||
void * s_priv; /* EXT2_VCB */
|
||||
struct dentry *s_root;
|
||||
void *s_fs_info;
|
||||
};
|
||||
|
||||
struct inode {
|
||||
__u32 i_ino; /* inode number */
|
||||
loff_t i_size; /* size */
|
||||
__u32 i_atime; /* Access time */
|
||||
__u32 i_ctime; /* Creation time */
|
||||
__u32 i_mtime; /* Modification time */
|
||||
__u32 i_dtime; /* Deletion Time */
|
||||
__u64 i_blocks;
|
||||
__u32 i_block[15];
|
||||
umode_t i_mode; /* mode */
|
||||
uid_t i_uid;
|
||||
gid_t i_gid;
|
||||
atomic_t i_count; /* ref count */
|
||||
__u16 i_nlink;
|
||||
__u32 i_generation;
|
||||
__u32 i_version;
|
||||
__u32 i_flags;
|
||||
|
||||
struct super_block *i_sb; /* super_block */
|
||||
void *i_priv; /* EXT2_MCB */
|
||||
|
||||
__u16 i_extra_isize; /* extra fields' size */
|
||||
__u64 i_file_acl;
|
||||
};
|
||||
|
||||
//
|
||||
// Inode state bits
|
||||
//
|
||||
|
||||
#define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */
|
||||
#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
|
||||
#define I_DIRTY_PAGES 4 /* Data-related inode changes pending */
|
||||
#define I_LOCK 8
|
||||
#define I_FREEING 16
|
||||
#define I_CLEAR 32
|
||||
|
||||
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
|
||||
|
||||
|
||||
struct dentry {
|
||||
atomic_t d_count;
|
||||
struct {
|
||||
int len;
|
||||
char *name;
|
||||
} d_name;
|
||||
struct inode *d_inode;
|
||||
struct dentry *d_parent;
|
||||
void *d_fsdata;
|
||||
struct super_block *d_sb;
|
||||
};
|
||||
|
||||
struct file {
|
||||
|
||||
unsigned int f_flags;
|
||||
umode_t f_mode;
|
||||
__u32 f_version;
|
||||
__int64 f_size;
|
||||
loff_t f_pos;
|
||||
struct dentry *f_dentry;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* File types
|
||||
*
|
||||
* NOTE! These match bits 12..15 of stat.st_mode
|
||||
* (ie "(i_mode >> 12) & 15").
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 4
|
||||
#define DT_BLK 6
|
||||
#define DT_REG 8
|
||||
#define DT_LNK 10
|
||||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
void iget(struct inode *inode);
|
||||
void iput(struct inode *inode);
|
||||
ULONGLONG bmap(struct inode *i, ULONGLONG b);
|
||||
|
||||
#endif /*_LINUX_FS_INCLUDE_*/
|
||||
#ifndef _LINUX_FS_INCLUDE_
|
||||
#define _LINUX_FS_INCLUDE_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
//
|
||||
// kdev
|
||||
//
|
||||
|
||||
#define NODEV 0
|
||||
|
||||
typedef struct block_device * kdev_t;
|
||||
|
||||
#define MINORBITS 8
|
||||
#define MINORMASK ((1U << MINORBITS) - 1)
|
||||
|
||||
#define MAJOR(dev) ((unsigned int)((int)(dev) >> MINORBITS))
|
||||
#define MINOR(dev) ((unsigned int)((int)(dev) & MINORMASK))
|
||||
|
||||
static inline unsigned int kdev_t_to_nr(kdev_t dev) {
|
||||
/*return (unsigned int)(MAJOR(dev)<<8) | MINOR(dev);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NODEV 0
|
||||
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
|
||||
|
||||
static inline kdev_t to_kdev_t(int dev)
|
||||
{
|
||||
#if 0
|
||||
int major, minor;
|
||||
#if 0
|
||||
major = (dev >> 16);
|
||||
if (!major) {
|
||||
major = (dev >> 8);
|
||||
minor = (dev & 0xff);
|
||||
} else
|
||||
minor = (dev & 0xffff);
|
||||
#else
|
||||
major = (dev >> 8);
|
||||
minor = (dev & 0xff);
|
||||
#endif
|
||||
return (kdev_t) MKDEV(major, minor);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// file system specific structures
|
||||
//
|
||||
|
||||
/*
|
||||
* Kernel pointers have redundant information, so we can use a
|
||||
* scheme where we can return either an error code or a dentry
|
||||
* pointer with the same return value.
|
||||
*
|
||||
* This should be a per-architecture thing, to allow different
|
||||
* error and pointer decisions.
|
||||
*/
|
||||
|
||||
struct super_block {
|
||||
unsigned long s_magic;
|
||||
unsigned long s_flags;
|
||||
unsigned long s_blocksize; /* blocksize */
|
||||
unsigned long long s_maxbytes;
|
||||
unsigned char s_blocksize_bits; /* bits of blocksize */
|
||||
unsigned char s_dirt; /* any thing */
|
||||
char s_id[30]; /* id string */
|
||||
kdev_t s_bdev; /* block_device */
|
||||
void * s_priv; /* EXT2_VCB */
|
||||
struct dentry *s_root;
|
||||
void *s_fs_info;
|
||||
};
|
||||
|
||||
struct inode {
|
||||
__u32 i_ino; /* inode number */
|
||||
loff_t i_size; /* size */
|
||||
__u32 i_atime; /* Access time */
|
||||
__u32 i_ctime; /* Creation time */
|
||||
__u32 i_mtime; /* Modification time */
|
||||
__u32 i_dtime; /* Deletion Time */
|
||||
__u64 i_blocks;
|
||||
__u32 i_block[15];
|
||||
umode_t i_mode; /* mode */
|
||||
uid_t i_uid;
|
||||
gid_t i_gid;
|
||||
atomic_t i_count; /* ref count */
|
||||
__u16 i_nlink;
|
||||
__u32 i_generation;
|
||||
__u32 i_version;
|
||||
__u32 i_flags;
|
||||
|
||||
struct super_block *i_sb; /* super_block */
|
||||
void *i_priv; /* EXT2_MCB */
|
||||
|
||||
__u16 i_extra_isize; /* extra fields' size */
|
||||
__u64 i_file_acl;
|
||||
};
|
||||
|
||||
//
|
||||
// Inode state bits
|
||||
//
|
||||
|
||||
#define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */
|
||||
#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
|
||||
#define I_DIRTY_PAGES 4 /* Data-related inode changes pending */
|
||||
#define I_LOCK 8
|
||||
#define I_FREEING 16
|
||||
#define I_CLEAR 32
|
||||
|
||||
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
|
||||
|
||||
|
||||
struct dentry {
|
||||
atomic_t d_count;
|
||||
struct {
|
||||
int len;
|
||||
char *name;
|
||||
} d_name;
|
||||
struct inode *d_inode;
|
||||
struct dentry *d_parent;
|
||||
void *d_fsdata;
|
||||
struct super_block *d_sb;
|
||||
};
|
||||
|
||||
struct file {
|
||||
|
||||
unsigned int f_flags;
|
||||
umode_t f_mode;
|
||||
__u32 f_version;
|
||||
__int64 f_size;
|
||||
loff_t f_pos;
|
||||
struct dentry *f_dentry;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* File types
|
||||
*
|
||||
* NOTE! These match bits 12..15 of stat.st_mode
|
||||
* (ie "(i_mode >> 12) & 15").
|
||||
*/
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1
|
||||
#define DT_CHR 2
|
||||
#define DT_DIR 4
|
||||
#define DT_BLK 6
|
||||
#define DT_REG 8
|
||||
#define DT_LNK 10
|
||||
#define DT_SOCK 12
|
||||
#define DT_WHT 14
|
||||
|
||||
void iget(struct inode *inode);
|
||||
void iput(struct inode *inode);
|
||||
ULONGLONG bmap(struct inode *i, ULONGLONG b);
|
||||
|
||||
#endif /*_LINUX_FS_INCLUDE_*/
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
/*
|
||||
* linux/fs/ext4/group.h
|
||||
*
|
||||
* Copyright (C) 2007 Cluster File Systems, Inc
|
||||
*
|
||||
* Author: Andreas Dilger <adilger@clusterfs.com>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_GROUP_H
|
||||
#define _LINUX_EXT4_GROUP_H
|
||||
|
||||
extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
|
||||
struct ext4_group_desc *gdp);
|
||||
extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
|
||||
struct ext4_group_desc *gdp);
|
||||
struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
|
||||
ext4_group_t block_group);
|
||||
extern unsigned ext4_init_block_bitmap(struct super_block *sb,
|
||||
struct buffer_head *bh,
|
||||
ext4_group_t group,
|
||||
struct ext4_group_desc *desc);
|
||||
#define ext4_free_blocks_after_init(sb, group, desc) \
|
||||
ext4_init_block_bitmap(sb, NULL, group, desc)
|
||||
extern unsigned ext4_init_inode_bitmap(struct super_block *sb,
|
||||
struct buffer_head *bh,
|
||||
ext4_group_t group,
|
||||
struct ext4_group_desc *desc);
|
||||
extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
|
||||
#endif /* _LINUX_EXT4_GROUP_H */
|
||||
/*
|
||||
* linux/fs/ext4/group.h
|
||||
*
|
||||
* Copyright (C) 2007 Cluster File Systems, Inc
|
||||
*
|
||||
* Author: Andreas Dilger <adilger@clusterfs.com>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT4_GROUP_H
|
||||
#define _LINUX_EXT4_GROUP_H
|
||||
|
||||
extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
|
||||
struct ext4_group_desc *gdp);
|
||||
extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
|
||||
struct ext4_group_desc *gdp);
|
||||
struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
|
||||
ext4_group_t block_group);
|
||||
extern unsigned ext4_init_block_bitmap(struct super_block *sb,
|
||||
struct buffer_head *bh,
|
||||
ext4_group_t group,
|
||||
struct ext4_group_desc *desc);
|
||||
#define ext4_free_blocks_after_init(sb, group, desc) \
|
||||
ext4_init_block_bitmap(sb, NULL, group, desc)
|
||||
extern unsigned ext4_init_inode_bitmap(struct super_block *sb,
|
||||
struct buffer_head *bh,
|
||||
ext4_group_t group,
|
||||
struct ext4_group_desc *desc);
|
||||
extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
|
||||
#endif /* _LINUX_EXT4_GROUP_H */
|
||||
|
||||
@@ -1,92 +1,92 @@
|
||||
/*
|
||||
* include/linux/journal-head.h
|
||||
*
|
||||
* buffer_head fields for JBD
|
||||
*
|
||||
* 27 May 2001 Andrew Morton <akpm@digeo.com>
|
||||
* Created - pulled out of fs.h
|
||||
*/
|
||||
|
||||
#ifndef JOURNAL_HEAD_H_INCLUDED
|
||||
#define JOURNAL_HEAD_H_INCLUDED
|
||||
|
||||
typedef unsigned int tid_t; /* Unique transaction ID */
|
||||
typedef struct transaction_s transaction_t; /* Compound transaction type */
|
||||
struct buffer_head;
|
||||
|
||||
struct journal_head {
|
||||
/*
|
||||
* Points back to our buffer_head. [jbd_lock_bh_journal_head()]
|
||||
*/
|
||||
struct buffer_head *b_bh;
|
||||
|
||||
/*
|
||||
* Reference count - see description in journal.c
|
||||
* [jbd_lock_bh_journal_head()]
|
||||
*/
|
||||
int b_jcount;
|
||||
|
||||
/*
|
||||
* Journalling list for this buffer [jbd_lock_bh_state()]
|
||||
*/
|
||||
unsigned b_jlist;
|
||||
|
||||
/*
|
||||
* This flag signals the buffer has been modified by
|
||||
* the currently running transaction
|
||||
* [jbd_lock_bh_state()]
|
||||
*/
|
||||
unsigned b_modified;
|
||||
|
||||
/*
|
||||
* Copy of the buffer data frozen for writing to the log.
|
||||
* [jbd_lock_bh_state()]
|
||||
*/
|
||||
char *b_frozen_data;
|
||||
|
||||
/*
|
||||
* Pointer to a saved copy of the buffer containing no uncommitted
|
||||
* deallocation references, so that allocations can avoid overwriting
|
||||
* uncommitted deletes. [jbd_lock_bh_state()]
|
||||
*/
|
||||
char *b_committed_data;
|
||||
|
||||
/*
|
||||
* Pointer to the compound transaction which owns this buffer's
|
||||
* metadata: either the running transaction or the committing
|
||||
* transaction (if there is one). Only applies to buffers on a
|
||||
* transaction's data or metadata journaling list.
|
||||
* [j_list_lock] [jbd_lock_bh_state()]
|
||||
*/
|
||||
transaction_t *b_transaction;
|
||||
|
||||
/*
|
||||
* Pointer to the running compound transaction which is currently
|
||||
* modifying the buffer's metadata, if there was already a transaction
|
||||
* committing it when the new transaction touched it.
|
||||
* [t_list_lock] [jbd_lock_bh_state()]
|
||||
*/
|
||||
transaction_t *b_next_transaction;
|
||||
|
||||
/*
|
||||
* Doubly-linked list of buffers on a transaction's data, metadata or
|
||||
* forget queue. [t_list_lock] [jbd_lock_bh_state()]
|
||||
*/
|
||||
struct journal_head *b_tnext, *b_tprev;
|
||||
|
||||
/*
|
||||
* Pointer to the compound transaction against which this buffer
|
||||
* is checkpointed. Only dirty buffers can be checkpointed.
|
||||
* [j_list_lock]
|
||||
*/
|
||||
transaction_t *b_cp_transaction;
|
||||
|
||||
/*
|
||||
* Doubly-linked list of buffers still remaining to be flushed
|
||||
* before an old transaction can be checkpointed.
|
||||
* [j_list_lock]
|
||||
*/
|
||||
struct journal_head *b_cpnext, *b_cpprev;
|
||||
};
|
||||
|
||||
#endif /* JOURNAL_HEAD_H_INCLUDED */
|
||||
/*
|
||||
* include/linux/journal-head.h
|
||||
*
|
||||
* buffer_head fields for JBD
|
||||
*
|
||||
* 27 May 2001 Andrew Morton <akpm@digeo.com>
|
||||
* Created - pulled out of fs.h
|
||||
*/
|
||||
|
||||
#ifndef JOURNAL_HEAD_H_INCLUDED
|
||||
#define JOURNAL_HEAD_H_INCLUDED
|
||||
|
||||
typedef unsigned int tid_t; /* Unique transaction ID */
|
||||
typedef struct transaction_s transaction_t; /* Compound transaction type */
|
||||
struct buffer_head;
|
||||
|
||||
struct journal_head {
|
||||
/*
|
||||
* Points back to our buffer_head. [jbd_lock_bh_journal_head()]
|
||||
*/
|
||||
struct buffer_head *b_bh;
|
||||
|
||||
/*
|
||||
* Reference count - see description in journal.c
|
||||
* [jbd_lock_bh_journal_head()]
|
||||
*/
|
||||
int b_jcount;
|
||||
|
||||
/*
|
||||
* Journalling list for this buffer [jbd_lock_bh_state()]
|
||||
*/
|
||||
unsigned b_jlist;
|
||||
|
||||
/*
|
||||
* This flag signals the buffer has been modified by
|
||||
* the currently running transaction
|
||||
* [jbd_lock_bh_state()]
|
||||
*/
|
||||
unsigned b_modified;
|
||||
|
||||
/*
|
||||
* Copy of the buffer data frozen for writing to the log.
|
||||
* [jbd_lock_bh_state()]
|
||||
*/
|
||||
char *b_frozen_data;
|
||||
|
||||
/*
|
||||
* Pointer to a saved copy of the buffer containing no uncommitted
|
||||
* deallocation references, so that allocations can avoid overwriting
|
||||
* uncommitted deletes. [jbd_lock_bh_state()]
|
||||
*/
|
||||
char *b_committed_data;
|
||||
|
||||
/*
|
||||
* Pointer to the compound transaction which owns this buffer's
|
||||
* metadata: either the running transaction or the committing
|
||||
* transaction (if there is one). Only applies to buffers on a
|
||||
* transaction's data or metadata journaling list.
|
||||
* [j_list_lock] [jbd_lock_bh_state()]
|
||||
*/
|
||||
transaction_t *b_transaction;
|
||||
|
||||
/*
|
||||
* Pointer to the running compound transaction which is currently
|
||||
* modifying the buffer's metadata, if there was already a transaction
|
||||
* committing it when the new transaction touched it.
|
||||
* [t_list_lock] [jbd_lock_bh_state()]
|
||||
*/
|
||||
transaction_t *b_next_transaction;
|
||||
|
||||
/*
|
||||
* Doubly-linked list of buffers on a transaction's data, metadata or
|
||||
* forget queue. [t_list_lock] [jbd_lock_bh_state()]
|
||||
*/
|
||||
struct journal_head *b_tnext, *b_tprev;
|
||||
|
||||
/*
|
||||
* Pointer to the compound transaction against which this buffer
|
||||
* is checkpointed. Only dirty buffers can be checkpointed.
|
||||
* [j_list_lock]
|
||||
*/
|
||||
transaction_t *b_cp_transaction;
|
||||
|
||||
/*
|
||||
* Doubly-linked list of buffers still remaining to be flushed
|
||||
* before an old transaction can be checkpointed.
|
||||
* [j_list_lock]
|
||||
*/
|
||||
struct journal_head *b_cpnext, *b_cpprev;
|
||||
};
|
||||
|
||||
#endif /* JOURNAL_HEAD_H_INCLUDED */
|
||||
|
||||
@@ -1,255 +1,255 @@
|
||||
#ifndef __LINUX_LIST_H__
|
||||
#define __LINUX_LIST_H__
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
#define prefetch(a) ((void *)a)
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head * new,
|
||||
struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline int list_empty_careful(const struct list_head *head)
|
||||
{
|
||||
struct list_head *next = head->next;
|
||||
return (next == head) && (next == head->prev);
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(char *)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
#ifndef list_for_each_prev
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list in reverse order
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
|
||||
pos = pos->prev, prefetch(pos->prev))
|
||||
|
||||
#endif /* list_for_each_prev */
|
||||
|
||||
#ifndef list_for_each_entry
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, type, member) \
|
||||
for (pos = list_entry((head)->next, type, member), \
|
||||
prefetch(pos->member.next); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, type, member), \
|
||||
prefetch(pos->member.next))
|
||||
#endif /* list_for_each_entry */
|
||||
|
||||
#ifndef list_for_each_entry_safe
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, type, member) \
|
||||
for (pos = list_entry((head)->next, type, member), \
|
||||
n = list_entry(pos->member.next, type, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, type, member))
|
||||
#endif /* list_for_each_entry_safe */
|
||||
|
||||
#endif /* __LINUX_LIST_H__ */
|
||||
#ifndef __LINUX_LIST_H__
|
||||
#define __LINUX_LIST_H__
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
#define prefetch(a) ((void *)a)
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head * new,
|
||||
struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline int list_empty_careful(const struct list_head *head)
|
||||
{
|
||||
struct list_head *next = head->next;
|
||||
return (next == head) && (next == head->prev);
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(char *)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
|
||||
pos = pos->next, prefetch(pos->next))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
#ifndef list_for_each_prev
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list in reverse order
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
|
||||
pos = pos->prev, prefetch(pos->prev))
|
||||
|
||||
#endif /* list_for_each_prev */
|
||||
|
||||
#ifndef list_for_each_entry
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, type, member) \
|
||||
for (pos = list_entry((head)->next, type, member), \
|
||||
prefetch(pos->member.next); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, type, member), \
|
||||
prefetch(pos->member.next))
|
||||
#endif /* list_for_each_entry */
|
||||
|
||||
#ifndef list_for_each_entry_safe
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, type, member) \
|
||||
for (pos = list_entry((head)->next, type, member), \
|
||||
n = list_entry(pos->member.next, type, member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, type, member))
|
||||
#endif /* list_for_each_entry_safe */
|
||||
|
||||
#endif /* __LINUX_LIST_H__ */
|
||||
|
||||
@@ -1,140 +1,140 @@
|
||||
/* Integer base 2 logarithm calculation
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_LOG2_H
|
||||
#define _LINUX_LOG2_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/*
|
||||
* deal with unrepresentable constant logarithms
|
||||
*/
|
||||
int ____ilog2_NaN(void);
|
||||
|
||||
/*
|
||||
* non-constant log of base 2 calculators
|
||||
* - the arch may override these in asm/bitops.h if they can be implemented
|
||||
* more efficiently than using fls() and fls64()
|
||||
* - the arch is not required to handle n==0 if implementing the fallback
|
||||
*/
|
||||
#ifndef CONFIG_ARCH_HAS_ILOG2_U32
|
||||
static inline __attribute__((const))
|
||||
int __ilog2_u32(u32 n)
|
||||
{
|
||||
return fls(n) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ARCH_HAS_ILOG2_U64
|
||||
static inline __attribute__((const))
|
||||
int __ilog2_u64(u64 n)
|
||||
{
|
||||
return fls64(n) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determine whether some value is a power of two, where zero is
|
||||
* *not* considered a power of two.
|
||||
*/
|
||||
|
||||
static inline __attribute__((const))
|
||||
bool is_power_of_2(unsigned long n)
|
||||
{
|
||||
return (n != 0 && ((n & (n - 1)) == 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* round up to nearest power of two
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
unsigned long __roundup_pow_of_two(unsigned long n)
|
||||
{
|
||||
return 1UL << fls_long(n - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* round down to nearest power of two
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
unsigned long __rounddown_pow_of_two(unsigned long n)
|
||||
{
|
||||
return 1UL << (fls_long(n) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
|
||||
* @n - parameter
|
||||
*
|
||||
* constant-capable log of base 2 calculation
|
||||
* - this can be used to initialise global variables from constant data, hence
|
||||
* the massive ternary operator construction
|
||||
*
|
||||
* selects the appropriately-sized optimised version depending on sizeof(n)
|
||||
*/
|
||||
#define ilog2(n) \
|
||||
( \
|
||||
(sizeof(n) <= 4) ? \
|
||||
__ilog2_u32(n) : \
|
||||
__ilog2_u64(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* roundup_pow_of_two - round the given value up to nearest power of two
|
||||
* @n - parameter
|
||||
*
|
||||
* round the given value up to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define roundup_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(n == 1) ? 1 : \
|
||||
(1UL << (ilog2((n) - 1) + 1)) \
|
||||
) : \
|
||||
__roundup_pow_of_two(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* rounddown_pow_of_two - round the given value down to nearest power of two
|
||||
* @n - parameter
|
||||
*
|
||||
* round the given value down to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define rounddown_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(n == 1) ? 0 : \
|
||||
(1UL << ilog2(n))) : \
|
||||
__rounddown_pow_of_two(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* order_base_2 - calculate the (rounded up) base 2 order of the argument
|
||||
* @n: parameter
|
||||
*
|
||||
* The first few values calculated by this routine:
|
||||
* ob2(0) = 0
|
||||
* ob2(1) = 0
|
||||
* ob2(2) = 1
|
||||
* ob2(3) = 2
|
||||
* ob2(4) = 2
|
||||
* ob2(5) = 3
|
||||
* ... and so on.
|
||||
*/
|
||||
|
||||
#define order_base_2(n) ilog2(roundup_pow_of_two(n))
|
||||
|
||||
#endif /* _LINUX_LOG2_H */
|
||||
/* Integer base 2 logarithm calculation
|
||||
*
|
||||
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_LOG2_H
|
||||
#define _LINUX_LOG2_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/*
|
||||
* deal with unrepresentable constant logarithms
|
||||
*/
|
||||
int ____ilog2_NaN(void);
|
||||
|
||||
/*
|
||||
* non-constant log of base 2 calculators
|
||||
* - the arch may override these in asm/bitops.h if they can be implemented
|
||||
* more efficiently than using fls() and fls64()
|
||||
* - the arch is not required to handle n==0 if implementing the fallback
|
||||
*/
|
||||
#ifndef CONFIG_ARCH_HAS_ILOG2_U32
|
||||
static inline __attribute__((const))
|
||||
int __ilog2_u32(u32 n)
|
||||
{
|
||||
return fls(n) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ARCH_HAS_ILOG2_U64
|
||||
static inline __attribute__((const))
|
||||
int __ilog2_u64(u64 n)
|
||||
{
|
||||
return fls64(n) - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determine whether some value is a power of two, where zero is
|
||||
* *not* considered a power of two.
|
||||
*/
|
||||
|
||||
static inline __attribute__((const))
|
||||
bool is_power_of_2(unsigned long n)
|
||||
{
|
||||
return (n != 0 && ((n & (n - 1)) == 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* round up to nearest power of two
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
unsigned long __roundup_pow_of_two(unsigned long n)
|
||||
{
|
||||
return 1UL << fls_long(n - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* round down to nearest power of two
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
unsigned long __rounddown_pow_of_two(unsigned long n)
|
||||
{
|
||||
return 1UL << (fls_long(n) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
|
||||
* @n - parameter
|
||||
*
|
||||
* constant-capable log of base 2 calculation
|
||||
* - this can be used to initialise global variables from constant data, hence
|
||||
* the massive ternary operator construction
|
||||
*
|
||||
* selects the appropriately-sized optimised version depending on sizeof(n)
|
||||
*/
|
||||
#define ilog2(n) \
|
||||
( \
|
||||
(sizeof(n) <= 4) ? \
|
||||
__ilog2_u32(n) : \
|
||||
__ilog2_u64(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* roundup_pow_of_two - round the given value up to nearest power of two
|
||||
* @n - parameter
|
||||
*
|
||||
* round the given value up to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define roundup_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(n == 1) ? 1 : \
|
||||
(1UL << (ilog2((n) - 1) + 1)) \
|
||||
) : \
|
||||
__roundup_pow_of_two(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* rounddown_pow_of_two - round the given value down to nearest power of two
|
||||
* @n - parameter
|
||||
*
|
||||
* round the given value down to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define rounddown_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(n == 1) ? 0 : \
|
||||
(1UL << ilog2(n))) : \
|
||||
__rounddown_pow_of_two(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* order_base_2 - calculate the (rounded up) base 2 order of the argument
|
||||
* @n: parameter
|
||||
*
|
||||
* The first few values calculated by this routine:
|
||||
* ob2(0) = 0
|
||||
* ob2(1) = 0
|
||||
* ob2(2) = 1
|
||||
* ob2(3) = 2
|
||||
* ob2(4) = 2
|
||||
* ob2(5) = 3
|
||||
* ... and so on.
|
||||
*/
|
||||
|
||||
#define order_base_2(n) ilog2(roundup_pow_of_two(n))
|
||||
|
||||
#endif /* _LINUX_LOG2_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,161 +1,161 @@
|
||||
/*
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
linux/include/linux/rbtree.h
|
||||
|
||||
To use rbtrees you'll have to implement your own insert and search cores.
|
||||
This will avoid us to use callbacks and to drop drammatically performances.
|
||||
I know it's not the cleaner way, but in C (not in C++) to get
|
||||
performances and genericity...
|
||||
|
||||
Some example of insert and search follows here. The search is a plain
|
||||
normal search over an ordered tree. The insert instead must be implemented
|
||||
int two steps: as first thing the code must insert the element in
|
||||
order as a red leaf in the tree, then the support library function
|
||||
rb_insert_color() must be called. Such function will do the
|
||||
not trivial work to rebalance the rbtree if necessary.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
static inline struct page * rb_search_page_cache(struct inode * inode,
|
||||
unsigned long offset)
|
||||
{
|
||||
struct rb_node * n = inode->i_rb_page_cache.rb_node;
|
||||
struct page * page;
|
||||
|
||||
while (n)
|
||||
{
|
||||
page = rb_entry(n, struct page, rb_page_cache);
|
||||
|
||||
if (offset < page->offset)
|
||||
n = n->rb_left;
|
||||
else if (offset > page->offset)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return page;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct page * __rb_insert_page_cache(struct inode * inode,
|
||||
unsigned long offset,
|
||||
struct rb_node * node)
|
||||
{
|
||||
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
|
||||
struct rb_node * parent = NULL;
|
||||
struct page * page;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
parent = *p;
|
||||
page = rb_entry(parent, struct page, rb_page_cache);
|
||||
|
||||
if (offset < page->offset)
|
||||
p = &(*p)->rb_left;
|
||||
else if (offset > page->offset)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return page;
|
||||
}
|
||||
|
||||
rb_link_node(node, parent, p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct page * rb_insert_page_cache(struct inode * inode,
|
||||
unsigned long offset,
|
||||
struct rb_node * node)
|
||||
{
|
||||
struct page * ret;
|
||||
if ((ret = __rb_insert_page_cache(inode, offset, node)))
|
||||
goto out;
|
||||
rb_insert_color(node, &inode->i_rb_page_cache);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_RBTREE_H
|
||||
#define _LINUX_RBTREE_H
|
||||
|
||||
struct rb_node
|
||||
{
|
||||
ULONG_PTR rb_parent_color;
|
||||
#define RB_RED 0
|
||||
#define RB_BLACK 1
|
||||
struct rb_node *rb_right;
|
||||
struct rb_node *rb_left;
|
||||
} __attribute__((aligned(sizeof(long))));
|
||||
/* The alignment might seem pointless, but allegedly CRIS needs it */
|
||||
|
||||
struct rb_root
|
||||
{
|
||||
struct rb_node *rb_node;
|
||||
};
|
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
|
||||
#define rb_color(r) ((r)->rb_parent_color & 1)
|
||||
#define rb_is_red(r) (!rb_color(r))
|
||||
#define rb_is_black(r) rb_color(r)
|
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
|
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (ULONG_PTR)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, ULONG_PTR color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
#define RB_ROOT (struct rb_root) { NULL, }
|
||||
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
|
||||
#define RB_EMPTY_NODE(node) (rb_parent(node) != node)
|
||||
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
|
||||
|
||||
extern void rb_insert_color(struct rb_node *, struct rb_root *);
|
||||
extern void rb_erase(struct rb_node *, struct rb_root *);
|
||||
|
||||
/* Find logical next and previous nodes in a tree */
|
||||
extern struct rb_node *rb_next(struct rb_node *);
|
||||
extern struct rb_node *rb_prev(struct rb_node *);
|
||||
extern struct rb_node *rb_first(struct rb_root *);
|
||||
extern struct rb_node *rb_last(struct rb_root *);
|
||||
|
||||
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
|
||||
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
|
||||
struct rb_root *root);
|
||||
|
||||
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
{
|
||||
node->rb_parent_color = (ULONG_PTR )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
extern void rb_insert(struct rb_root *root, struct rb_node *node,
|
||||
int (*cmp)(struct rb_node *, struct rb_node *));
|
||||
|
||||
#endif /* _LINUX_RBTREE_H */
|
||||
/*
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
linux/include/linux/rbtree.h
|
||||
|
||||
To use rbtrees you'll have to implement your own insert and search cores.
|
||||
This will avoid us to use callbacks and to drop drammatically performances.
|
||||
I know it's not the cleaner way, but in C (not in C++) to get
|
||||
performances and genericity...
|
||||
|
||||
Some example of insert and search follows here. The search is a plain
|
||||
normal search over an ordered tree. The insert instead must be implemented
|
||||
int two steps: as first thing the code must insert the element in
|
||||
order as a red leaf in the tree, then the support library function
|
||||
rb_insert_color() must be called. Such function will do the
|
||||
not trivial work to rebalance the rbtree if necessary.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
static inline struct page * rb_search_page_cache(struct inode * inode,
|
||||
unsigned long offset)
|
||||
{
|
||||
struct rb_node * n = inode->i_rb_page_cache.rb_node;
|
||||
struct page * page;
|
||||
|
||||
while (n)
|
||||
{
|
||||
page = rb_entry(n, struct page, rb_page_cache);
|
||||
|
||||
if (offset < page->offset)
|
||||
n = n->rb_left;
|
||||
else if (offset > page->offset)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return page;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct page * __rb_insert_page_cache(struct inode * inode,
|
||||
unsigned long offset,
|
||||
struct rb_node * node)
|
||||
{
|
||||
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
|
||||
struct rb_node * parent = NULL;
|
||||
struct page * page;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
parent = *p;
|
||||
page = rb_entry(parent, struct page, rb_page_cache);
|
||||
|
||||
if (offset < page->offset)
|
||||
p = &(*p)->rb_left;
|
||||
else if (offset > page->offset)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return page;
|
||||
}
|
||||
|
||||
rb_link_node(node, parent, p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct page * rb_insert_page_cache(struct inode * inode,
|
||||
unsigned long offset,
|
||||
struct rb_node * node)
|
||||
{
|
||||
struct page * ret;
|
||||
if ((ret = __rb_insert_page_cache(inode, offset, node)))
|
||||
goto out;
|
||||
rb_insert_color(node, &inode->i_rb_page_cache);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_RBTREE_H
|
||||
#define _LINUX_RBTREE_H
|
||||
|
||||
struct rb_node
|
||||
{
|
||||
ULONG_PTR rb_parent_color;
|
||||
#define RB_RED 0
|
||||
#define RB_BLACK 1
|
||||
struct rb_node *rb_right;
|
||||
struct rb_node *rb_left;
|
||||
} __attribute__((aligned(sizeof(long))));
|
||||
/* The alignment might seem pointless, but allegedly CRIS needs it */
|
||||
|
||||
struct rb_root
|
||||
{
|
||||
struct rb_node *rb_node;
|
||||
};
|
||||
|
||||
|
||||
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
|
||||
#define rb_color(r) ((r)->rb_parent_color & 1)
|
||||
#define rb_is_red(r) (!rb_color(r))
|
||||
#define rb_is_black(r) rb_color(r)
|
||||
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
|
||||
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
|
||||
|
||||
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & 3) | (ULONG_PTR)p;
|
||||
}
|
||||
static inline void rb_set_color(struct rb_node *rb, ULONG_PTR color)
|
||||
{
|
||||
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
|
||||
}
|
||||
|
||||
#define RB_ROOT (struct rb_root) { NULL, }
|
||||
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
|
||||
#define RB_EMPTY_NODE(node) (rb_parent(node) != node)
|
||||
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
|
||||
|
||||
extern void rb_insert_color(struct rb_node *, struct rb_root *);
|
||||
extern void rb_erase(struct rb_node *, struct rb_root *);
|
||||
|
||||
/* Find logical next and previous nodes in a tree */
|
||||
extern struct rb_node *rb_next(struct rb_node *);
|
||||
extern struct rb_node *rb_prev(struct rb_node *);
|
||||
extern struct rb_node *rb_first(struct rb_root *);
|
||||
extern struct rb_node *rb_last(struct rb_root *);
|
||||
|
||||
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
|
||||
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
|
||||
struct rb_root *root);
|
||||
|
||||
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
|
||||
struct rb_node ** rb_link)
|
||||
{
|
||||
node->rb_parent_color = (ULONG_PTR )parent;
|
||||
node->rb_left = node->rb_right = NULL;
|
||||
|
||||
*rb_link = node;
|
||||
}
|
||||
|
||||
extern void rb_insert(struct rb_root *root, struct rb_node *node,
|
||||
int (*cmp)(struct rb_node *, struct rb_node *));
|
||||
|
||||
#endif /* _LINUX_RBTREE_H */
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#ifndef _LINUX_STDDEF_H
|
||||
#define _LINUX_STDDEF_H
|
||||
|
||||
enum {
|
||||
false = 0,
|
||||
true = 1
|
||||
};
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_STDDEF_H */
|
||||
#ifndef _LINUX_STDDEF_H
|
||||
#define _LINUX_STDDEF_H
|
||||
|
||||
enum {
|
||||
false = 0,
|
||||
true = 1
|
||||
};
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_STDDEF_H */
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by ext2fsd.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 104
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by ext2fsd.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 104
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
||||
250
Ext4Fsd/lock.c
250
Ext4Fsd/lock.c
@@ -1,125 +1,125 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: lock.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2LockControl)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject = NULL;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PIRP Irp = NULL;
|
||||
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
BOOLEAN CompleteContext = TRUE;
|
||||
BOOLEAN CompleteIrp = TRUE;
|
||||
BOOLEAN bFcbAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
|
||||
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
||||
ASSERT(Fcb != NULL);
|
||||
if (Fcb->Identifier.Type == EXT2VCB) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
__leave;
|
||||
}
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
if (FlagOn(Fcb->Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
__leave;
|
||||
}
|
||||
|
||||
ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
|
||||
bFcbAcquired = TRUE;
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
|
||||
CompleteIrp = FALSE;
|
||||
|
||||
Status = FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
Ext2OplockComplete,
|
||||
NULL );
|
||||
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
CompleteContext = FALSE;
|
||||
__leave;
|
||||
}
|
||||
|
||||
//
|
||||
// FsRtlProcessFileLock acquires FileObject->FsContext->Resource while
|
||||
// modifying the file locks and calls IoCompleteRequest when it's done.
|
||||
//
|
||||
|
||||
Status = FsRtlProcessFileLock(
|
||||
&Fcb->FileLockAnchor,
|
||||
Irp,
|
||||
NULL );
|
||||
#if EXT2_DEBUG
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
DEBUG(DL_ERR, (
|
||||
"Ext2LockControl: %-16.16s %-31s Status: %#x ***\n",
|
||||
Ext2GetCurrentProcessName(),
|
||||
"IRP_MJ_LOCK_CONTROL",
|
||||
Status ));
|
||||
}
|
||||
#endif
|
||||
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
|
||||
|
||||
} __finally {
|
||||
|
||||
if (bFcbAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
|
||||
if (!CompleteIrp) {
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
if (CompleteContext) {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: lock.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2LockControl)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject = NULL;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
PEXT2_FCB Fcb = NULL;
|
||||
PIRP Irp = NULL;
|
||||
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
BOOLEAN CompleteContext = TRUE;
|
||||
BOOLEAN CompleteIrp = TRUE;
|
||||
BOOLEAN bFcbAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FileObject = IrpContext->FileObject;
|
||||
|
||||
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
||||
ASSERT(Fcb != NULL);
|
||||
if (Fcb->Identifier.Type == EXT2VCB) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
__leave;
|
||||
}
|
||||
|
||||
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
||||
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
||||
|
||||
if (FlagOn(Fcb->Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
__leave;
|
||||
}
|
||||
|
||||
ExAcquireResourceSharedLite(&Fcb->MainResource, TRUE);
|
||||
bFcbAcquired = TRUE;
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
|
||||
CompleteIrp = FALSE;
|
||||
|
||||
Status = FsRtlCheckOplock( &Fcb->Oplock,
|
||||
Irp,
|
||||
IrpContext,
|
||||
Ext2OplockComplete,
|
||||
NULL );
|
||||
|
||||
if (Status != STATUS_SUCCESS) {
|
||||
CompleteContext = FALSE;
|
||||
__leave;
|
||||
}
|
||||
|
||||
//
|
||||
// FsRtlProcessFileLock acquires FileObject->FsContext->Resource while
|
||||
// modifying the file locks and calls IoCompleteRequest when it's done.
|
||||
//
|
||||
|
||||
Status = FsRtlProcessFileLock(
|
||||
&Fcb->FileLockAnchor,
|
||||
Irp,
|
||||
NULL );
|
||||
#if EXT2_DEBUG
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
DEBUG(DL_ERR, (
|
||||
"Ext2LockControl: %-16.16s %-31s Status: %#x ***\n",
|
||||
Ext2GetCurrentProcessName(),
|
||||
"IRP_MJ_LOCK_CONTROL",
|
||||
Status ));
|
||||
}
|
||||
#endif
|
||||
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
|
||||
|
||||
} __finally {
|
||||
|
||||
if (bFcbAcquired) {
|
||||
ExReleaseResourceLite(&Fcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
|
||||
if (!CompleteIrp) {
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
if (CompleteContext) {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
1064
Ext4Fsd/misc.c
1064
Ext4Fsd/misc.c
File diff suppressed because it is too large
Load Diff
462
Ext4Fsd/nls.c
462
Ext4Fsd/nls.c
@@ -1,232 +1,232 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: nls.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GOBALS** ****************************************************************/
|
||||
|
||||
extern struct nls_table *tables;
|
||||
extern spinlock_t nls_lock;
|
||||
|
||||
/* DECLARES ****************************************************************/
|
||||
|
||||
#define FULL_CODEPAGES_SUPPORT
|
||||
|
||||
#ifdef FULL_CODEPAGES_SUPPORT
|
||||
|
||||
DECLARE_INIT(init_nls_ascii);
|
||||
DECLARE_EXIT(exit_nls_ascii);
|
||||
DECLARE_INIT(init_nls_cp1250);
|
||||
DECLARE_EXIT(exit_nls_cp1250);
|
||||
DECLARE_INIT(init_nls_cp1251);
|
||||
DECLARE_EXIT(exit_nls_cp1251);
|
||||
DECLARE_INIT(init_nls_cp1255);
|
||||
DECLARE_EXIT(exit_nls_cp1255);
|
||||
DECLARE_INIT(init_nls_cp437);
|
||||
DECLARE_EXIT(exit_nls_cp437);
|
||||
DECLARE_INIT(init_nls_cp737);
|
||||
DECLARE_EXIT(exit_nls_cp737);
|
||||
DECLARE_INIT(init_nls_cp775);
|
||||
DECLARE_EXIT(exit_nls_cp775);
|
||||
DECLARE_INIT(init_nls_cp850);
|
||||
DECLARE_EXIT(exit_nls_cp850);
|
||||
DECLARE_INIT(init_nls_cp852);
|
||||
DECLARE_EXIT(exit_nls_cp852);
|
||||
DECLARE_INIT(init_nls_cp855);
|
||||
DECLARE_EXIT(exit_nls_cp855);
|
||||
DECLARE_INIT(init_nls_cp857);
|
||||
DECLARE_EXIT(exit_nls_cp857);
|
||||
DECLARE_INIT(init_nls_cp860);
|
||||
DECLARE_EXIT(exit_nls_cp860);
|
||||
DECLARE_INIT(init_nls_cp861);
|
||||
DECLARE_EXIT(exit_nls_cp861);
|
||||
DECLARE_INIT(init_nls_cp862);
|
||||
DECLARE_EXIT(exit_nls_cp862);
|
||||
DECLARE_INIT(init_nls_cp863);
|
||||
DECLARE_EXIT(exit_nls_cp863);
|
||||
DECLARE_INIT(init_nls_cp864);
|
||||
DECLARE_EXIT(exit_nls_cp864);
|
||||
DECLARE_INIT(init_nls_cp865);
|
||||
DECLARE_EXIT(exit_nls_cp865);
|
||||
DECLARE_INIT(init_nls_cp866);
|
||||
DECLARE_EXIT(exit_nls_cp866);
|
||||
DECLARE_INIT(init_nls_cp869);
|
||||
DECLARE_EXIT(exit_nls_cp869);
|
||||
DECLARE_INIT(init_nls_cp874);
|
||||
DECLARE_EXIT(exit_nls_cp874);
|
||||
DECLARE_INIT(init_nls_cp932);
|
||||
DECLARE_EXIT(exit_nls_cp932);
|
||||
DECLARE_INIT(init_nls_cp949);
|
||||
DECLARE_EXIT(exit_nls_cp949);
|
||||
DECLARE_INIT(init_nls_euc_jp);
|
||||
DECLARE_EXIT(exit_nls_euc_jp);
|
||||
DECLARE_INIT(init_nls_iso8859_1);
|
||||
DECLARE_EXIT(exit_nls_iso8859_1);
|
||||
DECLARE_INIT(init_nls_iso8859_13);
|
||||
DECLARE_EXIT(exit_nls_iso8859_13);
|
||||
DECLARE_INIT(init_nls_iso8859_14);
|
||||
DECLARE_EXIT(exit_nls_iso8859_14);
|
||||
DECLARE_INIT(init_nls_iso8859_15);
|
||||
DECLARE_EXIT(exit_nls_iso8859_15);
|
||||
DECLARE_INIT(init_nls_iso8859_2);
|
||||
DECLARE_EXIT(exit_nls_iso8859_2);
|
||||
DECLARE_INIT(init_nls_iso8859_3);
|
||||
DECLARE_EXIT(exit_nls_iso8859_3);
|
||||
DECLARE_INIT(init_nls_iso8859_4);
|
||||
DECLARE_EXIT(exit_nls_iso8859_4);
|
||||
DECLARE_INIT(init_nls_iso8859_5);
|
||||
DECLARE_EXIT(exit_nls_iso8859_5);
|
||||
DECLARE_INIT(init_nls_iso8859_6);
|
||||
DECLARE_EXIT(exit_nls_iso8859_6);
|
||||
DECLARE_INIT(init_nls_iso8859_7);
|
||||
DECLARE_EXIT(exit_nls_iso8859_7);
|
||||
DECLARE_INIT(init_nls_iso8859_9);
|
||||
DECLARE_EXIT(exit_nls_iso8859_9);
|
||||
DECLARE_INIT(init_nls_koi8_r);
|
||||
DECLARE_EXIT(exit_nls_koi8_r);
|
||||
DECLARE_INIT(init_nls_koi8_ru);
|
||||
DECLARE_EXIT(exit_nls_koi8_ru);
|
||||
DECLARE_INIT(init_nls_koi8_u);
|
||||
DECLARE_EXIT(exit_nls_koi8_u);
|
||||
#endif //FULL_CODEPAGES_SUPPORT
|
||||
|
||||
/* gb2312 */
|
||||
DECLARE_INIT(init_nls_cp936);
|
||||
DECLARE_EXIT(exit_nls_cp936);
|
||||
|
||||
/* big5 */
|
||||
DECLARE_INIT(init_nls_cp950);
|
||||
DECLARE_EXIT(exit_nls_cp950);
|
||||
|
||||
/* utf8 */
|
||||
DECLARE_INIT(init_nls_utf8);
|
||||
DECLARE_EXIT(exit_nls_utf8);
|
||||
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
|
||||
int
|
||||
Ext2LoadAllNls()
|
||||
{
|
||||
int rc;
|
||||
|
||||
tables = NULL;
|
||||
spin_lock_init(&nls_lock);
|
||||
|
||||
/* loading utf8 ... */
|
||||
LOAD_NLS(init_nls_utf8);
|
||||
|
||||
#ifdef FULL_CODEPAGES_SUPPORT
|
||||
|
||||
/* loading chinese gb2312 and big5... */
|
||||
LOAD_NLS(init_nls_cp936);
|
||||
LOAD_NLS(init_nls_cp950);
|
||||
|
||||
/* loading all others */
|
||||
|
||||
LOAD_NLS(init_nls_ascii);
|
||||
LOAD_NLS(init_nls_cp1250);
|
||||
LOAD_NLS(init_nls_cp1251);
|
||||
LOAD_NLS(init_nls_cp1255);
|
||||
LOAD_NLS(init_nls_cp437);
|
||||
LOAD_NLS(init_nls_cp737);
|
||||
LOAD_NLS(init_nls_cp775);
|
||||
LOAD_NLS(init_nls_cp850);
|
||||
LOAD_NLS(init_nls_cp852);
|
||||
LOAD_NLS(init_nls_cp855);
|
||||
LOAD_NLS(init_nls_cp857);
|
||||
LOAD_NLS(init_nls_cp860);
|
||||
LOAD_NLS(init_nls_cp861);
|
||||
LOAD_NLS(init_nls_cp862);
|
||||
LOAD_NLS(init_nls_cp863);
|
||||
LOAD_NLS(init_nls_cp864);
|
||||
LOAD_NLS(init_nls_cp865);
|
||||
LOAD_NLS(init_nls_cp866);
|
||||
LOAD_NLS(init_nls_cp869);
|
||||
LOAD_NLS(init_nls_cp874);
|
||||
LOAD_NLS(init_nls_cp932);
|
||||
LOAD_NLS(init_nls_euc_jp);
|
||||
LOAD_NLS(init_nls_cp949);
|
||||
LOAD_NLS(init_nls_iso8859_1);
|
||||
LOAD_NLS(init_nls_iso8859_13);
|
||||
LOAD_NLS(init_nls_iso8859_14);
|
||||
LOAD_NLS(init_nls_iso8859_15);
|
||||
LOAD_NLS(init_nls_iso8859_2);
|
||||
LOAD_NLS(init_nls_iso8859_3);
|
||||
LOAD_NLS(init_nls_iso8859_4);
|
||||
LOAD_NLS(init_nls_iso8859_5);
|
||||
LOAD_NLS(init_nls_iso8859_6);
|
||||
LOAD_NLS(init_nls_iso8859_7);
|
||||
LOAD_NLS(init_nls_iso8859_9);
|
||||
LOAD_NLS(init_nls_koi8_r);
|
||||
LOAD_NLS(init_nls_koi8_u);
|
||||
LOAD_NLS(init_nls_koi8_ru);
|
||||
|
||||
#endif //FULL_CODEPAGES_SUPPORT
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
Ext2UnloadAllNls()
|
||||
{
|
||||
|
||||
#ifdef FULL_CODEPAGES_SUPPORT
|
||||
|
||||
UNLOAD_NLS(init_nls_ascii);
|
||||
UNLOAD_NLS(init_nls_cp1250);
|
||||
UNLOAD_NLS(exit_nls_cp1251);
|
||||
UNLOAD_NLS(exit_nls_cp1255);
|
||||
UNLOAD_NLS(exit_nls_cp437);
|
||||
UNLOAD_NLS(exit_nls_cp737);
|
||||
UNLOAD_NLS(exit_nls_cp775);
|
||||
UNLOAD_NLS(exit_nls_cp850);
|
||||
UNLOAD_NLS(exit_nls_cp852);
|
||||
UNLOAD_NLS(exit_nls_cp855);
|
||||
UNLOAD_NLS(exit_nls_cp857);
|
||||
UNLOAD_NLS(exit_nls_cp860);
|
||||
UNLOAD_NLS(exit_nls_cp861);
|
||||
UNLOAD_NLS(exit_nls_cp862);
|
||||
UNLOAD_NLS(exit_nls_cp863);
|
||||
UNLOAD_NLS(exit_nls_cp864);
|
||||
UNLOAD_NLS(exit_nls_cp865);
|
||||
UNLOAD_NLS(exit_nls_cp866);
|
||||
UNLOAD_NLS(exit_nls_cp869);
|
||||
UNLOAD_NLS(exit_nls_cp874);
|
||||
UNLOAD_NLS(exit_nls_euc_jp);
|
||||
UNLOAD_NLS(exit_nls_cp932);
|
||||
UNLOAD_NLS(exit_nls_cp949);
|
||||
UNLOAD_NLS(exit_nls_iso8859_1);
|
||||
UNLOAD_NLS(exit_nls_iso8859_13);
|
||||
UNLOAD_NLS(exit_nls_iso8859_14);
|
||||
UNLOAD_NLS(exit_nls_iso8859_15);
|
||||
UNLOAD_NLS(exit_nls_iso8859_2);
|
||||
UNLOAD_NLS(exit_nls_iso8859_3);
|
||||
UNLOAD_NLS(exit_nls_iso8859_4);
|
||||
UNLOAD_NLS(exit_nls_iso8859_5);
|
||||
UNLOAD_NLS(exit_nls_iso8859_6);
|
||||
UNLOAD_NLS(exit_nls_iso8859_7);
|
||||
UNLOAD_NLS(exit_nls_iso8859_9);
|
||||
UNLOAD_NLS(exit_nls_koi8_ru);
|
||||
UNLOAD_NLS(exit_nls_koi8_r);
|
||||
UNLOAD_NLS(exit_nls_koi8_u);
|
||||
|
||||
/* unloading chinese codepages */
|
||||
UNLOAD_NLS(exit_nls_cp950);
|
||||
UNLOAD_NLS(exit_nls_cp936);
|
||||
|
||||
#endif //FULL_CODEPAGES_SUPPORT
|
||||
|
||||
/* unloading nls of utf8 */
|
||||
UNLOAD_NLS(exit_nls_utf8);
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: nls.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GOBALS** ****************************************************************/
|
||||
|
||||
extern struct nls_table *tables;
|
||||
extern spinlock_t nls_lock;
|
||||
|
||||
/* DECLARES ****************************************************************/
|
||||
|
||||
#define FULL_CODEPAGES_SUPPORT
|
||||
|
||||
#ifdef FULL_CODEPAGES_SUPPORT
|
||||
|
||||
DECLARE_INIT(init_nls_ascii);
|
||||
DECLARE_EXIT(exit_nls_ascii);
|
||||
DECLARE_INIT(init_nls_cp1250);
|
||||
DECLARE_EXIT(exit_nls_cp1250);
|
||||
DECLARE_INIT(init_nls_cp1251);
|
||||
DECLARE_EXIT(exit_nls_cp1251);
|
||||
DECLARE_INIT(init_nls_cp1255);
|
||||
DECLARE_EXIT(exit_nls_cp1255);
|
||||
DECLARE_INIT(init_nls_cp437);
|
||||
DECLARE_EXIT(exit_nls_cp437);
|
||||
DECLARE_INIT(init_nls_cp737);
|
||||
DECLARE_EXIT(exit_nls_cp737);
|
||||
DECLARE_INIT(init_nls_cp775);
|
||||
DECLARE_EXIT(exit_nls_cp775);
|
||||
DECLARE_INIT(init_nls_cp850);
|
||||
DECLARE_EXIT(exit_nls_cp850);
|
||||
DECLARE_INIT(init_nls_cp852);
|
||||
DECLARE_EXIT(exit_nls_cp852);
|
||||
DECLARE_INIT(init_nls_cp855);
|
||||
DECLARE_EXIT(exit_nls_cp855);
|
||||
DECLARE_INIT(init_nls_cp857);
|
||||
DECLARE_EXIT(exit_nls_cp857);
|
||||
DECLARE_INIT(init_nls_cp860);
|
||||
DECLARE_EXIT(exit_nls_cp860);
|
||||
DECLARE_INIT(init_nls_cp861);
|
||||
DECLARE_EXIT(exit_nls_cp861);
|
||||
DECLARE_INIT(init_nls_cp862);
|
||||
DECLARE_EXIT(exit_nls_cp862);
|
||||
DECLARE_INIT(init_nls_cp863);
|
||||
DECLARE_EXIT(exit_nls_cp863);
|
||||
DECLARE_INIT(init_nls_cp864);
|
||||
DECLARE_EXIT(exit_nls_cp864);
|
||||
DECLARE_INIT(init_nls_cp865);
|
||||
DECLARE_EXIT(exit_nls_cp865);
|
||||
DECLARE_INIT(init_nls_cp866);
|
||||
DECLARE_EXIT(exit_nls_cp866);
|
||||
DECLARE_INIT(init_nls_cp869);
|
||||
DECLARE_EXIT(exit_nls_cp869);
|
||||
DECLARE_INIT(init_nls_cp874);
|
||||
DECLARE_EXIT(exit_nls_cp874);
|
||||
DECLARE_INIT(init_nls_cp932);
|
||||
DECLARE_EXIT(exit_nls_cp932);
|
||||
DECLARE_INIT(init_nls_cp949);
|
||||
DECLARE_EXIT(exit_nls_cp949);
|
||||
DECLARE_INIT(init_nls_euc_jp);
|
||||
DECLARE_EXIT(exit_nls_euc_jp);
|
||||
DECLARE_INIT(init_nls_iso8859_1);
|
||||
DECLARE_EXIT(exit_nls_iso8859_1);
|
||||
DECLARE_INIT(init_nls_iso8859_13);
|
||||
DECLARE_EXIT(exit_nls_iso8859_13);
|
||||
DECLARE_INIT(init_nls_iso8859_14);
|
||||
DECLARE_EXIT(exit_nls_iso8859_14);
|
||||
DECLARE_INIT(init_nls_iso8859_15);
|
||||
DECLARE_EXIT(exit_nls_iso8859_15);
|
||||
DECLARE_INIT(init_nls_iso8859_2);
|
||||
DECLARE_EXIT(exit_nls_iso8859_2);
|
||||
DECLARE_INIT(init_nls_iso8859_3);
|
||||
DECLARE_EXIT(exit_nls_iso8859_3);
|
||||
DECLARE_INIT(init_nls_iso8859_4);
|
||||
DECLARE_EXIT(exit_nls_iso8859_4);
|
||||
DECLARE_INIT(init_nls_iso8859_5);
|
||||
DECLARE_EXIT(exit_nls_iso8859_5);
|
||||
DECLARE_INIT(init_nls_iso8859_6);
|
||||
DECLARE_EXIT(exit_nls_iso8859_6);
|
||||
DECLARE_INIT(init_nls_iso8859_7);
|
||||
DECLARE_EXIT(exit_nls_iso8859_7);
|
||||
DECLARE_INIT(init_nls_iso8859_9);
|
||||
DECLARE_EXIT(exit_nls_iso8859_9);
|
||||
DECLARE_INIT(init_nls_koi8_r);
|
||||
DECLARE_EXIT(exit_nls_koi8_r);
|
||||
DECLARE_INIT(init_nls_koi8_ru);
|
||||
DECLARE_EXIT(exit_nls_koi8_ru);
|
||||
DECLARE_INIT(init_nls_koi8_u);
|
||||
DECLARE_EXIT(exit_nls_koi8_u);
|
||||
#endif //FULL_CODEPAGES_SUPPORT
|
||||
|
||||
/* gb2312 */
|
||||
DECLARE_INIT(init_nls_cp936);
|
||||
DECLARE_EXIT(exit_nls_cp936);
|
||||
|
||||
/* big5 */
|
||||
DECLARE_INIT(init_nls_cp950);
|
||||
DECLARE_EXIT(exit_nls_cp950);
|
||||
|
||||
/* utf8 */
|
||||
DECLARE_INIT(init_nls_utf8);
|
||||
DECLARE_EXIT(exit_nls_utf8);
|
||||
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
|
||||
int
|
||||
Ext2LoadAllNls()
|
||||
{
|
||||
int rc;
|
||||
|
||||
tables = NULL;
|
||||
spin_lock_init(&nls_lock);
|
||||
|
||||
/* loading utf8 ... */
|
||||
LOAD_NLS(init_nls_utf8);
|
||||
|
||||
#ifdef FULL_CODEPAGES_SUPPORT
|
||||
|
||||
/* loading chinese gb2312 and big5... */
|
||||
LOAD_NLS(init_nls_cp936);
|
||||
LOAD_NLS(init_nls_cp950);
|
||||
|
||||
/* loading all others */
|
||||
|
||||
LOAD_NLS(init_nls_ascii);
|
||||
LOAD_NLS(init_nls_cp1250);
|
||||
LOAD_NLS(init_nls_cp1251);
|
||||
LOAD_NLS(init_nls_cp1255);
|
||||
LOAD_NLS(init_nls_cp437);
|
||||
LOAD_NLS(init_nls_cp737);
|
||||
LOAD_NLS(init_nls_cp775);
|
||||
LOAD_NLS(init_nls_cp850);
|
||||
LOAD_NLS(init_nls_cp852);
|
||||
LOAD_NLS(init_nls_cp855);
|
||||
LOAD_NLS(init_nls_cp857);
|
||||
LOAD_NLS(init_nls_cp860);
|
||||
LOAD_NLS(init_nls_cp861);
|
||||
LOAD_NLS(init_nls_cp862);
|
||||
LOAD_NLS(init_nls_cp863);
|
||||
LOAD_NLS(init_nls_cp864);
|
||||
LOAD_NLS(init_nls_cp865);
|
||||
LOAD_NLS(init_nls_cp866);
|
||||
LOAD_NLS(init_nls_cp869);
|
||||
LOAD_NLS(init_nls_cp874);
|
||||
LOAD_NLS(init_nls_cp932);
|
||||
LOAD_NLS(init_nls_euc_jp);
|
||||
LOAD_NLS(init_nls_cp949);
|
||||
LOAD_NLS(init_nls_iso8859_1);
|
||||
LOAD_NLS(init_nls_iso8859_13);
|
||||
LOAD_NLS(init_nls_iso8859_14);
|
||||
LOAD_NLS(init_nls_iso8859_15);
|
||||
LOAD_NLS(init_nls_iso8859_2);
|
||||
LOAD_NLS(init_nls_iso8859_3);
|
||||
LOAD_NLS(init_nls_iso8859_4);
|
||||
LOAD_NLS(init_nls_iso8859_5);
|
||||
LOAD_NLS(init_nls_iso8859_6);
|
||||
LOAD_NLS(init_nls_iso8859_7);
|
||||
LOAD_NLS(init_nls_iso8859_9);
|
||||
LOAD_NLS(init_nls_koi8_r);
|
||||
LOAD_NLS(init_nls_koi8_u);
|
||||
LOAD_NLS(init_nls_koi8_ru);
|
||||
|
||||
#endif //FULL_CODEPAGES_SUPPORT
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
Ext2UnloadAllNls()
|
||||
{
|
||||
|
||||
#ifdef FULL_CODEPAGES_SUPPORT
|
||||
|
||||
UNLOAD_NLS(init_nls_ascii);
|
||||
UNLOAD_NLS(init_nls_cp1250);
|
||||
UNLOAD_NLS(exit_nls_cp1251);
|
||||
UNLOAD_NLS(exit_nls_cp1255);
|
||||
UNLOAD_NLS(exit_nls_cp437);
|
||||
UNLOAD_NLS(exit_nls_cp737);
|
||||
UNLOAD_NLS(exit_nls_cp775);
|
||||
UNLOAD_NLS(exit_nls_cp850);
|
||||
UNLOAD_NLS(exit_nls_cp852);
|
||||
UNLOAD_NLS(exit_nls_cp855);
|
||||
UNLOAD_NLS(exit_nls_cp857);
|
||||
UNLOAD_NLS(exit_nls_cp860);
|
||||
UNLOAD_NLS(exit_nls_cp861);
|
||||
UNLOAD_NLS(exit_nls_cp862);
|
||||
UNLOAD_NLS(exit_nls_cp863);
|
||||
UNLOAD_NLS(exit_nls_cp864);
|
||||
UNLOAD_NLS(exit_nls_cp865);
|
||||
UNLOAD_NLS(exit_nls_cp866);
|
||||
UNLOAD_NLS(exit_nls_cp869);
|
||||
UNLOAD_NLS(exit_nls_cp874);
|
||||
UNLOAD_NLS(exit_nls_euc_jp);
|
||||
UNLOAD_NLS(exit_nls_cp932);
|
||||
UNLOAD_NLS(exit_nls_cp949);
|
||||
UNLOAD_NLS(exit_nls_iso8859_1);
|
||||
UNLOAD_NLS(exit_nls_iso8859_13);
|
||||
UNLOAD_NLS(exit_nls_iso8859_14);
|
||||
UNLOAD_NLS(exit_nls_iso8859_15);
|
||||
UNLOAD_NLS(exit_nls_iso8859_2);
|
||||
UNLOAD_NLS(exit_nls_iso8859_3);
|
||||
UNLOAD_NLS(exit_nls_iso8859_4);
|
||||
UNLOAD_NLS(exit_nls_iso8859_5);
|
||||
UNLOAD_NLS(exit_nls_iso8859_6);
|
||||
UNLOAD_NLS(exit_nls_iso8859_7);
|
||||
UNLOAD_NLS(exit_nls_iso8859_9);
|
||||
UNLOAD_NLS(exit_nls_koi8_ru);
|
||||
UNLOAD_NLS(exit_nls_koi8_r);
|
||||
UNLOAD_NLS(exit_nls_koi8_u);
|
||||
|
||||
/* unloading chinese codepages */
|
||||
UNLOAD_NLS(exit_nls_cp950);
|
||||
UNLOAD_NLS(exit_nls_cp936);
|
||||
|
||||
#endif //FULL_CODEPAGES_SUPPORT
|
||||
|
||||
/* unloading nls of utf8 */
|
||||
UNLOAD_NLS(exit_nls_utf8);
|
||||
}
|
||||
792
Ext4Fsd/pnp.c
792
Ext4Fsd/pnp.c
@@ -1,397 +1,397 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: pnp.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
#if (_WIN32_WINNT >= 0x0500)
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt );
|
||||
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2Pnp)
|
||||
#pragma alloc_text(PAGE, Ext2PnpQueryRemove)
|
||||
#pragma alloc_text(PAGE, Ext2PnpRemove)
|
||||
#pragma alloc_text(PAGE, Ext2PnpCancelRemove)
|
||||
#pragma alloc_text(PAGE, Ext2PnpSurpriseRemove)
|
||||
#endif
|
||||
|
||||
|
||||
/* FUNCTIONS *************************************************************/
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt
|
||||
)
|
||||
{
|
||||
PKEVENT Event = (PKEVENT) Contxt;
|
||||
|
||||
KeSetEvent( Event, 0, FALSE );
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
|
||||
UNREFERENCED_PARAMETER( DeviceObject );
|
||||
UNREFERENCED_PARAMETER( Contxt );
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2Pnp (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
PIRP Irp;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
|
||||
ASSERT(Vcb != NULL);
|
||||
|
||||
if ( !((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)))) {
|
||||
__leave; // Status = STATUS_INVALID_PARAMETER
|
||||
}
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
|
||||
switch ( IrpSp->MinorFunction ) {
|
||||
|
||||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpQueryRemove...\n"));
|
||||
Status = Ext2PnpQueryRemove(IrpContext, Vcb);
|
||||
|
||||
break;
|
||||
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpRemove...\n"));
|
||||
Status = Ext2PnpRemove(IrpContext, Vcb);
|
||||
break;
|
||||
|
||||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpCancelRemove...\n"));
|
||||
Status = Ext2PnpCancelRemove(IrpContext, Vcb);
|
||||
break;
|
||||
|
||||
case IRP_MN_SURPRISE_REMOVAL:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpSupriseRemove...\n"));
|
||||
Status = Ext2PnpSurpriseRemove(IrpContext, Vcb);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
Irp = IrpContext->Irp;
|
||||
|
||||
if (Irp) {
|
||||
|
||||
//
|
||||
// Here we need pass the IRP to the disk driver.
|
||||
//
|
||||
|
||||
IoSkipCurrentIrpStackLocation( Irp );
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpQueryRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb
|
||||
)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
KEVENT Event;
|
||||
BOOLEAN bDeleted = FALSE;
|
||||
BOOLEAN VcbAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
|
||||
VcbAcquired = ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
|
||||
Ext2FlushFiles(IrpContext, Vcb, FALSE);
|
||||
Ext2FlushVolume(IrpContext, Vcb, FALSE);
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2LockVcb: Vcb=%xh FileObject=%xh ...\n",
|
||||
Vcb, IrpContext->FileObject));
|
||||
Status = Ext2LockVcb(Vcb, IrpContext->FileObject);
|
||||
|
||||
if (VcbAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
VcbAcquired = FALSE;
|
||||
}
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2PurgeVolume ...\n"));
|
||||
Ext2PurgeVolume(Vcb, TRUE);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( IrpContext->Irp,
|
||||
Ext2PnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Call lower level driver...\n"));
|
||||
Status = IoCallDriver( Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
Status = IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
ASSERT(!VcbAcquired);
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2CheckDismount ...\n"));
|
||||
bDeleted = Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2FlushVolume bDelted=%xh ...\n", bDeleted));
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (VcbAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteRequest(
|
||||
IrpContext->Irp, FALSE, (CCHAR)(NT_SUCCESS(Status)?
|
||||
IO_DISK_INCREMENT : IO_NO_INCREMENT) );
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb )
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
KEVENT Event;
|
||||
BOOLEAN bDeleted;
|
||||
|
||||
__try {
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpRemove by Ext2Pnp ...\n"));
|
||||
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
Status = Ext2LockVcb(Vcb, IrpContext->FileObject);
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
//
|
||||
// Setup the Irp. We'll send it to the lower disk driver.
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( IrpContext->Irp,
|
||||
Ext2PnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
Status = IoCallDriver( Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
/* purge volume cache */
|
||||
Ext2PurgeVolume(Vcb, FALSE);
|
||||
|
||||
/* dismount volume */
|
||||
bDeleted = Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
||||
SetLongFlag(Vcb->Flags, VCB_DEVICE_REMOVED);
|
||||
|
||||
} __finally {
|
||||
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteRequest(
|
||||
IrpContext->Irp, FALSE, (CCHAR)(NT_SUCCESS(Status)?
|
||||
IO_DISK_INCREMENT : IO_NO_INCREMENT) );
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpSurpriseRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb )
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KEVENT Event;
|
||||
BOOLEAN bDeleted;
|
||||
|
||||
__try {
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpSupriseRemove by Ext2Pnp ...\n"));
|
||||
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
|
||||
Status = Ext2LockVcb(Vcb, IrpContext->FileObject);
|
||||
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
//
|
||||
// Setup the Irp. We'll send it to the lower disk driver.
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( IrpContext->Irp,
|
||||
Ext2PnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
Status = IoCallDriver( Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
/* purge volume cache */
|
||||
Ext2PurgeVolume(Vcb, FALSE);
|
||||
|
||||
/* dismount volume */
|
||||
bDeleted = Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
||||
SetLongFlag(Vcb->Flags, VCB_DEVICE_REMOVED);
|
||||
|
||||
} __finally {
|
||||
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteRequest(
|
||||
IrpContext->Irp, FALSE, (CCHAR)(NT_SUCCESS(Status)?
|
||||
IO_DISK_INCREMENT : IO_NO_INCREMENT) );
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpCancelRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb
|
||||
)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpCancelRemove by Ext2Pnp ...\n"));
|
||||
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
|
||||
Status = Ext2UnlockVcb(Vcb, IrpContext->FileObject);
|
||||
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
IoSkipCurrentIrpStackLocation(IrpContext->Irp);
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, IrpContext->Irp);
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: pnp.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
#if (_WIN32_WINNT >= 0x0500)
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt );
|
||||
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2Pnp)
|
||||
#pragma alloc_text(PAGE, Ext2PnpQueryRemove)
|
||||
#pragma alloc_text(PAGE, Ext2PnpRemove)
|
||||
#pragma alloc_text(PAGE, Ext2PnpCancelRemove)
|
||||
#pragma alloc_text(PAGE, Ext2PnpSurpriseRemove)
|
||||
#endif
|
||||
|
||||
|
||||
/* FUNCTIONS *************************************************************/
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpCompletionRoutine (
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Contxt
|
||||
)
|
||||
{
|
||||
PKEVENT Event = (PKEVENT) Contxt;
|
||||
|
||||
KeSetEvent( Event, 0, FALSE );
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
|
||||
UNREFERENCED_PARAMETER( DeviceObject );
|
||||
UNREFERENCED_PARAMETER( Contxt );
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2Pnp (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
NTSTATUS Status = STATUS_INVALID_PARAMETER;
|
||||
|
||||
PIRP Irp;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
|
||||
ASSERT(Vcb != NULL);
|
||||
|
||||
if ( !((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)))) {
|
||||
__leave; // Status = STATUS_INVALID_PARAMETER
|
||||
}
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||||
|
||||
switch ( IrpSp->MinorFunction ) {
|
||||
|
||||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpQueryRemove...\n"));
|
||||
Status = Ext2PnpQueryRemove(IrpContext, Vcb);
|
||||
|
||||
break;
|
||||
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpRemove...\n"));
|
||||
Status = Ext2PnpRemove(IrpContext, Vcb);
|
||||
break;
|
||||
|
||||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpCancelRemove...\n"));
|
||||
Status = Ext2PnpCancelRemove(IrpContext, Vcb);
|
||||
break;
|
||||
|
||||
case IRP_MN_SURPRISE_REMOVAL:
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2Pnp: Ext2PnpSupriseRemove...\n"));
|
||||
Status = Ext2PnpSurpriseRemove(IrpContext, Vcb);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
Irp = IrpContext->Irp;
|
||||
|
||||
if (Irp) {
|
||||
|
||||
//
|
||||
// Here we need pass the IRP to the disk driver.
|
||||
//
|
||||
|
||||
IoSkipCurrentIrpStackLocation( Irp );
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpQueryRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb
|
||||
)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
KEVENT Event;
|
||||
BOOLEAN bDeleted = FALSE;
|
||||
BOOLEAN VcbAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
|
||||
VcbAcquired = ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
|
||||
Ext2FlushFiles(IrpContext, Vcb, FALSE);
|
||||
Ext2FlushVolume(IrpContext, Vcb, FALSE);
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2LockVcb: Vcb=%xh FileObject=%xh ...\n",
|
||||
Vcb, IrpContext->FileObject));
|
||||
Status = Ext2LockVcb(Vcb, IrpContext->FileObject);
|
||||
|
||||
if (VcbAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
VcbAcquired = FALSE;
|
||||
}
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2PurgeVolume ...\n"));
|
||||
Ext2PurgeVolume(Vcb, TRUE);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
__leave;
|
||||
}
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( IrpContext->Irp,
|
||||
Ext2PnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Call lower level driver...\n"));
|
||||
Status = IoCallDriver( Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
Status = IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
ASSERT(!VcbAcquired);
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2CheckDismount ...\n"));
|
||||
bDeleted = Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
||||
DEBUG(DL_PNP, ("Ext2PnpQueryRemove: Ext2FlushVolume bDelted=%xh ...\n", bDeleted));
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (VcbAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteRequest(
|
||||
IrpContext->Irp, FALSE, (CCHAR)(NT_SUCCESS(Status)?
|
||||
IO_DISK_INCREMENT : IO_NO_INCREMENT) );
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb )
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
KEVENT Event;
|
||||
BOOLEAN bDeleted;
|
||||
|
||||
__try {
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpRemove by Ext2Pnp ...\n"));
|
||||
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
Status = Ext2LockVcb(Vcb, IrpContext->FileObject);
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
//
|
||||
// Setup the Irp. We'll send it to the lower disk driver.
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( IrpContext->Irp,
|
||||
Ext2PnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
Status = IoCallDriver( Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
/* purge volume cache */
|
||||
Ext2PurgeVolume(Vcb, FALSE);
|
||||
|
||||
/* dismount volume */
|
||||
bDeleted = Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
||||
SetLongFlag(Vcb->Flags, VCB_DEVICE_REMOVED);
|
||||
|
||||
} __finally {
|
||||
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteRequest(
|
||||
IrpContext->Irp, FALSE, (CCHAR)(NT_SUCCESS(Status)?
|
||||
IO_DISK_INCREMENT : IO_NO_INCREMENT) );
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpSurpriseRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb )
|
||||
{
|
||||
NTSTATUS Status;
|
||||
KEVENT Event;
|
||||
BOOLEAN bDeleted;
|
||||
|
||||
__try {
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpSupriseRemove by Ext2Pnp ...\n"));
|
||||
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
|
||||
Status = Ext2LockVcb(Vcb, IrpContext->FileObject);
|
||||
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
//
|
||||
// Setup the Irp. We'll send it to the lower disk driver.
|
||||
//
|
||||
|
||||
IoCopyCurrentIrpStackLocationToNext(IrpContext->Irp);
|
||||
|
||||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||||
IoSetCompletionRoutine( IrpContext->Irp,
|
||||
Ext2PnpCompletionRoutine,
|
||||
&Event,
|
||||
TRUE,
|
||||
TRUE,
|
||||
TRUE );
|
||||
|
||||
Status = IoCallDriver( Vcb->TargetDeviceObject,
|
||||
IrpContext->Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
|
||||
KeWaitForSingleObject( &Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL );
|
||||
|
||||
Status = IrpContext->Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
/* purge volume cache */
|
||||
Ext2PurgeVolume(Vcb, FALSE);
|
||||
|
||||
/* dismount volume */
|
||||
bDeleted = Ext2CheckDismount(IrpContext, Vcb, TRUE);
|
||||
SetLongFlag(Vcb->Flags, VCB_DEVICE_REMOVED);
|
||||
|
||||
} __finally {
|
||||
|
||||
IrpContext->Irp->IoStatus.Status = Status;
|
||||
Ext2CompleteRequest(
|
||||
IrpContext->Irp, FALSE, (CCHAR)(NT_SUCCESS(Status)?
|
||||
IO_DISK_INCREMENT : IO_NO_INCREMENT) );
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2PnpCancelRemove (
|
||||
PEXT2_IRP_CONTEXT IrpContext,
|
||||
PEXT2_VCB Vcb
|
||||
)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
DEBUG(DL_PNP, ("Ext2PnpCancelRemove by Ext2Pnp ...\n"));
|
||||
|
||||
ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE );
|
||||
|
||||
Status = Ext2UnlockVcb(Vcb, IrpContext->FileObject);
|
||||
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
|
||||
IoSkipCurrentIrpStackLocation(IrpContext->Irp);
|
||||
|
||||
Status = IoCallDriver(Vcb->TargetDeviceObject, IrpContext->Irp);
|
||||
|
||||
IrpContext->Irp = NULL;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
#endif //(_WIN32_WINNT >= 0x0500)
|
||||
830
Ext4Fsd/rbtree.c
830
Ext4Fsd/rbtree.c
@@ -1,415 +1,415 @@
|
||||
/*
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
(C) 2002 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
linux/lib/rbtree.c
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *right = node->rb_right;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_right = right->rb_left))
|
||||
rb_set_parent(right->rb_left, node);
|
||||
right->rb_left = node;
|
||||
|
||||
rb_set_parent(right, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_left)
|
||||
parent->rb_left = right;
|
||||
else
|
||||
parent->rb_right = right;
|
||||
}
|
||||
else
|
||||
root->rb_node = right;
|
||||
rb_set_parent(node, right);
|
||||
}
|
||||
|
||||
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *left = node->rb_left;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_left = left->rb_right))
|
||||
rb_set_parent(left->rb_right, node);
|
||||
left->rb_right = node;
|
||||
|
||||
rb_set_parent(left, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_right)
|
||||
parent->rb_right = left;
|
||||
else
|
||||
parent->rb_left = left;
|
||||
}
|
||||
else
|
||||
root->rb_node = left;
|
||||
rb_set_parent(node, left);
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent, *gparent;
|
||||
|
||||
while ((parent = rb_parent(node)) && rb_is_red(parent))
|
||||
{
|
||||
gparent = rb_parent(parent);
|
||||
|
||||
if (parent == gparent->rb_left)
|
||||
{
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_right;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_right == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_left(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_right(gparent, root);
|
||||
} else {
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_left;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_right(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_left(gparent, root);
|
||||
}
|
||||
}
|
||||
|
||||
rb_set_black(root->rb_node);
|
||||
}
|
||||
EXPORT_SYMBOL(rb_insert_color);
|
||||
|
||||
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *other;
|
||||
|
||||
while ((!node || rb_is_black(node)) && node != root->rb_node)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
other = parent->rb_right;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_left(parent, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_right || rb_is_black(other->rb_right))
|
||||
{
|
||||
struct rb_node *o_left;
|
||||
if ((o_left = other->rb_left))
|
||||
rb_set_black(o_left);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_right(other, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
if (other->rb_right)
|
||||
rb_set_black(other->rb_right);
|
||||
__rb_rotate_left(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other = parent->rb_left;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_right(parent, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_left || rb_is_black(other->rb_left))
|
||||
{
|
||||
register struct rb_node *o_right;
|
||||
if ((o_right = other->rb_right))
|
||||
rb_set_black(o_right);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_left(other, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
if (other->rb_left)
|
||||
rb_set_black(other->rb_left);
|
||||
__rb_rotate_right(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
rb_set_black(node);
|
||||
}
|
||||
|
||||
void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *child, *parent;
|
||||
ULONG_PTR color;
|
||||
|
||||
if (!node->rb_left)
|
||||
child = node->rb_right;
|
||||
else if (!node->rb_right)
|
||||
child = node->rb_left;
|
||||
else
|
||||
{
|
||||
struct rb_node *old = node, *left;
|
||||
|
||||
node = node->rb_right;
|
||||
while ((left = node->rb_left) != NULL)
|
||||
node = left;
|
||||
child = node->rb_right;
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent == old) {
|
||||
parent->rb_right = child;
|
||||
parent = node;
|
||||
} else
|
||||
parent->rb_left = child;
|
||||
|
||||
node->rb_parent_color = old->rb_parent_color;
|
||||
node->rb_right = old->rb_right;
|
||||
node->rb_left = old->rb_left;
|
||||
|
||||
if (rb_parent(old))
|
||||
{
|
||||
if (rb_parent(old)->rb_left == old)
|
||||
rb_parent(old)->rb_left = node;
|
||||
else
|
||||
rb_parent(old)->rb_right = node;
|
||||
} else
|
||||
root->rb_node = node;
|
||||
|
||||
rb_set_parent(old->rb_left, node);
|
||||
if (old->rb_right)
|
||||
rb_set_parent(old->rb_right, node);
|
||||
goto color;
|
||||
}
|
||||
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
parent->rb_left = child;
|
||||
else
|
||||
parent->rb_right = child;
|
||||
}
|
||||
else
|
||||
root->rb_node = child;
|
||||
|
||||
color:
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
EXPORT_SYMBOL(rb_erase);
|
||||
|
||||
/*
|
||||
* This function returns the first node (in sort order) of the tree.
|
||||
*/
|
||||
struct rb_node *rb_first(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *n;
|
||||
|
||||
n = root->rb_node;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->rb_left)
|
||||
n = n->rb_left;
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_first);
|
||||
|
||||
struct rb_node *rb_last(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *n;
|
||||
|
||||
n = root->rb_node;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->rb_right)
|
||||
n = n->rb_right;
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_last);
|
||||
|
||||
struct rb_node *rb_next(struct rb_node *node)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
|
||||
/* If we have a right-hand child, go down and then left as far
|
||||
as we can. */
|
||||
if (node->rb_right) {
|
||||
node = node->rb_right;
|
||||
while (node->rb_left)
|
||||
node=node->rb_left;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* No right-hand children. Everything down and left is
|
||||
smaller than us, so any 'next' node must be in the general
|
||||
direction of our parent. Go up the tree; any time the
|
||||
ancestor is a right-hand child of its parent, keep going
|
||||
up. First time it's a left-hand child of its parent, said
|
||||
parent is our 'next' node. */
|
||||
while ((parent = rb_parent(node)) && node == parent->rb_right)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_next);
|
||||
|
||||
struct rb_node *rb_prev(struct rb_node *node)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
|
||||
/* If we have a left-hand child, go down and then right as far
|
||||
as we can. */
|
||||
if (node->rb_left) {
|
||||
node = node->rb_left;
|
||||
while (node->rb_right)
|
||||
node=node->rb_right;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* No left-hand children. Go up till we find an ancestor which
|
||||
is a right-hand child of its parent */
|
||||
while ((parent = rb_parent(node)) && node == parent->rb_left)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_prev);
|
||||
|
||||
void rb_replace_node(struct rb_node *victim, struct rb_node *new,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent = rb_parent(victim);
|
||||
|
||||
/* Set the surrounding nodes to point to the replacement */
|
||||
if (parent) {
|
||||
if (victim == parent->rb_left)
|
||||
parent->rb_left = new;
|
||||
else
|
||||
parent->rb_right = new;
|
||||
} else {
|
||||
root->rb_node = new;
|
||||
}
|
||||
if (victim->rb_left)
|
||||
rb_set_parent(victim->rb_left, new);
|
||||
if (victim->rb_right)
|
||||
rb_set_parent(victim->rb_right, new);
|
||||
|
||||
/* Copy the pointers/colour from the victim to the replacement */
|
||||
*new = *victim;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_replace_node);
|
||||
|
||||
void rb_insert(struct rb_root *root, struct rb_node *node,
|
||||
int (*cmp)(struct rb_node *, struct rb_node *))
|
||||
{
|
||||
struct rb_node **new = &(root->rb_node), *parent = NULL;
|
||||
|
||||
/* Figure out where to put new node */
|
||||
while (*new) {
|
||||
int result = cmp(node, *new);
|
||||
|
||||
parent = *new;
|
||||
if (result < 0)
|
||||
new = &((*new)->rb_left);
|
||||
else if (result > 0)
|
||||
new = &((*new)->rb_right);
|
||||
else
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Add new node and rebalance tree. */
|
||||
rb_link_node(node, parent, new);
|
||||
rb_insert_color(node, root);
|
||||
}
|
||||
EXPORT_SYMBOL(rb_insert);
|
||||
/*
|
||||
Red Black Trees
|
||||
(C) 1999 Andrea Arcangeli <andrea@suse.de>
|
||||
(C) 2002 David Woodhouse <dwmw2@infradead.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
linux/lib/rbtree.c
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *right = node->rb_right;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_right = right->rb_left))
|
||||
rb_set_parent(right->rb_left, node);
|
||||
right->rb_left = node;
|
||||
|
||||
rb_set_parent(right, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_left)
|
||||
parent->rb_left = right;
|
||||
else
|
||||
parent->rb_right = right;
|
||||
}
|
||||
else
|
||||
root->rb_node = right;
|
||||
rb_set_parent(node, right);
|
||||
}
|
||||
|
||||
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *left = node->rb_left;
|
||||
struct rb_node *parent = rb_parent(node);
|
||||
|
||||
if ((node->rb_left = left->rb_right))
|
||||
rb_set_parent(left->rb_right, node);
|
||||
left->rb_right = node;
|
||||
|
||||
rb_set_parent(left, parent);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
if (node == parent->rb_right)
|
||||
parent->rb_right = left;
|
||||
else
|
||||
parent->rb_left = left;
|
||||
}
|
||||
else
|
||||
root->rb_node = left;
|
||||
rb_set_parent(node, left);
|
||||
}
|
||||
|
||||
void rb_insert_color(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent, *gparent;
|
||||
|
||||
while ((parent = rb_parent(node)) && rb_is_red(parent))
|
||||
{
|
||||
gparent = rb_parent(parent);
|
||||
|
||||
if (parent == gparent->rb_left)
|
||||
{
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_right;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_right == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_left(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_right(gparent, root);
|
||||
} else {
|
||||
{
|
||||
register struct rb_node *uncle = gparent->rb_left;
|
||||
if (uncle && rb_is_red(uncle))
|
||||
{
|
||||
rb_set_black(uncle);
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
register struct rb_node *tmp;
|
||||
__rb_rotate_right(parent, root);
|
||||
tmp = parent;
|
||||
parent = node;
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
rb_set_black(parent);
|
||||
rb_set_red(gparent);
|
||||
__rb_rotate_left(gparent, root);
|
||||
}
|
||||
}
|
||||
|
||||
rb_set_black(root->rb_node);
|
||||
}
|
||||
EXPORT_SYMBOL(rb_insert_color);
|
||||
|
||||
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *other;
|
||||
|
||||
while ((!node || rb_is_black(node)) && node != root->rb_node)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
{
|
||||
other = parent->rb_right;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_left(parent, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_right || rb_is_black(other->rb_right))
|
||||
{
|
||||
struct rb_node *o_left;
|
||||
if ((o_left = other->rb_left))
|
||||
rb_set_black(o_left);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_right(other, root);
|
||||
other = parent->rb_right;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
if (other->rb_right)
|
||||
rb_set_black(other->rb_right);
|
||||
__rb_rotate_left(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other = parent->rb_left;
|
||||
if (rb_is_red(other))
|
||||
{
|
||||
rb_set_black(other);
|
||||
rb_set_red(parent);
|
||||
__rb_rotate_right(parent, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
|
||||
(!other->rb_right || rb_is_black(other->rb_right)))
|
||||
{
|
||||
rb_set_red(other);
|
||||
node = parent;
|
||||
parent = rb_parent(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other->rb_left || rb_is_black(other->rb_left))
|
||||
{
|
||||
register struct rb_node *o_right;
|
||||
if ((o_right = other->rb_right))
|
||||
rb_set_black(o_right);
|
||||
rb_set_red(other);
|
||||
__rb_rotate_left(other, root);
|
||||
other = parent->rb_left;
|
||||
}
|
||||
rb_set_color(other, rb_color(parent));
|
||||
rb_set_black(parent);
|
||||
if (other->rb_left)
|
||||
rb_set_black(other->rb_left);
|
||||
__rb_rotate_right(parent, root);
|
||||
node = root->rb_node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
rb_set_black(node);
|
||||
}
|
||||
|
||||
void rb_erase(struct rb_node *node, struct rb_root *root)
|
||||
{
|
||||
struct rb_node *child, *parent;
|
||||
ULONG_PTR color;
|
||||
|
||||
if (!node->rb_left)
|
||||
child = node->rb_right;
|
||||
else if (!node->rb_right)
|
||||
child = node->rb_left;
|
||||
else
|
||||
{
|
||||
struct rb_node *old = node, *left;
|
||||
|
||||
node = node->rb_right;
|
||||
while ((left = node->rb_left) != NULL)
|
||||
node = left;
|
||||
child = node->rb_right;
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent == old) {
|
||||
parent->rb_right = child;
|
||||
parent = node;
|
||||
} else
|
||||
parent->rb_left = child;
|
||||
|
||||
node->rb_parent_color = old->rb_parent_color;
|
||||
node->rb_right = old->rb_right;
|
||||
node->rb_left = old->rb_left;
|
||||
|
||||
if (rb_parent(old))
|
||||
{
|
||||
if (rb_parent(old)->rb_left == old)
|
||||
rb_parent(old)->rb_left = node;
|
||||
else
|
||||
rb_parent(old)->rb_right = node;
|
||||
} else
|
||||
root->rb_node = node;
|
||||
|
||||
rb_set_parent(old->rb_left, node);
|
||||
if (old->rb_right)
|
||||
rb_set_parent(old->rb_right, node);
|
||||
goto color;
|
||||
}
|
||||
|
||||
parent = rb_parent(node);
|
||||
color = rb_color(node);
|
||||
|
||||
if (child)
|
||||
rb_set_parent(child, parent);
|
||||
if (parent)
|
||||
{
|
||||
if (parent->rb_left == node)
|
||||
parent->rb_left = child;
|
||||
else
|
||||
parent->rb_right = child;
|
||||
}
|
||||
else
|
||||
root->rb_node = child;
|
||||
|
||||
color:
|
||||
if (color == RB_BLACK)
|
||||
__rb_erase_color(child, parent, root);
|
||||
}
|
||||
EXPORT_SYMBOL(rb_erase);
|
||||
|
||||
/*
|
||||
* This function returns the first node (in sort order) of the tree.
|
||||
*/
|
||||
struct rb_node *rb_first(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *n;
|
||||
|
||||
n = root->rb_node;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->rb_left)
|
||||
n = n->rb_left;
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_first);
|
||||
|
||||
struct rb_node *rb_last(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *n;
|
||||
|
||||
n = root->rb_node;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->rb_right)
|
||||
n = n->rb_right;
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_last);
|
||||
|
||||
struct rb_node *rb_next(struct rb_node *node)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
|
||||
/* If we have a right-hand child, go down and then left as far
|
||||
as we can. */
|
||||
if (node->rb_right) {
|
||||
node = node->rb_right;
|
||||
while (node->rb_left)
|
||||
node=node->rb_left;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* No right-hand children. Everything down and left is
|
||||
smaller than us, so any 'next' node must be in the general
|
||||
direction of our parent. Go up the tree; any time the
|
||||
ancestor is a right-hand child of its parent, keep going
|
||||
up. First time it's a left-hand child of its parent, said
|
||||
parent is our 'next' node. */
|
||||
while ((parent = rb_parent(node)) && node == parent->rb_right)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_next);
|
||||
|
||||
struct rb_node *rb_prev(struct rb_node *node)
|
||||
{
|
||||
struct rb_node *parent;
|
||||
|
||||
/* If we have a left-hand child, go down and then right as far
|
||||
as we can. */
|
||||
if (node->rb_left) {
|
||||
node = node->rb_left;
|
||||
while (node->rb_right)
|
||||
node=node->rb_right;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* No left-hand children. Go up till we find an ancestor which
|
||||
is a right-hand child of its parent */
|
||||
while ((parent = rb_parent(node)) && node == parent->rb_left)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_prev);
|
||||
|
||||
void rb_replace_node(struct rb_node *victim, struct rb_node *new,
|
||||
struct rb_root *root)
|
||||
{
|
||||
struct rb_node *parent = rb_parent(victim);
|
||||
|
||||
/* Set the surrounding nodes to point to the replacement */
|
||||
if (parent) {
|
||||
if (victim == parent->rb_left)
|
||||
parent->rb_left = new;
|
||||
else
|
||||
parent->rb_right = new;
|
||||
} else {
|
||||
root->rb_node = new;
|
||||
}
|
||||
if (victim->rb_left)
|
||||
rb_set_parent(victim->rb_left, new);
|
||||
if (victim->rb_right)
|
||||
rb_set_parent(victim->rb_right, new);
|
||||
|
||||
/* Copy the pointers/colour from the victim to the replacement */
|
||||
*new = *victim;
|
||||
}
|
||||
EXPORT_SYMBOL(rb_replace_node);
|
||||
|
||||
void rb_insert(struct rb_root *root, struct rb_node *node,
|
||||
int (*cmp)(struct rb_node *, struct rb_node *))
|
||||
{
|
||||
struct rb_node **new = &(root->rb_node), *parent = NULL;
|
||||
|
||||
/* Figure out where to put new node */
|
||||
while (*new) {
|
||||
int result = cmp(node, *new);
|
||||
|
||||
parent = *new;
|
||||
if (result < 0)
|
||||
new = &((*new)->rb_left);
|
||||
else if (result > 0)
|
||||
new = &((*new)->rb_right);
|
||||
else
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Add new node and rebalance tree. */
|
||||
rb_link_node(node, parent, new);
|
||||
rb_insert_color(node, root);
|
||||
}
|
||||
EXPORT_SYMBOL(rb_insert);
|
||||
|
||||
1890
Ext4Fsd/read.c
1890
Ext4Fsd/read.c
File diff suppressed because it is too large
Load Diff
@@ -1,118 +1,118 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: shutdown.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2ShutDown)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
Ext2ShutDown (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
PIRP Irp;
|
||||
|
||||
PEXT2_VCB Vcb;
|
||||
PLIST_ENTRY ListEntry;
|
||||
|
||||
BOOLEAN GlobalResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
ASSERT(IrpContext);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Ext2Global->Resource,
|
||||
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
|
||||
GlobalResourceAcquired = TRUE;
|
||||
|
||||
for (ListEntry = Ext2Global->VcbList.Flink;
|
||||
ListEntry != &(Ext2Global->VcbList);
|
||||
ListEntry = ListEntry->Flink ) {
|
||||
|
||||
Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
|
||||
|
||||
if (ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource,
|
||||
TRUE )) {
|
||||
|
||||
if (IsMounted(Vcb)) {
|
||||
|
||||
/* update mount count */
|
||||
Vcb->SuperBlock->s_mnt_count++;
|
||||
if (Vcb->SuperBlock->s_mnt_count >
|
||||
Vcb->SuperBlock->s_max_mnt_count ) {
|
||||
Vcb->SuperBlock->s_mnt_count =
|
||||
Vcb->SuperBlock->s_max_mnt_count;
|
||||
}
|
||||
Ext2SaveSuper(IrpContext, Vcb);
|
||||
|
||||
/* flush dirty cache for all files */
|
||||
Status = Ext2FlushFiles(IrpContext, Vcb, TRUE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
/* flush volume stream's cache to disk */
|
||||
Status = Ext2FlushVolume(IrpContext, Vcb, TRUE);
|
||||
|
||||
if (!NT_SUCCESS(Status) && Status != STATUS_MEDIA_WRITE_PROTECTED) {
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
/* send shutdown request to underlying disk */
|
||||
Ext2DiskShutDown(Vcb);
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
IoUnregisterFileSystem(Ext2Global->DiskdevObject);
|
||||
IoUnregisterFileSystem(Ext2Global->CdromdevObject);
|
||||
*/
|
||||
|
||||
} __finally {
|
||||
|
||||
if (GlobalResourceAcquired) {
|
||||
ExReleaseResourceLite(&Ext2Global->Resource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: shutdown.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2ShutDown)
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
Ext2ShutDown (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
PIRP Irp;
|
||||
|
||||
PEXT2_VCB Vcb;
|
||||
PLIST_ENTRY ListEntry;
|
||||
|
||||
BOOLEAN GlobalResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
ASSERT(IrpContext);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Ext2Global->Resource,
|
||||
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
|
||||
GlobalResourceAcquired = TRUE;
|
||||
|
||||
for (ListEntry = Ext2Global->VcbList.Flink;
|
||||
ListEntry != &(Ext2Global->VcbList);
|
||||
ListEntry = ListEntry->Flink ) {
|
||||
|
||||
Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
|
||||
|
||||
if (ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource,
|
||||
TRUE )) {
|
||||
|
||||
if (IsMounted(Vcb)) {
|
||||
|
||||
/* update mount count */
|
||||
Vcb->SuperBlock->s_mnt_count++;
|
||||
if (Vcb->SuperBlock->s_mnt_count >
|
||||
Vcb->SuperBlock->s_max_mnt_count ) {
|
||||
Vcb->SuperBlock->s_mnt_count =
|
||||
Vcb->SuperBlock->s_max_mnt_count;
|
||||
}
|
||||
Ext2SaveSuper(IrpContext, Vcb);
|
||||
|
||||
/* flush dirty cache for all files */
|
||||
Status = Ext2FlushFiles(IrpContext, Vcb, TRUE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
/* flush volume stream's cache to disk */
|
||||
Status = Ext2FlushVolume(IrpContext, Vcb, TRUE);
|
||||
|
||||
if (!NT_SUCCESS(Status) && Status != STATUS_MEDIA_WRITE_PROTECTED) {
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
/* send shutdown request to underlying disk */
|
||||
Ext2DiskShutDown(Vcb);
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
IoUnregisterFileSystem(Ext2Global->DiskdevObject);
|
||||
IoUnregisterFileSystem(Ext2Global->CdromdevObject);
|
||||
*/
|
||||
|
||||
} __finally {
|
||||
|
||||
if (GlobalResourceAcquired) {
|
||||
ExReleaseResourceLite(&Ext2Global->Resource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
@@ -1,409 +1,409 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: volinfo.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2QueryVolumeInformation)
|
||||
#pragma alloc_text(PAGE, Ext2SetVolumeInformation)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PIRP Irp = NULL;
|
||||
PIO_STACK_LOCATION IoStackLocation = NULL;
|
||||
PVOID Buffer;
|
||||
ULONG Length;
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
FS_INFORMATION_CLASS FsInformationClass;
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
//
|
||||
// This request is not allowed on the main device object
|
||||
//
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
if (!IsMounted(Vcb)) {
|
||||
Status = STATUS_VOLUME_DISMOUNTED;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (!ExAcquireResourceSharedLite(
|
||||
&Vcb->MainResource,
|
||||
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
|
||||
)) {
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
FsInformationClass =
|
||||
IoStackLocation->Parameters.QueryVolume.FsInformationClass;
|
||||
|
||||
Length = IoStackLocation->Parameters.QueryVolume.Length;
|
||||
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
RtlZeroMemory(Buffer, Length);
|
||||
|
||||
switch (FsInformationClass) {
|
||||
|
||||
case FileFsVolumeInformation:
|
||||
{
|
||||
PFILE_FS_VOLUME_INFORMATION FsVolInfo;
|
||||
ULONG VolumeLabelLength;
|
||||
ULONG RequiredLength;
|
||||
|
||||
if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsVolInfo = (PFILE_FS_VOLUME_INFORMATION) Buffer;
|
||||
FsVolInfo->VolumeCreationTime.QuadPart = 0;
|
||||
FsVolInfo->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
|
||||
VolumeLabelLength = Vcb->Vpb->VolumeLabelLength;
|
||||
FsVolInfo->VolumeLabelLength = VolumeLabelLength;
|
||||
/* We don't support ObjectId */
|
||||
FsVolInfo->SupportsObjects = FALSE;
|
||||
|
||||
RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION)
|
||||
+ VolumeLabelLength - sizeof(WCHAR);
|
||||
|
||||
if (Length < RequiredLength) {
|
||||
Irp->IoStatus.Information =
|
||||
sizeof(FILE_FS_VOLUME_INFORMATION);
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
RtlCopyMemory(FsVolInfo->VolumeLabel, Vcb->Vpb->VolumeLabel, Vcb->Vpb->VolumeLabelLength);
|
||||
|
||||
Irp->IoStatus.Information = RequiredLength;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileFsSizeInformation:
|
||||
{
|
||||
PFILE_FS_SIZE_INFORMATION FsSizeInfo;
|
||||
|
||||
if (Length < sizeof(FILE_FS_SIZE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsSizeInfo = (PFILE_FS_SIZE_INFORMATION) Buffer;
|
||||
FsSizeInfo->TotalAllocationUnits.QuadPart =
|
||||
ext3_blocks_count(SUPER_BLOCK);
|
||||
FsSizeInfo->AvailableAllocationUnits.QuadPart =
|
||||
ext3_free_blocks_count(SUPER_BLOCK);
|
||||
FsSizeInfo->SectorsPerAllocationUnit =
|
||||
Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector;
|
||||
FsSizeInfo->BytesPerSector =
|
||||
Vcb->DiskGeometry.BytesPerSector;
|
||||
|
||||
Irp->IoStatus.Information = sizeof(FILE_FS_SIZE_INFORMATION);
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileFsDeviceInformation:
|
||||
{
|
||||
PFILE_FS_DEVICE_INFORMATION FsDevInfo;
|
||||
|
||||
if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsDevInfo = (PFILE_FS_DEVICE_INFORMATION) Buffer;
|
||||
FsDevInfo->DeviceType =
|
||||
Vcb->TargetDeviceObject->DeviceType;
|
||||
|
||||
if (FsDevInfo->DeviceType != FILE_DEVICE_DISK) {
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
FsDevInfo->Characteristics =
|
||||
Vcb->TargetDeviceObject->Characteristics;
|
||||
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
SetFlag( FsDevInfo->Characteristics,
|
||||
FILE_READ_ONLY_DEVICE );
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = sizeof(FILE_FS_DEVICE_INFORMATION);
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileFsAttributeInformation:
|
||||
{
|
||||
PFILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
|
||||
ULONG RequiredLength;
|
||||
|
||||
if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsAttrInfo =
|
||||
(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_EXTENDED_ATTRIBUTES;
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
|
||||
}
|
||||
FsAttrInfo->MaximumComponentNameLength = EXT2_NAME_LEN;
|
||||
FsAttrInfo->FileSystemNameLength = 8;
|
||||
|
||||
RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
|
||||
8 - sizeof(WCHAR);
|
||||
|
||||
if (Length < RequiredLength) {
|
||||
Irp->IoStatus.Information =
|
||||
sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
|
||||
RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT4\0", 10);
|
||||
} else if (Vcb->IsExt3fs) {
|
||||
RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT3\0", 10);
|
||||
} else {
|
||||
RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT2\0", 10);
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = RequiredLength;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
#if (_WIN32_WINNT >= 0x0500)
|
||||
|
||||
case FileFsFullSizeInformation:
|
||||
{
|
||||
PFILE_FS_FULL_SIZE_INFORMATION PFFFSI;
|
||||
|
||||
if (Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
PFFFSI = (PFILE_FS_FULL_SIZE_INFORMATION) Buffer;
|
||||
|
||||
/*
|
||||
typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
|
||||
LARGE_INTEGER TotalAllocationUnits;
|
||||
LARGE_INTEGER CallerAvailableAllocationUnits;
|
||||
LARGE_INTEGER ActualAvailableAllocationUnits;
|
||||
ULONG SectorsPerAllocationUnit;
|
||||
ULONG BytesPerSector;
|
||||
} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
|
||||
*/
|
||||
|
||||
{
|
||||
PFFFSI->TotalAllocationUnits.QuadPart =
|
||||
ext3_blocks_count(SUPER_BLOCK);
|
||||
|
||||
PFFFSI->CallerAvailableAllocationUnits.QuadPart =
|
||||
ext3_free_blocks_count(SUPER_BLOCK);
|
||||
|
||||
/* - Vcb->SuperBlock->s_r_blocks_count; */
|
||||
PFFFSI->ActualAvailableAllocationUnits.QuadPart =
|
||||
ext3_free_blocks_count(SUPER_BLOCK);
|
||||
}
|
||||
|
||||
PFFFSI->SectorsPerAllocationUnit =
|
||||
Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector;
|
||||
|
||||
PFFFSI->BytesPerSector = Vcb->DiskGeometry.BytesPerSector;
|
||||
|
||||
Irp->IoStatus.Information = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
#endif // (_WIN32_WINNT >= 0x0500)
|
||||
|
||||
default:
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2SetVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PIRP Irp;
|
||||
PIO_STACK_LOCATION IoStackLocation;
|
||||
FS_INFORMATION_CLASS FsInformationClass;
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
//
|
||||
// This request is not allowed on the main device object
|
||||
//
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
ASSERT(IsMounted(Vcb));
|
||||
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE)) {
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
Ext2VerifyVcb(IrpContext, Vcb);
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
//Notes: SetVolume is not defined in ntddk.h of win2k ddk,
|
||||
// But it's same to QueryVolume ....
|
||||
FsInformationClass =
|
||||
IoStackLocation->Parameters./*SetVolume*/QueryVolume.FsInformationClass;
|
||||
|
||||
switch (FsInformationClass) {
|
||||
|
||||
case FileFsLabelInformation:
|
||||
{
|
||||
PFILE_FS_LABEL_INFORMATION VolLabelInfo = NULL;
|
||||
ULONG VolLabelLen;
|
||||
UNICODE_STRING LabelName ;
|
||||
|
||||
OEM_STRING OemName;
|
||||
|
||||
VolLabelInfo = (PFILE_FS_LABEL_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
|
||||
VolLabelLen = VolLabelInfo->VolumeLabelLength;
|
||||
|
||||
if (VolLabelLen > (16 * sizeof(WCHAR))) {
|
||||
Status = STATUS_INVALID_VOLUME_LABEL;
|
||||
__leave;
|
||||
}
|
||||
|
||||
RtlCopyMemory( Vcb->Vpb->VolumeLabel,
|
||||
VolLabelInfo->VolumeLabel,
|
||||
VolLabelLen );
|
||||
|
||||
RtlZeroMemory(Vcb->SuperBlock->s_volume_name, 16);
|
||||
LabelName.Buffer = VolLabelInfo->VolumeLabel;
|
||||
LabelName.MaximumLength = (USHORT)16 * sizeof(WCHAR);
|
||||
LabelName.Length = (USHORT)VolLabelLen;
|
||||
|
||||
OemName.Buffer = SUPER_BLOCK->s_volume_name;
|
||||
OemName.Length = 0;
|
||||
OemName.MaximumLength = 16;
|
||||
|
||||
Ext2UnicodeToOEM(Vcb, &OemName, &LabelName);
|
||||
Vcb->Vpb->VolumeLabelLength = (USHORT) VolLabelLen;
|
||||
|
||||
if (Ext2SaveSuper(IrpContext, Vcb)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
/*
|
||||
* COPYRIGHT: See COPYRIGHT.TXT
|
||||
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
||||
* FILE: volinfo.c
|
||||
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
||||
* HOMEPAGE: http://www.ext2fsd.com
|
||||
* UPDATE HISTORY:
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "ext2fs.h"
|
||||
|
||||
/* GLOBALS ***************************************************************/
|
||||
|
||||
extern PEXT2_GLOBAL Ext2Global;
|
||||
|
||||
/* DEFINITIONS *************************************************************/
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, Ext2QueryVolumeInformation)
|
||||
#pragma alloc_text(PAGE, Ext2SetVolumeInformation)
|
||||
#endif
|
||||
|
||||
|
||||
NTSTATUS
|
||||
Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PIRP Irp = NULL;
|
||||
PIO_STACK_LOCATION IoStackLocation = NULL;
|
||||
PVOID Buffer;
|
||||
ULONG Length;
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
FS_INFORMATION_CLASS FsInformationClass;
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
//
|
||||
// This request is not allowed on the main device object
|
||||
//
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
|
||||
if (!IsMounted(Vcb)) {
|
||||
Status = STATUS_VOLUME_DISMOUNTED;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (!ExAcquireResourceSharedLite(
|
||||
&Vcb->MainResource,
|
||||
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
|
||||
)) {
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
FsInformationClass =
|
||||
IoStackLocation->Parameters.QueryVolume.FsInformationClass;
|
||||
|
||||
Length = IoStackLocation->Parameters.QueryVolume.Length;
|
||||
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
RtlZeroMemory(Buffer, Length);
|
||||
|
||||
switch (FsInformationClass) {
|
||||
|
||||
case FileFsVolumeInformation:
|
||||
{
|
||||
PFILE_FS_VOLUME_INFORMATION FsVolInfo;
|
||||
ULONG VolumeLabelLength;
|
||||
ULONG RequiredLength;
|
||||
|
||||
if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsVolInfo = (PFILE_FS_VOLUME_INFORMATION) Buffer;
|
||||
FsVolInfo->VolumeCreationTime.QuadPart = 0;
|
||||
FsVolInfo->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
|
||||
VolumeLabelLength = Vcb->Vpb->VolumeLabelLength;
|
||||
FsVolInfo->VolumeLabelLength = VolumeLabelLength;
|
||||
/* We don't support ObjectId */
|
||||
FsVolInfo->SupportsObjects = FALSE;
|
||||
|
||||
RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION)
|
||||
+ VolumeLabelLength - sizeof(WCHAR);
|
||||
|
||||
if (Length < RequiredLength) {
|
||||
Irp->IoStatus.Information =
|
||||
sizeof(FILE_FS_VOLUME_INFORMATION);
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
RtlCopyMemory(FsVolInfo->VolumeLabel, Vcb->Vpb->VolumeLabel, Vcb->Vpb->VolumeLabelLength);
|
||||
|
||||
Irp->IoStatus.Information = RequiredLength;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileFsSizeInformation:
|
||||
{
|
||||
PFILE_FS_SIZE_INFORMATION FsSizeInfo;
|
||||
|
||||
if (Length < sizeof(FILE_FS_SIZE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsSizeInfo = (PFILE_FS_SIZE_INFORMATION) Buffer;
|
||||
FsSizeInfo->TotalAllocationUnits.QuadPart =
|
||||
ext3_blocks_count(SUPER_BLOCK);
|
||||
FsSizeInfo->AvailableAllocationUnits.QuadPart =
|
||||
ext3_free_blocks_count(SUPER_BLOCK);
|
||||
FsSizeInfo->SectorsPerAllocationUnit =
|
||||
Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector;
|
||||
FsSizeInfo->BytesPerSector =
|
||||
Vcb->DiskGeometry.BytesPerSector;
|
||||
|
||||
Irp->IoStatus.Information = sizeof(FILE_FS_SIZE_INFORMATION);
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileFsDeviceInformation:
|
||||
{
|
||||
PFILE_FS_DEVICE_INFORMATION FsDevInfo;
|
||||
|
||||
if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsDevInfo = (PFILE_FS_DEVICE_INFORMATION) Buffer;
|
||||
FsDevInfo->DeviceType =
|
||||
Vcb->TargetDeviceObject->DeviceType;
|
||||
|
||||
if (FsDevInfo->DeviceType != FILE_DEVICE_DISK) {
|
||||
DbgBreak();
|
||||
}
|
||||
|
||||
FsDevInfo->Characteristics =
|
||||
Vcb->TargetDeviceObject->Characteristics;
|
||||
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
SetFlag( FsDevInfo->Characteristics,
|
||||
FILE_READ_ONLY_DEVICE );
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = sizeof(FILE_FS_DEVICE_INFORMATION);
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case FileFsAttributeInformation:
|
||||
{
|
||||
PFILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
|
||||
ULONG RequiredLength;
|
||||
|
||||
if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
FsAttrInfo =
|
||||
(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_EXTENDED_ATTRIBUTES;
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
|
||||
}
|
||||
FsAttrInfo->MaximumComponentNameLength = EXT2_NAME_LEN;
|
||||
FsAttrInfo->FileSystemNameLength = 8;
|
||||
|
||||
RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
|
||||
8 - sizeof(WCHAR);
|
||||
|
||||
if (Length < RequiredLength) {
|
||||
Irp->IoStatus.Information =
|
||||
sizeof(FILE_FS_ATTRIBUTE_INFORMATION);
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
|
||||
RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT4\0", 10);
|
||||
} else if (Vcb->IsExt3fs) {
|
||||
RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT3\0", 10);
|
||||
} else {
|
||||
RtlCopyMemory(FsAttrInfo->FileSystemName, L"EXT2\0", 10);
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = RequiredLength;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
#if (_WIN32_WINNT >= 0x0500)
|
||||
|
||||
case FileFsFullSizeInformation:
|
||||
{
|
||||
PFILE_FS_FULL_SIZE_INFORMATION PFFFSI;
|
||||
|
||||
if (Length < sizeof(FILE_FS_FULL_SIZE_INFORMATION)) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
__leave;
|
||||
}
|
||||
|
||||
PFFFSI = (PFILE_FS_FULL_SIZE_INFORMATION) Buffer;
|
||||
|
||||
/*
|
||||
typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
|
||||
LARGE_INTEGER TotalAllocationUnits;
|
||||
LARGE_INTEGER CallerAvailableAllocationUnits;
|
||||
LARGE_INTEGER ActualAvailableAllocationUnits;
|
||||
ULONG SectorsPerAllocationUnit;
|
||||
ULONG BytesPerSector;
|
||||
} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
|
||||
*/
|
||||
|
||||
{
|
||||
PFFFSI->TotalAllocationUnits.QuadPart =
|
||||
ext3_blocks_count(SUPER_BLOCK);
|
||||
|
||||
PFFFSI->CallerAvailableAllocationUnits.QuadPart =
|
||||
ext3_free_blocks_count(SUPER_BLOCK);
|
||||
|
||||
/* - Vcb->SuperBlock->s_r_blocks_count; */
|
||||
PFFFSI->ActualAvailableAllocationUnits.QuadPart =
|
||||
ext3_free_blocks_count(SUPER_BLOCK);
|
||||
}
|
||||
|
||||
PFFFSI->SectorsPerAllocationUnit =
|
||||
Vcb->BlockSize / Vcb->DiskGeometry.BytesPerSector;
|
||||
|
||||
PFFFSI->BytesPerSector = Vcb->DiskGeometry.BytesPerSector;
|
||||
|
||||
Irp->IoStatus.Information = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
#endif // (_WIN32_WINNT >= 0x0500)
|
||||
|
||||
default:
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
Ext2SetVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
|
||||
{
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||||
PEXT2_VCB Vcb = NULL;
|
||||
PIRP Irp;
|
||||
PIO_STACK_LOCATION IoStackLocation;
|
||||
FS_INFORMATION_CLASS FsInformationClass;
|
||||
BOOLEAN VcbResourceAcquired = FALSE;
|
||||
|
||||
__try {
|
||||
|
||||
ASSERT(IrpContext != NULL);
|
||||
|
||||
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
||||
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
||||
|
||||
DeviceObject = IrpContext->DeviceObject;
|
||||
|
||||
//
|
||||
// This request is not allowed on the main device object
|
||||
//
|
||||
if (IsExt2FsDevice(DeviceObject)) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
__leave;
|
||||
}
|
||||
|
||||
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
||||
ASSERT(Vcb != NULL);
|
||||
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
||||
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
||||
ASSERT(IsMounted(Vcb));
|
||||
|
||||
if (IsVcbReadOnly(Vcb)) {
|
||||
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
||||
__leave;
|
||||
}
|
||||
|
||||
if (!ExAcquireResourceExclusiveLite(
|
||||
&Vcb->MainResource, TRUE)) {
|
||||
Status = STATUS_PENDING;
|
||||
__leave;
|
||||
}
|
||||
VcbResourceAcquired = TRUE;
|
||||
|
||||
Ext2VerifyVcb(IrpContext, Vcb);
|
||||
|
||||
Irp = IrpContext->Irp;
|
||||
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
//Notes: SetVolume is not defined in ntddk.h of win2k ddk,
|
||||
// But it's same to QueryVolume ....
|
||||
FsInformationClass =
|
||||
IoStackLocation->Parameters./*SetVolume*/QueryVolume.FsInformationClass;
|
||||
|
||||
switch (FsInformationClass) {
|
||||
|
||||
case FileFsLabelInformation:
|
||||
{
|
||||
PFILE_FS_LABEL_INFORMATION VolLabelInfo = NULL;
|
||||
ULONG VolLabelLen;
|
||||
UNICODE_STRING LabelName ;
|
||||
|
||||
OEM_STRING OemName;
|
||||
|
||||
VolLabelInfo = (PFILE_FS_LABEL_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
|
||||
VolLabelLen = VolLabelInfo->VolumeLabelLength;
|
||||
|
||||
if (VolLabelLen > (16 * sizeof(WCHAR))) {
|
||||
Status = STATUS_INVALID_VOLUME_LABEL;
|
||||
__leave;
|
||||
}
|
||||
|
||||
RtlCopyMemory( Vcb->Vpb->VolumeLabel,
|
||||
VolLabelInfo->VolumeLabel,
|
||||
VolLabelLen );
|
||||
|
||||
RtlZeroMemory(Vcb->SuperBlock->s_volume_name, 16);
|
||||
LabelName.Buffer = VolLabelInfo->VolumeLabel;
|
||||
LabelName.MaximumLength = (USHORT)16 * sizeof(WCHAR);
|
||||
LabelName.Length = (USHORT)VolLabelLen;
|
||||
|
||||
OemName.Buffer = SUPER_BLOCK->s_volume_name;
|
||||
OemName.Length = 0;
|
||||
OemName.MaximumLength = 16;
|
||||
|
||||
Ext2UnicodeToOEM(Vcb, &OemName, &LabelName);
|
||||
Vcb->Vpb->VolumeLabelLength = (USHORT) VolLabelLen;
|
||||
|
||||
if (Ext2SaveSuper(IrpContext, Vcb)) {
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
} __finally {
|
||||
|
||||
if (VcbResourceAcquired) {
|
||||
ExReleaseResourceLite(&Vcb->MainResource);
|
||||
}
|
||||
|
||||
if (!IrpContext->ExceptionInProgress) {
|
||||
if (Status == STATUS_PENDING) {
|
||||
Ext2QueueRequest(IrpContext);
|
||||
} else {
|
||||
Ext2CompleteIrpContext(IrpContext, Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
2846
Ext4Fsd/write.c
2846
Ext4Fsd/write.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user