1 /* Copyright (c) Mark Harmstone 2016
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
22 #include "btrfs_drv.h"
37 #define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | \
38 BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)
39 #define COMPAT_RO_SUPPORTED 0
41 static WCHAR device_name
[] = {'\\','B','t','r','f','s',0};
42 static WCHAR dosdevice_name
[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0};
44 PDRIVER_OBJECT drvobj
;
45 PDEVICE_OBJECT devobj
;
47 BOOL have_sse42
= FALSE
;
50 LIST_ENTRY uid_map_list
;
53 ERESOURCE global_loading_lock
;
54 UINT32 debug_log_level
= 0;
55 BOOL log_started
= FALSE
;
56 UNICODE_STRING log_device
, log_file
;
59 PFILE_OBJECT comfo
= NULL
;
60 PDEVICE_OBJECT comdo
= NULL
;
61 HANDLE log_handle
= NULL
;
64 int __security_cookie
= __LINE__
;
66 static NTSTATUS STDCALL
close_file(device_extension
* Vcb
, PFILE_OBJECT FileObject
);
74 static NTSTATUS STDCALL
dbg_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
75 read_context
* context
= conptr
;
77 // DbgPrint("dbg_completion\n");
79 context
->iosb
= Irp
->IoStatus
;
80 KeSetEvent(&context
->Event
, 0, FALSE
);
82 // return STATUS_SUCCESS;
83 return STATUS_MORE_PROCESSING_REQUIRED
;
86 #ifdef DEBUG_LONG_MESSAGES
87 void STDCALL
_debug_message(const char* func
, const char* file
, unsigned int line
, char* s
, ...) {
89 void STDCALL
_debug_message(const char* func
, char* s
, ...) {
92 PIO_STACK_LOCATION IrpSp
;
96 char *buf2
= NULL
, *buf
;
97 read_context
* context
= NULL
;
100 buf2
= ExAllocatePoolWithTag(NonPagedPool
, 1024, ALLOC_TAG
);
103 DbgPrint("Couldn't allocate buffer in debug_message\n");
107 #ifdef DEBUG_LONG_MESSAGES
108 sprintf(buf2
, "%p:%s:%s:%u:", PsGetCurrentThreadId(), func
, file
, line
);
110 sprintf(buf2
, "%p:%s:", PsGetCurrentThreadId(), func
);
112 buf
= &buf2
[strlen(buf2
)];
115 vsprintf(buf
, s
, ap
);
117 if (!log_started
|| (log_device
.Length
== 0 && log_file
.Length
== 0)) {
119 } else if (log_device
.Length
> 0) {
121 DbgPrint("comdo is NULL :-(\n");
126 length
= (UINT32
)strlen(buf2
);
128 offset
.u
.LowPart
= 0;
129 offset
.u
.HighPart
= 0;
131 context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(read_context
), ALLOC_TAG
);
133 DbgPrint("Couldn't allocate context in debug_message\n");
137 RtlZeroMemory(context
, sizeof(read_context
));
139 KeInitializeEvent(&context
->Event
, NotificationEvent
, FALSE
);
141 // status = ZwWriteFile(comh, NULL, NULL, NULL, &io, buf2, strlen(buf2), &offset, NULL);
143 Irp
= IoAllocateIrp(comdo
->StackSize
, FALSE
);
146 DbgPrint("IoAllocateIrp failed\n");
150 IrpSp
= IoGetNextIrpStackLocation(Irp
);
151 IrpSp
->MajorFunction
= IRP_MJ_WRITE
;
153 if (comdo
->Flags
& DO_BUFFERED_IO
) {
154 Irp
->AssociatedIrp
.SystemBuffer
= buf2
;
156 Irp
->Flags
= IRP_BUFFERED_IO
;
157 } else if (comdo
->Flags
& DO_DIRECT_IO
) {
158 Irp
->MdlAddress
= IoAllocateMdl(buf2
, length
, FALSE
, FALSE
, NULL
);
159 if (!Irp
->MdlAddress
) {
160 DbgPrint("IoAllocateMdl failed\n");
164 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoWriteAccess
);
166 Irp
->UserBuffer
= buf2
;
169 IrpSp
->Parameters
.Write
.Length
= length
;
170 IrpSp
->Parameters
.Write
.ByteOffset
= offset
;
172 Irp
->UserIosb
= &context
->iosb
;
174 Irp
->UserEvent
= &context
->Event
;
176 IoSetCompletionRoutine(Irp
, dbg_completion
, context
, TRUE
, TRUE
, TRUE
);
178 Status
= IoCallDriver(comdo
, Irp
);
180 if (Status
== STATUS_PENDING
) {
181 KeWaitForSingleObject(&context
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
182 Status
= context
->iosb
.Status
;
185 if (comdo
->Flags
& DO_DIRECT_IO
) {
186 MmUnlockPages(Irp
->MdlAddress
);
187 IoFreeMdl(Irp
->MdlAddress
);
190 if (!NT_SUCCESS(Status
)) {
191 DbgPrint("failed to write to COM1 - error %08x\n", Status
);
197 } else if (log_handle
!= NULL
) {
198 IO_STATUS_BLOCK iosb
;
200 length
= (UINT32
)strlen(buf2
);
202 Status
= ZwWriteFile(log_handle
, NULL
, NULL
, NULL
, &iosb
, buf2
, length
, NULL
, NULL
);
204 if (!NT_SUCCESS(Status
)) {
205 DbgPrint("failed to write to file - error %08x\n", Status
);
220 ULONG
sector_align( ULONG NumberToBeAligned
, ULONG Alignment
)
222 if( Alignment
& ( Alignment
- 1 ) )
225 // Alignment not a power of 2
228 return NumberToBeAligned
;
230 if( ( NumberToBeAligned
& ( Alignment
- 1 ) ) != 0 )
232 NumberToBeAligned
= NumberToBeAligned
+ Alignment
;
233 NumberToBeAligned
= NumberToBeAligned
& ( ~ (Alignment
-1) );
235 return NumberToBeAligned
;
238 int keycmp(const KEY
* key1
, const KEY
* key2
) {
239 if (key1
->obj_id
< key2
->obj_id
) {
241 } else if (key1
->obj_id
> key2
->obj_id
) {
245 if (key1
->obj_type
< key2
->obj_type
) {
247 } else if (key1
->obj_type
> key2
->obj_type
) {
251 if (key1
->offset
< key2
->offset
) {
253 } else if (key1
->offset
> key2
->offset
) {
260 BOOL
is_top_level(PIRP Irp
) {
261 if (!IoGetTopLevelIrp()) {
262 IoSetTopLevelIrp(Irp
);
269 static void STDCALL
DriverUnload(PDRIVER_OBJECT DriverObject
) {
270 UNICODE_STRING dosdevice_nameW
;
272 ERR("DriverUnload\n");
276 IoUnregisterFileSystem(DriverObject
->DeviceObject
);
278 dosdevice_nameW
.Buffer
= dosdevice_name
;
279 dosdevice_nameW
.Length
= dosdevice_nameW
.MaximumLength
= (USHORT
)wcslen(dosdevice_name
) * sizeof(WCHAR
);
281 IoDeleteSymbolicLink(&dosdevice_nameW
);
282 IoDeleteDevice(DriverObject
->DeviceObject
);
284 while (!IsListEmpty(&uid_map_list
)) {
285 LIST_ENTRY
* le
= RemoveHeadList(&uid_map_list
);
286 uid_map
* um
= CONTAINING_RECORD(le
, uid_map
, listentry
);
293 // FIXME - free volumes and their devpaths
297 ObDereferenceObject(comfo
);
303 ExDeleteResourceLite(&global_loading_lock
);
305 if (log_device
.Buffer
)
306 ExFreePool(log_device
.Buffer
);
309 ExFreePool(log_file
.Buffer
);
312 BOOL STDCALL
get_last_inode(device_extension
* Vcb
, root
* r
) {
314 traverse_ptr tp
, prev_tp
;
318 searchkey
.obj_id
= 0xffffffffffffffff;
319 searchkey
.obj_type
= 0xff;
320 searchkey
.offset
= 0xffffffffffffffff;
322 Status
= find_item(Vcb
, r
, &tp
, &searchkey
, FALSE
);
323 if (!NT_SUCCESS(Status
)) {
324 ERR("error - find_item returned %08x\n", Status
);
328 while (find_prev_item(Vcb
, &tp
, &prev_tp
, FALSE
)) {
331 TRACE("moving on to %llx,%x,%llx\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
333 if (tp
.item
->key
.obj_type
== TYPE_INODE_ITEM
|| (tp
.item
->key
.obj_type
== TYPE_ROOT_ITEM
&& !(tp
.item
->key
.obj_id
& 0x8000000000000000))) {
334 r
->lastinode
= tp
.item
->key
.obj_id
;
335 TRACE("last inode for tree %llx is %llx\n", r
->id
, r
->lastinode
);
340 r
->lastinode
= SUBVOL_ROOT_INODE
;
342 WARN("no INODE_ITEMs in tree %llx\n", r
->id
);
347 BOOL STDCALL
get_xattr(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, char* name
, UINT32 crc32
, UINT8
** data
, UINT16
* datalen
) {
354 TRACE("(%p, %llx, %llx, %s, %08x, %p, %p)\n", Vcb
, subvol
->id
, inode
, name
, crc32
, data
, datalen
);
356 searchkey
.obj_id
= inode
;
357 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
358 searchkey
.offset
= crc32
;
360 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
361 if (!NT_SUCCESS(Status
)) {
362 ERR("error - find_item returned %08x\n", Status
);
366 if (keycmp(&tp
.item
->key
, &searchkey
)) {
367 TRACE("could not find item (%llx,%x,%llx)\n", searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
);
371 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
372 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
376 xa
= (DIR_ITEM
*)tp
.item
->data
;
377 size
= tp
.item
->size
;
380 if (size
< sizeof(DIR_ITEM
) || size
< (sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
)) {
381 WARN("(%llx,%x,%llx) is truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
385 if (xa
->n
== strlen(name
) && RtlCompareMemory(name
, xa
->name
, xa
->n
) == xa
->n
) {
386 TRACE("found xattr %s in (%llx,%x,%llx)\n", name
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
);
391 *data
= ExAllocatePoolWithTag(PagedPool
, xa
->m
, ALLOC_TAG
);
393 ERR("out of memory\n");
397 RtlCopyMemory(*data
, &xa
->name
[xa
->n
], xa
->m
);
404 xasize
= sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
;
408 xa
= (DIR_ITEM
*)&xa
->name
[xa
->m
+ xa
->n
];
413 TRACE("xattr %s not found in (%llx,%x,%llx)\n", name
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
);
418 NTSTATUS STDCALL
set_xattr(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, char* name
, UINT32 crc32
, UINT8
* data
, UINT16 datalen
, LIST_ENTRY
* rollback
) {
425 TRACE("(%p, %llx, %llx, %s, %08x, %p, %u)\n", Vcb
, subvol
->id
, inode
, name
, crc32
, data
, datalen
);
427 searchkey
.obj_id
= inode
;
428 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
429 searchkey
.offset
= crc32
;
431 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
432 if (!NT_SUCCESS(Status
)) {
433 ERR("error - find_item returned %08x\n", Status
);
437 xasize
= sizeof(DIR_ITEM
) - 1 + (ULONG
)strlen(name
) + datalen
;
439 // FIXME - make sure xasize not too big
441 if (!keycmp(&tp
.item
->key
, &searchkey
)) { // key exists
443 ULONG size
= tp
.item
->size
;
445 xa
= (DIR_ITEM
*)tp
.item
->data
;
447 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
448 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
453 if (size
< sizeof(DIR_ITEM
) || size
< sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
) {
454 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
458 oldxasize
= sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
;
460 if (xa
->n
== strlen(name
) && RtlCompareMemory(name
, xa
->name
, xa
->n
) == xa
->n
) {
464 newdata
= ExAllocatePoolWithTag(PagedPool
, tp
.item
->size
+ xasize
- oldxasize
, ALLOC_TAG
);
466 ERR("out of memory\n");
467 return STATUS_INSUFFICIENT_RESOURCES
;
470 pos
= (UINT8
*)xa
- tp
.item
->data
;
471 if (pos
+ oldxasize
< tp
.item
->size
) { // copy after changed xattr
472 RtlCopyMemory(newdata
+ pos
+ xasize
, tp
.item
->data
+ pos
+ oldxasize
, tp
.item
->size
- pos
- oldxasize
);
475 if (pos
> 0) { // copy before changed xattr
476 RtlCopyMemory(newdata
, tp
.item
->data
, pos
);
477 xa
= (DIR_ITEM
*)(newdata
+ pos
);
479 xa
= (DIR_ITEM
*)newdata
;
482 xa
->key
.obj_type
= 0;
484 xa
->transid
= Vcb
->superblock
.generation
;
486 xa
->n
= (UINT16
)strlen(name
);
487 xa
->type
= BTRFS_TYPE_EA
;
488 RtlCopyMemory(xa
->name
, name
, strlen(name
));
489 RtlCopyMemory(xa
->name
+ strlen(name
), data
, datalen
);
491 delete_tree_item(Vcb
, &tp
, rollback
);
492 insert_tree_item(Vcb
, subvol
, inode
, TYPE_XATTR_ITEM
, crc32
, newdata
, tp
.item
->size
+ xasize
- oldxasize
, NULL
, rollback
);
497 if (xa
->m
+ xa
->n
>= size
) { // FIXME - test this works
498 // not found, add to end of data
499 newdata
= ExAllocatePoolWithTag(PagedPool
, tp
.item
->size
+ xasize
, ALLOC_TAG
);
501 ERR("out of memory\n");
502 return STATUS_INSUFFICIENT_RESOURCES
;
505 RtlCopyMemory(newdata
, tp
.item
->data
, tp
.item
->size
);
507 xa
= (DIR_ITEM
*)((UINT8
*)newdata
+ tp
.item
->size
);
509 xa
->key
.obj_type
= 0;
511 xa
->transid
= Vcb
->superblock
.generation
;
513 xa
->n
= (UINT16
)strlen(name
);
514 xa
->type
= BTRFS_TYPE_EA
;
515 RtlCopyMemory(xa
->name
, name
, strlen(name
));
516 RtlCopyMemory(xa
->name
+ strlen(name
), data
, datalen
);
518 delete_tree_item(Vcb
, &tp
, rollback
);
519 insert_tree_item(Vcb
, subvol
, inode
, TYPE_XATTR_ITEM
, crc32
, newdata
, tp
.item
->size
+ xasize
, NULL
, rollback
);
523 xa
= (DIR_ITEM
*)&xa
->name
[xa
->m
+ xa
->n
];
529 // add new DIR_ITEM struct
531 xa
= ExAllocatePoolWithTag(PagedPool
, xasize
, ALLOC_TAG
);
533 ERR("out of memory\n");
534 return STATUS_INSUFFICIENT_RESOURCES
;
538 xa
->key
.obj_type
= 0;
540 xa
->transid
= Vcb
->superblock
.generation
;
542 xa
->n
= (UINT16
)strlen(name
);
543 xa
->type
= BTRFS_TYPE_EA
;
544 RtlCopyMemory(xa
->name
, name
, strlen(name
));
545 RtlCopyMemory(xa
->name
+ strlen(name
), data
, datalen
);
547 insert_tree_item(Vcb
, subvol
, inode
, TYPE_XATTR_ITEM
, crc32
, xa
, xasize
, NULL
, rollback
);
550 return STATUS_SUCCESS
;
553 BOOL STDCALL
delete_xattr(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, char* name
, UINT32 crc32
, LIST_ENTRY
* rollback
) {
559 TRACE("(%p, %llx, %llx, %s, %08x)\n", Vcb
, subvol
->id
, inode
, name
, crc32
);
561 searchkey
.obj_id
= inode
;
562 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
563 searchkey
.offset
= crc32
;
565 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
566 if (!NT_SUCCESS(Status
)) {
567 ERR("error - find_item returned %08x\n", Status
);
571 if (!keycmp(&tp
.item
->key
, &searchkey
)) { // key exists
572 ULONG size
= tp
.item
->size
;
574 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
575 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
579 xa
= (DIR_ITEM
*)tp
.item
->data
;
584 if (size
< sizeof(DIR_ITEM
) || size
< sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
) {
585 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
590 oldxasize
= sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
;
592 if (xa
->n
== strlen(name
) && RtlCompareMemory(name
, xa
->name
, xa
->n
) == xa
->n
) {
594 UINT8
*newdata
, *dioff
;
596 newsize
= tp
.item
->size
- (sizeof(DIR_ITEM
) - 1 + xa
->n
+ xa
->m
);
598 delete_tree_item(Vcb
, &tp
, rollback
);
601 TRACE("xattr %s deleted\n", name
);
606 // FIXME - deleting collisions almost certainly works, but we should test it properly anyway
607 newdata
= ExAllocatePoolWithTag(PagedPool
, newsize
, ALLOC_TAG
);
609 ERR("out of memory\n");
613 if ((UINT8
*)xa
> tp
.item
->data
) {
614 RtlCopyMemory(newdata
, tp
.item
->data
, (UINT8
*)xa
- tp
.item
->data
);
615 dioff
= newdata
+ ((UINT8
*)xa
- tp
.item
->data
);
620 if ((UINT8
*)&xa
->name
[xa
->n
+xa
->m
] - tp
.item
->data
< tp
.item
->size
)
621 RtlCopyMemory(dioff
, &xa
->name
[xa
->n
+xa
->m
], tp
.item
->size
- ((UINT8
*)&xa
->name
[xa
->n
+xa
->m
] - tp
.item
->data
));
623 insert_tree_item(Vcb
, subvol
, inode
, TYPE_XATTR_ITEM
, crc32
, newdata
, newsize
, NULL
, rollback
);
629 if (xa
->m
+ xa
->n
>= size
) { // FIXME - test this works
630 WARN("xattr %s not found\n", name
);
634 xa
= (DIR_ITEM
*)&xa
->name
[xa
->m
+ xa
->n
];
640 WARN("xattr %s not found\n", name
);
646 NTSTATUS
add_dir_item(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, UINT32 crc32
, DIR_ITEM
* di
, ULONG disize
, LIST_ENTRY
* rollback
) {
652 searchkey
.obj_id
= inode
;
653 searchkey
.obj_type
= TYPE_DIR_ITEM
;
654 searchkey
.offset
= crc32
;
656 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
657 if (!NT_SUCCESS(Status
)) {
658 ERR("error - find_item returned %08x\n", Status
);
662 if (!keycmp(&tp
.item
->key
, &searchkey
)) {
663 ULONG maxlen
= Vcb
->superblock
.node_size
- sizeof(tree_header
) - sizeof(leaf_node
);
665 if (tp
.item
->size
+ disize
> maxlen
) {
666 WARN("DIR_ITEM was longer than maxlen (%u + %u > %u)\n", tp
.item
->size
, disize
, maxlen
);
667 return STATUS_INTERNAL_ERROR
;
670 di2
= ExAllocatePoolWithTag(PagedPool
, tp
.item
->size
+ disize
, ALLOC_TAG
);
672 ERR("out of memory\n");
673 return STATUS_INSUFFICIENT_RESOURCES
;
676 if (tp
.item
->size
> 0)
677 RtlCopyMemory(di2
, tp
.item
->data
, tp
.item
->size
);
679 RtlCopyMemory(di2
+ tp
.item
->size
, di
, disize
);
681 delete_tree_item(Vcb
, &tp
, rollback
);
683 insert_tree_item(Vcb
, subvol
, inode
, TYPE_DIR_ITEM
, crc32
, di2
, tp
.item
->size
+ disize
, NULL
, rollback
);
687 insert_tree_item(Vcb
, subvol
, inode
, TYPE_DIR_ITEM
, crc32
, di
, disize
, NULL
, rollback
);
690 return STATUS_SUCCESS
;
693 UINT64
find_next_dir_index(device_extension
* Vcb
, root
* subvol
, UINT64 inode
) {
695 traverse_ptr tp
, prev_tp
;
699 searchkey
.obj_id
= inode
;
700 searchkey
.obj_type
= TYPE_DIR_INDEX
+ 1;
701 searchkey
.offset
= 0;
703 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
704 if (!NT_SUCCESS(Status
)) {
705 ERR("error - find_item returned %08x\n", Status
);
709 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
710 if (!find_prev_item(Vcb
, &tp
, &prev_tp
, FALSE
)) {
713 TRACE("moving back to %llx,%x,%llx\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
717 if (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
== TYPE_DIR_INDEX
) {
718 dirpos
= tp
.item
->key
.offset
+ 1;
725 static NTSTATUS STDCALL
drv_close(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
727 PIO_STACK_LOCATION IrpSp
;
732 FsRtlEnterFileSystem();
734 top_level
= is_top_level(Irp
);
736 if (DeviceObject
== devobj
) {
737 TRACE("Closing file system\n");
738 Status
= STATUS_SUCCESS
;
742 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
744 // FIXME - unmount if called for volume
745 // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
747 Status
= close_file(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
);
750 Irp
->IoStatus
.Status
= Status
;
751 Irp
->IoStatus
.Information
= 0;
753 IoCompleteRequest( Irp
, IO_DISK_INCREMENT
);
756 IoSetTopLevelIrp(NULL
);
758 FsRtlExitFileSystem();
760 TRACE("returning %08x\n", Status
);
765 static NTSTATUS STDCALL
drv_write(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
768 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
770 FsRtlEnterFileSystem();
772 top_level
= is_top_level(Irp
);
774 // ERR("recursive = %s\n", Irp != IoGetTopLevelIrp() ? "TRUE" : "FALSE");
777 if (IrpSp
->MinorFunction
& IRP_MN_COMPLETE
) {
778 CcMdlWriteComplete(IrpSp
->FileObject
, &IrpSp
->Parameters
.Write
.ByteOffset
, Irp
->MdlAddress
);
780 Irp
->MdlAddress
= NULL
;
781 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
783 Status
= write_file(DeviceObject
, Irp
);
785 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
786 Status
= _SEH2_GetExceptionCode();
789 Irp
->IoStatus
.Status
= Status
;
791 TRACE("wrote %u bytes\n", Irp
->IoStatus
.Information
);
793 if (Status
!= STATUS_PENDING
)
794 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
797 IoSetTopLevelIrp(NULL
);
799 FsRtlExitFileSystem();
801 TRACE("returning %08x\n", Status
);
806 static NTSTATUS STDCALL
drv_query_ea(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
810 FsRtlEnterFileSystem();
812 top_level
= is_top_level(Irp
);
814 FIXME("STUB: query ea\n");
815 Status
= STATUS_NOT_IMPLEMENTED
;
817 Irp
->IoStatus
.Status
= Status
;
818 Irp
->IoStatus
.Information
= 0;
820 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
823 IoSetTopLevelIrp(NULL
);
825 FsRtlExitFileSystem();
830 static NTSTATUS STDCALL
drv_set_ea(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
832 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
835 FsRtlEnterFileSystem();
837 top_level
= is_top_level(Irp
);
839 FIXME("STUB: set ea\n");
840 Status
= STATUS_NOT_IMPLEMENTED
;
843 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
845 // FIXME - return STATUS_ACCESS_DENIED if subvol readonly
847 Irp
->IoStatus
.Status
= Status
;
848 Irp
->IoStatus
.Information
= 0;
850 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
853 IoSetTopLevelIrp(NULL
);
855 FsRtlExitFileSystem();
860 static NTSTATUS STDCALL
drv_flush_buffers(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
862 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
863 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
864 fcb
* fcb
= FileObject
->FsContext
;
867 TRACE("flush buffers\n");
869 FsRtlEnterFileSystem();
871 top_level
= is_top_level(Irp
);
873 Status
= STATUS_SUCCESS
;
874 Irp
->IoStatus
.Status
= Status
;
875 Irp
->IoStatus
.Information
= 0;
877 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
) {
878 CcFlushCache(&fcb
->nonpaged
->segment_object
, NULL
, 0, &Irp
->IoStatus
);
880 if (fcb
->Header
.PagingIoResource
) {
881 ExAcquireResourceExclusiveLite(fcb
->Header
.PagingIoResource
, TRUE
);
882 ExReleaseResourceLite(fcb
->Header
.PagingIoResource
);
885 Status
= Irp
->IoStatus
.Status
;
888 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
891 IoSetTopLevelIrp(NULL
);
893 FsRtlExitFileSystem();
898 static NTSTATUS STDCALL
drv_query_volume_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
899 PIO_STACK_LOCATION IrpSp
;
901 ULONG BytesCopied
= 0;
902 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
906 // An unfortunate necessity - we have to lie about our FS type. MPR!MprGetConnection polls for this,
907 // and compares it to a whitelist. If it doesn't match, it will return ERROR_NO_NET_OR_BAD_PATH,
908 // which prevents UAC from working.
909 // FIXME - only lie if we detect that we're being called by mpr.dll
911 WCHAR
* fs_name
= L
"NTFS";
912 ULONG fs_name_len
= 4 * sizeof(WCHAR
);
914 WCHAR
* fs_name
= L
"Btrfs";
915 ULONG fs_name_len
= 5 * sizeof(WCHAR
);
918 TRACE("query volume information\n");
920 FsRtlEnterFileSystem();
921 top_level
= is_top_level(Irp
);
923 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
925 Status
= STATUS_NOT_IMPLEMENTED
;
927 switch (IrpSp
->Parameters
.QueryVolume
.FsInformationClass
) {
928 case FileFsAttributeInformation
:
930 FILE_FS_ATTRIBUTE_INFORMATION
* data
= Irp
->AssociatedIrp
.SystemBuffer
;
931 BOOL overflow
= FALSE
;
932 ULONG orig_fs_name_len
= fs_name_len
;
934 TRACE("FileFsAttributeInformation\n");
936 if (IrpSp
->Parameters
.QueryVolume
.Length
< sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) - sizeof(WCHAR
) + fs_name_len
) {
937 if (IrpSp
->Parameters
.QueryVolume
.Length
> sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) - sizeof(WCHAR
))
938 fs_name_len
= IrpSp
->Parameters
.QueryVolume
.Length
- sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + sizeof(WCHAR
);
945 data
->FileSystemAttributes
= FILE_CASE_PRESERVED_NAMES
| FILE_CASE_SENSITIVE_SEARCH
|
946 FILE_UNICODE_ON_DISK
| FILE_NAMED_STREAMS
| FILE_SUPPORTS_HARD_LINKS
| FILE_PERSISTENT_ACLS
|
947 FILE_SUPPORTS_REPARSE_POINTS
;
949 data
->FileSystemAttributes
|= FILE_READ_ONLY_VOLUME
;
951 // should also be FILE_FILE_COMPRESSION when supported
952 data
->MaximumComponentNameLength
= 255; // FIXME - check
953 data
->FileSystemNameLength
= orig_fs_name_len
;
954 RtlCopyMemory(data
->FileSystemName
, fs_name
, fs_name_len
);
956 BytesCopied
= sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) - sizeof(WCHAR
) + fs_name_len
;
957 Status
= overflow
? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
;
961 case FileFsControlInformation
:
962 FIXME("STUB: FileFsControlInformation\n");
965 case FileFsDeviceInformation
:
966 FIXME("STUB: FileFsDeviceInformation\n");
969 case FileFsDriverPathInformation
:
970 FIXME("STUB: FileFsDriverPathInformation\n");
973 case FileFsFullSizeInformation
:
975 FILE_FS_FULL_SIZE_INFORMATION
* ffsi
= Irp
->AssociatedIrp
.SystemBuffer
;
976 UINT64 totalsize
, freespace
;
978 TRACE("FileFsFullSizeInformation\n");
980 // FIXME - calculate correctly for RAID
981 totalsize
= Vcb
->superblock
.total_bytes
/ Vcb
->superblock
.sector_size
;
982 freespace
= (Vcb
->superblock
.total_bytes
- Vcb
->superblock
.bytes_used
) / Vcb
->superblock
.sector_size
;
984 ffsi
->TotalAllocationUnits
.QuadPart
= totalsize
;
985 ffsi
->ActualAvailableAllocationUnits
.QuadPart
= freespace
;
986 ffsi
->CallerAvailableAllocationUnits
.QuadPart
= ffsi
->ActualAvailableAllocationUnits
.QuadPart
;
987 ffsi
->SectorsPerAllocationUnit
= 1;
988 ffsi
->BytesPerSector
= Vcb
->superblock
.sector_size
;
990 BytesCopied
= sizeof(FILE_FS_FULL_SIZE_INFORMATION
);
991 Status
= STATUS_SUCCESS
;
996 case FileFsObjectIdInformation
:
997 FIXME("STUB: FileFsObjectIdInformation\n");
1000 case FileFsSizeInformation
:
1002 FILE_FS_SIZE_INFORMATION
* ffsi
= Irp
->AssociatedIrp
.SystemBuffer
;
1003 UINT64 totalsize
, freespace
;
1005 TRACE("FileFsSizeInformation\n");
1007 // FIXME - calculate correctly for RAID
1008 // FIXME - is this returning the right free space?
1009 totalsize
= Vcb
->superblock
.dev_item
.num_bytes
/ Vcb
->superblock
.sector_size
;
1010 freespace
= (Vcb
->superblock
.dev_item
.num_bytes
- Vcb
->superblock
.dev_item
.bytes_used
) / Vcb
->superblock
.sector_size
;
1012 ffsi
->TotalAllocationUnits
.QuadPart
= totalsize
;
1013 ffsi
->AvailableAllocationUnits
.QuadPart
= freespace
;
1014 ffsi
->SectorsPerAllocationUnit
= 1;
1015 ffsi
->BytesPerSector
= Vcb
->superblock
.sector_size
;
1017 BytesCopied
= sizeof(FILE_FS_SIZE_INFORMATION
);
1018 Status
= STATUS_SUCCESS
;
1023 case FileFsVolumeInformation
:
1025 FILE_FS_VOLUME_INFORMATION
* data
= Irp
->AssociatedIrp
.SystemBuffer
;
1026 FILE_FS_VOLUME_INFORMATION ffvi
;
1027 BOOL overflow
= FALSE
;
1028 ULONG label_len
, orig_label_len
;
1030 TRACE("FileFsVolumeInformation\n");
1031 TRACE("max length = %u\n", IrpSp
->Parameters
.QueryVolume
.Length
);
1033 acquire_tree_lock(Vcb
, FALSE
);
1035 // orig_label_len = label_len = (ULONG)(wcslen(Vcb->label) * sizeof(WCHAR));
1036 RtlUTF8ToUnicodeN(NULL
, 0, &label_len
, Vcb
->superblock
.label
, (ULONG
)strlen(Vcb
->superblock
.label
));
1037 orig_label_len
= label_len
;
1039 if (IrpSp
->Parameters
.QueryVolume
.Length
< sizeof(FILE_FS_VOLUME_INFORMATION
) - sizeof(WCHAR
) + label_len
) {
1040 if (IrpSp
->Parameters
.QueryVolume
.Length
> sizeof(FILE_FS_VOLUME_INFORMATION
) - sizeof(WCHAR
))
1041 label_len
= IrpSp
->Parameters
.QueryVolume
.Length
- sizeof(FILE_FS_VOLUME_INFORMATION
) + sizeof(WCHAR
);
1048 TRACE("label_len = %u\n", label_len
);
1050 ffvi
.VolumeCreationTime
.QuadPart
= 0; // FIXME
1051 ffvi
.VolumeSerialNumber
= Vcb
->superblock
.uuid
.uuid
[12] << 24 | Vcb
->superblock
.uuid
.uuid
[13] << 16 | Vcb
->superblock
.uuid
.uuid
[14] << 8 | Vcb
->superblock
.uuid
.uuid
[15];
1052 ffvi
.VolumeLabelLength
= orig_label_len
;
1053 ffvi
.SupportsObjects
= FALSE
;
1055 RtlCopyMemory(data
, &ffvi
, min(sizeof(FILE_FS_VOLUME_INFORMATION
) - sizeof(WCHAR
), IrpSp
->Parameters
.QueryVolume
.Length
));
1057 if (label_len
> 0) {
1060 // RtlCopyMemory(&data->VolumeLabel[0], Vcb->label, label_len);
1061 RtlUTF8ToUnicodeN(&data
->VolumeLabel
[0], label_len
, &bytecount
, Vcb
->superblock
.label
, (ULONG
)strlen(Vcb
->superblock
.label
));
1062 TRACE("label = %.*S\n", label_len
/ sizeof(WCHAR
), data
->VolumeLabel
);
1065 release_tree_lock(Vcb
, FALSE
);
1067 BytesCopied
= sizeof(FILE_FS_VOLUME_INFORMATION
) - sizeof(WCHAR
) + label_len
;
1068 Status
= overflow
? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
;
1073 Status
= STATUS_INVALID_PARAMETER
;
1074 WARN("unknown FsInformatClass %u\n", IrpSp
->Parameters
.QueryVolume
.FsInformationClass
);
1078 // if (NT_SUCCESS(Status) && IrpSp->Parameters.QueryVolume.Length < BytesCopied) { // FIXME - should not copy anything if overflow
1079 // WARN("overflow: %u < %u\n", IrpSp->Parameters.QueryVolume.Length, BytesCopied);
1080 // BytesCopied = IrpSp->Parameters.QueryVolume.Length;
1081 // Status = STATUS_BUFFER_OVERFLOW;
1084 Irp
->IoStatus
.Status
= Status
;
1086 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
1087 Irp
->IoStatus
.Information
= 0;
1089 Irp
->IoStatus
.Information
= BytesCopied
;
1091 IoCompleteRequest( Irp
, IO_DISK_INCREMENT
);
1094 IoSetTopLevelIrp(NULL
);
1096 FsRtlExitFileSystem();
1098 TRACE("query volume information returning %08x\n", Status
);
1103 static NTSTATUS STDCALL
read_completion(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, PVOID conptr
) {
1104 read_context
* context
= conptr
;
1106 // DbgPrint("read_completion\n");
1108 context
->iosb
= Irp
->IoStatus
;
1109 KeSetEvent(&context
->Event
, 0, FALSE
);
1111 // return STATUS_SUCCESS;
1112 return STATUS_MORE_PROCESSING_REQUIRED
;
1115 // static void test_tree_deletion(device_extension* Vcb) {
1116 // KEY searchkey/*, endkey*/;
1117 // traverse_ptr tp, next_tp;
1120 // searchkey.obj_id = 0x100;
1121 // searchkey.obj_type = 0x54;
1122 // searchkey.offset = 0xca4ab2f5;
1124 // // endkey.obj_id = 0x100;
1125 // // endkey.obj_type = 0x60;
1126 // // endkey.offset = 0x15a;
1129 // while (r && r->id != 0x102)
1133 // ERR("error - could not find root\n");
1137 // if (!find_item(Vcb, r, &tp, &searchkey, NULL, FALSE)) {
1138 // ERR("error - could not find key\n");
1142 // while (TRUE/*keycmp(&tp.item->key, &endkey) < 1*/) {
1143 // tp.item->ignore = TRUE;
1144 // add_to_tree_cache(tc, tp.tree);
1146 // if (find_next_item(Vcb, &tp, &next_tp, NULL, FALSE)) {
1147 // free_traverse_ptr(&tp);
1153 // free_traverse_ptr(&tp);
1156 // static void test_tree_splitting(device_extension* Vcb) {
1159 // for (i = 0; i < 1000; i++) {
1160 // char* data = ExAllocatePoolWithTag(PagedPool, 4, ALLOC_TAG);
1162 // insert_tree_item(Vcb, Vcb->extent_root, 0, 0xfd, i, data, 4, NULL);
1166 // static void test_dropping_tree(device_extension* Vcb) {
1167 // LIST_ENTRY* le = Vcb->roots.Flink;
1169 // while (le != &Vcb->roots) {
1170 // root* r = CONTAINING_RECORD(le, root, list_entry);
1172 // if (r->id == 0x101) {
1173 // RemoveEntryList(&r->list_entry);
1174 // InsertTailList(&Vcb->drop_roots, &r->list_entry);
1182 NTSTATUS
create_root(device_extension
* Vcb
, UINT64 id
, root
** rootptr
, BOOL no_tree
, UINT64 offset
, LIST_ENTRY
* rollback
) {
1188 r
= ExAllocatePoolWithTag(PagedPool
, sizeof(root
), ALLOC_TAG
);
1190 ERR("out of memory\n");
1191 return STATUS_INSUFFICIENT_RESOURCES
;
1194 r
->nonpaged
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(root_nonpaged
), ALLOC_TAG
);
1196 ERR("out of memory\n");
1198 return STATUS_INSUFFICIENT_RESOURCES
;
1202 t
= ExAllocatePoolWithTag(PagedPool
, sizeof(tree
), ALLOC_TAG
);
1204 ERR("out of memory\n");
1205 ExFreePool(r
->nonpaged
);
1207 return STATUS_INSUFFICIENT_RESOURCES
;
1211 ri
= ExAllocatePoolWithTag(PagedPool
, sizeof(ROOT_ITEM
), ALLOC_TAG
);
1213 ERR("out of memory\n");
1218 ExFreePool(r
->nonpaged
);
1220 return STATUS_INSUFFICIENT_RESOURCES
;
1224 r
->treeholder
.address
= 0;
1225 r
->treeholder
.generation
= Vcb
->superblock
.generation
;
1226 r
->treeholder
.tree
= no_tree
? NULL
: t
;
1228 r
->path
.Buffer
= NULL
;
1229 RtlZeroMemory(&r
->root_item
, sizeof(ROOT_ITEM
));
1230 r
->root_item
.num_references
= 1;
1231 InitializeListHead(&r
->fcbs
);
1233 RtlCopyMemory(ri
, &r
->root_item
, sizeof(ROOT_ITEM
));
1235 // We ask here for a traverse_ptr to the item we're inserting, so we can
1236 // copy some of the tree's variables
1238 if (!insert_tree_item(Vcb
, Vcb
->root_root
, id
, TYPE_ROOT_ITEM
, offset
, ri
, sizeof(ROOT_ITEM
), &tp
, rollback
)) {
1239 ERR("insert_tree_item failed\n");
1245 ExFreePool(r
->nonpaged
);
1247 return STATUS_INTERNAL_ERROR
;
1250 ExInitializeResourceLite(&r
->nonpaged
->load_tree_lock
);
1252 InsertTailList(&Vcb
->roots
, &r
->list_entry
);
1255 t
->header
.fs_uuid
= tp
.tree
->header
.fs_uuid
;
1256 t
->header
.address
= 0;
1257 t
->header
.flags
= HEADER_FLAG_MIXED_BACKREF
| 1; // 1 == "written"? Why does the Linux driver record this?
1258 t
->header
.chunk_tree_uuid
= tp
.tree
->header
.chunk_tree_uuid
;
1259 t
->header
.generation
= Vcb
->superblock
.generation
;
1260 t
->header
.tree_id
= id
;
1261 t
->header
.num_items
= 0;
1262 t
->header
.level
= 0;
1264 t
->has_address
= FALSE
;
1271 InitializeListHead(&t
->itemlist
);
1274 t
->has_new_address
= FALSE
;
1275 t
->flags
= tp
.tree
->flags
;
1277 InsertTailList(&Vcb
->trees
, &t
->list_entry
);
1285 return STATUS_SUCCESS
;
1288 // static void test_creating_root(device_extension* Vcb) {
1290 // LIST_ENTRY rollback;
1294 // InitializeListHead(&rollback);
1296 // if (Vcb->root_root->lastinode == 0)
1297 // get_last_inode(Vcb, Vcb->root_root);
1299 // id = Vcb->root_root->lastinode > 0x100 ? (Vcb->root_root->lastinode + 1) : 0x101;
1300 // Status = create_root(Vcb, id, &r, &rollback);
1302 // if (!NT_SUCCESS(Status)) {
1303 // ERR("create_root returned %08x\n", Status);
1304 // do_rollback(Vcb, &rollback);
1306 // Vcb->root_root->lastinode = id;
1307 // clear_rollback(&rollback);
1311 static NTSTATUS STDCALL
set_label(device_extension
* Vcb
, FILE_FS_LABEL_INFORMATION
* ffli
) {
1315 TRACE("label = %.*S\n", ffli
->VolumeLabelLength
/ sizeof(WCHAR
), ffli
->VolumeLabel
);
1317 Status
= RtlUnicodeToUTF8N(NULL
, 0, &utf8len
, ffli
->VolumeLabel
, ffli
->VolumeLabelLength
);
1318 if (!NT_SUCCESS(Status
))
1321 if (utf8len
> MAX_LABEL_SIZE
) {
1322 Status
= STATUS_INVALID_VOLUME_LABEL
;
1326 // FIXME - check for '/' and '\\' and reject
1328 acquire_tree_lock(Vcb
, TRUE
);
1330 // utf8 = ExAllocatePoolWithTag(PagedPool, utf8len + 1, ALLOC_TAG);
1332 Status
= RtlUnicodeToUTF8N((PCHAR
)&Vcb
->superblock
.label
, MAX_LABEL_SIZE
* sizeof(WCHAR
), &utf8len
, ffli
->VolumeLabel
, ffli
->VolumeLabelLength
);
1333 if (!NT_SUCCESS(Status
))
1336 if (utf8len
< MAX_LABEL_SIZE
* sizeof(WCHAR
))
1337 RtlZeroMemory(Vcb
->superblock
.label
+ utf8len
, (MAX_LABEL_SIZE
* sizeof(WCHAR
)) - utf8len
);
1339 // test_tree_deletion(Vcb); // TESTING
1340 // test_tree_splitting(Vcb);
1341 // test_dropping_tree(Vcb);
1342 // test_creating_root(Vcb);
1344 Status
= consider_write(Vcb
);
1347 release_tree_lock(Vcb
, TRUE
);
1350 TRACE("returning %08x\n", Status
);
1355 static NTSTATUS STDCALL
drv_set_volume_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
1356 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1357 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
1361 TRACE("set volume information\n");
1363 FsRtlEnterFileSystem();
1365 top_level
= is_top_level(Irp
);
1367 Status
= STATUS_NOT_IMPLEMENTED
;
1369 if (Vcb
->readonly
) {
1370 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
1374 if (Vcb
->removing
) {
1375 Status
= STATUS_ACCESS_DENIED
;
1379 switch (IrpSp
->Parameters
.SetVolume
.FsInformationClass
) {
1380 case FileFsControlInformation
:
1381 FIXME("STUB: FileFsControlInformation\n");
1384 case FileFsLabelInformation
:
1385 TRACE("FileFsLabelInformation\n");
1387 Status
= set_label(Vcb
, Irp
->AssociatedIrp
.SystemBuffer
);
1390 case FileFsObjectIdInformation
:
1391 FIXME("STUB: FileFsObjectIdInformation\n");
1395 WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp
->Parameters
.SetVolume
.FsInformationClass
);
1400 Irp
->IoStatus
.Status
= Status
;
1401 Irp
->IoStatus
.Information
= 0;
1403 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
1406 IoSetTopLevelIrp(NULL
);
1408 FsRtlExitFileSystem();
1413 NTSTATUS
delete_dir_item(device_extension
* Vcb
, root
* subvol
, UINT64 parinode
, UINT32 crc32
, PANSI_STRING utf8
, LIST_ENTRY
* rollback
) {
1418 searchkey
.obj_id
= parinode
;
1419 searchkey
.obj_type
= TYPE_DIR_ITEM
;
1420 searchkey
.offset
= crc32
;
1422 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
1423 if (!NT_SUCCESS(Status
)) {
1424 ERR("error - find_item returned %08x\n", Status
);
1428 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
1429 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
1430 WARN("(%llx,%x,%llx) was %u bytes, expected %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
1435 di
= (DIR_ITEM
*)tp
.item
->data
;
1436 len
= tp
.item
->size
;
1439 if (di
->n
== utf8
->Length
&& RtlCompareMemory(di
->name
, utf8
->Buffer
, di
->n
) == di
->n
) {
1440 ULONG newlen
= tp
.item
->size
- (sizeof(DIR_ITEM
) - sizeof(char) + di
->n
+ di
->m
);
1442 delete_tree_item(Vcb
, &tp
, rollback
);
1445 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1447 UINT8
*newdi
= ExAllocatePoolWithTag(PagedPool
, newlen
, ALLOC_TAG
), *dioff
;
1450 ERR("out of memory\n");
1451 return STATUS_INSUFFICIENT_RESOURCES
;
1454 TRACE("modifying (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1456 if ((UINT8
*)di
> tp
.item
->data
) {
1457 RtlCopyMemory(newdi
, tp
.item
->data
, (UINT8
*)di
- tp
.item
->data
);
1458 dioff
= newdi
+ ((UINT8
*)di
- tp
.item
->data
);
1463 if ((UINT8
*)&di
->name
[di
->n
+ di
->m
] - tp
.item
->data
< tp
.item
->size
)
1464 RtlCopyMemory(dioff
, &di
->name
[di
->n
+ di
->m
], tp
.item
->size
- ((UINT8
*)&di
->name
[di
->n
+ di
->m
] - tp
.item
->data
));
1466 insert_tree_item(Vcb
, subvol
, parinode
, TYPE_DIR_ITEM
, crc32
, newdi
, newlen
, NULL
, rollback
);
1472 len
-= sizeof(DIR_ITEM
) - sizeof(char) + di
->n
+ di
->m
;
1473 di
= (DIR_ITEM
*)&di
->name
[di
->n
+ di
->m
];
1477 WARN("could not find DIR_ITEM for crc32 %08x\n", crc32
);
1480 return STATUS_SUCCESS
;
1483 NTSTATUS
delete_inode_ref(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, UINT64 parinode
, PANSI_STRING utf8
, UINT64
* index
, LIST_ENTRY
* rollback
) {
1486 BOOL changed
= FALSE
;
1489 searchkey
.obj_id
= inode
;
1490 searchkey
.obj_type
= TYPE_INODE_REF
;
1491 searchkey
.offset
= parinode
;
1493 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
1494 if (!NT_SUCCESS(Status
)) {
1495 ERR("error - find_item returned %08x\n", Status
);
1499 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
1500 if (tp
.item
->size
< sizeof(INODE_REF
)) {
1501 WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(INODE_REF
));
1506 ir
= (INODE_REF
*)tp
.item
->data
;
1507 len
= tp
.item
->size
;
1512 if (len
< sizeof(INODE_REF
) || len
< sizeof(INODE_REF
) - 1 + ir
->n
) {
1513 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1517 itemlen
= sizeof(INODE_REF
) - sizeof(char) + ir
->n
;
1519 if (ir
->n
== utf8
->Length
&& RtlCompareMemory(ir
->name
, utf8
->Buffer
, ir
->n
) == ir
->n
) {
1520 ULONG newlen
= tp
.item
->size
- itemlen
;
1522 delete_tree_item(Vcb
, &tp
, rollback
);
1526 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1528 UINT8
*newir
= ExAllocatePoolWithTag(PagedPool
, newlen
, ALLOC_TAG
), *iroff
;
1531 ERR("out of memory\n");
1532 return STATUS_INSUFFICIENT_RESOURCES
;
1535 TRACE("modifying (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1537 if ((UINT8
*)ir
> tp
.item
->data
) {
1538 RtlCopyMemory(newir
, tp
.item
->data
, (UINT8
*)ir
- tp
.item
->data
);
1539 iroff
= newir
+ ((UINT8
*)ir
- tp
.item
->data
);
1544 if ((UINT8
*)&ir
->name
[ir
->n
] - tp
.item
->data
< tp
.item
->size
)
1545 RtlCopyMemory(iroff
, &ir
->name
[ir
->n
], tp
.item
->size
- ((UINT8
*)&ir
->name
[ir
->n
] - tp
.item
->data
));
1547 insert_tree_item(Vcb
, subvol
, tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, newir
, newlen
, NULL
, rollback
);
1556 if (len
> itemlen
) {
1558 ir
= (INODE_REF
*)&ir
->name
[ir
->n
];
1564 WARN("found INODE_REF entry, but couldn't find filename\n");
1568 WARN("could not find INODE_REF entry for inode %llx in %llx\n", searchkey
.obj_id
, searchkey
.offset
);
1572 return STATUS_SUCCESS
;
1574 if (!(Vcb
->superblock
.incompat_flags
& BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF
))
1575 return STATUS_INTERNAL_ERROR
;
1577 searchkey
.obj_id
= inode
;
1578 searchkey
.obj_type
= TYPE_INODE_EXTREF
;
1579 searchkey
.offset
= calc_crc32c((UINT32
)parinode
, (UINT8
*)utf8
->Buffer
, utf8
->Length
);
1581 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
1582 if (!NT_SUCCESS(Status
)) {
1583 ERR("error - find_item returned %08x\n", Status
);
1587 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
1588 if (tp
.item
->size
< sizeof(INODE_EXTREF
)) {
1589 WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(INODE_EXTREF
));
1594 ier
= (INODE_EXTREF
*)tp
.item
->data
;
1595 len
= tp
.item
->size
;
1600 if (len
< sizeof(INODE_EXTREF
) || len
< sizeof(INODE_EXTREF
) - 1 + ier
->n
) {
1601 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1605 itemlen
= sizeof(INODE_EXTREF
) - sizeof(char) + ier
->n
;
1607 if (ier
->dir
== parinode
&& ier
->n
== utf8
->Length
&& RtlCompareMemory(ier
->name
, utf8
->Buffer
, ier
->n
) == ier
->n
) {
1608 ULONG newlen
= tp
.item
->size
- itemlen
;
1610 delete_tree_item(Vcb
, &tp
, rollback
);
1614 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1616 UINT8
*newier
= ExAllocatePoolWithTag(PagedPool
, newlen
, ALLOC_TAG
), *ieroff
;
1619 ERR("out of memory\n");
1620 return STATUS_INSUFFICIENT_RESOURCES
;
1623 TRACE("modifying (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1625 if ((UINT8
*)ier
> tp
.item
->data
) {
1626 RtlCopyMemory(newier
, tp
.item
->data
, (UINT8
*)ier
- tp
.item
->data
);
1627 ieroff
= newier
+ ((UINT8
*)ier
- tp
.item
->data
);
1632 if ((UINT8
*)&ier
->name
[ier
->n
] - tp
.item
->data
< tp
.item
->size
)
1633 RtlCopyMemory(ieroff
, &ier
->name
[ier
->n
], tp
.item
->size
- ((UINT8
*)&ier
->name
[ier
->n
] - tp
.item
->data
));
1635 insert_tree_item(Vcb
, subvol
, tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, newier
, newlen
, NULL
, rollback
);
1639 *index
= ier
->index
;
1644 if (len
> itemlen
) {
1646 ier
= (INODE_EXTREF
*)&ier
->name
[ier
->n
];
1652 WARN("couldn't find INODE_EXTREF entry either (offset = %08x)\n", (UINT32
)searchkey
.offset
);
1655 return changed
? STATUS_SUCCESS
: STATUS_INTERNAL_ERROR
;
1658 static NTSTATUS
delete_subvol(file_ref
* fileref
, LIST_ENTRY
* rollback
) {
1665 BOOL no_ref
= FALSE
;
1666 fcb
* fcb
= fileref
->fcb
;
1668 // delete ROOT_REF in root tree
1670 Status
= delete_root_ref(fcb
->Vcb
, fcb
->subvol
->id
, fileref
->parent
->fcb
->subvol
->id
, fileref
->parent
->fcb
->inode
, &fileref
->utf8
, &index
, rollback
);
1672 // A bug in Linux means that if you create a snapshot of a subvol containing another subvol,
1673 // the ROOT_REF and ROOT_BACKREF items won't be created, nor will num_references of ROOT_ITEM
1674 // be increased. In this case, we just unlink the subvol from its parent, and don't worry
1675 // about anything else.
1677 if (Status
== STATUS_NOT_FOUND
)
1679 else if (!NT_SUCCESS(Status
)) {
1680 ERR("delete_root_ref returned %08x\n", Status
);
1685 // delete ROOT_BACKREF in root tree
1687 Status
= update_root_backref(fcb
->Vcb
, fcb
->subvol
->id
, fileref
->parent
->fcb
->subvol
->id
, rollback
);
1688 if (!NT_SUCCESS(Status
)) {
1689 ERR("update_root_backref returned %08x\n", Status
);
1694 // delete DIR_ITEM in parent
1696 crc32
= calc_crc32c(0xfffffffe, (UINT8
*)fileref
->utf8
.Buffer
, fileref
->utf8
.Length
);
1697 Status
= delete_dir_item(fcb
->Vcb
, fileref
->parent
->fcb
->subvol
, fileref
->parent
->fcb
->inode
, crc32
, &fileref
->utf8
, rollback
);
1698 if (!NT_SUCCESS(Status
)) {
1699 ERR("delete_dir_item returned %08x\n", Status
);
1703 // delete DIR_INDEX in parent
1706 searchkey
.obj_id
= fileref
->parent
->fcb
->inode
;
1707 searchkey
.obj_type
= TYPE_DIR_INDEX
;
1708 searchkey
.offset
= index
;
1710 Status
= find_item(fcb
->Vcb
, fileref
->parent
->fcb
->subvol
, &tp
, &searchkey
, FALSE
);
1711 if (!NT_SUCCESS(Status
)) {
1712 ERR("find_item 1 returned %08x\n", Status
);
1716 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
1717 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
1718 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1722 traverse_ptr next_tp
;
1724 // If we have no ROOT_REF, we have to look through all the DIR_INDEX entries manually :-(
1726 searchkey
.obj_id
= fileref
->parent
->fcb
->inode
;
1727 searchkey
.obj_type
= TYPE_DIR_INDEX
;
1728 searchkey
.offset
= 0;
1730 Status
= find_item(fcb
->Vcb
, fileref
->parent
->fcb
->subvol
, &tp
, &searchkey
, FALSE
);
1731 if (!NT_SUCCESS(Status
)) {
1732 ERR("find_item 1 returned %08x\n", Status
);
1737 if (tp
.item
->key
.obj_type
== TYPE_DIR_INDEX
&& tp
.item
->size
>= sizeof(DIR_ITEM
)) {
1738 DIR_ITEM
* di
= (DIR_ITEM
*)tp
.item
->data
;
1740 if (di
->key
.obj_id
== fcb
->subvol
->id
&& di
->key
.obj_type
== TYPE_ROOT_ITEM
&& di
->n
== fileref
->utf8
.Length
&&
1741 tp
.item
->size
>= sizeof(DIR_ITEM
) - 1 + di
->m
+ di
->n
&& RtlCompareMemory(fileref
->utf8
.Buffer
, di
->name
, di
->n
) == di
->n
) {
1742 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
1747 b
= find_next_item(fcb
->Vcb
, &tp
, &next_tp
, FALSE
);
1752 if (tp
.item
->key
.obj_id
> searchkey
.obj_id
|| (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
> searchkey
.obj_type
))
1759 return STATUS_SUCCESS
;
1761 if (fcb
->subvol
->root_item
.num_references
> 1) {
1764 // change ROOT_ITEM num_references
1766 fcb
->subvol
->root_item
.num_references
--;
1768 searchkey
.obj_id
= fcb
->subvol
->id
;
1769 searchkey
.obj_type
= TYPE_ROOT_ITEM
;
1770 searchkey
.offset
= 0xffffffffffffffff;
1772 Status
= find_item(fcb
->Vcb
, fcb
->Vcb
->root_root
, &tp
, &searchkey
, FALSE
);
1773 if (!NT_SUCCESS(Status
)) {
1774 ERR("find_item 2 returned %08x\n", Status
);
1778 if (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
== searchkey
.obj_type
) {
1779 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
1780 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
1781 offset
= tp
.item
->key
.offset
;
1783 ERR("could not find ROOT_ITEM for subvol %llx\n", fcb
->subvol
->id
);
1787 ri
= ExAllocatePoolWithTag(PagedPool
, sizeof(ROOT_ITEM
), ALLOC_TAG
);
1789 ERR("out of memory\n");
1790 return STATUS_INSUFFICIENT_RESOURCES
;
1793 RtlCopyMemory(ri
, &fcb
->subvol
->root_item
, sizeof(ROOT_ITEM
));
1795 if (!insert_tree_item(fcb
->Vcb
, fcb
->Vcb
->root_root
, fcb
->subvol
->id
, TYPE_ROOT_ITEM
, offset
, ri
, sizeof(ROOT_ITEM
), NULL
, rollback
)) {
1796 ERR("insert_tree_item failed\n");
1797 return STATUS_INTERNAL_ERROR
;
1800 RemoveEntryList(&fcb
->subvol
->list_entry
);
1802 InsertTailList(&fcb
->Vcb
->drop_roots
, &fcb
->subvol
->list_entry
);
1805 return STATUS_SUCCESS
;
1808 static WCHAR
* file_desc_fcb(fcb
* fcb
) {
1813 if (fcb
->debug_desc
)
1814 return fcb
->debug_desc
;
1816 fcb
->debug_desc
= ExAllocatePoolWithTag(PagedPool
, 60 * sizeof(WCHAR
), ALLOC_TAG
);
1817 if (!fcb
->debug_desc
)
1818 return L
"(memory error)";
1820 // I know this is pretty hackish...
1821 // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
1822 // without the CRT, which breaks drivers.
1824 sprintf(s
, "subvol %x, inode %x", (UINT32
)fcb
->subvol
->id
, (UINT32
)fcb
->inode
);
1827 as
.Length
= as
.MaximumLength
= strlen(s
);
1829 us
.Buffer
= fcb
->debug_desc
;
1830 us
.MaximumLength
= 60 * sizeof(WCHAR
);
1833 RtlAnsiStringToUnicodeString(&us
, &as
, FALSE
);
1835 us
.Buffer
[us
.Length
/ sizeof(WCHAR
)] = 0;
1837 return fcb
->debug_desc
;
1840 WCHAR
* file_desc_fileref(file_ref
* fileref
) {
1841 if (fileref
->debug_desc
)
1842 return fileref
->debug_desc
;
1844 fileref
->debug_desc
= ExAllocatePoolWithTag(PagedPool
, fileref
->full_filename
.Length
+ sizeof(WCHAR
), ALLOC_TAG
);
1845 if (!fileref
->debug_desc
)
1846 return L
"(memory error)";
1848 RtlCopyMemory(fileref
->debug_desc
, fileref
->full_filename
.Buffer
, fileref
->full_filename
.Length
);
1849 fileref
->debug_desc
[fileref
->full_filename
.Length
/ sizeof(WCHAR
)] = 0;
1851 return fileref
->debug_desc
;
1854 WCHAR
* file_desc(PFILE_OBJECT FileObject
) {
1855 fcb
* fcb
= FileObject
->FsContext
;
1856 ccb
* ccb
= FileObject
->FsContext2
;
1857 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
1860 return file_desc_fileref(fileref
);
1862 return file_desc_fcb(fcb
);
1865 void send_notification_fileref(file_ref
* fileref
, ULONG filter_match
, ULONG action
) {
1866 fcb
* fcb
= fileref
->fcb
;
1868 FsRtlNotifyFullReportChange(fcb
->Vcb
->NotifySync
, &fcb
->Vcb
->DirNotifyList
, (PSTRING
)&fileref
->full_filename
, fileref
->name_offset
* sizeof(WCHAR
),
1869 NULL
, NULL
, filter_match
, action
, NULL
);
1872 NTSTATUS
delete_fileref(file_ref
* fileref
, PFILE_OBJECT FileObject
, LIST_ENTRY
* rollback
) {
1878 traverse_ptr tp
, tp2
;
1879 UINT64 parinode
, index
;
1881 INODE_ITEM
*ii
, *dirii
;
1884 LIST_ENTRY changed_sector_list
;
1885 fcb
* fcb
= fileref
->fcb
;
1887 LARGE_INTEGER freq
, time1
, time2
;
1890 if (fileref
->deleted
|| fcb
->deleted
) {
1891 WARN("trying to delete already-deleted file\n");
1892 return STATUS_SUCCESS
;
1895 if (fileref
== fcb
->Vcb
->root_fileref
) {
1896 ERR("error - trying to delete root FCB\n");
1897 return STATUS_INTERNAL_ERROR
;
1900 if (fcb
->inode
== SUBVOL_ROOT_INODE
) {
1901 Status
= delete_subvol(fileref
, rollback
);
1903 if (!NT_SUCCESS(Status
))
1906 parinode
= fileref
->parent
->fcb
->inode
;
1907 parsubvol
= fileref
->parent
->fcb
->subvol
;
1908 bytecount
= fileref
->utf8
.Length
;
1914 time1
= KeQueryPerformanceCounter(&freq
);
1917 KeQuerySystemTime(&time
);
1918 win_time_to_unix(time
, &now
);
1922 TRACE("deleting ADS\n");
1924 s
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsxattr
.Length
+ 1, ALLOC_TAG
);
1926 ERR("out of memory\n");
1927 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1931 RtlCopyMemory(s
, fcb
->adsxattr
.Buffer
, fcb
->adsxattr
.Length
);
1932 s
[fcb
->adsxattr
.Length
] = 0;
1934 if (!delete_xattr(fcb
->Vcb
, fileref
->parent
->fcb
->subvol
, fileref
->parent
->fcb
->inode
, s
, fcb
->adshash
, rollback
)) {
1935 ERR("failed to delete xattr %s\n", s
);
1940 fileref
->parent
->fcb
->inode_item
.transid
= fcb
->Vcb
->superblock
.generation
;
1941 fileref
->parent
->fcb
->inode_item
.sequence
++;
1942 fileref
->parent
->fcb
->inode_item
.st_ctime
= now
;
1944 searchkey
.obj_id
= fileref
->parent
->fcb
->inode
;
1945 searchkey
.obj_type
= TYPE_INODE_ITEM
;
1946 searchkey
.offset
= 0xffffffffffffffff;
1948 Status
= find_item(fcb
->Vcb
, fileref
->parent
->fcb
->subvol
, &tp
, &searchkey
, FALSE
);
1949 if (!NT_SUCCESS(Status
)) {
1950 ERR("error - find_item returned %08x\n", Status
);
1954 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) {
1955 ERR("error - could not find INODE_ITEM for inode %llx in subvol %llx\n", fileref
->parent
->fcb
->inode
, fileref
->parent
->fcb
->subvol
->id
);
1956 Status
= STATUS_INTERNAL_ERROR
;
1960 ii
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_ITEM
), ALLOC_TAG
);
1962 ERR("out of memory\n");
1963 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1967 RtlCopyMemory(ii
, &fileref
->parent
->fcb
->inode_item
, sizeof(INODE_ITEM
));
1968 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
1970 insert_tree_item(fcb
->Vcb
, fileref
->parent
->fcb
->subvol
, searchkey
.obj_id
, searchkey
.obj_type
, 0, ii
, sizeof(INODE_ITEM
), NULL
, rollback
);
1972 fileref
->parent
->fcb
->subvol
->root_item
.ctransid
= fcb
->Vcb
->superblock
.generation
;
1973 fileref
->parent
->fcb
->subvol
->root_item
.ctime
= now
;
1978 Status
= RtlUnicodeToUTF8N(NULL
, 0, &bytecount
, fileref
->filepart
.Buffer
, fileref
->filepart
.Length
);
1979 if (!NT_SUCCESS(Status
)) {
1980 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
1984 utf8
= ExAllocatePoolWithTag(PagedPool
, bytecount
+ 1, ALLOC_TAG
);
1986 ERR("out of memory\n");
1987 return STATUS_INSUFFICIENT_RESOURCES
;
1990 RtlUnicodeToUTF8N(utf8
, bytecount
, &bytecount
, fileref
->filepart
.Buffer
, fileref
->filepart
.Length
);
1991 utf8
[bytecount
] = 0;
1993 crc32
= calc_crc32c(0xfffffffe, (UINT8
*)utf8
, bytecount
);
1995 TRACE("deleting %.*S\n", file_desc_fileref(fileref
));
1997 if (fileref
->parent
->fcb
->subvol
== fcb
->subvol
)
1998 parinode
= fileref
->parent
->fcb
->inode
;
2000 parinode
= SUBVOL_ROOT_INODE
;
2002 parsubvol
= fcb
->subvol
;
2004 // delete DIR_ITEM (0x54)
2006 Status
= delete_dir_item(fcb
->Vcb
, fcb
->subvol
, parinode
, crc32
, &fileref
->utf8
, rollback
);
2007 if (!NT_SUCCESS(Status
)) {
2008 ERR("delete_dir_item returned %08x\n", Status
);
2012 // delete INODE_REF (0xc)
2016 Status
= delete_inode_ref(fcb
->Vcb
, fcb
->subvol
, fcb
->inode
, parinode
, &fileref
->utf8
, &index
, rollback
);
2018 // delete DIR_INDEX (0x60)
2020 searchkey
.obj_id
= parinode
;
2021 searchkey
.obj_type
= TYPE_DIR_INDEX
;
2022 searchkey
.offset
= index
;
2024 Status
= find_item(fcb
->Vcb
, fcb
->subvol
, &tp
, &searchkey
, FALSE
);
2025 if (!NT_SUCCESS(Status
)) {
2026 ERR("error - find_item returned %08x\n", Status
);
2027 Status
= STATUS_INTERNAL_ERROR
;
2031 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
2032 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
2033 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2036 // delete INODE_ITEM (0x1)
2038 searchkey
.obj_id
= fcb
->inode
;
2039 searchkey
.obj_type
= TYPE_INODE_ITEM
;
2040 searchkey
.offset
= 0;
2042 Status
= find_item(fcb
->Vcb
, fcb
->subvol
, &tp2
, &searchkey
, FALSE
);
2043 if (!NT_SUCCESS(Status
)) {
2044 ERR("error - find_item returned %08x\n", Status
);
2050 if (keycmp(&searchkey
, &tp
.item
->key
)) {
2051 ERR("error - INODE_ITEM not found\n");
2052 Status
= STATUS_INTERNAL_ERROR
;
2056 if (tp
.item
->size
< sizeof(INODE_ITEM
)) {
2057 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(INODE_ITEM
));
2058 Status
= STATUS_INTERNAL_ERROR
;
2062 ii
= (INODE_ITEM
*)tp
.item
->data
;
2063 TRACE("nlink = %u\n", ii
->st_nlink
);
2065 if (ii
->st_nlink
> 1) {
2068 newii
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_ITEM
), ALLOC_TAG
);
2070 ERR("out of memory\n");
2071 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2075 RtlCopyMemory(newii
, ii
, sizeof(INODE_ITEM
));
2077 newii
->transid
= fcb
->Vcb
->superblock
.generation
;
2079 newii
->st_ctime
= now
;
2081 TRACE("replacing (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2083 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
2085 if (!insert_tree_item(fcb
->Vcb
, fcb
->subvol
, tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, newii
, sizeof(INODE_ITEM
), NULL
, rollback
))
2086 ERR("error - failed to insert item\n");
2091 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
2092 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2094 fcb
->deleted
= TRUE
;
2096 // delete XATTR_ITEM (0x18)
2098 while (find_next_item(fcb
->Vcb
, &tp
, &tp2
, FALSE
)) {
2101 if (tp
.item
->key
.obj_id
== fcb
->inode
) {
2102 // FIXME - do metadata thing here too?
2103 if (tp
.item
->key
.obj_type
== TYPE_XATTR_ITEM
) {
2104 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
2105 TRACE("deleting (%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2113 InitializeListHead(&changed_sector_list
);
2115 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
&& fcb
->inode_item
.st_size
> 0) {
2116 Status
= excise_extents(fcb
->Vcb
, fcb
, 0, sector_align(fcb
->inode_item
.st_size
, fcb
->Vcb
->superblock
.sector_size
), &changed_sector_list
, rollback
);
2117 if (!NT_SUCCESS(Status
)) {
2118 ERR("excise_extents returned %08x\n", Status
);
2122 if (!(fcb
->inode_item
.flags
& BTRFS_INODE_NODATASUM
))
2123 update_checksum_tree(fcb
->Vcb
, &changed_sector_list
, rollback
);
2127 // update INODE_ITEM of parent
2129 searchkey
.obj_id
= parinode
;
2130 searchkey
.obj_type
= TYPE_INODE_ITEM
;
2131 searchkey
.offset
= 0;
2133 Status
= find_item(fcb
->Vcb
, parsubvol
, &tp
, &searchkey
, FALSE
);
2134 if (!NT_SUCCESS(Status
)) {
2135 ERR("error - find_tree returned %08x\n", Status
);
2139 if (keycmp(&searchkey
, &tp
.item
->key
)) {
2140 ERR("error - could not find INODE_ITEM for parent directory %llx in subvol %llx\n", parinode
, parsubvol
->id
);
2141 Status
= STATUS_INTERNAL_ERROR
;
2145 TRACE("fileref->parent->fcb->inode_item.st_size was %llx\n", fileref
->parent
->fcb
->inode_item
.st_size
);
2146 fileref
->parent
->fcb
->inode_item
.st_size
-= bytecount
* 2;
2147 TRACE("fileref->parent->fcb->inode_item.st_size now %llx\n", fileref
->parent
->fcb
->inode_item
.st_size
);
2148 fileref
->parent
->fcb
->inode_item
.transid
= fcb
->Vcb
->superblock
.generation
;
2149 fileref
->parent
->fcb
->inode_item
.sequence
++;
2150 fileref
->parent
->fcb
->inode_item
.st_ctime
= now
;
2151 fileref
->parent
->fcb
->inode_item
.st_mtime
= now
;
2153 dirii
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_ITEM
), ALLOC_TAG
);
2155 ERR("out of memory\n");
2156 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2160 RtlCopyMemory(dirii
, &fileref
->parent
->fcb
->inode_item
, sizeof(INODE_ITEM
));
2161 delete_tree_item(fcb
->Vcb
, &tp
, rollback
);
2163 insert_tree_item(fcb
->Vcb
, parsubvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, dirii
, sizeof(INODE_ITEM
), NULL
, rollback
);
2165 parsubvol
->root_item
.ctransid
= fcb
->Vcb
->superblock
.generation
;
2166 parsubvol
->root_item
.ctime
= now
;
2169 consider_write(fcb
->Vcb
);
2171 fileref
->deleted
= TRUE
;
2173 fcb
->Header
.AllocationSize
.QuadPart
= 0;
2174 fcb
->Header
.FileSize
.QuadPart
= 0;
2175 fcb
->Header
.ValidDataLength
.QuadPart
= 0;
2177 if (FileObject
&& FileObject
->PrivateCacheMap
) {
2180 ccfs
.AllocationSize
= fcb
->Header
.AllocationSize
;
2181 ccfs
.FileSize
= fcb
->Header
.FileSize
;
2182 ccfs
.ValidDataLength
= fcb
->Header
.ValidDataLength
;
2184 CcSetFileSizes(FileObject
, &ccfs
);
2187 // FIXME - set deleted flag of any open FCBs for ADS
2189 if (FileObject
&& FileObject
->FsContext2
) {
2190 ccb
* ccb
= FileObject
->FsContext2
;
2193 send_notification_fileref(ccb
->fileref
, fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_REMOVED
);
2197 time2
= KeQueryPerformanceCounter(NULL
);
2200 TRACE("time = %u (freq = %u)\n", (UINT32
)(time2
.QuadPart
- time1
.QuadPart
), (UINT32
)freq
.QuadPart
);
2202 Status
= STATUS_SUCCESS
;
2211 void _free_fcb(fcb
* fcb
, const char* func
, const char* file
, unsigned int line
) {
2214 rc
= InterlockedDecrement(&fcb
->refcount
);
2216 #ifdef DEBUG_FCB_REFCOUNTS
2217 // WARN("fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
2218 #ifdef DEBUG_LONG_MESSAGES
2219 _debug_message(func
, file
, line
, "fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb
, rc
, fcb
->subvol
? fcb
->subvol
->id
: 0, fcb
->inode
);
2221 _debug_message(func
, "fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb
, rc
, fcb
->subvol
? fcb
->subvol
->id
: 0, fcb
->inode
);
2228 ExAcquireResourceExclusiveLite(&fcb
->Vcb
->fcb_lock
, TRUE
);
2230 ExDeleteResourceLite(&fcb
->nonpaged
->resource
);
2231 ExDeleteResourceLite(&fcb
->nonpaged
->paging_resource
);
2232 ExFreePool(fcb
->nonpaged
);
2234 if (fcb
->list_entry
.Flink
)
2235 RemoveEntryList(&fcb
->list_entry
);
2238 ExFreePool(fcb
->sd
);
2240 if (fcb
->adsxattr
.Buffer
)
2241 ExFreePool(fcb
->adsxattr
.Buffer
);
2243 if (fcb
->debug_desc
)
2244 ExFreePool(fcb
->debug_desc
);
2246 FsRtlUninitializeFileLock(&fcb
->lock
);
2248 ExReleaseResourceLite(&fcb
->Vcb
->fcb_lock
);
2251 #ifdef DEBUG_FCB_REFCOUNTS
2252 #ifdef DEBUG_LONG_MESSAGES
2253 _debug_message(func
, file
, line
, "freeing fcb %p\n", fcb
);
2255 _debug_message(func
, "freeing fcb %p\n", fcb
);
2260 void _free_fileref(file_ref
* fr
, const char* func
, const char* file
, unsigned int line
) {
2263 rc
= InterlockedDecrement(&fr
->refcount
);
2265 #ifdef DEBUG_FCB_REFCOUNTS
2266 #ifdef DEBUG_LONG_MESSAGES
2267 _debug_message(func
, file
, line
, "fileref %p: refcount now %i\n", fr
, rc
);
2269 _debug_message(func
, "fileref %p: refcount now %i\n", fr
, rc
);
2275 ERR("fileref %p: refcount now %i\n", fr
, rc
);
2283 // FIXME - do we need a file_ref lock?
2285 // FIXME - do delete if needed
2287 if (fr
->filepart
.Buffer
)
2288 ExFreePool(fr
->filepart
.Buffer
);
2290 if (fr
->utf8
.Buffer
)
2291 ExFreePool(fr
->utf8
.Buffer
);
2293 if (fr
->full_filename
.Buffer
)
2294 ExFreePool(fr
->full_filename
.Buffer
);
2297 ExFreePool(fr
->debug_desc
);
2299 // FIXME - throw error if children not empty
2303 if (fr
->list_entry
.Flink
)
2304 RemoveEntryList(&fr
->list_entry
);
2307 free_fileref((file_ref
*)fr
->parent
);
2312 static NTSTATUS STDCALL
close_file(device_extension
* Vcb
, PFILE_OBJECT FileObject
) {
2315 file_ref
* fileref
= NULL
;
2317 TRACE("FileObject = %p\n", FileObject
);
2319 fcb
= FileObject
->FsContext
;
2321 TRACE("FCB was NULL, returning success\n");
2322 return STATUS_SUCCESS
;
2325 ccb
= FileObject
->FsContext2
;
2327 TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject
), fcb
);
2329 FsRtlNotifyCleanup(Vcb
->NotifySync
, &Vcb
->DirNotifyList
, ccb
);
2331 // FIXME - make sure notification gets sent if file is being deleted
2334 if (ccb
->query_string
.Buffer
)
2335 RtlFreeUnicodeString(&ccb
->query_string
);
2337 // FIXME - use refcounts for fileref
2338 fileref
= ccb
->fileref
;
2343 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
2345 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2348 free_fileref(fileref
);
2352 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2354 return STATUS_SUCCESS
;
2357 void STDCALL
uninit(device_extension
* Vcb
, BOOL flush
) {
2361 LIST_ENTRY rollback
;
2364 InitializeListHead(&rollback
);
2366 acquire_tree_lock(Vcb
, TRUE
);
2368 if (Vcb
->write_trees
> 0)
2369 do_write(Vcb
, &rollback
);
2373 clear_rollback(&rollback
);
2375 release_tree_lock(Vcb
, TRUE
);
2378 while (!IsListEmpty(&Vcb
->roots
)) {
2379 LIST_ENTRY
* le
= RemoveHeadList(&Vcb
->roots
);
2380 root
* r
= CONTAINING_RECORD(le
, root
, list_entry
);
2382 ExDeleteResourceLite(&r
->nonpaged
->load_tree_lock
);
2383 ExFreePool(r
->nonpaged
);
2387 while (!IsListEmpty(&Vcb
->chunks
)) {
2388 LIST_ENTRY
* le
= RemoveHeadList(&Vcb
->chunks
);
2389 c
= CONTAINING_RECORD(le
, chunk
, list_entry
);
2391 while (!IsListEmpty(&c
->space
)) {
2392 LIST_ENTRY
* le2
= RemoveHeadList(&c
->space
);
2393 s
= CONTAINING_RECORD(le2
, space
, list_entry
);
2399 ExFreePool(c
->devices
);
2401 ExFreePool(c
->chunk_item
);
2405 free_fcb(Vcb
->volume_fcb
);
2406 free_fileref(Vcb
->root_fileref
);
2408 for (i
= 0; i
< Vcb
->superblock
.num_devices
; i
++) {
2409 while (!IsListEmpty(&Vcb
->devices
[i
].disk_holes
)) {
2410 LIST_ENTRY
* le
= RemoveHeadList(&Vcb
->devices
[i
].disk_holes
);
2411 disk_hole
* dh
= CONTAINING_RECORD(le
, disk_hole
, listentry
);
2417 ExFreePool(Vcb
->devices
);
2419 ExDeleteResourceLite(&Vcb
->fcb_lock
);
2420 ExDeleteResourceLite(&Vcb
->load_lock
);
2421 ExDeleteResourceLite(&Vcb
->tree_lock
);
2423 ZwClose(Vcb
->flush_thread_handle
);
2426 static NTSTATUS STDCALL
drv_cleanup(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
2428 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2429 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
2435 FsRtlEnterFileSystem();
2437 top_level
= is_top_level(Irp
);
2439 if (DeviceObject
== devobj
) {
2440 TRACE("closing file system\n");
2441 Status
= STATUS_SUCCESS
;
2445 if (FileObject
&& FileObject
->FsContext
) {
2450 fcb
= FileObject
->FsContext
;
2451 ccb
= FileObject
->FsContext2
;
2452 fileref
= ccb
? ccb
->fileref
: NULL
;
2454 TRACE("cleanup called for FileObject %p\n", FileObject
);
2455 TRACE("fcb %p (%S), refcount = %u, open_count = %u\n", fcb
, file_desc(FileObject
), fcb
->refcount
, fcb
->open_count
);
2457 IoRemoveShareAccess(FileObject
, &fcb
->share_access
);
2459 oc
= InterlockedDecrement(&fcb
->open_count
);
2460 #ifdef DEBUG_FCB_REFCOUNTS
2461 ERR("fcb %p: open_count now %i\n", fcb
, oc
);
2464 if (ccb
&& ccb
->options
& FILE_DELETE_ON_CLOSE
&& fileref
)
2465 fileref
->delete_on_close
= TRUE
;
2467 if (fileref
&& fileref
->delete_on_close
&& fcb
->type
== BTRFS_TYPE_DIRECTORY
&& fcb
->inode_item
.st_size
> 0)
2468 fileref
->delete_on_close
= FALSE
;
2471 if (fileref
&& fileref
->delete_on_close
&& fileref
!= fcb
->Vcb
->root_fileref
&& fcb
!= fcb
->Vcb
->volume_fcb
) {
2472 LIST_ENTRY rollback
;
2473 InitializeListHead(&rollback
);
2475 acquire_tree_lock(fcb
->Vcb
, TRUE
);
2477 Status
= delete_fileref(fileref
, FileObject
, &rollback
);
2479 if (NT_SUCCESS(Status
)) {
2480 LARGE_INTEGER newlength
;
2482 if (FileObject
->Flags
& FO_CACHE_SUPPORTED
&& fcb
->nonpaged
->segment_object
.DataSectionObject
)
2483 CcPurgeCacheSection(&fcb
->nonpaged
->segment_object
, NULL
, 0, FALSE
);
2485 newlength
.QuadPart
= 0;
2487 if (!CcUninitializeCacheMap(FileObject
, &newlength
, NULL
)) {
2488 TRACE("CcUninitializeCacheMap failed\n");
2491 clear_rollback(&rollback
);
2493 do_rollback(fcb
->Vcb
, &rollback
);
2495 release_tree_lock(fcb
->Vcb
, TRUE
);
2496 } else if (FileObject
->Flags
& FO_CACHE_SUPPORTED
&& fcb
->nonpaged
->segment_object
.DataSectionObject
) {
2497 IO_STATUS_BLOCK iosb
;
2498 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, &iosb
);
2500 if (!NT_SUCCESS(iosb
.Status
)) {
2501 ERR("CcFlushCache returned %08x\n", iosb
.Status
);
2504 ExAcquireResourceExclusiveLite(fcb
->Header
.PagingIoResource
, TRUE
);
2505 ExReleaseResourceLite(fcb
->Header
.PagingIoResource
);
2507 CcPurgeCacheSection(&fcb
->nonpaged
->segment_object
, NULL
, 0, FALSE
);
2509 TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n",
2510 FileObject
, fcb
, fcb
->Header
.AllocationSize
.QuadPart
, fcb
->Header
.FileSize
.QuadPart
, fcb
->Header
.ValidDataLength
.QuadPart
);
2513 if (fcb
->Vcb
&& fcb
!= fcb
->Vcb
->volume_fcb
)
2514 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
2517 FileObject
->Flags
|= FO_CLEANUP_COMPLETE
;
2520 Status
= STATUS_SUCCESS
;
2523 Irp
->IoStatus
.Status
= Status
;
2524 Irp
->IoStatus
.Information
= 0;
2526 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2529 IoSetTopLevelIrp(NULL
);
2531 FsRtlExitFileSystem();
2536 ULONG STDCALL
get_file_attributes(device_extension
* Vcb
, INODE_ITEM
* ii
, root
* r
, UINT64 inode
, UINT8 type
, BOOL dotfile
, BOOL ignore_xa
) {
2543 if (!ignore_xa
&& get_xattr(Vcb
, r
, inode
, EA_DOSATTRIB
, EA_DOSATTRIB_HASH
, (UINT8
**)&eaval
, &ealen
)) {
2545 if (eaval
[0] == '0' && eaval
[1] == 'x') {
2549 for (i
= 2; i
< ealen
; i
++) {
2552 if (eaval
[i
] >= '0' && eaval
[i
] <= '9')
2553 dosnum
|= eaval
[i
] - '0';
2554 else if (eaval
[i
] >= 'a' && eaval
[i
] <= 'f')
2555 dosnum
|= eaval
[i
] + 10 - 'a';
2556 else if (eaval
[i
] >= 'A' && eaval
[i
] <= 'F')
2557 dosnum
|= eaval
[i
] + 10 - 'a';
2560 TRACE("DOSATTRIB: %08x\n", dosnum
);
2564 if (type
== BTRFS_TYPE_DIRECTORY
)
2565 dosnum
|= FILE_ATTRIBUTE_DIRECTORY
;
2566 else if (type
== BTRFS_TYPE_SYMLINK
)
2567 dosnum
|= FILE_ATTRIBUTE_REPARSE_POINT
;
2577 case BTRFS_TYPE_DIRECTORY
:
2578 att
= FILE_ATTRIBUTE_DIRECTORY
;
2581 case BTRFS_TYPE_SYMLINK
:
2582 att
= FILE_ATTRIBUTE_REPARSE_POINT
;
2591 att
|= FILE_ATTRIBUTE_HIDDEN
;
2594 att
|= FILE_ATTRIBUTE_ARCHIVE
;
2596 // FIXME - get READONLY from ii->st_mode
2597 // FIXME - return SYSTEM for block/char devices?
2600 att
= FILE_ATTRIBUTE_NORMAL
;
2605 // static int STDCALL utf8icmp(char* a, char* b) {
2606 // return strcmp(a, b); // FIXME - don't treat as ASCII
2609 NTSTATUS
sync_read_phys(PDEVICE_OBJECT DeviceObject
, LONGLONG StartingOffset
, ULONG Length
, PUCHAR Buffer
) {
2610 IO_STATUS_BLOCK
* IoStatus
;
2611 LARGE_INTEGER Offset
;
2613 PIO_STACK_LOCATION IrpSp
;
2615 read_context
* context
;
2619 context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(read_context
), ALLOC_TAG
);
2621 ERR("out of memory\n");
2622 return STATUS_INSUFFICIENT_RESOURCES
;
2625 RtlZeroMemory(context
, sizeof(read_context
));
2626 KeInitializeEvent(&context
->Event
, NotificationEvent
, FALSE
);
2628 IoStatus
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IO_STATUS_BLOCK
), ALLOC_TAG
);
2630 ERR("out of memory\n");
2631 ExFreePool(context
);
2632 return STATUS_INSUFFICIENT_RESOURCES
;
2635 Offset
.QuadPart
= StartingOffset
;
2637 // Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, Buffer, Length, &Offset, /*&Event*/NULL, IoStatus);
2638 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
2641 ERR("IoAllocateIrp failed\n");
2642 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2646 IrpSp
= IoGetNextIrpStackLocation(Irp
);
2647 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2649 if (DeviceObject
->Flags
& DO_BUFFERED_IO
) {
2650 FIXME("FIXME - buffered IO\n");
2651 } else if (DeviceObject
->Flags
& DO_DIRECT_IO
) {
2652 // TRACE("direct IO\n");
2654 Irp
->MdlAddress
= IoAllocateMdl(Buffer
, Length
, FALSE
, FALSE
, NULL
);
2655 if (!Irp
->MdlAddress
) {
2656 ERR("IoAllocateMdl failed\n");
2657 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2661 // TRACE("got MDL %p from buffer %p\n", Irp->MdlAddress, Buffer);
2664 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoWriteAccess
);
2666 // TRACE("neither buffered nor direct IO\n");
2667 Irp
->UserBuffer
= Buffer
;
2670 IrpSp
->Parameters
.Read
.Length
= Length
;
2671 IrpSp
->Parameters
.Read
.ByteOffset
= Offset
;
2673 Irp
->UserIosb
= IoStatus
;
2674 // Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2676 Irp
->UserEvent
= &context
->Event
;
2678 // IoQueueThreadIrp(Irp);
2680 IoSetCompletionRoutine(Irp
, read_completion
, context
, TRUE
, TRUE
, TRUE
);
2684 // Stack = IoGetNextIrpStackLocation(Irp);
2685 // Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2688 // TRACE("Calling IO Driver... with irp %p\n", Irp);
2689 Status
= IoCallDriver(DeviceObject
, Irp
);
2691 // TRACE("Waiting for IO Operation for %p\n", Irp);
2692 if (Status
== STATUS_PENDING
) {
2693 // TRACE("Operation pending\n");
2694 KeWaitForSingleObject(&context
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
2695 // TRACE("Getting IO Status... for %p\n", Irp);
2696 Status
= context
->iosb
.Status
;
2699 if (DeviceObject
->Flags
& DO_DIRECT_IO
) {
2700 MmUnlockPages(Irp
->MdlAddress
);
2701 IoFreeMdl(Irp
->MdlAddress
);
2707 ExFreePool(IoStatus
);
2708 ExFreePool(context
);
2713 static NTSTATUS STDCALL
read_superblock(device_extension
* Vcb
, PDEVICE_OBJECT device
) {
2716 unsigned int i
, to_read
;
2719 to_read
= sector_align(sizeof(superblock
), device
->SectorSize
);
2721 sb
= ExAllocatePoolWithTag(NonPagedPool
, to_read
, ALLOC_TAG
);
2723 ERR("out of memory\n");
2724 return STATUS_INSUFFICIENT_RESOURCES
;
2729 while (superblock_addrs
[i
] > 0) {
2730 if (i
> 0 && superblock_addrs
[i
] + sizeof(superblock
) > Vcb
->length
)
2733 Status
= sync_read_phys(device
, superblock_addrs
[i
], to_read
, (PUCHAR
)sb
);
2734 if (!NT_SUCCESS(Status
)) {
2735 ERR("Failed to read superblock %u: %08x\n", i
, Status
);
2740 TRACE("got superblock %u!\n", i
);
2742 if (i
== 0 || sb
->generation
> Vcb
->superblock
.generation
)
2743 RtlCopyMemory(&Vcb
->superblock
, sb
, sizeof(superblock
));
2750 crc32
= calc_crc32c(0xffffffff, (UINT8
*)&Vcb
->superblock
.uuid
, (ULONG
)sizeof(superblock
) - sizeof(Vcb
->superblock
.checksum
));
2752 TRACE("crc32 was %08x, expected %08x\n", crc32
, *((UINT32
*)Vcb
->superblock
.checksum
));
2754 if (crc32
!= *((UINT32
*)Vcb
->superblock
.checksum
))
2755 return STATUS_INTERNAL_ERROR
; // FIXME - correct error?
2757 TRACE("label is %s\n", Vcb
->superblock
.label
);
2758 // utf8_to_utf16(Vcb->superblock.label, Vcb->label, MAX_LABEL_SIZE * sizeof(WCHAR));
2760 return STATUS_SUCCESS
;
2763 NTSTATUS STDCALL
dev_ioctl(PDEVICE_OBJECT DeviceObject
, ULONG ControlCode
, PVOID InputBuffer
, ULONG InputBufferSize
,
2764 PVOID OutputBuffer
, ULONG OutputBufferSize
, BOOLEAN Override
, IO_STATUS_BLOCK
* iosb
)
2769 PIO_STACK_LOCATION Stack
;
2770 IO_STATUS_BLOCK IoStatus
;
2772 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2774 Irp
= IoBuildDeviceIoControlRequest(ControlCode
,
2784 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
2787 Stack
= IoGetNextIrpStackLocation(Irp
);
2788 Stack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2791 Status
= IoCallDriver(DeviceObject
, Irp
);
2793 if (Status
== STATUS_PENDING
) {
2794 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
2795 Status
= IoStatus
.Status
;
2804 // static void STDCALL find_chunk_root(device_extension* Vcb) {
2809 // while (i < Vcb->superblock.n) {
2810 // key = &Vcb->superblock.sys_chunk_array[i];
2811 // i += sizeof(KEY);
2817 // static void STDCALL insert_ltp(device_extension* Vcb, log_to_phys* ltp) {
2818 // if (!Vcb->log_to_phys) {
2819 // Vcb->log_to_phys = ltp;
2820 // ltp->next = NULL;
2824 // // FIXME - these should be ordered
2825 // ltp->next = Vcb->log_to_phys;
2826 // Vcb->log_to_phys = ltp;
2829 static NTSTATUS STDCALL
add_root(device_extension
* Vcb
, UINT64 id
, UINT64 addr
, traverse_ptr
* tp
) {
2830 root
* r
= ExAllocatePoolWithTag(PagedPool
, sizeof(root
), ALLOC_TAG
);
2832 ERR("out of memory\n");
2833 return STATUS_INSUFFICIENT_RESOURCES
;
2837 r
->path
.Buffer
= NULL
;
2838 r
->treeholder
.address
= addr
;
2839 r
->treeholder
.tree
= NULL
;
2840 init_tree_holder(&r
->treeholder
);
2841 InitializeListHead(&r
->fcbs
);
2843 r
->nonpaged
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(root_nonpaged
), ALLOC_TAG
);
2845 ERR("out of memory\n");
2847 return STATUS_INSUFFICIENT_RESOURCES
;
2850 ExInitializeResourceLite(&r
->nonpaged
->load_tree_lock
);
2855 RtlCopyMemory(&r
->root_item
, tp
->item
->data
, min(sizeof(ROOT_ITEM
), tp
->item
->size
));
2856 if (tp
->item
->size
< sizeof(ROOT_ITEM
))
2857 RtlZeroMemory(((UINT8
*)&r
->root_item
) + tp
->item
->size
, sizeof(ROOT_ITEM
) - tp
->item
->size
);
2860 InsertTailList(&Vcb
->roots
, &r
->list_entry
);
2863 case BTRFS_ROOT_ROOT
:
2867 case BTRFS_ROOT_EXTENT
:
2868 Vcb
->extent_root
= r
;
2871 case BTRFS_ROOT_CHUNK
:
2872 Vcb
->chunk_root
= r
;
2875 case BTRFS_ROOT_DEVTREE
:
2879 case BTRFS_ROOT_CHECKSUM
:
2880 Vcb
->checksum_root
= r
;
2883 case BTRFS_ROOT_UUID
:
2888 return STATUS_SUCCESS
;
2891 static NTSTATUS STDCALL
look_for_roots(device_extension
* Vcb
) {
2892 traverse_ptr tp
, next_tp
;
2897 searchkey
.obj_id
= 0;
2898 searchkey
.obj_type
= 0;
2899 searchkey
.offset
= 0;
2901 Status
= find_item(Vcb
, Vcb
->root_root
, &tp
, &searchkey
, FALSE
);
2902 if (!NT_SUCCESS(Status
)) {
2903 ERR("error - find_tree returned %08x\n", Status
);
2908 TRACE("(%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2910 if (tp
.item
->key
.obj_type
== TYPE_ROOT_ITEM
) {
2911 ROOT_ITEM
* ri
= (ROOT_ITEM
*)tp
.item
->data
;
2913 if (tp
.item
->size
< offsetof(ROOT_ITEM
, byte_limit
)) {
2914 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, offsetof(ROOT_ITEM
, byte_limit
));
2916 TRACE("root %llx - address %llx\n", tp
.item
->key
.obj_id
, ri
->block_number
);
2918 Status
= add_root(Vcb
, tp
.item
->key
.obj_id
, ri
->block_number
, &tp
);
2919 if (!NT_SUCCESS(Status
)) {
2920 ERR("add_root returned %08x\n", Status
);
2926 b
= find_next_item(Vcb
, &tp
, &next_tp
, FALSE
);
2932 return STATUS_SUCCESS
;
2935 static NTSTATUS
add_disk_hole(LIST_ENTRY
* disk_holes
, UINT64 address
, UINT64 size
) {
2936 disk_hole
* dh
= ExAllocatePoolWithTag(PagedPool
, sizeof(disk_hole
), ALLOC_TAG
);
2939 ERR("out of memory\n");
2940 return STATUS_INSUFFICIENT_RESOURCES
;
2943 dh
->address
= address
;
2945 dh
->provisional
= FALSE
;
2947 InsertTailList(disk_holes
, &dh
->listentry
);
2949 return STATUS_SUCCESS
;
2952 static NTSTATUS
find_disk_holes(device_extension
* Vcb
, device
* dev
) {
2954 traverse_ptr tp
, next_tp
;
2959 InitializeListHead(&dev
->disk_holes
);
2961 searchkey
.obj_id
= dev
->devitem
.dev_id
;
2962 searchkey
.obj_type
= TYPE_DEV_EXTENT
;
2963 searchkey
.offset
= 0;
2965 Status
= find_item(Vcb
, Vcb
->dev_root
, &tp
, &searchkey
, FALSE
);
2966 if (!NT_SUCCESS(Status
)) {
2967 ERR("error - find_tree returned %08x\n", Status
);
2974 if (tp
.item
->key
.obj_id
== dev
->devitem
.dev_id
&& tp
.item
->key
.obj_type
== TYPE_DEV_EXTENT
) {
2975 if (tp
.item
->size
>= sizeof(DEV_EXTENT
)) {
2976 DEV_EXTENT
* de
= (DEV_EXTENT
*)tp
.item
->data
;
2978 if (tp
.item
->key
.offset
> lastaddr
) {
2979 Status
= add_disk_hole(&dev
->disk_holes
, lastaddr
, tp
.item
->key
.offset
- lastaddr
);
2980 if (!NT_SUCCESS(Status
)) {
2981 ERR("add_disk_hole returned %08x\n", Status
);
2986 lastaddr
= tp
.item
->key
.offset
+ de
->length
;
2988 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DEV_EXTENT
));
2992 b
= find_next_item(Vcb
, &tp
, &next_tp
, FALSE
);
2996 if (tp
.item
->key
.obj_id
> searchkey
.obj_id
|| tp
.item
->key
.obj_type
> searchkey
.obj_type
)
3001 if (lastaddr
< dev
->devitem
.num_bytes
) {
3002 Status
= add_disk_hole(&dev
->disk_holes
, lastaddr
, dev
->devitem
.num_bytes
- lastaddr
);
3003 if (!NT_SUCCESS(Status
)) {
3004 ERR("add_disk_hole returned %08x\n", Status
);
3009 // FIXME - free disk_holes when unmounting
3011 return STATUS_SUCCESS
;
3014 device
* find_device_from_uuid(device_extension
* Vcb
, BTRFS_UUID
* uuid
) {
3017 for (i
= 0; i
< Vcb
->superblock
.num_devices
; i
++) {
3018 TRACE("device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", i
,
3019 Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[0], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[1], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[2], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[3], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[4], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[5], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[6], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[7],
3020 Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[8], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[9], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[10], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[11], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[12], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[13], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[14], Vcb
->devices
[i
].devitem
.device_uuid
.uuid
[15]);
3022 if (Vcb
->devices
[i
].devobj
&& RtlCompareMemory(&Vcb
->devices
[i
].devitem
.device_uuid
, uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
3023 TRACE("returning device %llx\n", i
);
3024 return &Vcb
->devices
[i
];
3028 WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
3029 uuid
->uuid
[0], uuid
->uuid
[1], uuid
->uuid
[2], uuid
->uuid
[3], uuid
->uuid
[4], uuid
->uuid
[5], uuid
->uuid
[6], uuid
->uuid
[7],
3030 uuid
->uuid
[8], uuid
->uuid
[9], uuid
->uuid
[10], uuid
->uuid
[11], uuid
->uuid
[12], uuid
->uuid
[13], uuid
->uuid
[14], uuid
->uuid
[15]);
3035 static NTSTATUS STDCALL
load_chunk_root(device_extension
* Vcb
) {
3036 traverse_ptr tp
, next_tp
;
3043 searchkey
.obj_id
= 0;
3044 searchkey
.obj_type
= 0;
3045 searchkey
.offset
= 0;
3047 Status
= find_item(Vcb
, Vcb
->chunk_root
, &tp
, &searchkey
, FALSE
);
3048 if (!NT_SUCCESS(Status
)) {
3049 ERR("error - find_item returned %08x\n", Status
);
3054 TRACE("(%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
3056 if (tp
.item
->key
.obj_id
== 1 && tp
.item
->key
.obj_type
== TYPE_DEV_ITEM
&& tp
.item
->key
.offset
== 1) {
3057 // FIXME - this is a hack; make this work with multiple devices!
3058 if (tp
.item
->size
> 0)
3059 RtlCopyMemory(&Vcb
->devices
[0].devitem
, tp
.item
->data
, min(tp
.item
->size
, sizeof(DEV_ITEM
)));
3060 } else if (tp
.item
->key
.obj_type
== TYPE_CHUNK_ITEM
) {
3061 if (tp
.item
->size
< sizeof(CHUNK_ITEM
)) {
3062 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(CHUNK_ITEM
));
3064 c
= ExAllocatePoolWithTag(PagedPool
, sizeof(chunk
), ALLOC_TAG
);
3067 ERR("out of memory\n");
3068 return STATUS_INSUFFICIENT_RESOURCES
;
3071 c
->size
= tp
.item
->size
;
3072 c
->offset
= tp
.item
->key
.offset
;
3073 c
->used
= c
->oldused
= 0;
3074 c
->space_changed
= FALSE
;
3078 c
->chunk_item
= ExAllocatePoolWithTag(PagedPool
, tp
.item
->size
, ALLOC_TAG
);
3080 if (!c
->chunk_item
) {
3081 ERR("out of memory\n");
3082 return STATUS_INSUFFICIENT_RESOURCES
;
3085 RtlCopyMemory(c
->chunk_item
, tp
.item
->data
, tp
.item
->size
);
3087 if (c
->chunk_item
->num_stripes
> 0) {
3088 CHUNK_ITEM_STRIPE
* cis
= (CHUNK_ITEM_STRIPE
*)&c
->chunk_item
[1];
3090 c
->devices
= ExAllocatePoolWithTag(PagedPool
, sizeof(device
*) * c
->chunk_item
->num_stripes
, ALLOC_TAG
);
3093 ERR("out of memory\n");
3094 return STATUS_INSUFFICIENT_RESOURCES
;
3097 for (i
= 0; i
< c
->chunk_item
->num_stripes
; i
++) {
3098 c
->devices
[i
] = find_device_from_uuid(Vcb
, &cis
[i
].dev_uuid
);
3099 TRACE("device %llu = %p\n", i
, c
->devices
[i
]);
3104 InitializeListHead(&c
->space
);
3106 InsertTailList(&Vcb
->chunks
, &c
->list_entry
);
3110 b
= find_next_item(Vcb
, &tp
, &next_tp
, FALSE
);
3116 Vcb
->log_to_phys_loaded
= TRUE
;
3118 return STATUS_SUCCESS
;
3121 void protect_superblocks(device_extension
* Vcb
, chunk
* c
) {
3123 UINT64 off_start
, off_end
;
3125 // FIXME - this will need modifying for RAID
3127 while (superblock_addrs
[i
] != 0) {
3128 CHUNK_ITEM
* ci
= c
->chunk_item
;
3129 CHUNK_ITEM_STRIPE
* cis
= (CHUNK_ITEM_STRIPE
*)&ci
[1];
3131 for (j
= 0; j
< ci
->num_stripes
; j
++) {
3132 if (cis
[j
].offset
+ ci
->size
> superblock_addrs
[i
] && cis
[j
].offset
<= superblock_addrs
[i
] + sizeof(superblock
)) {
3133 TRACE("cut out superblock in chunk %llx\n", c
->offset
);
3135 // The Linux driver protects the whole stripe in which the superblock lives
3137 off_start
= ((superblock_addrs
[i
] - cis
[j
].offset
) / c
->chunk_item
->stripe_length
) * c
->chunk_item
->stripe_length
;
3138 off_end
= sector_align(superblock_addrs
[i
] - cis
[j
].offset
+ sizeof(superblock
), c
->chunk_item
->stripe_length
);
3140 add_to_space_list(c
, c
->offset
+ off_start
, off_end
- off_start
, SPACE_TYPE_USED
);
3148 static NTSTATUS STDCALL
find_chunk_usage(device_extension
* Vcb
) {
3149 LIST_ENTRY
* le
= Vcb
->chunks
.Flink
;
3153 BLOCK_GROUP_ITEM
* bgi
;
3157 // block_group_item size=7f0000 chunktreeid=100 flags=1
3159 searchkey
.obj_type
= TYPE_BLOCK_GROUP_ITEM
;
3161 while (le
!= &Vcb
->chunks
) {
3162 c
= CONTAINING_RECORD(le
, chunk
, list_entry
);
3164 searchkey
.obj_id
= c
->offset
;
3165 searchkey
.offset
= c
->chunk_item
->size
;
3167 Status
= find_item(Vcb
, Vcb
->extent_root
, &tp
, &searchkey
, FALSE
);
3168 if (!NT_SUCCESS(Status
)) {
3169 ERR("error - find_item returned %08x\n", Status
);
3173 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
3174 if (tp
.item
->size
>= sizeof(BLOCK_GROUP_ITEM
)) {
3175 bgi
= (BLOCK_GROUP_ITEM
*)tp
.item
->data
;
3177 c
->used
= c
->oldused
= bgi
->used
;
3179 TRACE("chunk %llx has %llx bytes used\n", c
->offset
, c
->used
);
3181 ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n",
3182 Vcb
->extent_root
->id
, tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(BLOCK_GROUP_ITEM
));
3186 // if (addr >= c->offset && (addr - c->offset) < c->chunk_item->size && c->chunk_item->num_stripes > 0) {
3187 // cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
3189 // return (addr - c->offset) + cis->offset;
3192 // FIXME - make sure we free occasionally after doing one of these, or we
3193 // might use up a lot of memory with a big disk.
3195 Status
= load_free_space_cache(Vcb
, c
);
3196 if (!NT_SUCCESS(Status
)) {
3197 ERR("load_free_space_cache returned %08x\n", Status
);
3201 protect_superblocks(Vcb
, c
);
3206 return STATUS_SUCCESS
;
3209 // static void STDCALL root_test(device_extension* Vcb) {
3212 // traverse_ptr tp, next_tp;
3217 // if (r->id == 0x102)
3223 // ERR("Could not find root tree.\n");
3227 // searchkey.obj_id = 0x1b6;
3228 // searchkey.obj_type = 0xb;
3229 // searchkey.offset = 0;
3231 // if (!find_item(Vcb, r, &tp, &searchkey, NULL, FALSE)) {
3232 // ERR("Could not find first item.\n");
3238 // TRACE("%x,%x,%x\n", (UINT32)tp.item->key.obj_id, tp.item->key.obj_type, (UINT32)tp.item->key.offset);
3240 // b = find_prev_item(Vcb, &tp, &next_tp, NULL, FALSE);
3243 // free_traverse_ptr(&tp);
3248 // free_traverse_ptr(&tp);
3251 static NTSTATUS
load_sys_chunks(device_extension
* Vcb
) {
3253 ULONG n
= Vcb
->superblock
.n
;
3256 if (n
> sizeof(KEY
)) {
3257 RtlCopyMemory(&key
, &Vcb
->superblock
.sys_chunk_array
[Vcb
->superblock
.n
- n
], sizeof(KEY
));
3260 return STATUS_SUCCESS
;
3262 TRACE("bootstrap: %llx,%x,%llx\n", key
.obj_id
, key
.obj_type
, key
.offset
);
3264 if (key
.obj_type
== TYPE_CHUNK_ITEM
) {
3269 if (n
< sizeof(CHUNK_ITEM
))
3270 return STATUS_SUCCESS
;
3272 ci
= (CHUNK_ITEM
*)&Vcb
->superblock
.sys_chunk_array
[Vcb
->superblock
.n
- n
];
3273 cisize
= sizeof(CHUNK_ITEM
) + (ci
->num_stripes
* sizeof(CHUNK_ITEM_STRIPE
));
3276 return STATUS_SUCCESS
;
3278 sc
= ExAllocatePoolWithTag(PagedPool
, sizeof(sys_chunk
), ALLOC_TAG
);
3281 ERR("out of memory\n");
3282 return STATUS_INSUFFICIENT_RESOURCES
;
3287 sc
->data
= ExAllocatePoolWithTag(PagedPool
, sc
->size
, ALLOC_TAG
);
3290 ERR("out of memory\n");
3291 return STATUS_INSUFFICIENT_RESOURCES
;
3294 RtlCopyMemory(sc
->data
, ci
, sc
->size
);
3295 InsertTailList(&Vcb
->sys_chunks
, &sc
->list_entry
);
3299 ERR("unexpected item %llx,%x,%llx in bootstrap\n", key
.obj_id
, key
.obj_type
, key
.offset
);
3300 return STATUS_INTERNAL_ERROR
;
3304 return STATUS_SUCCESS
;
3307 static root
* find_default_subvol(device_extension
* Vcb
) {
3311 UNICODE_STRING filename
;
3314 static WCHAR fn
[] = L
"default";
3315 static UINT32 crc32
= 0x8dbfc2d2;
3317 if (Vcb
->superblock
.incompat_flags
& BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL
) {
3318 filename
.Buffer
= fn
;
3319 filename
.Length
= filename
.MaximumLength
= (USHORT
)wcslen(fn
) * sizeof(WCHAR
);
3321 if (!find_file_in_dir_with_crc32(Vcb
, &filename
, crc32
, Vcb
->root_root
, Vcb
->superblock
.root_dir_objectid
, &subvol
, &inode
, &type
, NULL
))
3322 WARN("couldn't find default subvol DIR_ITEM, using default tree\n");
3327 le
= Vcb
->roots
.Flink
;
3328 while (le
!= &Vcb
->roots
) {
3329 root
* r
= CONTAINING_RECORD(le
, root
, list_entry
);
3331 if (r
->id
== BTRFS_ROOT_FSTREE
)
3340 static BOOL
is_device_removable(PDEVICE_OBJECT devobj
) {
3342 STORAGE_HOTPLUG_INFO shi
;
3344 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_GET_HOTPLUG_INFO
, NULL
, 0, &shi
, sizeof(STORAGE_HOTPLUG_INFO
), TRUE
, NULL
);
3346 if (!NT_SUCCESS(Status
)) {
3347 ERR("dev_ioctl returned %08x\n", Status
);
3351 return shi
.MediaRemovable
!= 0 ? TRUE
: FALSE
;
3354 static ULONG
get_device_change_count(PDEVICE_OBJECT devobj
) {
3357 IO_STATUS_BLOCK iosb
;
3359 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_CHECK_VERIFY
, NULL
, 0, &cc
, sizeof(ULONG
), TRUE
, &iosb
);
3361 if (!NT_SUCCESS(Status
)) {
3362 ERR("dev_ioctl returned %08x\n", Status
);
3366 if (iosb
.Information
< sizeof(ULONG
)) {
3367 ERR("iosb.Information was too short\n");
3374 static NTSTATUS STDCALL
mount_vol(PDEVICE_OBJECT DeviceObject
, PIRP Irp
) {
3375 PIO_STACK_LOCATION Stack
;
3376 PDEVICE_OBJECT NewDeviceObject
= NULL
;
3377 PDEVICE_OBJECT DeviceToMount
;
3379 device_extension
* Vcb
= NULL
;
3380 PARTITION_INFORMATION_EX piex
;
3385 fcb
* root_fcb
= NULL
;
3387 TRACE("mount_vol called\n");
3389 if (DeviceObject
!= devobj
)
3391 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3395 Stack
= IoGetCurrentIrpStackLocation(Irp
);
3396 DeviceToMount
= Stack
->Parameters
.MountVolume
.DeviceObject
;
3398 // Status = NtfsHasFileSystem(DeviceToMount);
3399 // if (!NT_SUCCESS(Status))
3404 Status
= dev_ioctl(DeviceToMount
, IOCTL_DISK_GET_PARTITION_INFO_EX
, NULL
, 0,
3405 &piex
, sizeof(piex
), TRUE
, NULL
);
3406 if (!NT_SUCCESS(Status
)) {
3407 ERR("error reading partition information: %08x\n", Status
);
3408 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3412 Status
= IoCreateDevice(drvobj
,
3413 sizeof(device_extension
),
3415 FILE_DEVICE_DISK_FILE_SYSTEM
,
3419 if (!NT_SUCCESS(Status
)) {
3420 ERR("IoCreateDevice returned %08x\n", Status
);
3421 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3425 // TRACE("DEV_ITEM = %x, superblock = %x\n", sizeof(DEV_ITEM), sizeof(superblock));
3427 NewDeviceObject
->Flags
|= DO_DIRECT_IO
;
3428 Vcb
= (PVOID
)NewDeviceObject
->DeviceExtension
;
3429 RtlZeroMemory(Vcb
, sizeof(device_extension
));
3431 ExInitializeResourceLite(&Vcb
->tree_lock
);
3432 Vcb
->tree_lock_counter
= 0;
3433 Vcb
->open_trees
= 0;
3434 Vcb
->write_trees
= 0;
3436 ExInitializeResourceLite(&Vcb
->fcb_lock
);
3437 ExInitializeResourceLite(&Vcb
->DirResource
);
3439 ExAcquireResourceExclusiveLite(&global_loading_lock
, TRUE
);
3440 InsertTailList(&VcbList
, &Vcb
->list_entry
);
3441 ExReleaseResourceLite(&global_loading_lock
);
3443 ExInitializeResourceLite(&Vcb
->load_lock
);
3444 ExAcquireResourceExclusiveLite(&Vcb
->load_lock
, TRUE
);
3446 // Vcb->Identifier.Type = NTFS_TYPE_VCB;
3447 // Vcb->Identifier.Size = sizeof(NTFS_TYPE_VCB);
3449 // Status = NtfsGetVolumeData(DeviceToMount,
3451 // if (!NT_SUCCESS(Status))
3454 // Vcb->device = DeviceToMount;
3455 DeviceToMount
->Flags
|= DO_DIRECT_IO
;
3457 // Status = dev_ioctl(DeviceToMount, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
3458 // &Vcb->geometry, sizeof(DISK_GEOMETRY), TRUE);
3459 // if (!NT_SUCCESS(Status)) {
3460 // ERR("error reading disk geometry: %08x\n", Status);
3463 // TRACE("media type = %u, cylinders = %u, tracks per cylinder = %u, sectors per track = %u, bytes per sector = %u\n",
3464 // Vcb->geometry.MediaType, Vcb->geometry.Cylinders, Vcb->geometry.TracksPerCylinder,
3465 // Vcb->geometry.SectorsPerTrack, Vcb->geometry.BytesPerSector);
3468 Vcb
->length
= piex
.PartitionLength
.QuadPart
;
3469 TRACE("partition length = %u\n", piex
.PartitionLength
);
3471 Status
= read_superblock(Vcb
, DeviceToMount
);
3472 if (!NT_SUCCESS(Status
)) {
3473 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3477 if (Vcb
->superblock
.magic
!= BTRFS_MAGIC
) {
3478 ERR("not a BTRFS volume\n");
3479 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3482 TRACE("btrfs magic found\n");
3485 if (Vcb
->superblock
.incompat_flags
& ~INCOMPAT_SUPPORTED
) {
3486 WARN("cannot mount because of unsupported incompat flags (%llx)\n", Vcb
->superblock
.incompat_flags
& ~INCOMPAT_SUPPORTED
);
3487 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3492 while (le
!= &volumes
) {
3493 volume
* v
= CONTAINING_RECORD(le
, volume
, list_entry
);
3495 if (RtlCompareMemory(&Vcb
->superblock
.uuid
, &v
->fsuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
) && v
->devnum
< Vcb
->superblock
.dev_item
.dev_id
) {
3496 // skipping over device in RAID which isn't the first one
3497 // FIXME - hide this in My Computer
3498 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3505 // FIXME - remove this when we can
3506 if (Vcb
->superblock
.num_devices
> 1) {
3507 WARN("not mounting - multiple devices not yet implemented\n");
3508 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3512 Vcb
->readonly
= FALSE
;
3513 if (Vcb
->superblock
.compat_ro_flags
& ~COMPAT_RO_SUPPORTED
) {
3514 WARN("mounting read-only because of unsupported flags (%llx)\n", Vcb
->superblock
.compat_ro_flags
& ~COMPAT_RO_SUPPORTED
);
3515 Vcb
->readonly
= TRUE
;
3518 Vcb
->superblock
.generation
++;
3519 Vcb
->superblock
.incompat_flags
|= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF
;
3521 Vcb
->devices
= ExAllocatePoolWithTag(PagedPool
, sizeof(device
) * Vcb
->superblock
.num_devices
, ALLOC_TAG
);
3522 if (!Vcb
->devices
) {
3523 ERR("out of memory\n");
3524 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3528 Vcb
->devices
[0].devobj
= DeviceToMount
;
3529 RtlCopyMemory(&Vcb
->devices
[0].devitem
, &Vcb
->superblock
.dev_item
, sizeof(DEV_ITEM
));
3530 Vcb
->devices
[0].removable
= is_device_removable(Vcb
->devices
[0].devobj
);
3531 Vcb
->devices
[0].change_count
= Vcb
->devices
[0].removable
? get_device_change_count(Vcb
->devices
[0].devobj
) : 0;
3533 if (Vcb
->superblock
.num_devices
> 1)
3534 RtlZeroMemory(&Vcb
->devices
[1], sizeof(DEV_ITEM
) * (Vcb
->superblock
.num_devices
- 1));
3536 // FIXME - find other devices, if there are any
3538 TRACE("DeviceToMount = %p\n", DeviceToMount
);
3539 TRACE("Stack->Parameters.MountVolume.Vpb = %p\n", Stack
->Parameters
.MountVolume
.Vpb
);
3541 NewDeviceObject
->StackSize
= DeviceToMount
->StackSize
+ 1;
3542 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3544 // find_chunk_root(Vcb);
3545 // Vcb->chunk_root_phys_addr = Vcb->superblock.chunk_tree_addr; // FIXME - map from logical to physical (bootstrapped)
3547 // Vcb->root_tree_phys_addr = logical_to_physical(Vcb, Vcb->superblock.root_tree_addr);
3549 InitializeListHead(&Vcb
->roots
);
3550 InitializeListHead(&Vcb
->drop_roots
);
3552 Vcb
->log_to_phys_loaded
= FALSE
;
3554 Vcb
->max_inline
= Vcb
->superblock
.node_size
/ 2;
3556 // Vcb->write_trees = NULL;
3558 add_root(Vcb
, BTRFS_ROOT_CHUNK
, Vcb
->superblock
.chunk_tree_addr
, NULL
);
3560 if (!Vcb
->chunk_root
) {
3561 ERR("Could not load chunk root.\n");
3562 Status
= STATUS_INTERNAL_ERROR
;
3566 InitializeListHead(&Vcb
->sys_chunks
);
3567 Status
= load_sys_chunks(Vcb
);
3568 if (!NT_SUCCESS(Status
)) {
3569 ERR("load_sys_chunks returned %08x\n", Status
);
3573 InitializeListHead(&Vcb
->chunks
);
3574 InitializeListHead(&Vcb
->trees
);
3576 InitializeListHead(&Vcb
->DirNotifyList
);
3578 FsRtlNotifyInitializeSync(&Vcb
->NotifySync
);
3580 Status
= load_chunk_root(Vcb
);
3581 if (!NT_SUCCESS(Status
)) {
3582 ERR("load_chunk_root returned %08x\n", Status
);
3586 add_root(Vcb
, BTRFS_ROOT_ROOT
, Vcb
->superblock
.root_tree_addr
, NULL
);
3588 if (!Vcb
->root_root
) {
3589 ERR("Could not load root of roots.\n");
3590 Status
= STATUS_INTERNAL_ERROR
;
3594 Status
= look_for_roots(Vcb
);
3595 if (!NT_SUCCESS(Status
)) {
3596 ERR("look_for_roots returned %08x\n", Status
);
3600 Status
= find_chunk_usage(Vcb
);
3601 if (!NT_SUCCESS(Status
)) {
3602 ERR("find_chunk_usage returned %08x\n", Status
);
3606 // We've already increased the generation by one
3607 if (!Vcb
->readonly
&& Vcb
->superblock
.generation
- 1 != Vcb
->superblock
.cache_generation
) {
3608 WARN("generation was %llx, free-space cache generation was %llx; clearing cache...\n", Vcb
->superblock
.generation
- 1, Vcb
->superblock
.cache_generation
);
3609 Status
= clear_free_space_cache(Vcb
);
3610 if (!NT_SUCCESS(Status
)) {
3611 ERR("clear_free_space_cache returned %08x\n", Status
);
3616 Vcb
->volume_fcb
= create_fcb();
3617 if (!Vcb
->volume_fcb
) {
3618 ERR("out of memory\n");
3619 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3623 Vcb
->volume_fcb
->Vcb
= Vcb
;
3624 Vcb
->volume_fcb
->sd
= NULL
;
3626 root_fcb
= create_fcb();
3628 ERR("out of memory\n");
3629 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3633 root_fcb
->Vcb
= Vcb
;
3634 root_fcb
->inode
= SUBVOL_ROOT_INODE
;
3635 root_fcb
->type
= BTRFS_TYPE_DIRECTORY
;
3637 #ifdef DEBUG_FCB_REFCOUNTS
3638 WARN("volume FCB = %p\n", Vcb
->volume_fcb
);
3639 WARN("root FCB = %p\n", root_fcb
);
3642 root_fcb
->subvol
= find_default_subvol(Vcb
);
3644 if (!root_fcb
->subvol
) {
3645 ERR("could not find top subvol\n");
3646 Status
= STATUS_INTERNAL_ERROR
;
3650 searchkey
.obj_id
= root_fcb
->inode
;
3651 searchkey
.obj_type
= TYPE_INODE_ITEM
;
3652 searchkey
.offset
= 0xffffffffffffffff;
3654 Status
= find_item(Vcb
, root_fcb
->subvol
, &tp
, &searchkey
, FALSE
);
3655 if (!NT_SUCCESS(Status
)) {
3656 ERR("error - find_item returned %08x\n", Status
);
3660 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) {
3661 ERR("couldn't find INODE_ITEM for root directory\n");
3662 Status
= STATUS_INTERNAL_ERROR
;
3666 if (tp
.item
->size
> 0)
3667 RtlCopyMemory(&root_fcb
->inode_item
, tp
.item
->data
, min(sizeof(INODE_ITEM
), tp
.item
->size
));
3669 fcb_get_sd(root_fcb
, NULL
);
3671 root_fcb
->atts
= get_file_attributes(Vcb
, &root_fcb
->inode_item
, root_fcb
->subvol
, root_fcb
->inode
, root_fcb
->type
, FALSE
, FALSE
);
3673 Vcb
->root_fileref
= create_fileref();
3674 if (!Vcb
->root_fileref
) {
3675 ERR("out of memory\n");
3676 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3680 Vcb
->root_fileref
->fcb
= root_fcb
;
3681 InsertTailList(&root_fcb
->subvol
->fcbs
, &root_fcb
->list_entry
);
3683 Vcb
->root_fileref
->full_filename
.Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(WCHAR
), ALLOC_TAG
);
3685 if (!Vcb
->root_fileref
->full_filename
.Buffer
) {
3686 ERR("out of memory\n");
3687 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3691 Vcb
->root_fileref
->full_filename
.Buffer
[0] = '\\';
3692 Vcb
->root_fileref
->full_filename
.Length
= Vcb
->root_fileref
->full_filename
.MaximumLength
= sizeof(WCHAR
);
3694 for (i
= 0; i
< Vcb
->superblock
.num_devices
; i
++) {
3695 Status
= find_disk_holes(Vcb
, &Vcb
->devices
[i
]);
3696 if (!NT_SUCCESS(Status
)) {
3697 ERR("find_disk_holes returned %08x\n", Status
);
3704 // Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
3705 // Vcb->StorageDevice);
3707 // InitializeListHead(&Vcb->FcbListHead);
3709 // Fcb = NtfsCreateFCB(NULL, Vcb);
3712 // Status = STATUS_INSUFFICIENT_RESOURCES;
3716 // Ccb = ExAllocatePoolWithTag(NonPagedPool,
3717 // sizeof(NTFS_CCB),
3721 // Status = STATUS_INSUFFICIENT_RESOURCES;
3725 // RtlZeroMemory(Ccb, sizeof(NTFS_CCB));
3727 // Ccb->Identifier.Type = NTFS_TYPE_CCB;
3728 // Ccb->Identifier.Size = sizeof(NTFS_TYPE_CCB);
3730 // Vcb->StreamFileObject->FsContext = Fcb;
3731 // Vcb->StreamFileObject->FsContext2 = Ccb;
3732 // Vcb->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
3733 // Vcb->StreamFileObject->PrivateCacheMap = NULL;
3734 // Vcb->StreamFileObject->Vpb = Vcb->Vpb;
3735 // Ccb->PtrFileObject = Vcb->StreamFileObject;
3736 // Fcb->FileObject = Vcb->StreamFileObject;
3737 // Fcb->Vcb = (PDEVICE_EXTENSION)Vcb->StorageDevice;
3739 // Fcb->Flags = FCB_IS_VOLUME_STREAM;
3741 // Fcb->RFCB.FileSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
3742 // Fcb->RFCB.ValidDataLength.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
3743 // Fcb->RFCB.AllocationSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; /* Correct? */
3745 // CcInitializeCacheMap(Vcb->StreamFileObject,
3746 // (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
3748 // &(NtfsGlobalData->CacheMgrCallbacks),
3751 // ExInitializeResourceLite(&Vcb->LogToPhysLock);
3753 KeInitializeSpinLock(&Vcb
->FcbListLock
);
3755 // /* Get serial number */
3756 // NewDeviceObject->Vpb->SerialNumber = Vcb->NtfsInfo.SerialNumber;
3758 // /* Get volume label */
3759 // NewDeviceObject->Vpb->VolumeLabelLength = Vcb->NtfsInfo.VolumeLabelLength;
3760 // RtlCopyMemory(NewDeviceObject->Vpb->VolumeLabel,
3761 // Vcb->NtfsInfo.VolumeLabel,
3762 // Vcb->NtfsInfo.VolumeLabelLength);
3764 NewDeviceObject
->Vpb
= Stack
->Parameters
.MountVolume
.Vpb
;
3765 Stack
->Parameters
.MountVolume
.Vpb
->DeviceObject
= NewDeviceObject
;
3766 Stack
->Parameters
.MountVolume
.Vpb
->RealDevice
= DeviceToMount
;
3767 Stack
->Parameters
.MountVolume
.Vpb
->Flags
|= VPB_MOUNTED
;
3768 NewDeviceObject
->Vpb
->VolumeLabelLength
= 4; // FIXME
3769 NewDeviceObject
->Vpb
->VolumeLabel
[0] = '?';
3770 NewDeviceObject
->Vpb
->VolumeLabel
[1] = 0;
3771 NewDeviceObject
->Vpb
->ReferenceCount
++; // FIXME - should we deref this at any point?
3773 Status
= PsCreateSystemThread(&Vcb
->flush_thread_handle
, 0, NULL
, NULL
, NULL
, flush_thread
, NewDeviceObject
);
3774 if (!NT_SUCCESS(Status
)) {
3775 ERR("PsCreateSystemThread returned %08x\n", Status
);
3779 Status
= STATUS_SUCCESS
;
3782 // if (!NT_SUCCESS(Status))
3785 // if (Vcb && Vcb->StreamFileObject)
3786 // ObDereferenceObject(Vcb->StreamFileObject);
3794 // if (NewDeviceObject)
3795 // IoDeleteDevice(NewDeviceObject);
3799 ExReleaseResourceLite(&Vcb
->load_lock
);
3802 if (!NT_SUCCESS(Status
)) {
3804 if (Vcb
->root_fileref
)
3805 free_fileref(Vcb
->root_fileref
);
3809 if (Vcb
->volume_fcb
)
3810 free_fcb(Vcb
->volume_fcb
);
3812 ExDeleteResourceLite(&Vcb
->tree_lock
);
3813 ExDeleteResourceLite(&Vcb
->load_lock
);
3814 ExDeleteResourceLite(&Vcb
->fcb_lock
);
3815 ExDeleteResourceLite(&Vcb
->DirResource
);
3818 ExFreePoolWithTag(Vcb
->devices
, ALLOC_TAG
);
3820 RemoveEntryList(&Vcb
->list_entry
);
3823 if (NewDeviceObject
)
3824 IoDeleteDevice(NewDeviceObject
);
3827 TRACE("mount_vol done (status: %lx)\n", Status
);
3832 static NTSTATUS STDCALL
drv_file_system_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3833 PIO_STACK_LOCATION IrpSp
;
3837 TRACE("file system control\n");
3839 FsRtlEnterFileSystem();
3841 top_level
= is_top_level(Irp
);
3843 status
= STATUS_NOT_IMPLEMENTED
;
3845 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3847 Irp
->IoStatus
.Information
= 0;
3849 switch (IrpSp
->MinorFunction
) {
3850 case IRP_MN_MOUNT_VOLUME
:
3851 TRACE("IRP_MN_MOUNT_VOLUME\n");
3853 // Irp->IoStatus.Status = STATUS_SUCCESS;
3854 status
= mount_vol(DeviceObject
, Irp
);
3855 // IrpSp->Parameters.MountVolume.DeviceObject = 0x0badc0de;
3856 // IrpSp->Parameters.MountVolume.Vpb = 0xdeadbeef;
3858 // IoCompleteRequest( Irp, IO_DISK_INCREMENT );
3860 // return Irp->IoStatus.Status;
3863 case IRP_MN_KERNEL_CALL
:
3864 TRACE("IRP_MN_KERNEL_CALL\n");
3866 status
= fsctl_request(DeviceObject
, Irp
, IrpSp
->Parameters
.FileSystemControl
.FsControlCode
, FALSE
);
3869 case IRP_MN_USER_FS_REQUEST
:
3870 TRACE("IRP_MN_USER_FS_REQUEST\n");
3872 status
= fsctl_request(DeviceObject
, Irp
, IrpSp
->Parameters
.FileSystemControl
.FsControlCode
, TRUE
);
3875 case IRP_MN_VERIFY_VOLUME
:
3876 FIXME("STUB: IRP_MN_VERIFY_VOLUME\n");
3883 Irp
->IoStatus
.Status
= status
;
3885 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3888 IoSetTopLevelIrp(NULL
);
3890 FsRtlExitFileSystem();
3895 static NTSTATUS STDCALL
drv_lock_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3897 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3898 fcb
* fcb
= IrpSp
->FileObject
->FsContext
;
3901 FsRtlEnterFileSystem();
3903 top_level
= is_top_level(Irp
);
3905 TRACE("lock control\n");
3907 Status
= FsRtlProcessFileLock(&fcb
->lock
, Irp
, NULL
);
3909 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
3912 IoSetTopLevelIrp(NULL
);
3914 FsRtlExitFileSystem();
3919 static NTSTATUS STDCALL
drv_device_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3921 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3922 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
3923 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
3927 FIXME("STUB: device control\n");
3929 FsRtlEnterFileSystem();
3931 top_level
= is_top_level(Irp
);
3933 Irp
->IoStatus
.Information
= 0;
3935 WARN("control code = %x\n", IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
);
3938 ERR("FileObject was NULL\n");
3939 Status
= STATUS_INVALID_PARAMETER
;
3944 fcb
= FileObject
->FsContext
;
3947 ERR("FCB was NULL\n");
3948 Status
= STATUS_INVALID_PARAMETER
;
3952 if (fcb
== Vcb
->volume_fcb
) {
3953 FIXME("FIXME - pass through\n");
3954 Status
= STATUS_NOT_IMPLEMENTED
;
3956 TRACE("filename = %S\n", file_desc(FileObject
));
3958 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
) {
3959 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
3960 TRACE("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
3961 Status
= STATUS_INVALID_PARAMETER
;
3965 WARN("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",
3966 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
, (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0xff0000) >> 16,
3967 (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0xc000) >> 14, (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0x3ffc) >> 2,
3968 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0x3);
3969 Status
= STATUS_INVALID_PARAMETER
;
3975 Irp
->IoStatus
.Status
= Status
;
3977 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
3980 IoSetTopLevelIrp(NULL
);
3982 FsRtlExitFileSystem();
3987 static NTSTATUS STDCALL
drv_shutdown(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3993 FsRtlEnterFileSystem();
3995 top_level
= is_top_level(Irp
);
3997 Status
= STATUS_SUCCESS
;
3999 while (!IsListEmpty(&VcbList
)) {
4000 LIST_ENTRY
* le
= RemoveHeadList(&VcbList
);
4001 device_extension
* Vcb
= CONTAINING_RECORD(le
, device_extension
, list_entry
);
4003 TRACE("shutting down Vcb %p\n", Vcb
);
4008 Irp
->IoStatus
.Status
= Status
;
4009 Irp
->IoStatus
.Information
= 0;
4011 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
4014 IoSetTopLevelIrp(NULL
);
4016 FsRtlExitFileSystem();
4021 BOOL
is_file_name_valid(PUNICODE_STRING us
) {
4024 if (us
->Length
< sizeof(WCHAR
))
4027 if (us
->Length
> 255 * sizeof(WCHAR
))
4030 for (i
= 0; i
< us
->Length
/ sizeof(WCHAR
); i
++) {
4031 if (us
->Buffer
[i
] == '/' || us
->Buffer
[i
] == '<' || us
->Buffer
[i
] == '>' || us
->Buffer
[i
] == ':' || us
->Buffer
[i
] == '"' ||
4032 us
->Buffer
[i
] == '|' || us
->Buffer
[i
] == '?' || us
->Buffer
[i
] == '*' || (us
->Buffer
[i
] >= 1 && us
->Buffer
[i
] <= 31))
4036 if (us
->Buffer
[0] == '.' && (us
->Length
== sizeof(WCHAR
) || (us
->Length
== 2 * sizeof(WCHAR
) && us
->Buffer
[1] == '.')))
4043 static void STDCALL
init_serial() {
4046 Status
= IoGetDeviceObjectPointer(&log_device
, FILE_WRITE_DATA
, &comfo
, &comdo
);
4047 if (!NT_SUCCESS(Status
)) {
4048 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
4054 static void STDCALL
check_cpu() {
4055 unsigned int cpuInfo
[4];
4057 __get_cpuid(1, &cpuInfo
[0], &cpuInfo
[1], &cpuInfo
[2], &cpuInfo
[3]);
4058 have_sse42
= cpuInfo
[2] & bit_SSE4_2
;
4060 __cpuid(cpuInfo
, 1);
4061 have_sse42
= cpuInfo
[2] & (1 << 20);
4065 TRACE("SSE4.2 is supported\n");
4067 TRACE("SSE4.2 not supported\n");
4071 static void STDCALL
read_registry(PUNICODE_STRING regpath
) {
4074 OBJECT_ATTRIBUTES oa
;
4078 ULONG kvfilen
, retlen
, i
;
4079 KEY_VALUE_FULL_INFORMATION
* kvfi
;
4081 const WCHAR mappings
[] = L
"\\Mappings";
4083 static WCHAR def_log_file
[] = L
"\\??\\C:\\btrfs.log";
4086 path
= ExAllocatePoolWithTag(PagedPool
, regpath
->Length
+ (wcslen(mappings
) * sizeof(WCHAR
)), ALLOC_TAG
);
4088 ERR("out of memory\n");
4092 RtlCopyMemory(path
, regpath
->Buffer
, regpath
->Length
);
4093 RtlCopyMemory((UINT8
*)path
+ regpath
->Length
, mappings
, wcslen(mappings
) * sizeof(WCHAR
));
4096 us
.Length
= us
.MaximumLength
= regpath
->Length
+ ((USHORT
)wcslen(mappings
) * sizeof(WCHAR
));
4098 InitializeObjectAttributes(&oa
, &us
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
4100 // FIXME - keep open and do notify for changes
4101 Status
= ZwCreateKey(&h
, KEY_QUERY_VALUE
, &oa
, 0, NULL
, REG_OPTION_NON_VOLATILE
, &dispos
);
4103 if (!NT_SUCCESS(Status
)) {
4104 ERR("ZwCreateKey returned %08x\n", Status
);
4109 if (dispos
== REG_OPENED_EXISTING_KEY
) {
4110 kvfilen
= sizeof(KEY_VALUE_FULL_INFORMATION
) + 256;
4111 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4114 ERR("out of memory\n");
4122 Status
= ZwEnumerateValueKey(h
, i
, KeyValueFullInformation
, kvfi
, kvfilen
, &retlen
);
4124 if (NT_SUCCESS(Status
) && kvfi
->DataLength
> 0) {
4127 RtlCopyMemory(&val
, (UINT8
*)kvfi
+ kvfi
->DataOffset
, min(kvfi
->DataLength
, sizeof(UINT32
)));
4129 TRACE("entry %u = %.*S = %u\n", i
, kvfi
->NameLength
/ sizeof(WCHAR
), kvfi
->Name
, val
);
4131 add_user_mapping(kvfi
->Name
, kvfi
->NameLength
/ sizeof(WCHAR
), val
);
4135 } while (Status
!= STATUS_NO_MORE_ENTRIES
);
4143 InitializeObjectAttributes(&oa
, regpath
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
4145 Status
= ZwCreateKey(&h
, KEY_QUERY_VALUE
, &oa
, 0, NULL
, REG_OPTION_NON_VOLATILE
, &dispos
);
4147 if (!NT_SUCCESS(Status
)) {
4148 ERR("ZwCreateKey returned %08x\n", Status
);
4152 RtlInitUnicodeString(&us
, L
"DebugLogLevel");
4156 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4158 if ((Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) && kvfilen
> 0) {
4159 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4162 ERR("out of memory\n");
4167 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4169 if (NT_SUCCESS(Status
)) {
4170 if (kvfi
->Type
== REG_DWORD
&& kvfi
->DataLength
>= sizeof(UINT32
)) {
4171 RtlCopyMemory(&debug_log_level
, ((UINT8
*)kvfi
) + kvfi
->DataOffset
, sizeof(UINT32
));
4173 Status
= ZwDeleteValueKey(h
, &us
);
4174 if (!NT_SUCCESS(Status
)) {
4175 ERR("ZwDeleteValueKey returned %08x\n", Status
);
4178 Status
= ZwSetValueKey(h
, &us
, 0, REG_DWORD
, &debug_log_level
, sizeof(debug_log_level
));
4179 if (!NT_SUCCESS(Status
)) {
4180 ERR("ZwSetValueKey reutrned %08x\n", Status
);
4186 } else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) {
4187 Status
= ZwSetValueKey(h
, &us
, 0, REG_DWORD
, &debug_log_level
, sizeof(debug_log_level
));
4189 if (!NT_SUCCESS(Status
)) {
4190 ERR("ZwSetValueKey reutrned %08x\n", Status
);
4193 ERR("ZwQueryValueKey returned %08x\n", Status
);
4196 RtlInitUnicodeString(&us
, L
"LogDevice");
4200 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4202 if ((Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) && kvfilen
> 0) {
4203 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4206 ERR("out of memory\n");
4211 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4213 if (NT_SUCCESS(Status
)) {
4214 if ((kvfi
->Type
== REG_SZ
|| kvfi
->Type
== REG_EXPAND_SZ
) && kvfi
->DataLength
>= sizeof(WCHAR
)) {
4215 log_device
.Length
= log_device
.MaximumLength
= kvfi
->DataLength
;
4216 log_device
.Buffer
= ExAllocatePoolWithTag(PagedPool
, kvfi
->DataLength
, ALLOC_TAG
);
4218 if (!log_device
.Buffer
) {
4219 ERR("out of memory\n");
4225 RtlCopyMemory(log_device
.Buffer
, ((UINT8
*)kvfi
) + kvfi
->DataOffset
, kvfi
->DataLength
);
4227 if (log_device
.Buffer
[(log_device
.Length
/ sizeof(WCHAR
)) - 1] == 0)
4228 log_device
.Length
-= sizeof(WCHAR
);
4230 ERR("LogDevice was type %u, length %u\n", kvfi
->Type
, kvfi
->DataLength
);
4232 Status
= ZwDeleteValueKey(h
, &us
);
4233 if (!NT_SUCCESS(Status
)) {
4234 ERR("ZwDeleteValueKey returned %08x\n", Status
);
4240 } else if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) {
4241 ERR("ZwQueryValueKey returned %08x\n", Status
);
4244 RtlInitUnicodeString(&us
, L
"LogFile");
4248 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4250 if ((Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) && kvfilen
> 0) {
4251 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4254 ERR("out of memory\n");
4259 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4261 if (NT_SUCCESS(Status
)) {
4262 if ((kvfi
->Type
== REG_SZ
|| kvfi
->Type
== REG_EXPAND_SZ
) && kvfi
->DataLength
>= sizeof(WCHAR
)) {
4263 log_file
.Length
= log_file
.MaximumLength
= kvfi
->DataLength
;
4264 log_file
.Buffer
= ExAllocatePoolWithTag(PagedPool
, kvfi
->DataLength
, ALLOC_TAG
);
4266 if (!log_file
.Buffer
) {
4267 ERR("out of memory\n");
4273 RtlCopyMemory(log_file
.Buffer
, ((UINT8
*)kvfi
) + kvfi
->DataOffset
, kvfi
->DataLength
);
4275 if (log_file
.Buffer
[(log_file
.Length
/ sizeof(WCHAR
)) - 1] == 0)
4276 log_file
.Length
-= sizeof(WCHAR
);
4278 ERR("LogFile was type %u, length %u\n", kvfi
->Type
, kvfi
->DataLength
);
4280 Status
= ZwDeleteValueKey(h
, &us
);
4281 if (!NT_SUCCESS(Status
)) {
4282 ERR("ZwDeleteValueKey returned %08x\n", Status
);
4288 } else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) {
4289 Status
= ZwSetValueKey(h
, &us
, 0, REG_SZ
, def_log_file
, (wcslen(def_log_file
) + 1) * sizeof(WCHAR
));
4291 if (!NT_SUCCESS(Status
)) {
4292 ERR("ZwSetValueKey returned %08x\n", Status
);
4295 ERR("ZwQueryValueKey returned %08x\n", Status
);
4298 if (log_file
.Length
== 0) {
4299 log_file
.Length
= log_file
.MaximumLength
= wcslen(def_log_file
) * sizeof(WCHAR
);
4300 log_file
.Buffer
= ExAllocatePoolWithTag(PagedPool
, log_file
.MaximumLength
, ALLOC_TAG
);
4302 if (!log_file
.Buffer
) {
4303 ERR("out of memory\n");
4308 RtlCopyMemory(log_file
.Buffer
, def_log_file
, log_file
.Length
);
4316 static void init_logging() {
4317 if (log_device
.Length
> 0)
4319 else if (log_file
.Length
> 0) {
4321 OBJECT_ATTRIBUTES oa
;
4322 IO_STATUS_BLOCK iosb
;
4327 InitializeObjectAttributes(&oa
, &log_file
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
4329 Status
= ZwCreateFile(&log_handle
, FILE_WRITE_DATA
, &oa
, &iosb
, NULL
, FILE_ATTRIBUTE_NORMAL
, FILE_SHARE_READ
,
4330 FILE_OPEN_IF
, FILE_NON_DIRECTORY_FILE
| FILE_WRITE_THROUGH
| FILE_SYNCHRONOUS_IO_ALERT
, NULL
, 0);
4332 if (!NT_SUCCESS(Status
)) {
4333 ERR("ZwCreateFile returned %08x\n", Status
);
4337 if (iosb
.Information
== FILE_OPENED
) { // already exists
4338 FILE_STANDARD_INFORMATION fsi
;
4339 FILE_POSITION_INFORMATION fpi
;
4341 static char delim
[] = "\n---\n";
4343 // move to end of file
4345 Status
= ZwQueryInformationFile(log_handle
, &iosb
, &fsi
, sizeof(FILE_STANDARD_INFORMATION
), FileStandardInformation
);
4347 if (!NT_SUCCESS(Status
)) {
4348 ERR("ZwQueryInformationFile returned %08x\n", Status
);
4352 fpi
.CurrentByteOffset
= fsi
.EndOfFile
;
4354 Status
= ZwSetInformationFile(log_handle
, &iosb
, &fpi
, sizeof(FILE_POSITION_INFORMATION
), FilePositionInformation
);
4356 if (!NT_SUCCESS(Status
)) {
4357 ERR("ZwSetInformationFile returned %08x\n", Status
);
4361 Status
= ZwWriteFile(log_handle
, NULL
, NULL
, NULL
, &iosb
, delim
, strlen(delim
), NULL
, NULL
);
4363 if (!NT_SUCCESS(Status
)) {
4364 ERR("ZwWriteFile returned %08x\n", Status
);
4369 dateline
= ExAllocatePoolWithTag(PagedPool
, 256, ALLOC_TAG
);
4372 ERR("out of memory\n");
4376 KeQuerySystemTime(&time
);
4378 RtlTimeToTimeFields(&time
, &tf
);
4380 sprintf(dateline
, "Starting logging at %04u-%02u-%02u %02u:%02u:%02u\n", tf
.Year
, tf
.Month
, tf
.Day
, tf
.Hour
, tf
.Minute
, tf
.Second
);
4382 Status
= ZwWriteFile(log_handle
, NULL
, NULL
, NULL
, &iosb
, dateline
, strlen(dateline
), NULL
, NULL
);
4384 if (!NT_SUCCESS(Status
)) {
4385 ERR("ZwWriteFile returned %08x\n", Status
);
4389 ExFreePool(dateline
);
4394 NTSTATUS STDCALL
DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
) {
4396 PDEVICE_OBJECT DeviceObject
;
4397 UNICODE_STRING device_nameW
;
4398 UNICODE_STRING dosdevice_nameW
;
4400 InitializeListHead(&uid_map_list
);
4402 log_device
.Buffer
= NULL
;
4403 log_device
.Length
= log_device
.MaximumLength
= 0;
4404 log_file
.Buffer
= NULL
;
4405 log_file
.Length
= log_file
.MaximumLength
= 0;
4407 read_registry(RegistryPath
);
4410 if (debug_log_level
> 0)
4416 TRACE("DriverEntry\n");
4422 // TRACE("check CRC32C: %08x\n", calc_crc32c((UINT8*)"123456789", 9)); // should be e3069283
4424 drvobj
= DriverObject
;
4426 DriverObject
->DriverUnload
= DriverUnload
;
4428 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = (PDRIVER_DISPATCH
)drv_create
;
4429 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = (PDRIVER_DISPATCH
)drv_close
;
4430 DriverObject
->MajorFunction
[IRP_MJ_READ
] = (PDRIVER_DISPATCH
)drv_read
;
4431 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = (PDRIVER_DISPATCH
)drv_write
;
4432 DriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] = (PDRIVER_DISPATCH
)drv_query_information
;
4433 DriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] = (PDRIVER_DISPATCH
)drv_set_information
;
4434 DriverObject
->MajorFunction
[IRP_MJ_QUERY_EA
] = (PDRIVER_DISPATCH
)drv_query_ea
;
4435 DriverObject
->MajorFunction
[IRP_MJ_SET_EA
] = (PDRIVER_DISPATCH
)drv_set_ea
;
4436 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = (PDRIVER_DISPATCH
)drv_flush_buffers
;
4437 DriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] = (PDRIVER_DISPATCH
)drv_query_volume_information
;
4438 DriverObject
->MajorFunction
[IRP_MJ_SET_VOLUME_INFORMATION
] = (PDRIVER_DISPATCH
)drv_set_volume_information
;
4439 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = (PDRIVER_DISPATCH
)drv_cleanup
;
4440 DriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] = (PDRIVER_DISPATCH
)drv_directory_control
;
4441 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = (PDRIVER_DISPATCH
)drv_file_system_control
;
4442 DriverObject
->MajorFunction
[IRP_MJ_LOCK_CONTROL
] = (PDRIVER_DISPATCH
)drv_lock_control
;
4443 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = (PDRIVER_DISPATCH
)drv_device_control
;
4444 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = (PDRIVER_DISPATCH
)drv_shutdown
;
4445 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = (PDRIVER_DISPATCH
)drv_pnp
;
4446 DriverObject
->MajorFunction
[IRP_MJ_QUERY_SECURITY
] = (PDRIVER_DISPATCH
)drv_query_security
;
4447 DriverObject
->MajorFunction
[IRP_MJ_SET_SECURITY
] = (PDRIVER_DISPATCH
)drv_set_security
;
4449 init_fast_io_dispatch(&DriverObject
->FastIoDispatch
);
4451 device_nameW
.Buffer
= device_name
;
4452 device_nameW
.Length
= device_nameW
.MaximumLength
= (USHORT
)wcslen(device_name
) * sizeof(WCHAR
);
4453 dosdevice_nameW
.Buffer
= dosdevice_name
;
4454 dosdevice_nameW
.Length
= dosdevice_nameW
.MaximumLength
= (USHORT
)wcslen(dosdevice_name
) * sizeof(WCHAR
);
4456 Status
= IoCreateDevice(DriverObject
, 0, &device_nameW
, FILE_DEVICE_DISK_FILE_SYSTEM
, 0, FALSE
, &DeviceObject
);
4457 if (!NT_SUCCESS(Status
)) {
4458 ERR("IoCreateDevice returned %08x\n", Status
);
4462 devobj
= DeviceObject
;
4464 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4466 Status
= IoCreateSymbolicLink(&dosdevice_nameW
, &device_nameW
);
4467 if (!NT_SUCCESS(Status
)) {
4468 ERR("IoCreateSymbolicLink returned %08x\n", Status
);
4472 Status
= init_cache();
4473 if (!NT_SUCCESS(Status
)) {
4474 ERR("init_cache returned %08x\n", Status
);
4478 InitializeListHead(&volumes
);
4479 look_for_vols(&volumes
);
4481 InitializeListHead(&VcbList
);
4482 ExInitializeResourceLite(&global_loading_lock
);
4484 IoRegisterFileSystem(DeviceObject
);
4486 return STATUS_SUCCESS
;