https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ea6b9622c4328b1d3c511…
commit ea6b9622c4328b1d3c51196edf004febb12dd68b
Author: Trevor Thompson <tmt256(a)email.vccs.edu>
AuthorDate: Sun Jun 12 04:02:52 2016 +0000
[NTFS]
Add fixes to WriteAttribute():
-Remove erroneous check for end of run (before writing to the last run returned)
-Properly dereference RealLengthWritten pointer, as reported in CR-90
svn path=/branches/GSoC_2016/NTFS/; revision=71616
---
drivers/filesystems/ntfs/mft.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c
index 43b38ef2ab..1294264e69 100644
--- a/drivers/filesystems/ntfs/mft.c
+++ b/drivers/filesystems/ntfs/mft.c
@@ -517,17 +517,6 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
}
else
DataRunStartLCN = -1;
-
- if (*DataRun == 0)
- {
- if (Length == 0)
- return STATUS_SUCCESS;
-
- // This code shouldn't execute, because we should have extended the allocation size
- // or failed the request by now. It's just a sanity check.
- DPRINT1("Encountered EOF before expected!\n");
- return STATUS_END_OF_FILE;
- }
}
// Do we have more data to write?
@@ -556,7 +545,7 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
Length -= WriteLength;
SourceBuffer += WriteLength;
- RealLengthWritten += WriteLength;
+ *RealLengthWritten += WriteLength;
// We finished this request, but there's still data in this data run.
if (Length == 0 && WriteLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=58a13831ef75324ed2b31…
commit 58a13831ef75324ed2b3101c1c98ecffeabe942b
Author: Trevor Thompson <tmt256(a)email.vccs.edu>
AuthorDate: Sun May 1 16:21:53 2016 +0000
[NTFS]
Added minimal write support from CORE-10998 along with updates as suggested by CR-90.
svn path=/branches/GSoC_2016/NTFS/; revision=71224
---
drivers/filesystems/ntfs/blockdev.c | 177 +++++++++++++++-
drivers/filesystems/ntfs/create.c | 10 +-
drivers/filesystems/ntfs/mft.c | 269 ++++++++++++++++++++++++
drivers/filesystems/ntfs/misc.c | 58 ++++++
drivers/filesystems/ntfs/ntfs.h | 30 +++
drivers/filesystems/ntfs/rw.c | 396 +++++++++++++++++++++++++++++++++++-
6 files changed, 931 insertions(+), 9 deletions(-)
diff --git a/drivers/filesystems/ntfs/blockdev.c b/drivers/filesystems/ntfs/blockdev.c
index 6c90131b19..1ae67e52d7 100644
--- a/drivers/filesystems/ntfs/blockdev.c
+++ b/drivers/filesystems/ntfs/blockdev.c
@@ -20,7 +20,8 @@
* PROJECT: ReactOS kernel
* FILE: drivers/filesystem/ntfs/blockdev.c
* PURPOSE: NTFS filesystem driver
- * PROGRAMMER: Eric Kohl
+ * PROGRAMMERS: Eric Kohl
+ * Trevor Thompson
*/
/* INCLUDES *****************************************************************/
@@ -129,6 +130,180 @@ NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject,
return Status;
}
+/**
+* @name NtfsWriteDisk
+* @implemented
+*
+* Writes data from the given buffer to the given DeviceObject.
+*
+* @param DeviceObject
+* Device to write to
+*
+* @param StartingOffset
+* Offset, in bytes, from the start of the device object where the data will be written
+*
+* @param Length
+* How much data will be written, in bytes
+*
+* @param SectorSize
+* Size of the sector on the disk that the write must be aligned to
+*
+* @param Buffer
+* The data that's being written to the device
+*
+* @return
+* STATUS_SUCCESS in case of success, STATUS_INSUFFICIENT_RESOURCES if a memory allocation failed,
+* or whatever status IoCallDriver() sets.
+*
+* @remarks Called by NtfsWriteFile(). May perform a read-modify-write operation if the
+* requested write is not sector-aligned.
+*
+*/
+NTSTATUS
+NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject,
+ IN LONGLONG StartingOffset,
+ IN ULONG Length,
+ IN ULONG SectorSize,
+ IN const PUCHAR Buffer)
+{
+ IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER Offset;
+ KEVENT Event;
+ PIRP Irp;
+ NTSTATUS Status;
+ ULONGLONG RealWriteOffset;
+ ULONG RealLength;
+ BOOLEAN AllocatedBuffer = FALSE;
+ PUCHAR TempBuffer = NULL;
+
+ DPRINT("NtfsWriteDisk(%p, %I64x, %u, %u, %p)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer);
+
+ if (Length == 0)
+ return STATUS_SUCCESS;
+
+ RealWriteOffset = (ULONGLONG)StartingOffset;
+ RealLength = Length;
+
+ // Does the write need to be adjusted to be sector-aligned?
+ if ((RealWriteOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
+ {
+ ULONGLONG relativeOffset;
+
+ // We need to do a read-modify-write. We'll start be copying the entire
+ // contents of every sector that will be overwritten.
+ // TODO: Optimize (read no more than necessary)
+
+ RealWriteOffset = ROUND_DOWN(StartingOffset, SectorSize);
+ RealLength = ROUND_UP(Length, SectorSize);
+
+ // Would the end of our sector-aligned write fall short of the requested write?
+ if (RealWriteOffset + RealLength < StartingOffset + Length)
+ {
+ RealLength += SectorSize;
+ }
+
+ // Did we underestimate the memory required somehow?
+ if (RealLength + RealWriteOffset < StartingOffset + Length)
+ {
+ DPRINT1("\a\t\t\t\t\tFIXME: calculated less memory than needed!\n");
+ DPRINT1("StartingOffset: %lu\tLength: %lu\tRealWriteOffset: %lu\tRealLength: %lu\n",
+ StartingOffset, Length, RealWriteOffset, RealLength);
+
+ RealLength += SectorSize;
+ }
+
+ // Allocate a buffer to copy the existing data to
+ TempBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength, TAG_NTFS);
+
+ // Did we fail to allocate it?
+ if (TempBuffer == NULL)
+ {
+ DPRINT1("Not enough memory!\n");
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Read the sectors we'll be overwriting into TempBuffer
+ Status = NtfsReadDisk(DeviceObject, RealWriteOffset, RealLength, SectorSize, TempBuffer, FALSE);
+
+ // Did we fail the read?
+ if (!NT_SUCCESS(Status))
+ {
+ RtlSecureZeroMemory(TempBuffer, RealLength);
+ ExFreePoolWithTag(TempBuffer, TAG_NTFS);
+ return Status;
+ }
+
+ // Calculate where the new data should be written to, relative to the start of TempBuffer
+ relativeOffset = StartingOffset - RealWriteOffset;
+
+ // Modify the tempbuffer with the data being read
+ RtlCopyMemory(TempBuffer + relativeOffset, Buffer, Length);
+
+ AllocatedBuffer = TRUE;
+ }
+
+ // set the destination offset
+ Offset.QuadPart = RealWriteOffset;
+
+ // setup the notification event for the write
+ KeInitializeEvent(&Event,
+ NotificationEvent,
+ FALSE);
+
+ DPRINT("Building synchronous FSD Request...\n");
+
+ // Build an IRP requesting the lower-level [disk] driver to perform the write
+ // TODO: Forward the existing IRP instead
+ Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
+ DeviceObject,
+ // if we allocated a temp buffer, use that instead of the Buffer parameter
+ ((AllocatedBuffer) ? TempBuffer : Buffer),
+ RealLength,
+ &Offset,
+ &Event,
+ &IoStatus);
+ // Did we fail to build the IRP?
+ if (Irp == NULL)
+ {
+ DPRINT1("IoBuildSynchronousFsdRequest failed\n");
+
+ if (AllocatedBuffer)
+ {
+ RtlSecureZeroMemory(TempBuffer, RealLength);
+ ExFreePoolWithTag(TempBuffer, TAG_NTFS);
+ }
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Call the next-lower driver to perform the write
+ DPRINT("Calling IO Driver with irp %p\n", Irp);
+ Status = IoCallDriver(DeviceObject, Irp);
+
+ // Wait until the next-lower driver has completed the IRP
+ DPRINT("Waiting for IO Operation for %p\n", Irp);
+ if (Status == STATUS_PENDING)
+ {
+ DPRINT("Operation pending\n");
+ KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
+ DPRINT("Getting IO Status... for %p\n", Irp);
+ Status = IoStatus.Status;
+ }
+
+ if (AllocatedBuffer)
+ {
+ // zero the buffer before freeing it, so private user data can't be snooped
+ RtlSecureZeroMemory(TempBuffer, RealLength);
+
+ ExFreePoolWithTag(TempBuffer, TAG_NTFS);
+ }
+
+ DPRINT("NtfsWriteDisk() done (Status %x)\n", Status);
+
+ return Status;
+}
+
NTSTATUS
NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
IN ULONG DiskSector,
diff --git a/drivers/filesystems/ntfs/create.c b/drivers/filesystems/ntfs/create.c
index 4a4a6a6a8d..5662806880 100644
--- a/drivers/filesystems/ntfs/create.c
+++ b/drivers/filesystems/ntfs/create.c
@@ -476,26 +476,26 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
return Status;
}
- /* HUGLY HACK: remain RO so far... */
+ /* HUGLY HACK: Can't overwrite or supersede a file yet... */
if (RequestedDisposition == FILE_OVERWRITE ||
RequestedDisposition == FILE_OVERWRITE_IF ||
RequestedDisposition == FILE_SUPERSEDE)
{
- DPRINT1("Denying write request on NTFS volume\n");
+ DPRINT1("Cannot yet perform an overwrite or supersede request on NTFS volume\n");
NtfsCloseFile(DeviceExt, FileObject);
return STATUS_ACCESS_DENIED;
}
}
else
{
- /* HUGLY HACK: remain RO so far... */
+ /* HUGLY HACK: Can't create new files yet... */
if (RequestedDisposition == FILE_CREATE ||
RequestedDisposition == FILE_OPEN_IF ||
RequestedDisposition == FILE_OVERWRITE_IF ||
RequestedDisposition == FILE_SUPERSEDE)
{
- DPRINT1("Denying write request on NTFS volume\n");
- return STATUS_ACCESS_DENIED;
+ DPRINT1("Denying file creation request on NTFS volume\n");
+ return STATUS_CANNOT_MAKE;
}
}
diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c
index d02a32dc23..43b38ef2ab 100644
--- a/drivers/filesystems/ntfs/mft.c
+++ b/drivers/filesystems/ntfs/mft.c
@@ -24,6 +24,7 @@
* Valentin Verkhovsky
* Pierre Schweitzer (pierre(a)reactos.org)
* Hervé Poussineau (hpoussin(a)reactos.org)
+ * Trevor Thompson
*/
/* INCLUDES *****************************************************************/
@@ -31,6 +32,7 @@
#include "ntfs.h"
#define NDEBUG
+#undef NDEBUG
#include <debug.h>
/* FUNCTIONS ****************************************************************/
@@ -334,6 +336,273 @@ ReadAttribute(PDEVICE_EXTENSION Vcb,
}
+/**
+* @name WriteAttribute
+* @implemented
+*
+* Writes an NTFS attribute to the disk. It presently borrows a lot of code from ReadAttribute(),
+* and it still needs more documentation / cleaning up.
+*
+* @param Vcb
+* Volume Control Block indicating which volume to write the attribute to
+*
+* @param Context
+* Pointer to an NTFS_ATTR_CONTEXT that has information about the attribute
+*
+* @param Offset
+* Offset, in bytes, from the beginning of the attribute indicating where to start
+* writing data
+*
+* @param Buffer
+* The data that's being written to the device
+*
+* @param Length
+* How much data will be written, in bytes
+*
+* @param RealLengthWritten
+* Pointer to a ULONG which will receive how much data was written, in bytes
+*
+* @return
+* STATUS_SUCCESS if successful, an error code otherwise. STATUS_NOT_IMPLEMENTED if
+* writing to a sparse file.
+*
+* @remarks Note that in this context the word "attribute" isn't referring read-only, hidden,
+* etc. - the file's data is actually stored in an attribute in NTFS parlance.
+*
+*/
+
+NTSTATUS
+WriteAttribute(PDEVICE_EXTENSION Vcb,
+ PNTFS_ATTR_CONTEXT Context,
+ ULONGLONG Offset,
+ const PUCHAR Buffer,
+ ULONG Length,
+ PULONG RealLengthWritten)
+{
+ ULONGLONG LastLCN;
+ PUCHAR DataRun;
+ LONGLONG DataRunOffset;
+ ULONGLONG DataRunLength;
+ LONGLONG DataRunStartLCN;
+ ULONGLONG CurrentOffset;
+ ULONG WriteLength;
+ NTSTATUS Status;
+ PUCHAR SourceBuffer = Buffer;
+ LONGLONG StartingOffset;
+
+ DPRINT("WriteAttribute(%p, %p, %I64U, %p, %lu)\n", Vcb, Context, Offset, Buffer, Length);
+
+ // is this a resident attribute?
+ if (!Context->Record.IsNonResident)
+ {
+ DPRINT1("FIXME: Writing to resident NTFS records (small files) is not supported at this time.\n");
+ // (TODO: This should be really easy to implement)
+
+ /* LeftOver code from ReadAttribute(), may be helpful:
+ if (Offset > Context->Record.Resident.ValueLength)
+ return 0;
+ if (Offset + Length > Context->Record.Resident.ValueLength)
+ Length = (ULONG)(Context->Record.Resident.ValueLength - Offset);
+ RtlCopyMemory(Buffer, (PCHAR)&Context->Record + Context->Record.Resident.ValueOffset + Offset, Length);
+ return Length;*/
+
+ return STATUS_NOT_IMPLEMENTED; // until we implement it
+ }
+
+ // This is a non-resident attribute.
+
+ // I. Find the corresponding start data run.
+
+ *RealLengthWritten = 0;
+
+ // FIXME: Cache seems to be non-working. Disable it for now
+ //if(Context->CacheRunOffset <= Offset && Offset < Context->CacheRunOffset + Context->CacheRunLength * Volume->ClusterSize)
+ /*if (0)
+ {
+ DataRun = Context->CacheRun;
+ LastLCN = Context->CacheRunLastLCN;
+ DataRunStartLCN = Context->CacheRunStartLCN;
+ DataRunLength = Context->CacheRunLength;
+ CurrentOffset = Context->CacheRunCurrentOffset;
+ }
+ else*/
+ {
+ LastLCN = 0;
+ DataRun = (PUCHAR)&Context->Record + Context->Record.NonResident.MappingPairsOffset;
+ CurrentOffset = 0;
+
+ while (1)
+ {
+ DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
+ if (DataRunOffset != -1)
+ {
+ // Normal data run.
+ // DPRINT1("Writing to normal data run, LastLCN %I64u DataRunOffset %I64d\n", LastLCN, DataRunOffset);
+ DataRunStartLCN = LastLCN + DataRunOffset;
+ LastLCN = DataRunStartLCN;
+ }
+ else
+ {
+ // Sparse data run. We can't support writing to sparse files yet
+ // (it may require increasing the allocation size).
+ DataRunStartLCN = -1;
+ DPRINT1("FIXME: Writing to sparse files is not supported yet!\n");
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ // Have we reached the data run we're trying to write to?
+ if (Offset >= CurrentOffset &&
+ Offset < CurrentOffset + (DataRunLength * Vcb->NtfsInfo.BytesPerCluster))
+ {
+ break;
+ }
+
+ if (*DataRun == 0)
+ {
+ // We reached the last assigned cluster
+ // TODO: assign new clusters to the end of the file.
+ // (Presently, this code will never be reached, the write should have already failed by now)
+ return STATUS_END_OF_FILE;
+ }
+
+ CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
+ }
+ }
+
+ // II. Go through the run list and write the data
+
+ /* REVIEWME -- As adapted from NtfsReadAttribute():
+ We seem to be making a special case for the first applicable data run, but I'm not sure why.
+ Does it have something to do with (not) caching? Is this strategy equally applicable to writing? */
+
+ WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset), Length);
+
+ StartingOffset = DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster + Offset - CurrentOffset;
+
+ // Write the data to the disk
+ Status = NtfsWriteDisk(Vcb->StorageDevice,
+ StartingOffset,
+ WriteLength,
+ Vcb->NtfsInfo.BytesPerSector,
+ (PVOID)SourceBuffer);
+
+ // Did the write fail?
+ if (!NT_SUCCESS(Status))
+ {
+ Context->CacheRun = DataRun;
+ Context->CacheRunOffset = Offset;
+ Context->CacheRunStartLCN = DataRunStartLCN;
+ Context->CacheRunLength = DataRunLength;
+ Context->CacheRunLastLCN = LastLCN;
+ Context->CacheRunCurrentOffset = CurrentOffset;
+
+ return Status;
+ }
+
+ Length -= WriteLength;
+ SourceBuffer += WriteLength;
+ *RealLengthWritten += WriteLength;
+
+ // Did we write to the end of the data run?
+ if (WriteLength == DataRunLength * Vcb->NtfsInfo.BytesPerCluster - (Offset - CurrentOffset))
+ {
+ // Advance to the next data run
+ CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
+ DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
+
+ if (DataRunOffset != (ULONGLONG)-1)
+ {
+ DataRunStartLCN = LastLCN + DataRunOffset;
+ LastLCN = DataRunStartLCN;
+ }
+ else
+ DataRunStartLCN = -1;
+
+ if (*DataRun == 0)
+ {
+ if (Length == 0)
+ return STATUS_SUCCESS;
+
+ // This code shouldn't execute, because we should have extended the allocation size
+ // or failed the request by now. It's just a sanity check.
+ DPRINT1("Encountered EOF before expected!\n");
+ return STATUS_END_OF_FILE;
+ }
+ }
+
+ // Do we have more data to write?
+ while (Length > 0)
+ {
+ // Make sure we don't write past the end of the current data run
+ WriteLength = (ULONG)min(DataRunLength * Vcb->NtfsInfo.BytesPerCluster, Length);
+
+ // Are we dealing with a sparse data run?
+ if (DataRunStartLCN == -1)
+ {
+ DPRINT1("FIXME: Don't know how to write to sparse files yet! (DataRunStartLCN == -1)\n");
+ return STATUS_NOT_IMPLEMENTED;
+ }
+ else
+ {
+ // write the data to the disk
+ Status = NtfsWriteDisk(Vcb->StorageDevice,
+ DataRunStartLCN * Vcb->NtfsInfo.BytesPerCluster,
+ WriteLength,
+ Vcb->NtfsInfo.BytesPerSector,
+ (PVOID)SourceBuffer);
+ if (!NT_SUCCESS(Status))
+ break;
+ }
+
+ Length -= WriteLength;
+ SourceBuffer += WriteLength;
+ RealLengthWritten += WriteLength;
+
+ // We finished this request, but there's still data in this data run.
+ if (Length == 0 && WriteLength != DataRunLength * Vcb->NtfsInfo.BytesPerCluster)
+ break;
+
+ // Go to next run in the list.
+
+ if (*DataRun == 0)
+ {
+ // that was the last run
+ if (Length > 0)
+ {
+ // Failed sanity check.
+ DPRINT1("Encountered EOF before expected!\n");
+ return STATUS_END_OF_FILE;
+ }
+
+ break;
+ }
+
+ // Advance to the next data run
+ CurrentOffset += DataRunLength * Vcb->NtfsInfo.BytesPerCluster;
+ DataRun = DecodeRun(DataRun, &DataRunOffset, &DataRunLength);
+ if (DataRunOffset != -1)
+ {
+ // Normal data run.
+ DataRunStartLCN = LastLCN + DataRunOffset;
+ LastLCN = DataRunStartLCN;
+ }
+ else
+ {
+ // Sparse data run.
+ DataRunStartLCN = -1;
+ }
+ } // end while (Length > 0) [more data to write]
+
+ Context->CacheRun = DataRun;
+ Context->CacheRunOffset = Offset + *RealLengthWritten;
+ Context->CacheRunStartLCN = DataRunStartLCN;
+ Context->CacheRunLength = DataRunLength;
+ Context->CacheRunLastLCN = LastLCN;
+ Context->CacheRunCurrentOffset = CurrentOffset;
+
+ return Status;
+}
+
NTSTATUS
ReadFileRecord(PDEVICE_EXTENSION Vcb,
ULONGLONG index,
diff --git a/drivers/filesystems/ntfs/misc.c b/drivers/filesystems/ntfs/misc.c
index ba461b04a8..76b77134c9 100644
--- a/drivers/filesystems/ntfs/misc.c
+++ b/drivers/filesystems/ntfs/misc.c
@@ -130,4 +130,62 @@ NtfsGetUserBuffer(PIRP Irp,
}
}
+/**
+* @name NtfsLockUserBuffer
+* @implemented
+*
+* Ensures the IRP has an MDL Address.
+*
+* @param Irp
+* Irp with the UserBuffer that needs locking
+*
+* @param Length
+* Size of the Irp->UserBuffer, in bytes
+*
+* @param Operation
+* What kind of access does the driver need to the buffer. Set to
+* IoReadAccess, IoWriteAccess, or IoModifyAccess.
+*
+* @return
+* STATUS_SUCCESS in case of success, STATUS_INSUFFICIENT_RESOURCES
+* or an exception code otherwise.
+*
+* @remarks Trevor Thompson shamelessly ripped this from
+* VfatLockUserBuffer(). Only the name was changed.
+*
+*/
+NTSTATUS
+NtfsLockUserBuffer(IN PIRP Irp,
+ IN ULONG Length,
+ IN LOCK_OPERATION Operation)
+{
+ ASSERT(Irp);
+
+ if (Irp->MdlAddress)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
+
+ if (!Irp->MdlAddress)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ _SEH2_TRY
+ {
+ MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ IoFreeMdl(Irp->MdlAddress);
+ Irp->MdlAddress = NULL;
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ return STATUS_SUCCESS;
+}
+
/* EOF */
diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h
index 9e987c923f..f80bb973fe 100644
--- a/drivers/filesystems/ntfs/ntfs.h
+++ b/drivers/filesystems/ntfs/ntfs.h
@@ -550,6 +550,13 @@ NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject,
IN OUT PUCHAR Buffer,
IN BOOLEAN Override);
+NTSTATUS
+NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject,
+ IN LONGLONG StartingOffset,
+ IN ULONG Length,
+ IN ULONG SectorSize,
+ IN PUCHAR Buffer);
+
NTSTATUS
NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
IN ULONG DiskSector,
@@ -741,6 +748,14 @@ ReadAttribute(PDEVICE_EXTENSION Vcb,
PCHAR Buffer,
ULONG Length);
+NTSTATUS
+WriteAttribute(PDEVICE_EXTENSION Vcb,
+ PNTFS_ATTR_CONTEXT Context,
+ ULONGLONG Offset,
+ const PUCHAR Buffer,
+ ULONG Length,
+ PULONG LengthWritten);
+
ULONGLONG
AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord);
@@ -817,6 +832,21 @@ PVOID
NtfsGetUserBuffer(PIRP Irp,
BOOLEAN Paging);
+NTSTATUS
+NtfsLockUserBuffer(IN PIRP Irp,
+ IN ULONG Length,
+ IN LOCK_OPERATION Operation);
+
+#if 0
+BOOLEAN
+wstrcmpjoki(PWSTR s1, PWSTR s2);
+
+VOID
+CdfsSwapString(PWCHAR Out,
+ PUCHAR In,
+ ULONG Count);
+#endif
+
VOID
NtfsFileFlagsToAttributes(ULONG NtfsAttributes,
PULONG FileAttributes);
diff --git a/drivers/filesystems/ntfs/rw.c b/drivers/filesystems/ntfs/rw.c
index 0437b61d99..076a3e8578 100644
--- a/drivers/filesystems/ntfs/rw.c
+++ b/drivers/filesystems/ntfs/rw.c
@@ -22,6 +22,7 @@
* PURPOSE: NTFS filesystem driver
* PROGRAMMERS: Art Yerkes
* Pierre Schweitzer (pierre(a)reactos.org)
+ * Trevor Thompson
*/
/* INCLUDES *****************************************************************/
@@ -255,14 +256,403 @@ NtfsRead(PNTFS_IRP_CONTEXT IrpContext)
return Status;
}
+/**
+* @name NtfsWriteFile
+* @implemented
+*
+* Writes a file to the disk. It presently borrows a lot of code from NtfsReadFile() and
+* VFatWriteFileData(). It needs some more work before it will be complete; it won't handle
+* page files, asnyc io, cached writes, etc.
+*
+* @param DeviceExt
+* Points to the target disk's DEVICE_EXTENSION
+*
+* @param FileObject
+* Pointer to a FILE_OBJECT describing the target file
+*
+* @param Buffer
+* The data that's being written to the file
+*
+* @Param Length
+* The size of the data buffer being written, in bytes
+*
+* @param WriteOffset
+* Offset, in bytes, from the beginning of the file. Indicates where to start
+* writing data.
+*
+* @param IrpFlags
+* TODO: flags are presently ignored in code.
+*
+* @param LengthWritten
+* Pointer to a ULONG. This ULONG will be set to the number of bytes successfully written.
+*
+* @return
+* STATUS_SUCCESS if successful, STATUS_NOT_IMPLEMENTED if a required feature isn't implemented,
+* STATUS_INSUFFICIENT_RESOURCES if an allocation failed, STATUS_ACCESS_DENIED if the write itself fails,
+* STATUS_PARTIAL_COPY or STATUS_UNSUCCESSFUL if ReadFileRecord() fails, or
+* STATUS_OBJECT_NAME_NOT_FOUND if the file's data stream could not be found.
+*
+* @remarks Called by NtfsWrite(). It may perform a read-modify-write operation if the requested write is
+* not sector-aligned. LengthWritten only refers to how much of the requested data has been written;
+* extra data that needs to be written to make the write sector-aligned will not affect it.
+*
+*/
+NTSTATUS NtfsWriteFile(PDEVICE_EXTENSION DeviceExt,
+ PFILE_OBJECT FileObject,
+ const PUCHAR Buffer,
+ ULONG Length,
+ ULONG WriteOffset,
+ ULONG IrpFlags,
+ PULONG LengthWritten)
+{
+ NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+ PNTFS_FCB Fcb;
+ PFILE_RECORD_HEADER FileRecord;
+ PNTFS_ATTR_CONTEXT DataContext;
+ ULONGLONG StreamSize;
+
+ DPRINT("NtfsWriteFile(%p, %p, %p, %u, %u, %x, %p)\n", DeviceExt, FileObject, Buffer, Length, WriteOffset, IrpFlags, LengthWritten);
+
+ *LengthWritten = 0;
+
+ ASSERT(DeviceExt);
+
+ if (Length == 0)
+ {
+ if (Buffer == NULL)
+ return STATUS_SUCCESS;
+ else
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // get the File control block
+ Fcb = (PNTFS_FCB)FileObject->FsContext;
+ ASSERT(Fcb);
+
+ DPRINT("Fcb->PathName: %wS\n", Fcb->PathName);
+ DPRINT("Fcb->ObjectName: %wS\n", Fcb->ObjectName);
+
+ // we don't yet handle compression
+ if (NtfsFCBIsCompressed(Fcb))
+ {
+ DPRINT("Compressed file!\n");
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ // allocate non-paged memory for the FILE_RECORD_HEADER
+ FileRecord = ExAllocatePoolWithTag(NonPagedPool, DeviceExt->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+ if (FileRecord == NULL)
+ {
+ DPRINT1("Not enough memory! Can't write %wS!\n", Fcb->PathName);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // read the FILE_RECORD_HEADER from the drive (or cache)
+ DPRINT("Reading file record...\n");
+ Status = ReadFileRecord(DeviceExt, Fcb->MFTIndex, FileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ // We couldn't get the file's record. Free the memory and return the error
+ DPRINT1("Can't find record for %wS!\n", Fcb->ObjectName);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ DPRINT("Found record for %wS\n", Fcb->ObjectName);
+
+ // Find the attribute (in the NTFS sense of the word) with the data stream for our file
+ DPRINT("Finding Data Attribute...\n");
+ Status = FindAttribute(DeviceExt, FileRecord, AttributeData, Fcb->Stream, wcslen(Fcb->Stream), &DataContext);
+
+ // Did we fail to find the attribute?
+ if (!NT_SUCCESS(Status))
+ {
+ NTSTATUS BrowseStatus;
+ FIND_ATTR_CONTXT Context;
+ PNTFS_ATTR_RECORD Attribute;
+
+ DPRINT1("No '%S' data stream associated with file!\n", Fcb->Stream);
+
+ // Couldn't find the requested data stream; print a list of streams available
+ BrowseStatus = FindFirstAttribute(&Context, DeviceExt, FileRecord, FALSE, &Attribute);
+ while (NT_SUCCESS(BrowseStatus))
+ {
+ if (Attribute->Type == AttributeData)
+ {
+ UNICODE_STRING Name;
+
+ Name.Length = Attribute->NameLength * sizeof(WCHAR);
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
+ DPRINT1("Data stream: '%wZ' available\n", &Name);
+ }
+
+ BrowseStatus = FindNextAttribute(&Context, &Attribute);
+ }
+ FindCloseAttribute(&Context);
+
+ ReleaseAttributeContext(DataContext);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Get the size of the stream on disk
+ StreamSize = AttributeDataLength(&DataContext->Record);
+
+ DPRINT("WriteOffset: %lu\tStreamSize: %I64u\n", WriteOffset, StreamSize);
+
+ // Are we trying to write beyond the end of the stream?
+ if (WriteOffset + Length > StreamSize)
+ {
+ // TODO: allocate additional clusters as needed and expand stream
+ DPRINT1("WriteOffset: %lu\tLength: %lu\tStreamSize: %I64u\n", WriteOffset, Length, StreamSize);
+ DPRINT1("TODO: Stream embiggening (appending files) is not yet supported!\n");
+ ReleaseAttributeContext(DataContext);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ *LengthWritten = 0; // We didn't write anything
+ return STATUS_ACCESS_DENIED; // temporarily; we don't change file sizes yet
+ }
+
+ DPRINT("Length: %lu\tWriteOffset: %lu\tStreamSize: %I64u\n", Length, WriteOffset, StreamSize);
+
+ // Write the data to the attribute
+ Status = WriteAttribute(DeviceExt, DataContext, WriteOffset, Buffer, Length, LengthWritten);
+
+ // Did the write fail?
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Write failure!\n");
+ ReleaseAttributeContext(DataContext);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+
+ return Status;
+ }
+
+ // This should never happen:
+ if (*LengthWritten != Length)
+ {
+ DPRINT1("\a\tNTFS DRIVER ERROR: length written (%lu) differs from requested (%lu), but no error was indicated!\n",
+ *LengthWritten, Length);
+ Status = STATUS_UNEXPECTED_IO_ERROR;
+ }
+
+ ReleaseAttributeContext(DataContext);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+
+ return Status;
+}
+/**
+* @name NtfsWrite
+* @implemented
+*
+* Handles IRP_MJ_WRITE I/O Request Packets for NTFS. This code borrows a lot from
+* VfatWrite, and needs a lot of cleaning up. It also needs a lot more of the code
+* from VfatWrite integrated.
+*
+* @param IrpContext
+* Points to an NTFS_IRP_CONTEXT which describes the write
+*
+* @return
+* STATUS_SUCCESS if successful,
+* STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
+* STATUS_INVALID_DEVICE_REQUEST if called on the main device object,
+* STATUS_NOT_IMPLEMENTED or STATUS_ACCESS_DENIED if a required feature isn't implemented.
+* STATUS_PARTIAL_COPY, STATUS_UNSUCCESSFUL, or STATUS_OBJECT_NAME_NOT_FOUND if NtfsWriteFile() fails.
+*
+* @remarks Called by NtfsDispatch() in response to an IRP_MJ_WRITE request. Page files are not implemented.
+* Support for large files (>4gb) is not implemented. Cached writes, file locks, transactions, etc - not implemented.
+*
+*/
NTSTATUS
NtfsWrite(PNTFS_IRP_CONTEXT IrpContext)
{
- DPRINT("NtfsWrite(IrpContext %p)\n",IrpContext);
+ PNTFS_FCB Fcb;
+ PERESOURCE Resource = NULL;
+ LARGE_INTEGER ByteOffset;
+ PUCHAR Buffer;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Length = 0;
+ ULONG ReturnedWriteLength = 0;
+ PDEVICE_OBJECT DeviceObject = NULL;
+ PDEVICE_EXTENSION DeviceExt = NULL;
+ PFILE_OBJECT FileObject = NULL;
+ PIRP Irp = NULL;
+ ULONG BytesPerSector;
+
+ DPRINT("NtfsWrite(IrpContext %p)\n", IrpContext);
+ ASSERT(IrpContext);
+
+ // This request is not allowed on the main device object
+ if (IrpContext->DeviceObject == NtfsGlobalData->DeviceObject)
+ {
+ DPRINT1("\t\t\t\tNtfsWrite is called with the main device object.\n");
+
+ Irp->IoStatus.Information = 0;
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ // get the I/O request packet
+ Irp = IrpContext->Irp;
+
+ // get the File control block
+ Fcb = (PNTFS_FCB)IrpContext->FileObject->FsContext;
+ ASSERT(Fcb);
+
+ DPRINT("About to write %wS\n", Fcb->ObjectName);
+ DPRINT("NTFS Version: %d.%d\n", Fcb->Vcb->NtfsInfo.MajorVersion, Fcb->Vcb->NtfsInfo.MinorVersion);
+
+ // setup some more locals
+ FileObject = IrpContext->FileObject;
+ DeviceObject = IrpContext->DeviceObject;
+ DeviceExt = DeviceObject->DeviceExtension;
+ BytesPerSector = DeviceExt->StorageDevice->SectorSize;
+ Length = IrpContext->Stack->Parameters.Write.Length;
+
+ // get the file offset we'll be writing to
+ ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
+ if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE &&
+ ByteOffset.u.HighPart == -1)
+ {
+ ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
+ }
+
+ DPRINT("ByteOffset: %I64u\tLength: %lu\tBytes per sector: %lu\n", ByteOffset.QuadPart,
+ Length, BytesPerSector);
- IrpContext->Irp->IoStatus.Information = 0;
- return STATUS_NOT_SUPPORTED;
+ if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
+ {
+ // TODO: Support large files
+ DPRINT1("FIXME: Writing to large files is not yet supported at this time.\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Is this a non-cached write? A non-buffered write?
+ if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME) ||
+ IrpContext->FileObject->Flags & FILE_NO_INTERMEDIATE_BUFFERING)
+ {
+ // non-cached and non-buffered writes must be sector aligned
+ if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
+ {
+ DPRINT1("Non-cached writes and non-buffered writes must be sector aligned!\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (Length == 0)
+ {
+ DPRINT1("Null write!\n");
+
+ IrpContext->Irp->IoStatus.Information = 0;
+
+ // FIXME: Doesn't accurately detect when a user passes NULL to WriteFile() for the buffer
+ if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
+ {
+ // FIXME: Update last write time
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // get the Resource
+ if (Fcb->Flags & FCB_IS_VOLUME)
+ {
+ Resource = &DeviceExt->DirResource;
+ }
+ else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
+ {
+ Resource = &Fcb->PagingIoResource;
+ }
+ else
+ {
+ Resource = &Fcb->MainResource;
+ }
+
+ // acquire exclusive access to the Resource
+ if (!ExAcquireResourceExclusiveLite(Resource, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+ {
+ return STATUS_CANT_WAIT;
+ }
+
+ /* From VfatWrite(). Todo: Handle file locks
+ if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
+ FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
+ {
+ if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
+ {
+ Status = STATUS_FILE_LOCK_CONFLICT;
+ goto ByeBye;
+ }
+ }*/
+
+ // Is this an async request to a file?
+ if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
+ {
+ DPRINT1("FIXME: Async writes not supported in NTFS!\n");
+
+ ExReleaseResourceLite(Resource);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ // get the buffer of data the user is trying to write
+ Buffer = NtfsGetUserBuffer(Irp, BooleanFlagOn(Irp->Flags, IRP_PAGING_IO));
+ ASSERT(Buffer);
+
+ // lock the buffer
+ Status = NtfsLockUserBuffer(Irp, Length, IoReadAccess);
+
+ // were we unable to lock the buffer?
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Unable to lock user buffer!\n");
+
+ ExReleaseResourceLite(Resource);
+ return Status;
+ }
+
+ DPRINT("Existing File Size(Fcb->RFCB.FileSize.QuadPart): %I64u\n", Fcb->RFCB.FileSize.QuadPart);
+ DPRINT("About to write the data. Length: %lu\n", Length);
+
+ // TODO: handle HighPart of ByteOffset (large files)
+
+ // write the file
+ Status = NtfsWriteFile(DeviceExt,
+ FileObject,
+ Buffer,
+ Length,
+ ByteOffset.LowPart,
+ Irp->Flags,
+ &ReturnedWriteLength);
+
+ IrpContext->Irp->IoStatus.Status = Status;
+
+ // was the write successful?
+ if (NT_SUCCESS(Status))
+ {
+ // TODO: Update timestamps
+
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ // advance the file pointer
+ FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + ReturnedWriteLength;
+ }
+
+ IrpContext->PriorityBoost = IO_DISK_INCREMENT;
+ }
+ else
+ {
+ DPRINT1("Write not Succesful!\tReturned length: %lu\n", ReturnedWriteLength);
+ }
+
+ Irp->IoStatus.Information = ReturnedWriteLength;
+
+ // Note: We leave the user buffer that we locked alone, it's up to the I/O manager to unlock and free it
+
+ ExReleaseResourceLite(Resource);
+
+ return Status;
}
/* EOF */
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=18d6584da443c23b1b139…
commit 18d6584da443c23b1b139d6995007781b495e868
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Dec 9 21:22:55 2017 +0100
[FASTFAT] Fix FastFAT not returning short name for FAT volumes in FileBothDirectoryInformation case
This is likely due to a copy paste error where long name was copied twice and short never.
Fun fact: this was not affecting FATX volumes
Fun fact2: this was defeating a buffer overflow check and thus was allowing buffer overflow!
CORE-14088
---
drivers/filesystems/fastfat/dir.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/filesystems/fastfat/dir.c b/drivers/filesystems/fastfat/dir.c
index 51359c4966..dd53080cda 100644
--- a/drivers/filesystems/fastfat/dir.c
+++ b/drivers/filesystems/fastfat/dir.c
@@ -427,9 +427,10 @@ VfatGetFileBothInformation(
{
pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
- RtlCopyMemory(pInfo->FileName,
- DirContext->LongNameU.Buffer,
- DirContext->LongNameU.Length);
+ ASSERT(pInfo->ShortNameLength / sizeof(WCHAR) <= 12);
+ RtlCopyMemory(pInfo->ShortName,
+ DirContext->ShortNameU.Buffer,
+ DirContext->ShortNameU.Length);
/* pInfo->FileIndex = ; */
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=48250aef6e1fbc00822b3…
commit 48250aef6e1fbc00822b338322f8d5fe050fe138
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Dec 9 21:10:32 2017 +0100
[CHKDSK] Don't continue repair if volume is in use
This makes use of previous commit vfatlib improvements that allow
caller to stop chkdsk if locking fail, which will happen if volume is in use.
That way, ReactOS users won't be able any longer to f*** up their C:\ volume
by attempting to chkdsk -f it!
CORE-14087
---
base/system/chkdsk/chkdsk.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/base/system/chkdsk/chkdsk.c b/base/system/chkdsk/chkdsk.c
index 57a7b26aef..76dc975098 100644
--- a/base/system/chkdsk/chkdsk.c
+++ b/base/system/chkdsk/chkdsk.c
@@ -228,6 +228,7 @@ ChkdskCallback(
DWORD Modifier,
PVOID Argument)
{
+ BOOLEAN Ret;
PDWORD percent;
PBOOLEAN status;
PTEXTOUTPUT output;
@@ -236,6 +237,7 @@ ChkdskCallback(
// We get other types of commands,
// but we don't have to pay attention to them
//
+ Ret = TRUE;
switch (Command)
{
case UNKNOWN2:
@@ -259,7 +261,8 @@ ChkdskCallback(
break;
case VOLUMEINUSE:
- ConPuts(StdOut, L"VOLUMEINUSE\n");
+ ConPuts(StdOut, L"Volume is in use and cannot be locked\n");
+ Ret = FALSE;
break;
case UNKNOWN9:
@@ -313,7 +316,7 @@ ChkdskCallback(
}
break;
}
- return TRUE;
+ return Ret;
}
#ifndef FMIFS_IMPORT_DLL
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6a224a38a15bd3b02ce3b…
commit 6a224a38a15bd3b02ce3b20eef3a3f2ccf68ab96
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Dec 9 21:07:09 2017 +0100
[VFATLIB] Make Chkdsk handle volume opening locking failures.
For instance, when repair is required, we can ask the caller whether we should
continue or not in case locking failed.
Also, introduced a hack for 1st stage where IopParseDevice() hack is in usage
so that broken NTSTATUS is diverted to appropriate status.
That way, usetup will properly continue even if locking failed (due to its
callback stub!)
CORE-14087
---
sdk/lib/fslib/vfatlib/check/io.c | 18 +++++++++++++++---
sdk/lib/fslib/vfatlib/check/io.h | 2 +-
sdk/lib/fslib/vfatlib/vfatlib.c | 16 +++++++++++++++-
3 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/sdk/lib/fslib/vfatlib/check/io.c b/sdk/lib/fslib/vfatlib/check/io.c
index 17db7a1c8e..2eca2abdd4 100644
--- a/sdk/lib/fslib/vfatlib/check/io.c
+++ b/sdk/lib/fslib/vfatlib/check/io.c
@@ -159,7 +159,7 @@ static off_t WIN32lseek(HANDLE fd, off_t offset, int whence)
/******************************************************************************/
-void fs_open(PUNICODE_STRING DriveRoot, int read_write)
+NTSTATUS fs_open(PUNICODE_STRING DriveRoot, int read_write)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
@@ -180,11 +180,14 @@ void fs_open(PUNICODE_STRING DriveRoot, int read_write)
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenFile() failed with status 0x%.08x\n", Status);
- return;
+ return Status;
}
// If read_write is specified, then the volume should be exclusively locked
- if (read_write) fs_lock(TRUE);
+ if (read_write)
+ {
+ Status = fs_lock(TRUE);
+ }
// Query geometry and partition info, to have bytes per sector, etc
@@ -192,6 +195,8 @@ void fs_open(PUNICODE_STRING DriveRoot, int read_write)
changes = last = NULL;
did_change = 0;
+
+ return Status;
}
BOOLEAN fs_isdirty(void)
@@ -231,6 +236,13 @@ NTSTATUS fs_lock(BOOLEAN LockVolume)
if (!NT_SUCCESS(Status))
{
DPRINT1("NtFsControlFile() failed with Status 0x%08x\n", Status);
+#if 1
+ /* FIXME: ReactOS HACK for 1stage due to IopParseDevice() hack */
+ if (Status == STATUS_INVALID_DEVICE_REQUEST)
+ {
+ Status = STATUS_ACCESS_DENIED;
+ }
+#endif
}
return Status;
diff --git a/sdk/lib/fslib/vfatlib/check/io.h b/sdk/lib/fslib/vfatlib/check/io.h
index 1178cd1e5b..23c6fd6a71 100644
--- a/sdk/lib/fslib/vfatlib/check/io.h
+++ b/sdk/lib/fslib/vfatlib/check/io.h
@@ -34,7 +34,7 @@
//#include <sys/types.h> /* for loff_t */
// #include <fcntl.h> /* for off_t */
-void fs_open(PUNICODE_STRING DriveRoot, int read_write);
+NTSTATUS fs_open(PUNICODE_STRING DriveRoot, int read_write);
/* Opens the file system PATH. If RW is zero, the file system is opened
read-only, otherwise, it is opened read-write. */
diff --git a/sdk/lib/fslib/vfatlib/vfatlib.c b/sdk/lib/fslib/vfatlib/vfatlib.c
index 267d3a1275..8db6e8a11a 100644
--- a/sdk/lib/fslib/vfatlib/vfatlib.c
+++ b/sdk/lib/fslib/vfatlib/vfatlib.c
@@ -383,6 +383,7 @@ VfatChkdsk(IN PUNICODE_STRING DriveRoot,
BOOLEAN salvage_files;
ULONG free_clusters;
DOS_FS fs;
+ NTSTATUS Status;
RtlZeroMemory(&fs, sizeof(fs));
@@ -403,7 +404,20 @@ VfatChkdsk(IN PUNICODE_STRING DriveRoot,
salvage_files = TRUE;
/* Open filesystem and lock it */
- fs_open(DriveRoot, FsCheckFlags & FSCHECK_READ_WRITE);
+ Status = fs_open(DriveRoot, FsCheckFlags & FSCHECK_READ_WRITE);
+ if (Status == STATUS_ACCESS_DENIED)
+ {
+ /* We failed to lock, ask the caller whether we should continue */
+ if (Callback(VOLUMEINUSE, 0, NULL))
+ {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ fs_close(FALSE);
+ return STATUS_DISK_CORRUPT_ERROR;
+ }
if (CheckOnlyIfDirty && !fs_isdirty())
{