// update open FCBs
// FIXME - speed this up(?)
- ExAcquireResourceSharedLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_shared(Vcb);
le = Vcb->all_fcbs.Flink;
while (le != &Vcb->all_fcbs) {
le = le->Flink;
}
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
} else
do_rollback(Vcb, &rollback);
return;
}
- ExAcquireResourceExclusiveLite(&fcb->Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(fcb->Vcb);
le = fcb->hardlinks.Flink;
while (le != &fcb->hardlinks) {
le = le->Flink;
}
- ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
+ release_fcb_lock(fcb->Vcb);
}
void mark_fcb_dirty(_In_ fcb* fcb) {
Vcb = fcb->Vcb;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
if (fileref)
free_fileref(fcb->Vcb, fileref);
else
free_fcb(Vcb, fcb);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
return STATUS_SUCCESS;
}
KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early
KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, Vcb->volume_fcb);
free_fcb(Vcb, Vcb->dummy_fcb);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
if (Vcb->root_file)
ObDereferenceObject(Vcb->root_file);
chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->cache) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, c->cache);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
c->cache = NULL;
}
ExFreePool(c->devices);
if (c->cache) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, c->cache);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
}
ExDeleteResourceLite(&c->range_locks_lock);
ZwClose(Vcb->flush_thread_handle);
}
-NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) {
+NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) {
LARGE_INTEGER newlength, time;
BTRFS_TIME now;
NTSTATUS Status;
}
fileref->fcb->deleted = TRUE;
+
+ le = fileref->children.Flink;
+ while (le != &fileref->children) {
+ file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry);
+
+ if (fr2->fcb->ads) {
+ fr2->fcb->deleted = TRUE;
+ mark_fcb_dirty(fr2->fcb);
+ }
+
+ le = le->Flink;
+ }
}
if (fileref->dc) {
mark_fcb_dirty(fileref->fcb); // so ROOT_ITEM gets updated
} else {
+ LIST_ENTRY* le;
+
// FIXME - we need a lock here
RemoveEntryList(&fileref->fcb->subvol->list_entry);
InsertTailList(&fileref->fcb->Vcb->drop_roots, &fileref->fcb->subvol->list_entry);
+
+ le = fileref->children.Flink;
+ while (le != &fileref->children) {
+ file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry);
+
+ if (fr2->fcb->ads) {
+ fr2->fcb->deleted = TRUE;
+ mark_fcb_dirty(fr2->fcb);
+ }
+
+ le = le->Flink;
+ }
}
}
} else {
locked = FALSE;
// fcb_lock needs to be acquired before fcb->Header.Resource
- ExAcquireResourceExclusiveLite(&fcb->Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(fcb->Vcb);
Status = delete_fileref(fileref, FileObject, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08x\n", Status);
do_rollback(fcb->Vcb, &rollback);
- ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
+ release_fcb_lock(fcb->Vcb);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
goto exit;
}
- ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
+ release_fcb_lock(fcb->Vcb);
locked = FALSE;
if (Vcb->root_file)
ObDereferenceObject(Vcb->root_file);
else if (Vcb->root_fileref) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, Vcb->root_fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
} else if (root_fcb) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, root_fcb);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
}
if (Vcb->volume_fcb) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, Vcb->volume_fcb);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
}
ExDeleteResourceLite(&Vcb->tree_lock);
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
+ FILEVERSION 1,0,1,0
+ PRODUCTVERSION 1,0,1,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs"
- VALUE "FileVersion", "1.0"
+ VALUE "FileVersion", "1.0.1"
VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-17"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
- VALUE "ProductVersion", "1.0"
+ VALUE "ProductVersion", "1.0.1"
END
END
BLOCK "VarFileInfo"
#define _Create_lock_level_(a)
#define _Lock_level_order_(a,b)
#define _Has_lock_level_(a)
+#define _Requires_lock_not_held_(a)
+#define _Acquires_exclusive_lock_(a)
+#define _Acquires_shared_lock_(a)
#endif
#endif
UINT64 create_total_time;
UINT64 open_fcb_calls;
UINT64 open_fcb_time;
+ UINT64 open_fileref_child_calls;
+ UINT64 open_fileref_child_time;
+ UINT64 fcb_lock_time;
} debug_stats;
#endif
LIST_ENTRY list_entry;
} name_bit;
+_Requires_lock_not_held_(Vcb->fcb_lock)
+_Acquires_shared_lock_(Vcb->fcb_lock)
+static __inline void acquire_fcb_lock_shared(device_extension* Vcb) {
+#ifdef DEBUG_STATS
+ LARGE_INTEGER time1, time2;
+
+ if (ExAcquireResourceSharedLite(&Vcb->fcb_lock, FALSE))
+ return;
+
+ time1 = KeQueryPerformanceCounter(NULL);
+#endif
+
+ ExAcquireResourceSharedLite(&Vcb->fcb_lock, TRUE);
+
+#ifdef DEBUG_STATS
+ time2 = KeQueryPerformanceCounter(NULL);
+ Vcb->stats.fcb_lock_time += time2.QuadPart - time1.QuadPart;
+#endif
+}
+
+_Requires_lock_not_held_(Vcb->fcb_lock)
+_Acquires_exclusive_lock_(Vcb->fcb_lock)
+static __inline void acquire_fcb_lock_exclusive(device_extension* Vcb) {
+#ifdef DEBUG_STATS
+ LARGE_INTEGER time1, time2;
+
+ if (ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, FALSE))
+ return;
+
+ time1 = KeQueryPerformanceCounter(NULL);
+#endif
+
+ ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+
+#ifdef DEBUG_STATS
+ time2 = KeQueryPerformanceCounter(NULL);
+ Vcb->stats.fcb_lock_time += time2.QuadPart - time1.QuadPart;
+#endif
+}
+
+_Requires_lock_held_(Vcb->fcb_lock)
+_Releases_lock_(Vcb->fcb_lock)
+static __inline void release_fcb_lock(device_extension* Vcb) {
+ ExReleaseResourceLite(&Vcb->fcb_lock);
+}
+
static __inline void* map_user_buffer(PIRP Irp, ULONG priority) {
if (!Irp->MdlAddress) {
return Irp->UserBuffer;
WCHAR* file_desc_fileref(_In_ file_ref* fileref);
void mark_fcb_dirty(_In_ fcb* fcb);
void mark_fileref_dirty(_In_ file_ref* fileref);
-NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback);
+NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback);
void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length);
void chunk_unlock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length);
void init_device(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ BOOL get_nums);
return STATUS_OBJECT_PATH_NOT_FOUND;
}
+ // if path starts with two backslashes, ignore one of them
+ if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\') {
+ fnus2.Buffer++;
+ fnus2.Length -= sizeof(WCHAR);
+ fnus2.MaximumLength -= sizeof(WCHAR);
+ }
+
if (fnus2.Length == sizeof(WCHAR)) {
if (Vcb->root_fileref->open_count == 0 && !(Vcb->Vpb->Flags & VPB_MOUNTED)) // don't allow root to be opened on unmounted FS
return STATUS_DEVICE_NOT_READY;
name_bit* nb = CONTAINING_RECORD(le, name_bit, list_entry);
BOOL lastpart = le->Flink == &parts || (has_stream && le->Flink->Flink == &parts);
BOOL streampart = has_stream && le->Flink == &parts;
+#ifdef DEBUG_STATS
+ LARGE_INTEGER time1, time2;
+#endif
+#ifdef DEBUG_STATS
+ time1 = KeQueryPerformanceCounter(NULL);
+#endif
Status = open_fileref_child(Vcb, sf, &nb->us, case_sensitive, lastpart, streampart, pooltype, &sf2, Irp);
+#ifdef DEBUG_STATS
+ time2 = KeQueryPerformanceCounter(NULL);
+ Vcb->stats.open_fileref_child_calls++;
+ Vcb->stats.open_fileref_child_time += time2.QuadPart - time1.QuadPart;
+#endif
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_OBJECT_PATH_NOT_FOUND || Status == STATUS_OBJECT_NAME_NOT_FOUND)
TRACE("open_fileref_child returned %08x\n", Status);
if (parfileref->fcb == Vcb->dummy_fcb)
return STATUS_ACCESS_DENIED;
+ if (options & FILE_DIRECTORY_FILE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY)
+ return STATUS_INVALID_PARAMETER;
+
Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
if (!NT_SUCCESS(Status)) {
ERR("RtlUnicodeToUTF8N returned %08x\n", Status);
TRACE("requested attributes = %x\n", IrpSp->Parameters.Create.FileAttributes);
- IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
-
- defda = FILE_ATTRIBUTE_ARCHIVE;
+ defda = 0;
if (utf8[0] == '.')
defda |= FILE_ATTRIBUTE_HIDDEN;
} else
IrpSp->Parameters.Create.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
+ if (!(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
+ defda |= FILE_ATTRIBUTE_ARCHIVE;
+ }
+
TRACE("defda = %x\n", defda);
if (IrpSp->Parameters.Create.FileAttributes == FILE_ATTRIBUTE_NORMAL)
*pfileref = fileref;
- send_notification_fileref(parfileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, &fileref->dc->name);
+ send_notification_fileref(parfileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_ADDED_STREAM, &fileref->dc->name);
return STATUS_SUCCESS;
}
if (Vcb->readonly)
return STATUS_MEDIA_WRITE_PROTECTED;
+ if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ return STATUS_CANNOT_DELETE;
+
dsus.Buffer = datasuf;
dsus.Length = dsus.MaximumLength = (USHORT)wcslen(datasuf) * sizeof(WCHAR);
fpus.Buffer = NULL;
goto exit;
}
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
if (options & FILE_OPEN_BY_FILE_ID) {
if (fn.Length == sizeof(UINT64) && related && RequestedDisposition == FILE_OPEN) {
} else {
WARN("FILE_OPEN_BY_FILE_ID only supported for inodes\n");
Status = STATUS_NOT_IMPLEMENTED;
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
} else {
if (related && fn.Length != 0 && fn.Buffer[0] == '\\') {
- Status = STATUS_OBJECT_NAME_INVALID;
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ Status = STATUS_INVALID_PARAMETER;
+ release_fcb_lock(Vcb);
goto exit;
}
Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
Status = STATUS_OBJECT_NAME_COLLISION;
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) {
TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n");
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
} else if (Status == STATUS_OBJECT_PATH_NOT_FOUND) {
TRACE("open_fileref returned %08x\n", Status);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
} else {
ERR("open_fileref returned %08x\n", Status);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
file_ref* sf;
BOOL readonly;
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
LARGE_INTEGER zero;
if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || is_subvol_readonly(fileref->fcb->subvol, Irp)) {
Status = STATUS_ACCESS_DENIED;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
if (Vcb->readonly) {
Status = STATUS_MEDIA_WRITE_PROTECTED;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) {
Status = STATUS_USER_MAPPED_FILE;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
TRACE("SeAccessCheck failed, returning %08x\n", Status);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
TRACE("could not open as deletion pending\n");
Status = STATUS_DELETE_PENDING;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) ||
is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
+ if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
+ Status = STATUS_CANNOT_DELETE;
+
+ acquire_fcb_lock_exclusive(Vcb);
+ free_fileref(Vcb, fileref);
+ release_fcb_lock(Vcb);
+
+ goto exit;
+ }
+
if (readonly) {
ACCESS_MASK allowed;
} else if (granted_access & ~allowed) {
Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
}
- if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || Vcb->readonly ||
- is_subvol_readonly(fileref->fcb->subvol, Irp) || readonly)) {
- Status = STATUS_CANNOT_DELETE;
-
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
- free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
-
- goto exit;
- }
-
if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) {
REPARSE_DATA_BUFFER* data;
Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
Status = STATUS_FILE_IS_A_DIRECTORY;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref));
Status = STATUS_NOT_A_DIRECTORY;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
else
WARN("IoCheckShareAccess failed, returning %08x\n", Status);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
+ if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))) {
+ IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
+
+ acquire_fcb_lock_exclusive(Vcb);
+ free_fileref(Vcb, fileref);
+ release_fcb_lock(Vcb);
+
+ Status = STATUS_ACCESS_DENIED;
+ goto exit;
+ }
+
if (fileref->fcb->ads) {
Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref, FALSE);
if (!NT_SUCCESS(Status)) {
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
}
if (!fileref->fcb->ads) {
+ LIST_ENTRY* le;
+
if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
ULONG offset;
FILE_FULL_EA_INFORMATION* eainfo;
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
fileref->fcb->ealen = 0;
}
}
+
+ // remove streams and send notifications
+ le = fileref->fcb->dir_children_index.Flink;
+ while (le != &fileref->fcb->dir_children_index) {
+ dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
+ LIST_ENTRY* le2 = le->Flink;
+
+ if (dc->index == 0) {
+ if (!dc->fileref) {
+ file_ref* fr2;
+
+ Status = open_fileref_child(Vcb, fileref, &dc->name, TRUE, TRUE, TRUE, PagedPool, &fr2, NULL);
+ if (!NT_SUCCESS(Status))
+ WARN("open_fileref_child returned %08x\n", Status);
+ }
+
+ if (dc->fileref) {
+ send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
+
+ Status = delete_fileref(dc->fileref, NULL, NULL, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("delete_fileref returned %08x\n", Status);
+
+ acquire_fcb_lock_exclusive(Vcb);
+ free_fileref(Vcb, fileref);
+ release_fcb_lock(Vcb);
+
+ goto exit;
+ }
+ }
+ } else
+ break;
+
+ le = le2;
+ }
}
KeQuerySystemTime(&time);
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fileref);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto exit;
}
#ifdef DEBUG_STATS
open_type = 2;
#endif
- Status = file_create(Irp, DeviceObject->DeviceExtension, FileObject, related, loaded_related, &fn, RequestedDisposition, options, rollback);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, rollback);
+ release_fcb_lock(Vcb);
Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
}
exit:
if (loaded_related) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, related);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
}
if (Status == STATUS_SUCCESS) {
return STATUS_NO_MORE_FILES;
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
- ExAcquireResourceSharedLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_shared(Vcb);
TRACE("%S\n", file_desc(IrpSp->FileObject));
TRACE(" unknown flags: %u\n", flags);
}
- initial = !ccb->query_string.Buffer;
-
if (IrpSp->Flags & SL_RESTART_SCAN) {
ccb->query_dir_offset = 0;
RtlFreeUnicodeString(&ccb->query_string);
ccb->query_string.Buffer = NULL;
}
+
+ ccb->has_wildcard = FALSE;
+ ccb->specific_file = FALSE;
}
+ initial = !ccb->query_string.Buffer;
+
if (IrpSp->Parameters.QueryDirectory.FileName && IrpSp->Parameters.QueryDirectory.FileName->Length > 1) {
TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer);
ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
end2:
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
TRACE("returning %08x\n", Status);
if (!fileref)
return STATUS_INVALID_PARAMETER;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
end:
ExReleaseResourceLite(fcb->Header.Resource);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
// send notification that directory is about to be deleted
if (NT_SUCCESS(Status) && fdi->DeleteFile && fcb->type == BTRFS_TYPE_DIRECTORY) {
}
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->ads) {
do_rollback(Vcb, &rollback);
ExReleaseResourceLite(fcb->Header.Resource);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
TRACE("extending stream to %llx bytes\n", end);
if (end > fcb->adsmaxlen) {
- ERR("error - xattr too long (%llu > %u)\n", end, fcb->adsmaxlen);
+ ERR("error - xattr too long (%u > %u)\n", end, fcb->adsmaxlen);
return STATUS_DISK_FULL;
}
set_size = TRUE;
}
- filter = FILE_NOTIFY_CHANGE_SIZE;
+ filter = FILE_NOTIFY_CHANGE_STREAM_SIZE;
if (!ccb->user_set_write_time) {
KeQuerySystemTime(&time);
mark_fcb_dirty(fileref->parent->fcb);
}
- send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name);
+ send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED_STREAM, &fileref->dc->name);
goto end;
}
}
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->type == BTRFS_TYPE_DIRECTORY) {
do_rollback(Vcb, &rollback);
ExReleaseResourceLite(fcb->Header.Resource);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
len = bytes_needed;
}
} else {
- ExAcquireResourceExclusiveLite(&fcb->Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(fcb->Vcb);
if (IsListEmpty(&fcb->hardlinks)) {
bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) + fileref->dc->name.Length - sizeof(WCHAR);
}
}
- ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
+ release_fcb_lock(fcb->Vcb);
}
fli->BytesNeeded = bytes_needed;
#ifdef DEBUG_STATS
static void print_stats(device_extension* Vcb) {
+ LARGE_INTEGER freq;
+
ERR("READ STATS:\n");
ERR("number of reads: %llu\n", Vcb->stats.num_reads);
ERR("data read: %llu bytes\n", Vcb->stats.data_read);
ERR("disk time taken: %llu\n", Vcb->stats.read_disk_time);
ERR("other time taken: %llu\n", Vcb->stats.read_total_time - Vcb->stats.read_csum_time - Vcb->stats.read_disk_time);
- ERR("OPEN STATS:\n");
+ KeQueryPerformanceCounter(&freq);
+
+ ERR("OPEN STATS (freq = %llu):\n", freq.QuadPart);
ERR("number of opens: %llu\n", Vcb->stats.num_opens);
ERR("total time taken: %llu\n", Vcb->stats.open_total_time);
ERR("number of overwrites: %llu\n", Vcb->stats.num_overwrites);
ERR("number of creates: %llu\n", Vcb->stats.num_creates);
ERR("calls to open_fcb: %llu\n", Vcb->stats.open_fcb_calls);
ERR("time spent in open_fcb: %llu\n", Vcb->stats.open_fcb_time);
+ ERR("calls to open_fileref_child: %llu\n", Vcb->stats.open_fileref_child_calls);
+ ERR("time spent in open_fileref_child: %llu\n", Vcb->stats.open_fileref_child_time);
+ ERR("time spent waiting for fcb_lock: %llu\n", Vcb->stats.fcb_lock_time);
ERR("total time taken: %llu\n", Vcb->stats.create_total_time);
RtlZeroMemory(&Vcb->stats, sizeof(debug_stats));
rootfcb->inode_item_changed = TRUE;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
InsertTailList(&r->fcbs, &rootfcb->list_entry);
InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
rootfcb->Header.IsFastIoPossible = fast_io_possible(rootfcb);
rootfcb->Header.AllocationSize.QuadPart = 0;
if (!fr) {
ERR("out of memory\n");
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fcb(Vcb, rootfcb);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
fr->fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fr->fcb->hash_ptrs) {
ERR("out of memory\n");
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fr);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
fr->fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fr->fcb->hash_ptrs_uc) {
ERR("out of memory\n");
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fr);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
end2:
if (fr) {
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
free_fileref(Vcb, fr);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
}
return Status;
if (Vcb->locked)
return STATUS_SUCCESS;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED;
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
goto end;
}
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
if (Vcb->balance.thread && KeReadStateEvent(&Vcb->balance.event)) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
if (!NT_SUCCESS(Status)) {
ERR("do_write returned %08x\n", Status);
ExReleaseResourceLite(&Vcb->tree_lock);
+ ExFreePool(newvpb);
goto end;
}
name.Length = name.MaximumLength = bmn->namelen;
name.Buffer = bmn->name;
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
Status = find_file_in_dir(&name, parfcb, &subvol, &inode, &dc, TRUE);
if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) {
Status = STATUS_SUCCESS;
end:
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ExFreePool(utf8.Buffer);
return STATUS_INTERNAL_ERROR;
}
- ExAcquireResourceSharedLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_shared(Vcb);
Status = open_fileref_by_inode(Vcb, r, r->root_item.objid, &fr, Irp);
if (!NT_SUCCESS(Status)) {
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ERR("open_fileref_by_inode returned %08x\n", Status);
return Status;
}
free_fileref(Vcb, fr);
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
return Status;
}
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED;
}
end:
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
return STATUS_SUCCESS;
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
- ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
+ acquire_fcb_lock_exclusive(Vcb);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED;
Status = STATUS_SUCCESS;
end:
- ExReleaseResourceLite(&Vcb->fcb_lock);
+ release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
return STATUS_PENDING;
}
- if (!(Irp->Flags & IRP_PAGING_IO) && FileObject->SectionObjectPointer->DataSectionObject) {
- IO_STATUS_BLOCK iosb;
-
- CcFlushCache(FileObject->SectionObjectPointer, &IrpSp->Parameters.Read.ByteOffset, length, &iosb);
-
- if (!NT_SUCCESS(iosb.Status)) {
- ERR("CcFlushCache returned %08x\n", iosb.Status);
- return iosb.Status;
- }
- }
-
if (fcb->ads)
Status = read_stream(fcb, data, start, length, bytes_read);
else
if (Irp->Flags & IRP_PAGING_IO)
wait = TRUE;
+ if (!(Irp->Flags & IRP_PAGING_IO) && FileObject->SectionObjectPointer->DataSectionObject) {
+ IO_STATUS_BLOCK iosb;
+
+ CcFlushCache(FileObject->SectionObjectPointer, &IrpSp->Parameters.Read.ByteOffset, IrpSp->Parameters.Read.Length, &iosb);
+ if (!NT_SUCCESS(iosb.Status)) {
+ ERR("CcFlushCache returned %08x\n", iosb.Status);
+ return iosb.Status;
+ }
+ }
+
if (!ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) {
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
Status = STATUS_PENDING;
return STATUS_INVALID_PARAMETER;
}
+ // IFSTest insists on this, for some reason...
+ if (Irp->UserBuffer)
+ return STATUS_INVALID_PARAMETER;
+
fcb = FileObject->FsContext;
ccb = FileObject->FsContext2;
return STATUS_INVALID_PARAMETER;
}
- // It isn't documented what permissions FSCTL_SET_REPARSE_POINT needs, but CreateSymbolicLinkW
- // creates a file with FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE.
- if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_WRITE_ATTRIBUTES)) {
+ if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA))) {
WARN("insufficient privileges\n");
return STATUS_ACCESS_DENIED;
}
if (buflen < sizeof(ULONG)) {
WARN("buffer was not long enough to hold tag\n");
- Status = STATUS_INVALID_PARAMETER;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto end;
+ }
+
+ Status = FsRtlValidateReparsePointBuffer(buflen, rdb);
+ if (!NT_SUCCESS(Status)) {
+ ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
goto end;
}
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
ERR("IOCTL_MOUNTMGR_QUERY_POINTS 1 returned %08x\n", Status);
-
- if (mmps.Size > 0) {
+ else if (mmps.Size > 0) {
MOUNTMGR_MOUNT_POINTS* mmps2;
mmps2 = ExAllocatePoolWithTag(NonPagedPool, mmps.Size, ALLOC_TAG);
ZwClose(h);
+end:
ExFreePool(kvfi);
-end:
ExFreePool(path.Buffer);
return degraded;
Status = _SEH2_GetExceptionCode();
} _SEH2_END;
+ if (changed_length) {
+ send_notification_fcb(fcb->ads ? fileref->parent : fileref, fcb->ads ? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE,
+ fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name : NULL);
+ }
+
goto end;
}
fileref->parent->fcb->inode_item_changed = TRUE;
if (changed_length)
- filter |= FILE_NOTIFY_CHANGE_SIZE;
+ filter |= FILE_NOTIFY_CHANGE_STREAM_SIZE;
+
+ filter |= FILE_NOTIFY_CHANGE_STREAM_WRITE;
}
if (!ccb->user_set_write_time) {
Status = STATUS_SUCCESS;
if (filter != 0)
- send_notification_fcb(fcb->ads ? fileref->parent : fileref, filter, FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name : NULL);
+ send_notification_fcb(fcb->ads ? fileref->parent : fileref, filter, fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED,
+ fcb->ads && fileref->dc ? &fileref->dc->name : NULL);
end:
if (NT_SUCCESS(Status) && FileObject->Flags & FO_SYNCHRONOUS_IO && !paging_io) {