Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matt-wu/Ext3Fsd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xExt3Fsd/create.c64
-rw-r--r--Ext3Fsd/dirctl.c30
-rwxr-xr-xExt3Fsd/ext3/generic.c63
-rw-r--r--Ext3Fsd/fsctl.c602
-rwxr-xr-xExt3Fsd/include/ext2fs.h49
-rwxr-xr-xExt3Fsd/memory.c7
-rwxr-xr-xExt3Fsd/read.c9
-rwxr-xr-xExt3Fsd/volinfo.c3
-rwxr-xr-xExt3Fsd/write.c7
9 files changed, 790 insertions, 44 deletions
diff --git a/Ext3Fsd/create.c b/Ext3Fsd/create.c
index 8b28418..fcaba3a 100755
--- a/Ext3Fsd/create.c
+++ b/Ext3Fsd/create.c
@@ -68,7 +68,7 @@ Ext2FollowLink (
IN PEXT2_VCB Vcb,
IN PEXT2_MCB Parent,
IN PEXT2_MCB Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
)
{
NTSTATUS Status = STATUS_LINK_FAILED;
@@ -88,12 +88,12 @@ Ext2FollowLink (
/* exit if we jump into a possible symlink forever loop */
if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS ||
- IoGetRemainingStackSize() < 1024) {
+ IoGetRemainingStackSize() < 1024) {
__leave;
}
/* read the symlink target path */
- if (Mcb->Inode.i_size < EXT2_LINKLEN_IN_INODE) {
+ if (!Mcb->Inode.i_blocks) {
OemName.Buffer = (PUCHAR) (&Mcb->Inode.i_block[0]);
OemName.Length = (USHORT)Mcb->Inode.i_size;
@@ -113,14 +113,12 @@ Ext2FollowLink (
bOemBuffer = TRUE;
RtlZeroMemory(OemName.Buffer, OemName.MaximumLength);
- Status = Ext2ReadInode(
+ Status = Ext2ReadSymlink(
IrpContext,
Vcb,
Mcb,
- (ULONGLONG)0,
OemName.Buffer,
(ULONG)(Mcb->Inode.i_size),
- FALSE,
NULL);
if (!NT_SUCCESS(Status)) {
__leave;
@@ -170,9 +168,9 @@ Ext2FollowLink (
}
if (Target == NULL /* link target doesn't exist */ ||
- Target == Mcb /* symlink points to itself */ ||
- IsMcbSpecialFile(Target) /* target not resolved*/ ||
- IsFileDeleted(Target) /* target deleted */ ) {
+ Target == Mcb /* symlink points to itself */ ||
+ IsMcbSpecialFile(Target) /* target not resolved*/ ||
+ IsFileDeleted(Target) /* target deleted */ ) {
if (Target) {
ASSERT(Target->Refercount > 0);
@@ -180,7 +178,6 @@ Ext2FollowLink (
}
ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
- Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL;
Mcb->Target = NULL;
} else if (IsMcbSymLink(Target)) {
@@ -194,15 +191,18 @@ Ext2FollowLink (
SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ASSERT(Mcb->Target->Refercount > 0);
- Mcb->FileAttr = Target->FileAttr;
-
+
} else {
Mcb->Target = Target;
SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ASSERT(Mcb->Target->Refercount > 0);
- Mcb->FileAttr = Target->FileAttr;
+ }
+
+ /* add directory flag to file attribute */
+ if (Mcb->Target && IsMcbDirectory(Mcb->Target)) {
+ Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY;
}
} __finally {
@@ -275,7 +275,7 @@ Ext2LookupFile (
IN PUNICODE_STRING FullName,
IN PEXT2_MCB Parent,
OUT PEXT2_MCB * Ext2Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
)
{
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
@@ -289,12 +289,16 @@ Ext2LookupFile (
BOOLEAN bParent = FALSE;
BOOLEAN bDirectory = FALSE;
BOOLEAN LockAcquired = FALSE;
+ BOOLEAN bNotFollow = FALSE;
__try {
ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
LockAcquired = TRUE;
+ bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW);
+ Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
+
*Ext2Mcb = NULL;
DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName));
@@ -394,7 +398,7 @@ Ext2LookupFile (
Parent = Mcb;
if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) &&
- (Mcb->Refercount == 1)) {
+ Mcb->Refercount == 1) {
ASSERT(Mcb->Target);
ASSERT(Mcb->Target->Refercount > 0);
@@ -460,9 +464,11 @@ Ext2LookupFile (
if (S_ISDIR(Mcb->Inode.i_mode)) {
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
} else {
- SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
- if (!S_ISREG(Mcb->Inode.i_mode) &&
- !S_ISLNK(Mcb->Inode.i_mode)) {
+ if (S_ISREG(Mcb->Inode.i_mode)) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
+ } else if (S_ISLNK(Mcb->Inode.i_mode)) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+ } else {
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
}
}
@@ -484,7 +490,7 @@ Ext2LookupFile (
Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime);
/* process symlink */
- if (S_ISLNK(Mcb->Inode.i_mode)) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) {
Ext2FollowLink( IrpContext,
Vcb,
Parent,
@@ -706,9 +712,11 @@ Ext2CreateFile(
BOOLEAN DeleteOnClose;
BOOLEAN TemporaryFile;
BOOLEAN CaseSensitive;
+ BOOLEAN OpenReparsePoint;
ACCESS_MASK DesiredAccess;
ULONG ShareAccess;
+ ULONG CcbFlags = 0;
RtlZeroMemory(&FileName, sizeof(UNICODE_STRING));
@@ -726,6 +734,9 @@ Ext2CreateFile(
NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
+ /* Try to open reparse point (symlink) itself ? */
+ OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT);
+
CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
@@ -841,7 +852,8 @@ Ext2CreateFile(
&FileName,
ParentMcb,
&Mcb,
- 0 );
+ 0 /* always follow link */
+ );
McbExisting:
if (!NT_SUCCESS(Status)) {
@@ -1101,7 +1113,7 @@ Dissecting:
if (IsMcbDirectory(Mcb)) {
if ((CreateDisposition != FILE_OPEN) &&
- (CreateDisposition != FILE_OPEN_IF)) {
+ (CreateDisposition != FILE_OPEN_IF)) {
Status = STATUS_OBJECT_NAME_COLLISION;
Ext2DerefMcb(Mcb);
@@ -1144,7 +1156,11 @@ Openit:
/* refer it's target if it's a symlink, so both refered */
if (IsMcbSymLink(Mcb)) {
- if (IsFileDeleted(Mcb->Target)) {
+
+ if (OpenReparsePoint) {
+ /* set Ccb flag */
+ CcbFlags = CCB_OPEN_REPARSE_POINT;
+ } else if (IsFileDeleted(Mcb->Target)) {
DbgBreak();
SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
@@ -1396,7 +1412,7 @@ Openit:
&(Fcb->ShareAccess) );
}
- Ccb = Ext2AllocateCcb(SymLink);
+ Ccb = Ext2AllocateCcb(CcbFlags, SymLink);
if (!Ccb) {
Status = STATUS_INSUFFICIENT_RESOURCES;
DbgBreak();
@@ -1682,7 +1698,7 @@ Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
return STATUS_SHARING_VIOLATION;
}
- Ccb = Ext2AllocateCcb(NULL);
+ Ccb = Ext2AllocateCcb(0, NULL);
if (Ccb == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout;
diff --git a/Ext3Fsd/dirctl.c b/Ext3Fsd/dirctl.c
index 611c515..6840dc0 100644
--- a/Ext3Fsd/dirctl.c
+++ b/Ext3Fsd/dirctl.c
@@ -94,6 +94,8 @@ Ext2ProcessEntry(
LONGLONG AllocationSize;
ULONG FileAttributes = 0;
+ BOOLEAN IsEntrySymlink = FALSE;
+
*EntrySize = 0;
NameLength = pName->Length;
ASSERT((UsedLength & 7) == 0);
@@ -118,7 +120,12 @@ Ext2ProcessEntry(
DEBUG(DL_CP, ("Ext2ProcessDirEntry: %wZ in %wZ\n", pName, &Dcb->Mcb->FullName ));
Mcb = Ext2SearchMcb(Vcb, Dcb->Mcb, pName);
- if (NULL == Mcb) {
+ if (NULL != Mcb) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && NULL == Mcb->Target) {
+ Ext2FollowLink( IrpContext, Vcb, Dcb->Mcb, Mcb, 0);
+ }
+
+ } else {
Inode.i_ino = in;
Inode.i_sb = &Vcb->sb;
@@ -134,7 +141,7 @@ Ext2ProcessEntry(
} else if (S_ISLNK(Inode.i_mode)) {
DEBUG(DL_RES, ("Ext2ProcessDirEntry: SymLink: %wZ\\%wZ\n",
&Dcb->Mcb->FullName, pName));
- Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb, 0);
+ Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb,0);
if (Mcb && IsMcbSpecialFile(Mcb)) {
Ext2DerefMcb(Mcb);
@@ -154,6 +161,7 @@ Ext2ProcessEntry(
ASSERT(!IsMcbSymLink(Target));
if (IsMcbDirectory(Target)) {
FileSize = 0;
+ FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
} else {
FileSize = Target->Inode.i_size;
}
@@ -169,6 +177,10 @@ Ext2ProcessEntry(
}
}
+ if (IsInodeSymLink(&Mcb->Inode)) {
+ IsEntrySymlink = TRUE;
+ }
+
} else {
if (S_ISDIR(Inode.i_mode)) {
@@ -179,6 +191,9 @@ Ext2ProcessEntry(
if (S_ISDIR(Inode.i_mode)) {
FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+ } else if (S_ISLNK(Inode.i_mode)) {
+ FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT;
+ IsEntrySymlink = TRUE;
} else {
FileAttributes = FILE_ATTRIBUTE_NORMAL;
}
@@ -252,8 +267,14 @@ Ext2ProcessEntry(
if (FIF) {
FIF->FileId.QuadPart = (LONGLONG) in;
+ if (IsEntrySymlink) {
+ FIF->EaSize = IO_REPARSE_TAG_SYMLINK;
+ }
RtlCopyMemory(&FIF->FileName[0], &pName->Buffer[0], NameLength);
} else if (FFI) {
+ if (IsEntrySymlink) {
+ FFI->EaSize = IO_REPARSE_TAG_SYMLINK;
+ }
RtlCopyMemory(&FFI->FileName[0], &pName->Buffer[0], NameLength);
} else {
RtlCopyMemory(&FDI->FileName[0], &pName->Buffer[0], NameLength);
@@ -300,6 +321,9 @@ Ext2ProcessEntry(
if (FIB) {
FIB->FileId.QuadPart = (LONGLONG)in;
+ if (IsEntrySymlink) {
+ FIB->EaSize = IO_REPARSE_TAG_SYMLINK;
+ }
RtlCopyMemory(&FIB->FileName[0], &pName->Buffer[0], NameLength);
} else {
RtlCopyMemory(&FBI->FileName[0], &pName->Buffer[0], NameLength);
@@ -1241,4 +1265,4 @@ Ext2IsDirectoryEmpty (
}
return !!ext3_is_dir_empty(IrpContext, &Mcb->Inode);
-} \ No newline at end of file
+}
diff --git a/Ext3Fsd/ext3/generic.c b/Ext3Fsd/ext3/generic.c
index d2565b0..2456a6a 100755
--- a/Ext3Fsd/ext3/generic.c
+++ b/Ext3Fsd/ext3/generic.c
@@ -1433,6 +1433,69 @@ Ext2AddEntry (
NTSTATUS
+Ext2SetFileType (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN PEXT2_MCB Mcb
+ )
+{
+ struct inode *dir = Dcb->Inode;
+ struct buffer_head *bh = NULL;
+ struct ext3_dir_entry_2 *de;
+ struct inode *inode;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
+ return STATUS_SUCCESS;
+ }
+
+ if (!IsDirectory(Dcb)) {
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+ MainResourceAcquired = TRUE;
+
+ __try {
+
+ Ext2ReferXcb(&Dcb->ReferenceCount);
+
+ bh = ext3_find_entry(IrpContext, Mcb->de, &de);
+ if (!bh)
+ __leave;
+
+ inode = &Mcb->Inode;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ __leave;
+
+ ext3_set_de_type(inode->i_sb, de, inode->i_mode);
+ mark_buffer_dirty(bh);
+
+ //if (!inode->i_nlink)
+ // ext3_orphan_add(handle, inode);
+
+ dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
+ ext3_mark_inode_dirty(IrpContext, dir);
+
+ Status = STATUS_SUCCESS;
+
+ } __finally {
+
+ Ext2DerefXcb(&Dcb->ReferenceCount);
+
+ if (MainResourceAcquired)
+ ExReleaseResourceLite(&Dcb->MainResource);
+
+ if (bh)
+ brelse(bh);
+ }
+
+ return Status;
+}
+
+NTSTATUS
Ext2RemoveEntry (
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
diff --git a/Ext3Fsd/fsctl.c b/Ext3Fsd/fsctl.c
index 3dca92c..941ac5b 100644
--- a/Ext3Fsd/fsctl.c
+++ b/Ext3Fsd/fsctl.c
@@ -1287,6 +1287,595 @@ Ext2GetRetrievalPointerBase (
return Status;
}
+NTSTATUS
+Ext2InspectReparseData(
+ IN PREPARSE_DATA_BUFFER RDB,
+ IN ULONG InputBufferLength
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!RDB) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (InputBufferLength < RDB->ReparseDataLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+ if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
+ > (PUCHAR)RDB + InputBufferLength ) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
+ + RDB->SymbolicLinkReparseBuffer.PrintNameLength
+ > (PUCHAR)RDB + InputBufferLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+out:
+ return Status;
+}
+
+VOID
+Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
+{
+ ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
+ REPARSE_DATA_BUFFER_HEADER_SIZE);
+ RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+ RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+ PathBufferLength * sizeof(WCHAR);
+ RDB->Reserved = 0;
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+ RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
+ RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
+}
+
+NTSTATUS
+Ext2ReadSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesRead
+ )
+{
+ return Ext2ReadInode ( IrpContext,
+ Vcb,
+ Mcb,
+ 0,
+ Buffer,
+ Size,
+ FALSE,
+ BytesRead);
+}
+
+
+
+NTSTATUS
+Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PVOID OutputBuffer;
+ ULONG OutputBufferLength;
+ ULONG BytesRead = 0;
+
+ PREPARSE_DATA_BUFFER RDB;
+
+ UNICODE_STRING UniName;
+ OEM_STRING OemName;
+
+ PCHAR OemNameBuffer = NULL;
+ int OemNameLength = 0, i;
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Mcb = IrpContext->Fcb->Mcb;
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ __try {
+
+ if (!Mcb || !IsInodeSymLink(&Mcb->Inode)) {
+ Status = STATUS_NOT_A_REPARSE_POINT;
+ __leave;
+ }
+
+ OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
+ OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
+ if (!RDB) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ __leave;
+ }
+
+ OemNameLength = (ULONG)Mcb->Inode.i_size;
+ if (OemNameLength > USHRT_MAX) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ OemName.Length = (USHORT)OemNameLength;
+ OemName.MaximumLength = OemNameLength + 1;
+ OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
+ OemName.MaximumLength,
+ 'NL2E');
+ if (!OemNameBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ Status = Ext2ReadSymlink(IrpContext,
+ Vcb,
+ Mcb,
+ OemNameBuffer,
+ OemNameLength,
+ &BytesRead
+ );
+ OemName.Buffer[OemName.Length] = '\0';
+ for (i = 0;i < OemName.Length;i++) {
+ if (OemName.Buffer[i] == '/') {
+ OemName.Buffer[i] = '\\';
+ }
+ }
+
+ if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
+ UniName.Length = USHRT_MAX;
+ } else {
+ UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
+ }
+ UniName.MaximumLength = UniName.Length;
+ UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
+ Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
+ if (UniName.MaximumLength < 2*UniName.Length) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ __leave;
+ }
+
+ Ext2InitializeReparseData(RDB, UniName.Length);
+ UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
+ /*
+ (PWCHAR)((PUCHAR)&
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+ */
+ Ext2OEMToUnicode(Vcb, &UniName, &OemName);
+ RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
+ UniName.Buffer, UniName.Length);
+
+ Status = STATUS_SUCCESS;
+
+ } __finally {
+
+ if (OemNameBuffer) {
+ Ext2FreePool(OemNameBuffer, 'NL2E');
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2WriteSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesWritten
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
+
+ if (Size >= EXT2_LINKLEN_IN_INODE) {
+
+ /* initialize inode i_block[] */
+ if (0 == Mcb->Inode.i_blocks) {
+ memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+ ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ }
+
+ Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
+ 0, Buffer, Size,
+ FALSE, BytesWritten);
+ if (!NT_SUCCESS(Status)) {
+ goto out;
+ }
+
+ } else {
+
+ /* free inode blocks before writing in line */
+ if (Mcb->Inode.i_blocks) {
+ LARGE_INTEGER Zero = {0, 0};
+ Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
+ }
+
+ ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+ RtlCopyMemory(Data, Buffer, Size);
+ }
+
+ Mcb->Inode.i_size = Size;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+ if (BytesWritten) {
+ *BytesWritten = Size;
+ }
+
+out:
+ return Status;
+}
+
+
+NTSTATUS
+Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN bNewParentDcb = FALSE;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ ULONG BytesWritten = 0;
+
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ PREPARSE_DATA_BUFFER RDB;
+
+ UNICODE_STRING UniName;
+ OEM_STRING OemName;
+
+ PCHAR OemNameBuffer = NULL;
+ int OemNameLength = 0, i;
+
+
+ __try {
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Fcb = IrpContext->Fcb;
+ Mcb = Fcb->Mcb;
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ bNewParentDcb = TRUE;
+ }
+ }
+
+ if (!Mcb)
+ __leave;
+
+ if (!ExAcquireResourceSharedLite(
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ MainResourceAcquired = TRUE;
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+
+ RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
+ Status = Ext2InspectReparseData(RDB, InputBufferLength);
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ UniName.MaximumLength = UniName.Length;
+ UniName.Buffer =
+ (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+
+ OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
+ if (OemNameLength > USHRT_MAX) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ OemName.Length = (USHORT)OemNameLength;
+ OemName.MaximumLength = OemNameLength + 1;
+ OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
+ OemName.MaximumLength,
+ 'NL2E');
+ if (!OemNameBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
+ OemName.Buffer[OemName.Length] = '\0';
+ for (i = 0;i < OemName.Length;i++) {
+ if (OemName.Buffer[i] == '\\') {
+ OemName.Buffer[i] = '/';
+ }
+ }
+
+ /* overwrite inode mode as type SYMLINK */
+ Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+
+ Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
+ OemNameLength, &BytesWritten);
+ if (NT_SUCCESS(Status)) {
+ Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+ }
+
+ } __finally {
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (OemNameBuffer) {
+ Ext2FreePool(OemNameBuffer, 'NL2E');
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ Mcb,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ FILE_ACTION_MODIFIED );
+ }
+
+ if (bNewParentDcb) {
+ ASSERT(ParentDcb != NULL);
+ if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(ParentDcb);
+ ParentDcb = NULL;
+ } else {
+ DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
+ }
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2TruncateSymlink(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Mcb,
+ ULONG Size
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
+ ULONG len = (ULONG)Mcb->Inode.i_size;
+ LARGE_INTEGER NewSize;
+
+ if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
+
+ RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
+ Mcb->Inode.i_size = Size;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+ } else {
+ NewSize.QuadPart = Size;
+ status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
+
+
+/* FIXME: We can only handle one reparse point right now. */
+NTSTATUS
+Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN bNewParentDcb = FALSE;
+ BOOLEAN bFcbAllocated = FALSE;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ __try {
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Mcb = IrpContext->Fcb->Mcb;
+ Irp = IrpContext->Irp;
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ bNewParentDcb = TRUE;
+ }
+ }
+
+ if (!Mcb) {
+ Status = STATUS_NOT_A_REPARSE_POINT;
+ __leave;
+ }
+
+ Fcb = Ext2AllocateFcb (Vcb, Mcb);
+ if (Fcb) {
+ bFcbAllocated = TRUE;
+ } else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+ Ext2ReferXcb(&Fcb->ReferenceCount);
+
+ if (!ExAcquireResourceSharedLite(
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ MainResourceAcquired = TRUE;
+
+ Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+ if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+ SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ }
+ ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+ ClearFlag(Mcb->Inode.i_flags, S_IFLNK);
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ if (NT_SUCCESS(Status)) {
+ Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+ }
+
+ } __finally {
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ Mcb,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ FILE_ACTION_MODIFIED );
+
+ }
+
+ if (bNewParentDcb) {
+ ASSERT(ParentDcb != NULL);
+ if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(ParentDcb);
+ ParentDcb = NULL;
+ } else {
+ DEBUG(DL_RES, ( "Ext2DeleteReparsePoint: ParentDcb is resued.\n"));
+ }
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ if (bFcbAllocated) {
+ if (Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
+ Ext2FreeFcb(Fcb);
+ }
+ }
+ }
+
+ return Status;
+}
NTSTATUS
Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
@@ -1302,7 +1891,6 @@ Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
Irp = IrpContext->Irp;
-
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
#ifndef _GNU_NTIFS_
@@ -1315,6 +1903,18 @@ Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
switch (FsControlCode) {
+ case FSCTL_GET_REPARSE_POINT:
+ Status = Ext2GetReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_SET_REPARSE_POINT:
+ Status = Ext2SetReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_DELETE_REPARSE_POINT:
+ Status = Ext2DeleteReparsePoint(IrpContext);
+ break;
+
case FSCTL_LOCK_VOLUME:
Status = Ext2LockVolume(IrpContext);
break;
diff --git a/Ext3Fsd/include/ext2fs.h b/Ext3Fsd/include/ext2fs.h
index 2b41390..b4d4084 100755
--- a/Ext3Fsd/include/ext2fs.h
+++ b/Ext3Fsd/include/ext2fs.h
@@ -805,7 +805,7 @@ struct _EXT2_MCB {
// Link List Info
PEXT2_MCB Parent; // Parent
- PEXT2_MCB Next; // Brothers
+ PEXT2_MCB Next; // Siblings
union {
PEXT2_MCB Child; // Children Mcb nodes
@@ -929,7 +929,7 @@ typedef struct _EXT2_CCB {
#define CCB_FROM_POOL 0x00000001
#define CCB_VOLUME_DASD_PURGE 0x00000002
#define CCB_LAST_WRITE_UPDATED 0x00000004
-
+#define CCB_OPEN_REPARSE_POINT 0x00000008
#define CCB_DELETE_ON_CLOSE 0x00000010
#define CCB_ALLOW_EXTENDED_DASD_IO 0x80000000
@@ -1248,7 +1248,7 @@ Ext2FollowLink (
IN PEXT2_VCB Vcb,
IN PEXT2_MCB Parent,
IN PEXT2_MCB Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
);
NTSTATUS
@@ -1267,6 +1267,9 @@ Ext2IsSpecialSystemFile(
IN BOOLEAN bDirectory
);
+#define EXT2_LOOKUP_FLAG_MASK (0xFF00000)
+#define EXT2_LOOKUP_NOT_FOLLOW (0x8000000)
+
NTSTATUS
Ext2LookupFile (
IN PEXT2_IRP_CONTEXT IrpContext,
@@ -1274,7 +1277,7 @@ Ext2LookupFile (
IN PUNICODE_STRING FullName,
IN PEXT2_MCB Parent,
OUT PEXT2_MCB * Ext2Mcb,
- IN USHORT Linkdep
+ IN ULONG Linkdep
);
NTSTATUS
@@ -1859,6 +1862,14 @@ Ext2AddEntry (
);
NTSTATUS
+Ext2SetFileType (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN PEXT2_MCB Mcb
+);
+
+NTSTATUS
Ext2RemoveEntry (
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
@@ -2139,6 +2150,34 @@ Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext);
// Fsctl.c
//
+NTSTATUS
+Ext2ReadSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesRead
+ );
+
+NTSTATUS
+Ext2WriteSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesWritten
+);
+
+NTSTATUS
+Ext2TruncateSymlink(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Mcb,
+ ULONG Size
+);
+
//
// MountPoint process workitem
//
@@ -2375,7 +2414,7 @@ VOID
Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb);
PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB SymLink);
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink);
VOID
Ext2FreeMcb (
diff --git a/Ext3Fsd/memory.c b/Ext3Fsd/memory.c
index 9d047b2..6f7b5b5 100755
--- a/Ext3Fsd/memory.c
+++ b/Ext3Fsd/memory.c
@@ -138,8 +138,6 @@ Ext2AllocateFcb (
{
PEXT2_FCB Fcb;
- ASSERT(!IsMcbSymLink(Mcb));
-
Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
&(Ext2Global->Ext2FcbLookasideList));
@@ -216,7 +214,7 @@ Ext2FreeFcb (IN PEXT2_FCB Fcb)
#endif
if ((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
- (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
+ (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
ASSERT (Fcb->Mcb->Fcb == Fcb);
if (IsMcbSpecialFile(Fcb->Mcb) || IsFileDeleted(Fcb->Mcb)) {
@@ -283,7 +281,7 @@ Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
}
PEXT2_CCB
-Ext2AllocateCcb (PEXT2_MCB SymLink)
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
{
PEXT2_CCB Ccb;
@@ -299,6 +297,7 @@ Ext2AllocateCcb (PEXT2_MCB SymLink)
Ccb->Identifier.Type = EXT2CCB;
Ccb->Identifier.Size = sizeof(EXT2_CCB);
+ Ccb->Flags = Flags;
Ccb->SymLink = SymLink;
if (SymLink) {
diff --git a/Ext3Fsd/read.c b/Ext3Fsd/read.c
index ae08722..e727424 100755
--- a/Ext3Fsd/read.c
+++ b/Ext3Fsd/read.c
@@ -347,11 +347,9 @@ Ext2ReadInode (
/* handle fast symlinks */
- if (S_ISLNK(Mcb->Inode.i_mode) &&
- Mcb->Inode.i_size < EXT2_LINKLEN_IN_INODE) {
+ if (S_ISLNK(Mcb->Inode.i_mode) && 0 == Mcb->Inode.i_blocks) {
PUCHAR Data = (PUCHAR) (&Mcb->Inode.i_block[0]);
-
if (!Buffer) {
Status = STATUS_INSUFFICIENT_RESOURCES;
__leave;
@@ -534,6 +532,11 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
&Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
+ if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ||
IsFileDeleted(Fcb->Mcb)) {
Status = STATUS_FILE_DELETED;
diff --git a/Ext3Fsd/volinfo.c b/Ext3Fsd/volinfo.c
index b0bcb9b..65ed938 100755
--- a/Ext3Fsd/volinfo.c
+++ b/Ext3Fsd/volinfo.c
@@ -187,7 +187,8 @@ Ext2QueryVolumeInformation (IN PEXT2_IRP_CONTEXT IrpContext)
FsAttrInfo =
(PFILE_FS_ATTRIBUTE_INFORMATION) Buffer;
FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS |
- FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+ FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
+ FILE_SUPPORTS_REPARSE_POINTS;
if (IsVcbReadOnly(Vcb)) {
FsAttrInfo->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
}
diff --git a/Ext3Fsd/write.c b/Ext3Fsd/write.c
index 721b911..5afaef5 100755
--- a/Ext3Fsd/write.c
+++ b/Ext3Fsd/write.c
@@ -651,7 +651,7 @@ Ext2WriteInode (
IN ULONG Size,
IN BOOLEAN bDirectIo,
OUT PULONG BytesWritten
-)
+ )
{
PEXT2_EXTENT Chain = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
@@ -668,7 +668,7 @@ Ext2WriteInode (
Mcb,
Offset,
Size,
- IsMcbDirectory(Mcb) ? FALSE : TRUE,
+ S_ISDIR(Mcb->Inode.i_mode) ? FALSE : TRUE,
&Chain
);
@@ -735,6 +735,7 @@ Ext2WriteInode (
return Status;
}
+
NTSTATUS
Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
{
@@ -806,7 +807,7 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
&Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));
- if (IsSpecialFile(Fcb)) {
+ if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
Status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}