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 // FIXME - stop async threads
2380 free_fcb(Vcb
->volume_fcb
);
2381 free_fileref(Vcb
->root_fileref
);
2383 // FIXME - free any open fcbs?
2385 while (!IsListEmpty(&Vcb
->roots
)) {
2386 LIST_ENTRY
* le
= RemoveHeadList(&Vcb
->roots
);
2387 root
* r
= CONTAINING_RECORD(le
, root
, list_entry
);
2389 ExDeleteResourceLite(&r
->nonpaged
->load_tree_lock
);
2390 ExFreePool(r
->nonpaged
);
2394 while (!IsListEmpty(&Vcb
->chunks
)) {
2395 LIST_ENTRY
* le
= RemoveHeadList(&Vcb
->chunks
);
2396 c
= CONTAINING_RECORD(le
, chunk
, list_entry
);
2398 while (!IsListEmpty(&c
->space
)) {
2399 LIST_ENTRY
* le2
= RemoveHeadList(&c
->space
);
2400 s
= CONTAINING_RECORD(le2
, space
, list_entry
);
2406 ExFreePool(c
->devices
);
2408 ExFreePool(c
->chunk_item
);
2412 for (i
= 0; i
< Vcb
->superblock
.num_devices
; i
++) {
2413 while (!IsListEmpty(&Vcb
->devices
[i
].disk_holes
)) {
2414 LIST_ENTRY
* le
= RemoveHeadList(&Vcb
->devices
[i
].disk_holes
);
2415 disk_hole
* dh
= CONTAINING_RECORD(le
, disk_hole
, listentry
);
2421 ExFreePool(Vcb
->devices
);
2423 ExDeleteResourceLite(&Vcb
->fcb_lock
);
2424 ExDeleteResourceLite(&Vcb
->load_lock
);
2425 ExDeleteResourceLite(&Vcb
->tree_lock
);
2427 ZwClose(Vcb
->flush_thread_handle
);
2430 static NTSTATUS STDCALL
drv_cleanup(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
2432 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2433 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
2439 FsRtlEnterFileSystem();
2441 top_level
= is_top_level(Irp
);
2443 if (DeviceObject
== devobj
) {
2444 TRACE("closing file system\n");
2445 Status
= STATUS_SUCCESS
;
2449 if (FileObject
&& FileObject
->FsContext
) {
2454 fcb
= FileObject
->FsContext
;
2455 ccb
= FileObject
->FsContext2
;
2456 fileref
= ccb
? ccb
->fileref
: NULL
;
2458 TRACE("cleanup called for FileObject %p\n", FileObject
);
2459 TRACE("fcb %p (%S), refcount = %u, open_count = %u\n", fcb
, file_desc(FileObject
), fcb
->refcount
, fcb
->open_count
);
2461 IoRemoveShareAccess(FileObject
, &fcb
->share_access
);
2463 oc
= InterlockedDecrement(&fcb
->open_count
);
2464 #ifdef DEBUG_FCB_REFCOUNTS
2465 ERR("fcb %p: open_count now %i\n", fcb
, oc
);
2468 if (ccb
&& ccb
->options
& FILE_DELETE_ON_CLOSE
&& fileref
)
2469 fileref
->delete_on_close
= TRUE
;
2471 if (fileref
&& fileref
->delete_on_close
&& fcb
->type
== BTRFS_TYPE_DIRECTORY
&& fcb
->inode_item
.st_size
> 0)
2472 fileref
->delete_on_close
= FALSE
;
2475 if (fileref
&& fileref
->delete_on_close
&& fileref
!= fcb
->Vcb
->root_fileref
&& fcb
!= fcb
->Vcb
->volume_fcb
) {
2476 LIST_ENTRY rollback
;
2477 InitializeListHead(&rollback
);
2479 acquire_tree_lock(fcb
->Vcb
, TRUE
);
2481 Status
= delete_fileref(fileref
, FileObject
, &rollback
);
2483 if (NT_SUCCESS(Status
)) {
2484 LARGE_INTEGER newlength
;
2486 if (FileObject
->Flags
& FO_CACHE_SUPPORTED
&& fcb
->nonpaged
->segment_object
.DataSectionObject
)
2487 CcPurgeCacheSection(&fcb
->nonpaged
->segment_object
, NULL
, 0, FALSE
);
2489 newlength
.QuadPart
= 0;
2491 if (!CcUninitializeCacheMap(FileObject
, &newlength
, NULL
)) {
2492 TRACE("CcUninitializeCacheMap failed\n");
2495 clear_rollback(&rollback
);
2497 do_rollback(fcb
->Vcb
, &rollback
);
2499 release_tree_lock(fcb
->Vcb
, TRUE
);
2500 } else if (FileObject
->Flags
& FO_CACHE_SUPPORTED
&& fcb
->nonpaged
->segment_object
.DataSectionObject
) {
2501 IO_STATUS_BLOCK iosb
;
2502 CcFlushCache(FileObject
->SectionObjectPointer
, NULL
, 0, &iosb
);
2504 if (!NT_SUCCESS(iosb
.Status
)) {
2505 ERR("CcFlushCache returned %08x\n", iosb
.Status
);
2508 ExAcquireResourceExclusiveLite(fcb
->Header
.PagingIoResource
, TRUE
);
2509 ExReleaseResourceLite(fcb
->Header
.PagingIoResource
);
2511 CcPurgeCacheSection(&fcb
->nonpaged
->segment_object
, NULL
, 0, FALSE
);
2513 TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n",
2514 FileObject
, fcb
, fcb
->Header
.AllocationSize
.QuadPart
, fcb
->Header
.FileSize
.QuadPart
, fcb
->Header
.ValidDataLength
.QuadPart
);
2517 if (fcb
->Vcb
&& fcb
!= fcb
->Vcb
->volume_fcb
)
2518 CcUninitializeCacheMap(FileObject
, NULL
, NULL
);
2521 FileObject
->Flags
|= FO_CLEANUP_COMPLETE
;
2524 Status
= STATUS_SUCCESS
;
2527 Irp
->IoStatus
.Status
= Status
;
2528 Irp
->IoStatus
.Information
= 0;
2530 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2533 IoSetTopLevelIrp(NULL
);
2535 FsRtlExitFileSystem();
2540 ULONG STDCALL
get_file_attributes(device_extension
* Vcb
, INODE_ITEM
* ii
, root
* r
, UINT64 inode
, UINT8 type
, BOOL dotfile
, BOOL ignore_xa
) {
2547 if (!ignore_xa
&& get_xattr(Vcb
, r
, inode
, EA_DOSATTRIB
, EA_DOSATTRIB_HASH
, (UINT8
**)&eaval
, &ealen
)) {
2549 if (eaval
[0] == '0' && eaval
[1] == 'x') {
2553 for (i
= 2; i
< ealen
; i
++) {
2556 if (eaval
[i
] >= '0' && eaval
[i
] <= '9')
2557 dosnum
|= eaval
[i
] - '0';
2558 else if (eaval
[i
] >= 'a' && eaval
[i
] <= 'f')
2559 dosnum
|= eaval
[i
] + 10 - 'a';
2560 else if (eaval
[i
] >= 'A' && eaval
[i
] <= 'F')
2561 dosnum
|= eaval
[i
] + 10 - 'a';
2564 TRACE("DOSATTRIB: %08x\n", dosnum
);
2568 if (type
== BTRFS_TYPE_DIRECTORY
)
2569 dosnum
|= FILE_ATTRIBUTE_DIRECTORY
;
2570 else if (type
== BTRFS_TYPE_SYMLINK
)
2571 dosnum
|= FILE_ATTRIBUTE_REPARSE_POINT
;
2581 case BTRFS_TYPE_DIRECTORY
:
2582 att
= FILE_ATTRIBUTE_DIRECTORY
;
2585 case BTRFS_TYPE_SYMLINK
:
2586 att
= FILE_ATTRIBUTE_REPARSE_POINT
;
2595 att
|= FILE_ATTRIBUTE_HIDDEN
;
2598 att
|= FILE_ATTRIBUTE_ARCHIVE
;
2600 // FIXME - get READONLY from ii->st_mode
2601 // FIXME - return SYSTEM for block/char devices?
2604 att
= FILE_ATTRIBUTE_NORMAL
;
2609 // static int STDCALL utf8icmp(char* a, char* b) {
2610 // return strcmp(a, b); // FIXME - don't treat as ASCII
2613 NTSTATUS
sync_read_phys(PDEVICE_OBJECT DeviceObject
, LONGLONG StartingOffset
, ULONG Length
, PUCHAR Buffer
) {
2614 IO_STATUS_BLOCK
* IoStatus
;
2615 LARGE_INTEGER Offset
;
2617 PIO_STACK_LOCATION IrpSp
;
2619 read_context
* context
;
2623 context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(read_context
), ALLOC_TAG
);
2625 ERR("out of memory\n");
2626 return STATUS_INSUFFICIENT_RESOURCES
;
2629 RtlZeroMemory(context
, sizeof(read_context
));
2630 KeInitializeEvent(&context
->Event
, NotificationEvent
, FALSE
);
2632 IoStatus
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IO_STATUS_BLOCK
), ALLOC_TAG
);
2634 ERR("out of memory\n");
2635 ExFreePool(context
);
2636 return STATUS_INSUFFICIENT_RESOURCES
;
2639 Offset
.QuadPart
= StartingOffset
;
2641 // Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, Buffer, Length, &Offset, /*&Event*/NULL, IoStatus);
2642 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
2645 ERR("IoAllocateIrp failed\n");
2646 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2650 IrpSp
= IoGetNextIrpStackLocation(Irp
);
2651 IrpSp
->MajorFunction
= IRP_MJ_READ
;
2653 if (DeviceObject
->Flags
& DO_BUFFERED_IO
) {
2654 FIXME("FIXME - buffered IO\n");
2655 } else if (DeviceObject
->Flags
& DO_DIRECT_IO
) {
2656 // TRACE("direct IO\n");
2658 Irp
->MdlAddress
= IoAllocateMdl(Buffer
, Length
, FALSE
, FALSE
, NULL
);
2659 if (!Irp
->MdlAddress
) {
2660 ERR("IoAllocateMdl failed\n");
2661 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2665 // TRACE("got MDL %p from buffer %p\n", Irp->MdlAddress, Buffer);
2668 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoWriteAccess
);
2670 // TRACE("neither buffered nor direct IO\n");
2671 Irp
->UserBuffer
= Buffer
;
2674 IrpSp
->Parameters
.Read
.Length
= Length
;
2675 IrpSp
->Parameters
.Read
.ByteOffset
= Offset
;
2677 Irp
->UserIosb
= IoStatus
;
2678 // Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2680 Irp
->UserEvent
= &context
->Event
;
2682 // IoQueueThreadIrp(Irp);
2684 IoSetCompletionRoutine(Irp
, read_completion
, context
, TRUE
, TRUE
, TRUE
);
2688 // Stack = IoGetNextIrpStackLocation(Irp);
2689 // Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2692 // TRACE("Calling IO Driver... with irp %p\n", Irp);
2693 Status
= IoCallDriver(DeviceObject
, Irp
);
2695 // TRACE("Waiting for IO Operation for %p\n", Irp);
2696 if (Status
== STATUS_PENDING
) {
2697 // TRACE("Operation pending\n");
2698 KeWaitForSingleObject(&context
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
2699 // TRACE("Getting IO Status... for %p\n", Irp);
2700 Status
= context
->iosb
.Status
;
2703 if (DeviceObject
->Flags
& DO_DIRECT_IO
) {
2704 MmUnlockPages(Irp
->MdlAddress
);
2705 IoFreeMdl(Irp
->MdlAddress
);
2711 ExFreePool(IoStatus
);
2712 ExFreePool(context
);
2717 static NTSTATUS STDCALL
read_superblock(device_extension
* Vcb
, PDEVICE_OBJECT device
) {
2720 unsigned int i
, to_read
;
2723 to_read
= sector_align(sizeof(superblock
), device
->SectorSize
);
2725 sb
= ExAllocatePoolWithTag(NonPagedPool
, to_read
, ALLOC_TAG
);
2727 ERR("out of memory\n");
2728 return STATUS_INSUFFICIENT_RESOURCES
;
2733 while (superblock_addrs
[i
] > 0) {
2734 if (i
> 0 && superblock_addrs
[i
] + sizeof(superblock
) > Vcb
->length
)
2737 Status
= sync_read_phys(device
, superblock_addrs
[i
], to_read
, (PUCHAR
)sb
);
2738 if (!NT_SUCCESS(Status
)) {
2739 ERR("Failed to read superblock %u: %08x\n", i
, Status
);
2744 TRACE("got superblock %u!\n", i
);
2746 if (i
== 0 || sb
->generation
> Vcb
->superblock
.generation
)
2747 RtlCopyMemory(&Vcb
->superblock
, sb
, sizeof(superblock
));
2754 crc32
= calc_crc32c(0xffffffff, (UINT8
*)&Vcb
->superblock
.uuid
, (ULONG
)sizeof(superblock
) - sizeof(Vcb
->superblock
.checksum
));
2756 TRACE("crc32 was %08x, expected %08x\n", crc32
, *((UINT32
*)Vcb
->superblock
.checksum
));
2758 if (crc32
!= *((UINT32
*)Vcb
->superblock
.checksum
))
2759 return STATUS_INTERNAL_ERROR
; // FIXME - correct error?
2761 TRACE("label is %s\n", Vcb
->superblock
.label
);
2762 // utf8_to_utf16(Vcb->superblock.label, Vcb->label, MAX_LABEL_SIZE * sizeof(WCHAR));
2764 return STATUS_SUCCESS
;
2767 NTSTATUS STDCALL
dev_ioctl(PDEVICE_OBJECT DeviceObject
, ULONG ControlCode
, PVOID InputBuffer
, ULONG InputBufferSize
,
2768 PVOID OutputBuffer
, ULONG OutputBufferSize
, BOOLEAN Override
, IO_STATUS_BLOCK
* iosb
)
2773 PIO_STACK_LOCATION Stack
;
2774 IO_STATUS_BLOCK IoStatus
;
2776 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
2778 Irp
= IoBuildDeviceIoControlRequest(ControlCode
,
2788 if (!Irp
) return STATUS_INSUFFICIENT_RESOURCES
;
2791 Stack
= IoGetNextIrpStackLocation(Irp
);
2792 Stack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
2795 Status
= IoCallDriver(DeviceObject
, Irp
);
2797 if (Status
== STATUS_PENDING
) {
2798 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
2799 Status
= IoStatus
.Status
;
2808 // static void STDCALL find_chunk_root(device_extension* Vcb) {
2813 // while (i < Vcb->superblock.n) {
2814 // key = &Vcb->superblock.sys_chunk_array[i];
2815 // i += sizeof(KEY);
2821 // static void STDCALL insert_ltp(device_extension* Vcb, log_to_phys* ltp) {
2822 // if (!Vcb->log_to_phys) {
2823 // Vcb->log_to_phys = ltp;
2824 // ltp->next = NULL;
2828 // // FIXME - these should be ordered
2829 // ltp->next = Vcb->log_to_phys;
2830 // Vcb->log_to_phys = ltp;
2833 static NTSTATUS STDCALL
add_root(device_extension
* Vcb
, UINT64 id
, UINT64 addr
, traverse_ptr
* tp
) {
2834 root
* r
= ExAllocatePoolWithTag(PagedPool
, sizeof(root
), ALLOC_TAG
);
2836 ERR("out of memory\n");
2837 return STATUS_INSUFFICIENT_RESOURCES
;
2841 r
->path
.Buffer
= NULL
;
2842 r
->treeholder
.address
= addr
;
2843 r
->treeholder
.tree
= NULL
;
2844 init_tree_holder(&r
->treeholder
);
2845 InitializeListHead(&r
->fcbs
);
2847 r
->nonpaged
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(root_nonpaged
), ALLOC_TAG
);
2849 ERR("out of memory\n");
2851 return STATUS_INSUFFICIENT_RESOURCES
;
2854 ExInitializeResourceLite(&r
->nonpaged
->load_tree_lock
);
2859 RtlCopyMemory(&r
->root_item
, tp
->item
->data
, min(sizeof(ROOT_ITEM
), tp
->item
->size
));
2860 if (tp
->item
->size
< sizeof(ROOT_ITEM
))
2861 RtlZeroMemory(((UINT8
*)&r
->root_item
) + tp
->item
->size
, sizeof(ROOT_ITEM
) - tp
->item
->size
);
2864 InsertTailList(&Vcb
->roots
, &r
->list_entry
);
2867 case BTRFS_ROOT_ROOT
:
2871 case BTRFS_ROOT_EXTENT
:
2872 Vcb
->extent_root
= r
;
2875 case BTRFS_ROOT_CHUNK
:
2876 Vcb
->chunk_root
= r
;
2879 case BTRFS_ROOT_DEVTREE
:
2883 case BTRFS_ROOT_CHECKSUM
:
2884 Vcb
->checksum_root
= r
;
2887 case BTRFS_ROOT_UUID
:
2892 return STATUS_SUCCESS
;
2895 static NTSTATUS STDCALL
look_for_roots(device_extension
* Vcb
) {
2896 traverse_ptr tp
, next_tp
;
2901 searchkey
.obj_id
= 0;
2902 searchkey
.obj_type
= 0;
2903 searchkey
.offset
= 0;
2905 Status
= find_item(Vcb
, Vcb
->root_root
, &tp
, &searchkey
, FALSE
);
2906 if (!NT_SUCCESS(Status
)) {
2907 ERR("error - find_tree returned %08x\n", Status
);
2912 TRACE("(%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2914 if (tp
.item
->key
.obj_type
== TYPE_ROOT_ITEM
) {
2915 ROOT_ITEM
* ri
= (ROOT_ITEM
*)tp
.item
->data
;
2917 if (tp
.item
->size
< offsetof(ROOT_ITEM
, byte_limit
)) {
2918 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
));
2920 TRACE("root %llx - address %llx\n", tp
.item
->key
.obj_id
, ri
->block_number
);
2922 Status
= add_root(Vcb
, tp
.item
->key
.obj_id
, ri
->block_number
, &tp
);
2923 if (!NT_SUCCESS(Status
)) {
2924 ERR("add_root returned %08x\n", Status
);
2930 b
= find_next_item(Vcb
, &tp
, &next_tp
, FALSE
);
2936 return STATUS_SUCCESS
;
2939 static NTSTATUS
add_disk_hole(LIST_ENTRY
* disk_holes
, UINT64 address
, UINT64 size
) {
2940 disk_hole
* dh
= ExAllocatePoolWithTag(PagedPool
, sizeof(disk_hole
), ALLOC_TAG
);
2943 ERR("out of memory\n");
2944 return STATUS_INSUFFICIENT_RESOURCES
;
2947 dh
->address
= address
;
2949 dh
->provisional
= FALSE
;
2951 InsertTailList(disk_holes
, &dh
->listentry
);
2953 return STATUS_SUCCESS
;
2956 static NTSTATUS
find_disk_holes(device_extension
* Vcb
, device
* dev
) {
2958 traverse_ptr tp
, next_tp
;
2963 InitializeListHead(&dev
->disk_holes
);
2965 searchkey
.obj_id
= dev
->devitem
.dev_id
;
2966 searchkey
.obj_type
= TYPE_DEV_EXTENT
;
2967 searchkey
.offset
= 0;
2969 Status
= find_item(Vcb
, Vcb
->dev_root
, &tp
, &searchkey
, FALSE
);
2970 if (!NT_SUCCESS(Status
)) {
2971 ERR("error - find_tree returned %08x\n", Status
);
2978 if (tp
.item
->key
.obj_id
== dev
->devitem
.dev_id
&& tp
.item
->key
.obj_type
== TYPE_DEV_EXTENT
) {
2979 if (tp
.item
->size
>= sizeof(DEV_EXTENT
)) {
2980 DEV_EXTENT
* de
= (DEV_EXTENT
*)tp
.item
->data
;
2982 if (tp
.item
->key
.offset
> lastaddr
) {
2983 Status
= add_disk_hole(&dev
->disk_holes
, lastaddr
, tp
.item
->key
.offset
- lastaddr
);
2984 if (!NT_SUCCESS(Status
)) {
2985 ERR("add_disk_hole returned %08x\n", Status
);
2990 lastaddr
= tp
.item
->key
.offset
+ de
->length
;
2992 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
));
2996 b
= find_next_item(Vcb
, &tp
, &next_tp
, FALSE
);
3000 if (tp
.item
->key
.obj_id
> searchkey
.obj_id
|| tp
.item
->key
.obj_type
> searchkey
.obj_type
)
3005 if (lastaddr
< dev
->devitem
.num_bytes
) {
3006 Status
= add_disk_hole(&dev
->disk_holes
, lastaddr
, dev
->devitem
.num_bytes
- lastaddr
);
3007 if (!NT_SUCCESS(Status
)) {
3008 ERR("add_disk_hole returned %08x\n", Status
);
3013 // FIXME - free disk_holes when unmounting
3015 return STATUS_SUCCESS
;
3018 device
* find_device_from_uuid(device_extension
* Vcb
, BTRFS_UUID
* uuid
) {
3021 for (i
= 0; i
< Vcb
->superblock
.num_devices
; i
++) {
3022 TRACE("device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", i
,
3023 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],
3024 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]);
3026 if (Vcb
->devices
[i
].devobj
&& RtlCompareMemory(&Vcb
->devices
[i
].devitem
.device_uuid
, uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
3027 TRACE("returning device %llx\n", i
);
3028 return &Vcb
->devices
[i
];
3032 WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
3033 uuid
->uuid
[0], uuid
->uuid
[1], uuid
->uuid
[2], uuid
->uuid
[3], uuid
->uuid
[4], uuid
->uuid
[5], uuid
->uuid
[6], uuid
->uuid
[7],
3034 uuid
->uuid
[8], uuid
->uuid
[9], uuid
->uuid
[10], uuid
->uuid
[11], uuid
->uuid
[12], uuid
->uuid
[13], uuid
->uuid
[14], uuid
->uuid
[15]);
3039 static NTSTATUS STDCALL
load_chunk_root(device_extension
* Vcb
) {
3040 traverse_ptr tp
, next_tp
;
3047 searchkey
.obj_id
= 0;
3048 searchkey
.obj_type
= 0;
3049 searchkey
.offset
= 0;
3051 Status
= find_item(Vcb
, Vcb
->chunk_root
, &tp
, &searchkey
, FALSE
);
3052 if (!NT_SUCCESS(Status
)) {
3053 ERR("error - find_item returned %08x\n", Status
);
3058 TRACE("(%llx,%x,%llx)\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
3060 if (tp
.item
->key
.obj_id
== 1 && tp
.item
->key
.obj_type
== TYPE_DEV_ITEM
&& tp
.item
->key
.offset
== 1) {
3061 // FIXME - this is a hack; make this work with multiple devices!
3062 if (tp
.item
->size
> 0)
3063 RtlCopyMemory(&Vcb
->devices
[0].devitem
, tp
.item
->data
, min(tp
.item
->size
, sizeof(DEV_ITEM
)));
3064 } else if (tp
.item
->key
.obj_type
== TYPE_CHUNK_ITEM
) {
3065 if (tp
.item
->size
< sizeof(CHUNK_ITEM
)) {
3066 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
));
3068 c
= ExAllocatePoolWithTag(PagedPool
, sizeof(chunk
), ALLOC_TAG
);
3071 ERR("out of memory\n");
3072 return STATUS_INSUFFICIENT_RESOURCES
;
3075 c
->size
= tp
.item
->size
;
3076 c
->offset
= tp
.item
->key
.offset
;
3077 c
->used
= c
->oldused
= 0;
3078 c
->space_changed
= FALSE
;
3082 c
->chunk_item
= ExAllocatePoolWithTag(PagedPool
, tp
.item
->size
, ALLOC_TAG
);
3084 if (!c
->chunk_item
) {
3085 ERR("out of memory\n");
3086 return STATUS_INSUFFICIENT_RESOURCES
;
3089 RtlCopyMemory(c
->chunk_item
, tp
.item
->data
, tp
.item
->size
);
3091 if (c
->chunk_item
->num_stripes
> 0) {
3092 CHUNK_ITEM_STRIPE
* cis
= (CHUNK_ITEM_STRIPE
*)&c
->chunk_item
[1];
3094 c
->devices
= ExAllocatePoolWithTag(PagedPool
, sizeof(device
*) * c
->chunk_item
->num_stripes
, ALLOC_TAG
);
3097 ERR("out of memory\n");
3098 return STATUS_INSUFFICIENT_RESOURCES
;
3101 for (i
= 0; i
< c
->chunk_item
->num_stripes
; i
++) {
3102 c
->devices
[i
] = find_device_from_uuid(Vcb
, &cis
[i
].dev_uuid
);
3103 TRACE("device %llu = %p\n", i
, c
->devices
[i
]);
3108 InitializeListHead(&c
->space
);
3110 InsertTailList(&Vcb
->chunks
, &c
->list_entry
);
3114 b
= find_next_item(Vcb
, &tp
, &next_tp
, FALSE
);
3120 Vcb
->log_to_phys_loaded
= TRUE
;
3122 return STATUS_SUCCESS
;
3125 void protect_superblocks(device_extension
* Vcb
, chunk
* c
) {
3127 UINT64 off_start
, off_end
;
3129 // FIXME - this will need modifying for RAID
3131 while (superblock_addrs
[i
] != 0) {
3132 CHUNK_ITEM
* ci
= c
->chunk_item
;
3133 CHUNK_ITEM_STRIPE
* cis
= (CHUNK_ITEM_STRIPE
*)&ci
[1];
3135 for (j
= 0; j
< ci
->num_stripes
; j
++) {
3136 if (cis
[j
].offset
+ ci
->size
> superblock_addrs
[i
] && cis
[j
].offset
<= superblock_addrs
[i
] + sizeof(superblock
)) {
3137 TRACE("cut out superblock in chunk %llx\n", c
->offset
);
3139 // The Linux driver protects the whole stripe in which the superblock lives
3141 off_start
= ((superblock_addrs
[i
] - cis
[j
].offset
) / c
->chunk_item
->stripe_length
) * c
->chunk_item
->stripe_length
;
3142 off_end
= sector_align(superblock_addrs
[i
] - cis
[j
].offset
+ sizeof(superblock
), c
->chunk_item
->stripe_length
);
3144 add_to_space_list(c
, c
->offset
+ off_start
, off_end
- off_start
, SPACE_TYPE_USED
);
3152 static NTSTATUS STDCALL
find_chunk_usage(device_extension
* Vcb
) {
3153 LIST_ENTRY
* le
= Vcb
->chunks
.Flink
;
3157 BLOCK_GROUP_ITEM
* bgi
;
3161 // block_group_item size=7f0000 chunktreeid=100 flags=1
3163 searchkey
.obj_type
= TYPE_BLOCK_GROUP_ITEM
;
3165 while (le
!= &Vcb
->chunks
) {
3166 c
= CONTAINING_RECORD(le
, chunk
, list_entry
);
3168 searchkey
.obj_id
= c
->offset
;
3169 searchkey
.offset
= c
->chunk_item
->size
;
3171 Status
= find_item(Vcb
, Vcb
->extent_root
, &tp
, &searchkey
, FALSE
);
3172 if (!NT_SUCCESS(Status
)) {
3173 ERR("error - find_item returned %08x\n", Status
);
3177 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
3178 if (tp
.item
->size
>= sizeof(BLOCK_GROUP_ITEM
)) {
3179 bgi
= (BLOCK_GROUP_ITEM
*)tp
.item
->data
;
3181 c
->used
= c
->oldused
= bgi
->used
;
3183 TRACE("chunk %llx has %llx bytes used\n", c
->offset
, c
->used
);
3185 ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n",
3186 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
));
3190 // if (addr >= c->offset && (addr - c->offset) < c->chunk_item->size && c->chunk_item->num_stripes > 0) {
3191 // cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
3193 // return (addr - c->offset) + cis->offset;
3196 // FIXME - make sure we free occasionally after doing one of these, or we
3197 // might use up a lot of memory with a big disk.
3199 Status
= load_free_space_cache(Vcb
, c
);
3200 if (!NT_SUCCESS(Status
)) {
3201 ERR("load_free_space_cache returned %08x\n", Status
);
3205 protect_superblocks(Vcb
, c
);
3210 return STATUS_SUCCESS
;
3213 // static void STDCALL root_test(device_extension* Vcb) {
3216 // traverse_ptr tp, next_tp;
3221 // if (r->id == 0x102)
3227 // ERR("Could not find root tree.\n");
3231 // searchkey.obj_id = 0x1b6;
3232 // searchkey.obj_type = 0xb;
3233 // searchkey.offset = 0;
3235 // if (!find_item(Vcb, r, &tp, &searchkey, NULL, FALSE)) {
3236 // ERR("Could not find first item.\n");
3242 // TRACE("%x,%x,%x\n", (UINT32)tp.item->key.obj_id, tp.item->key.obj_type, (UINT32)tp.item->key.offset);
3244 // b = find_prev_item(Vcb, &tp, &next_tp, NULL, FALSE);
3247 // free_traverse_ptr(&tp);
3252 // free_traverse_ptr(&tp);
3255 static NTSTATUS
load_sys_chunks(device_extension
* Vcb
) {
3257 ULONG n
= Vcb
->superblock
.n
;
3260 if (n
> sizeof(KEY
)) {
3261 RtlCopyMemory(&key
, &Vcb
->superblock
.sys_chunk_array
[Vcb
->superblock
.n
- n
], sizeof(KEY
));
3264 return STATUS_SUCCESS
;
3266 TRACE("bootstrap: %llx,%x,%llx\n", key
.obj_id
, key
.obj_type
, key
.offset
);
3268 if (key
.obj_type
== TYPE_CHUNK_ITEM
) {
3273 if (n
< sizeof(CHUNK_ITEM
))
3274 return STATUS_SUCCESS
;
3276 ci
= (CHUNK_ITEM
*)&Vcb
->superblock
.sys_chunk_array
[Vcb
->superblock
.n
- n
];
3277 cisize
= sizeof(CHUNK_ITEM
) + (ci
->num_stripes
* sizeof(CHUNK_ITEM_STRIPE
));
3280 return STATUS_SUCCESS
;
3282 sc
= ExAllocatePoolWithTag(PagedPool
, sizeof(sys_chunk
), ALLOC_TAG
);
3285 ERR("out of memory\n");
3286 return STATUS_INSUFFICIENT_RESOURCES
;
3291 sc
->data
= ExAllocatePoolWithTag(PagedPool
, sc
->size
, ALLOC_TAG
);
3294 ERR("out of memory\n");
3295 return STATUS_INSUFFICIENT_RESOURCES
;
3298 RtlCopyMemory(sc
->data
, ci
, sc
->size
);
3299 InsertTailList(&Vcb
->sys_chunks
, &sc
->list_entry
);
3303 ERR("unexpected item %llx,%x,%llx in bootstrap\n", key
.obj_id
, key
.obj_type
, key
.offset
);
3304 return STATUS_INTERNAL_ERROR
;
3308 return STATUS_SUCCESS
;
3311 static root
* find_default_subvol(device_extension
* Vcb
) {
3315 UNICODE_STRING filename
;
3318 static WCHAR fn
[] = L
"default";
3319 static UINT32 crc32
= 0x8dbfc2d2;
3321 if (Vcb
->superblock
.incompat_flags
& BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL
) {
3322 filename
.Buffer
= fn
;
3323 filename
.Length
= filename
.MaximumLength
= (USHORT
)wcslen(fn
) * sizeof(WCHAR
);
3325 if (!find_file_in_dir_with_crc32(Vcb
, &filename
, crc32
, Vcb
->root_root
, Vcb
->superblock
.root_dir_objectid
, &subvol
, &inode
, &type
, NULL
))
3326 WARN("couldn't find default subvol DIR_ITEM, using default tree\n");
3331 le
= Vcb
->roots
.Flink
;
3332 while (le
!= &Vcb
->roots
) {
3333 root
* r
= CONTAINING_RECORD(le
, root
, list_entry
);
3335 if (r
->id
== BTRFS_ROOT_FSTREE
)
3344 static BOOL
is_device_removable(PDEVICE_OBJECT devobj
) {
3346 STORAGE_HOTPLUG_INFO shi
;
3348 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_GET_HOTPLUG_INFO
, NULL
, 0, &shi
, sizeof(STORAGE_HOTPLUG_INFO
), TRUE
, NULL
);
3350 if (!NT_SUCCESS(Status
)) {
3351 ERR("dev_ioctl returned %08x\n", Status
);
3355 return shi
.MediaRemovable
!= 0 ? TRUE
: FALSE
;
3358 static ULONG
get_device_change_count(PDEVICE_OBJECT devobj
) {
3361 IO_STATUS_BLOCK iosb
;
3363 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_CHECK_VERIFY
, NULL
, 0, &cc
, sizeof(ULONG
), TRUE
, &iosb
);
3365 if (!NT_SUCCESS(Status
)) {
3366 ERR("dev_ioctl returned %08x\n", Status
);
3370 if (iosb
.Information
< sizeof(ULONG
)) {
3371 ERR("iosb.Information was too short\n");
3378 static NTSTATUS STDCALL
mount_vol(PDEVICE_OBJECT DeviceObject
, PIRP Irp
) {
3379 PIO_STACK_LOCATION Stack
;
3380 PDEVICE_OBJECT NewDeviceObject
= NULL
;
3381 PDEVICE_OBJECT DeviceToMount
;
3383 device_extension
* Vcb
= NULL
;
3384 PARTITION_INFORMATION_EX piex
;
3389 fcb
* root_fcb
= NULL
;
3391 TRACE("mount_vol called\n");
3393 if (DeviceObject
!= devobj
)
3395 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3399 Stack
= IoGetCurrentIrpStackLocation(Irp
);
3400 DeviceToMount
= Stack
->Parameters
.MountVolume
.DeviceObject
;
3402 // Status = NtfsHasFileSystem(DeviceToMount);
3403 // if (!NT_SUCCESS(Status))
3408 Status
= dev_ioctl(DeviceToMount
, IOCTL_DISK_GET_PARTITION_INFO_EX
, NULL
, 0,
3409 &piex
, sizeof(piex
), TRUE
, NULL
);
3410 if (!NT_SUCCESS(Status
)) {
3411 ERR("error reading partition information: %08x\n", Status
);
3412 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3416 Status
= IoCreateDevice(drvobj
,
3417 sizeof(device_extension
),
3419 FILE_DEVICE_DISK_FILE_SYSTEM
,
3423 if (!NT_SUCCESS(Status
)) {
3424 ERR("IoCreateDevice returned %08x\n", Status
);
3425 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3429 // TRACE("DEV_ITEM = %x, superblock = %x\n", sizeof(DEV_ITEM), sizeof(superblock));
3431 NewDeviceObject
->Flags
|= DO_DIRECT_IO
;
3432 Vcb
= (PVOID
)NewDeviceObject
->DeviceExtension
;
3433 RtlZeroMemory(Vcb
, sizeof(device_extension
));
3435 ExInitializeResourceLite(&Vcb
->tree_lock
);
3436 Vcb
->tree_lock_counter
= 0;
3437 Vcb
->open_trees
= 0;
3438 Vcb
->write_trees
= 0;
3440 ExInitializeResourceLite(&Vcb
->fcb_lock
);
3441 ExInitializeResourceLite(&Vcb
->DirResource
);
3443 ExAcquireResourceExclusiveLite(&global_loading_lock
, TRUE
);
3444 InsertTailList(&VcbList
, &Vcb
->list_entry
);
3445 ExReleaseResourceLite(&global_loading_lock
);
3447 ExInitializeResourceLite(&Vcb
->load_lock
);
3448 ExAcquireResourceExclusiveLite(&Vcb
->load_lock
, TRUE
);
3450 // Vcb->Identifier.Type = NTFS_TYPE_VCB;
3451 // Vcb->Identifier.Size = sizeof(NTFS_TYPE_VCB);
3453 // Status = NtfsGetVolumeData(DeviceToMount,
3455 // if (!NT_SUCCESS(Status))
3458 // Vcb->device = DeviceToMount;
3459 DeviceToMount
->Flags
|= DO_DIRECT_IO
;
3461 // Status = dev_ioctl(DeviceToMount, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
3462 // &Vcb->geometry, sizeof(DISK_GEOMETRY), TRUE);
3463 // if (!NT_SUCCESS(Status)) {
3464 // ERR("error reading disk geometry: %08x\n", Status);
3467 // TRACE("media type = %u, cylinders = %u, tracks per cylinder = %u, sectors per track = %u, bytes per sector = %u\n",
3468 // Vcb->geometry.MediaType, Vcb->geometry.Cylinders, Vcb->geometry.TracksPerCylinder,
3469 // Vcb->geometry.SectorsPerTrack, Vcb->geometry.BytesPerSector);
3472 Vcb
->length
= piex
.PartitionLength
.QuadPart
;
3473 TRACE("partition length = %u\n", piex
.PartitionLength
);
3475 Status
= read_superblock(Vcb
, DeviceToMount
);
3476 if (!NT_SUCCESS(Status
)) {
3477 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3481 if (Vcb
->superblock
.magic
!= BTRFS_MAGIC
) {
3482 ERR("not a BTRFS volume\n");
3483 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3486 TRACE("btrfs magic found\n");
3489 if (Vcb
->superblock
.incompat_flags
& ~INCOMPAT_SUPPORTED
) {
3490 WARN("cannot mount because of unsupported incompat flags (%llx)\n", Vcb
->superblock
.incompat_flags
& ~INCOMPAT_SUPPORTED
);
3491 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3496 while (le
!= &volumes
) {
3497 volume
* v
= CONTAINING_RECORD(le
, volume
, list_entry
);
3499 if (RtlCompareMemory(&Vcb
->superblock
.uuid
, &v
->fsuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
) && v
->devnum
< Vcb
->superblock
.dev_item
.dev_id
) {
3500 // skipping over device in RAID which isn't the first one
3501 // FIXME - hide this in My Computer
3502 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3509 // FIXME - remove this when we can
3510 if (Vcb
->superblock
.num_devices
> 1) {
3511 WARN("not mounting - multiple devices not yet implemented\n");
3512 Status
= STATUS_UNRECOGNIZED_VOLUME
;
3516 Vcb
->readonly
= FALSE
;
3517 if (Vcb
->superblock
.compat_ro_flags
& ~COMPAT_RO_SUPPORTED
) {
3518 WARN("mounting read-only because of unsupported flags (%llx)\n", Vcb
->superblock
.compat_ro_flags
& ~COMPAT_RO_SUPPORTED
);
3519 Vcb
->readonly
= TRUE
;
3522 Vcb
->superblock
.generation
++;
3523 Vcb
->superblock
.incompat_flags
|= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF
;
3525 Vcb
->devices
= ExAllocatePoolWithTag(PagedPool
, sizeof(device
) * Vcb
->superblock
.num_devices
, ALLOC_TAG
);
3526 if (!Vcb
->devices
) {
3527 ERR("out of memory\n");
3528 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3532 Vcb
->devices
[0].devobj
= DeviceToMount
;
3533 RtlCopyMemory(&Vcb
->devices
[0].devitem
, &Vcb
->superblock
.dev_item
, sizeof(DEV_ITEM
));
3534 Vcb
->devices
[0].removable
= is_device_removable(Vcb
->devices
[0].devobj
);
3535 Vcb
->devices
[0].change_count
= Vcb
->devices
[0].removable
? get_device_change_count(Vcb
->devices
[0].devobj
) : 0;
3537 if (Vcb
->superblock
.num_devices
> 1)
3538 RtlZeroMemory(&Vcb
->devices
[1], sizeof(DEV_ITEM
) * (Vcb
->superblock
.num_devices
- 1));
3540 // FIXME - find other devices, if there are any
3542 TRACE("DeviceToMount = %p\n", DeviceToMount
);
3543 TRACE("Stack->Parameters.MountVolume.Vpb = %p\n", Stack
->Parameters
.MountVolume
.Vpb
);
3545 NewDeviceObject
->StackSize
= DeviceToMount
->StackSize
+ 1;
3546 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
3548 // find_chunk_root(Vcb);
3549 // Vcb->chunk_root_phys_addr = Vcb->superblock.chunk_tree_addr; // FIXME - map from logical to physical (bootstrapped)
3551 // Vcb->root_tree_phys_addr = logical_to_physical(Vcb, Vcb->superblock.root_tree_addr);
3553 InitializeListHead(&Vcb
->roots
);
3554 InitializeListHead(&Vcb
->drop_roots
);
3556 Vcb
->log_to_phys_loaded
= FALSE
;
3558 Vcb
->max_inline
= Vcb
->superblock
.node_size
/ 2;
3560 // Vcb->write_trees = NULL;
3562 add_root(Vcb
, BTRFS_ROOT_CHUNK
, Vcb
->superblock
.chunk_tree_addr
, NULL
);
3564 if (!Vcb
->chunk_root
) {
3565 ERR("Could not load chunk root.\n");
3566 Status
= STATUS_INTERNAL_ERROR
;
3570 InitializeListHead(&Vcb
->sys_chunks
);
3571 Status
= load_sys_chunks(Vcb
);
3572 if (!NT_SUCCESS(Status
)) {
3573 ERR("load_sys_chunks returned %08x\n", Status
);
3577 InitializeListHead(&Vcb
->chunks
);
3578 InitializeListHead(&Vcb
->trees
);
3580 InitializeListHead(&Vcb
->DirNotifyList
);
3582 FsRtlNotifyInitializeSync(&Vcb
->NotifySync
);
3584 Status
= load_chunk_root(Vcb
);
3585 if (!NT_SUCCESS(Status
)) {
3586 ERR("load_chunk_root returned %08x\n", Status
);
3590 add_root(Vcb
, BTRFS_ROOT_ROOT
, Vcb
->superblock
.root_tree_addr
, NULL
);
3592 if (!Vcb
->root_root
) {
3593 ERR("Could not load root of roots.\n");
3594 Status
= STATUS_INTERNAL_ERROR
;
3598 Status
= look_for_roots(Vcb
);
3599 if (!NT_SUCCESS(Status
)) {
3600 ERR("look_for_roots returned %08x\n", Status
);
3604 Status
= find_chunk_usage(Vcb
);
3605 if (!NT_SUCCESS(Status
)) {
3606 ERR("find_chunk_usage returned %08x\n", Status
);
3610 // We've already increased the generation by one
3611 if (!Vcb
->readonly
&& Vcb
->superblock
.generation
- 1 != Vcb
->superblock
.cache_generation
) {
3612 WARN("generation was %llx, free-space cache generation was %llx; clearing cache...\n", Vcb
->superblock
.generation
- 1, Vcb
->superblock
.cache_generation
);
3613 Status
= clear_free_space_cache(Vcb
);
3614 if (!NT_SUCCESS(Status
)) {
3615 ERR("clear_free_space_cache returned %08x\n", Status
);
3620 Vcb
->volume_fcb
= create_fcb();
3621 if (!Vcb
->volume_fcb
) {
3622 ERR("out of memory\n");
3623 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3627 Vcb
->volume_fcb
->Vcb
= Vcb
;
3628 Vcb
->volume_fcb
->sd
= NULL
;
3630 root_fcb
= create_fcb();
3632 ERR("out of memory\n");
3633 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3637 root_fcb
->Vcb
= Vcb
;
3638 root_fcb
->inode
= SUBVOL_ROOT_INODE
;
3639 root_fcb
->type
= BTRFS_TYPE_DIRECTORY
;
3641 #ifdef DEBUG_FCB_REFCOUNTS
3642 WARN("volume FCB = %p\n", Vcb
->volume_fcb
);
3643 WARN("root FCB = %p\n", root_fcb
);
3646 root_fcb
->subvol
= find_default_subvol(Vcb
);
3648 if (!root_fcb
->subvol
) {
3649 ERR("could not find top subvol\n");
3650 Status
= STATUS_INTERNAL_ERROR
;
3654 searchkey
.obj_id
= root_fcb
->inode
;
3655 searchkey
.obj_type
= TYPE_INODE_ITEM
;
3656 searchkey
.offset
= 0xffffffffffffffff;
3658 Status
= find_item(Vcb
, root_fcb
->subvol
, &tp
, &searchkey
, FALSE
);
3659 if (!NT_SUCCESS(Status
)) {
3660 ERR("error - find_item returned %08x\n", Status
);
3664 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) {
3665 ERR("couldn't find INODE_ITEM for root directory\n");
3666 Status
= STATUS_INTERNAL_ERROR
;
3670 if (tp
.item
->size
> 0)
3671 RtlCopyMemory(&root_fcb
->inode_item
, tp
.item
->data
, min(sizeof(INODE_ITEM
), tp
.item
->size
));
3673 fcb_get_sd(root_fcb
, NULL
);
3675 root_fcb
->atts
= get_file_attributes(Vcb
, &root_fcb
->inode_item
, root_fcb
->subvol
, root_fcb
->inode
, root_fcb
->type
, FALSE
, FALSE
);
3677 Vcb
->root_fileref
= create_fileref();
3678 if (!Vcb
->root_fileref
) {
3679 ERR("out of memory\n");
3680 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3684 Vcb
->root_fileref
->fcb
= root_fcb
;
3685 InsertTailList(&root_fcb
->subvol
->fcbs
, &root_fcb
->list_entry
);
3687 Vcb
->root_fileref
->full_filename
.Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(WCHAR
), ALLOC_TAG
);
3689 if (!Vcb
->root_fileref
->full_filename
.Buffer
) {
3690 ERR("out of memory\n");
3691 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3695 Vcb
->root_fileref
->full_filename
.Buffer
[0] = '\\';
3696 Vcb
->root_fileref
->full_filename
.Length
= Vcb
->root_fileref
->full_filename
.MaximumLength
= sizeof(WCHAR
);
3698 for (i
= 0; i
< Vcb
->superblock
.num_devices
; i
++) {
3699 Status
= find_disk_holes(Vcb
, &Vcb
->devices
[i
]);
3700 if (!NT_SUCCESS(Status
)) {
3701 ERR("find_disk_holes returned %08x\n", Status
);
3708 // Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
3709 // Vcb->StorageDevice);
3711 // InitializeListHead(&Vcb->FcbListHead);
3713 // Fcb = NtfsCreateFCB(NULL, Vcb);
3716 // Status = STATUS_INSUFFICIENT_RESOURCES;
3720 // Ccb = ExAllocatePoolWithTag(NonPagedPool,
3721 // sizeof(NTFS_CCB),
3725 // Status = STATUS_INSUFFICIENT_RESOURCES;
3729 // RtlZeroMemory(Ccb, sizeof(NTFS_CCB));
3731 // Ccb->Identifier.Type = NTFS_TYPE_CCB;
3732 // Ccb->Identifier.Size = sizeof(NTFS_TYPE_CCB);
3734 // Vcb->StreamFileObject->FsContext = Fcb;
3735 // Vcb->StreamFileObject->FsContext2 = Ccb;
3736 // Vcb->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
3737 // Vcb->StreamFileObject->PrivateCacheMap = NULL;
3738 // Vcb->StreamFileObject->Vpb = Vcb->Vpb;
3739 // Ccb->PtrFileObject = Vcb->StreamFileObject;
3740 // Fcb->FileObject = Vcb->StreamFileObject;
3741 // Fcb->Vcb = (PDEVICE_EXTENSION)Vcb->StorageDevice;
3743 // Fcb->Flags = FCB_IS_VOLUME_STREAM;
3745 // Fcb->RFCB.FileSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
3746 // Fcb->RFCB.ValidDataLength.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
3747 // Fcb->RFCB.AllocationSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; /* Correct? */
3749 // CcInitializeCacheMap(Vcb->StreamFileObject,
3750 // (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
3752 // &(NtfsGlobalData->CacheMgrCallbacks),
3755 // ExInitializeResourceLite(&Vcb->LogToPhysLock);
3757 KeInitializeSpinLock(&Vcb
->FcbListLock
);
3759 // /* Get serial number */
3760 // NewDeviceObject->Vpb->SerialNumber = Vcb->NtfsInfo.SerialNumber;
3762 // /* Get volume label */
3763 // NewDeviceObject->Vpb->VolumeLabelLength = Vcb->NtfsInfo.VolumeLabelLength;
3764 // RtlCopyMemory(NewDeviceObject->Vpb->VolumeLabel,
3765 // Vcb->NtfsInfo.VolumeLabel,
3766 // Vcb->NtfsInfo.VolumeLabelLength);
3768 NewDeviceObject
->Vpb
= Stack
->Parameters
.MountVolume
.Vpb
;
3769 Stack
->Parameters
.MountVolume
.Vpb
->DeviceObject
= NewDeviceObject
;
3770 Stack
->Parameters
.MountVolume
.Vpb
->RealDevice
= DeviceToMount
;
3771 Stack
->Parameters
.MountVolume
.Vpb
->Flags
|= VPB_MOUNTED
;
3772 NewDeviceObject
->Vpb
->VolumeLabelLength
= 4; // FIXME
3773 NewDeviceObject
->Vpb
->VolumeLabel
[0] = '?';
3774 NewDeviceObject
->Vpb
->VolumeLabel
[1] = 0;
3775 NewDeviceObject
->Vpb
->ReferenceCount
++; // FIXME - should we deref this at any point?
3777 Status
= PsCreateSystemThread(&Vcb
->flush_thread_handle
, 0, NULL
, NULL
, NULL
, flush_thread
, NewDeviceObject
);
3778 if (!NT_SUCCESS(Status
)) {
3779 ERR("PsCreateSystemThread returned %08x\n", Status
);
3783 Status
= STATUS_SUCCESS
;
3786 // if (!NT_SUCCESS(Status))
3789 // if (Vcb && Vcb->StreamFileObject)
3790 // ObDereferenceObject(Vcb->StreamFileObject);
3798 // if (NewDeviceObject)
3799 // IoDeleteDevice(NewDeviceObject);
3803 ExReleaseResourceLite(&Vcb
->load_lock
);
3806 if (!NT_SUCCESS(Status
)) {
3808 if (Vcb
->root_fileref
)
3809 free_fileref(Vcb
->root_fileref
);
3813 if (Vcb
->volume_fcb
)
3814 free_fcb(Vcb
->volume_fcb
);
3816 ExDeleteResourceLite(&Vcb
->tree_lock
);
3817 ExDeleteResourceLite(&Vcb
->load_lock
);
3818 ExDeleteResourceLite(&Vcb
->fcb_lock
);
3819 ExDeleteResourceLite(&Vcb
->DirResource
);
3822 ExFreePoolWithTag(Vcb
->devices
, ALLOC_TAG
);
3824 RemoveEntryList(&Vcb
->list_entry
);
3827 if (NewDeviceObject
)
3828 IoDeleteDevice(NewDeviceObject
);
3831 TRACE("mount_vol done (status: %lx)\n", Status
);
3836 static NTSTATUS STDCALL
drv_file_system_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3837 PIO_STACK_LOCATION IrpSp
;
3841 TRACE("file system control\n");
3843 FsRtlEnterFileSystem();
3845 top_level
= is_top_level(Irp
);
3847 status
= STATUS_NOT_IMPLEMENTED
;
3849 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
3851 Irp
->IoStatus
.Information
= 0;
3853 switch (IrpSp
->MinorFunction
) {
3854 case IRP_MN_MOUNT_VOLUME
:
3855 TRACE("IRP_MN_MOUNT_VOLUME\n");
3857 // Irp->IoStatus.Status = STATUS_SUCCESS;
3858 status
= mount_vol(DeviceObject
, Irp
);
3859 // IrpSp->Parameters.MountVolume.DeviceObject = 0x0badc0de;
3860 // IrpSp->Parameters.MountVolume.Vpb = 0xdeadbeef;
3862 // IoCompleteRequest( Irp, IO_DISK_INCREMENT );
3864 // return Irp->IoStatus.Status;
3867 case IRP_MN_KERNEL_CALL
:
3868 TRACE("IRP_MN_KERNEL_CALL\n");
3870 status
= fsctl_request(DeviceObject
, Irp
, IrpSp
->Parameters
.FileSystemControl
.FsControlCode
, FALSE
);
3873 case IRP_MN_USER_FS_REQUEST
:
3874 TRACE("IRP_MN_USER_FS_REQUEST\n");
3876 status
= fsctl_request(DeviceObject
, Irp
, IrpSp
->Parameters
.FileSystemControl
.FsControlCode
, TRUE
);
3879 case IRP_MN_VERIFY_VOLUME
:
3880 FIXME("STUB: IRP_MN_VERIFY_VOLUME\n");
3887 Irp
->IoStatus
.Status
= status
;
3889 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
3892 IoSetTopLevelIrp(NULL
);
3894 FsRtlExitFileSystem();
3899 static NTSTATUS STDCALL
drv_lock_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3901 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3902 fcb
* fcb
= IrpSp
->FileObject
->FsContext
;
3905 FsRtlEnterFileSystem();
3907 top_level
= is_top_level(Irp
);
3909 TRACE("lock control\n");
3911 Status
= FsRtlProcessFileLock(&fcb
->lock
, Irp
, NULL
);
3913 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
3916 IoSetTopLevelIrp(NULL
);
3918 FsRtlExitFileSystem();
3923 static NTSTATUS STDCALL
drv_device_control(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3925 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3926 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
3927 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
3931 FIXME("STUB: device control\n");
3933 FsRtlEnterFileSystem();
3935 top_level
= is_top_level(Irp
);
3937 Irp
->IoStatus
.Information
= 0;
3939 WARN("control code = %x\n", IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
);
3942 ERR("FileObject was NULL\n");
3943 Status
= STATUS_INVALID_PARAMETER
;
3948 fcb
= FileObject
->FsContext
;
3951 ERR("FCB was NULL\n");
3952 Status
= STATUS_INVALID_PARAMETER
;
3956 if (fcb
== Vcb
->volume_fcb
) {
3957 FIXME("FIXME - pass through\n");
3958 Status
= STATUS_NOT_IMPLEMENTED
;
3960 TRACE("filename = %S\n", file_desc(FileObject
));
3962 switch (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
) {
3963 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
3964 TRACE("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
3965 Status
= STATUS_INVALID_PARAMETER
;
3969 WARN("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",
3970 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
, (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0xff0000) >> 16,
3971 (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0xc000) >> 14, (IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0x3ffc) >> 2,
3972 IrpSp
->Parameters
.DeviceIoControl
.IoControlCode
& 0x3);
3973 Status
= STATUS_INVALID_PARAMETER
;
3979 Irp
->IoStatus
.Status
= Status
;
3981 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
3984 IoSetTopLevelIrp(NULL
);
3986 FsRtlExitFileSystem();
3991 static NTSTATUS STDCALL
drv_shutdown(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3997 FsRtlEnterFileSystem();
3999 top_level
= is_top_level(Irp
);
4001 Status
= STATUS_SUCCESS
;
4003 while (!IsListEmpty(&VcbList
)) {
4004 LIST_ENTRY
* le
= RemoveHeadList(&VcbList
);
4005 device_extension
* Vcb
= CONTAINING_RECORD(le
, device_extension
, list_entry
);
4007 TRACE("shutting down Vcb %p\n", Vcb
);
4012 Irp
->IoStatus
.Status
= Status
;
4013 Irp
->IoStatus
.Information
= 0;
4015 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
4018 IoSetTopLevelIrp(NULL
);
4020 FsRtlExitFileSystem();
4025 BOOL
is_file_name_valid(PUNICODE_STRING us
) {
4028 if (us
->Length
< sizeof(WCHAR
))
4031 if (us
->Length
> 255 * sizeof(WCHAR
))
4034 for (i
= 0; i
< us
->Length
/ sizeof(WCHAR
); i
++) {
4035 if (us
->Buffer
[i
] == '/' || us
->Buffer
[i
] == '<' || us
->Buffer
[i
] == '>' || us
->Buffer
[i
] == ':' || us
->Buffer
[i
] == '"' ||
4036 us
->Buffer
[i
] == '|' || us
->Buffer
[i
] == '?' || us
->Buffer
[i
] == '*' || (us
->Buffer
[i
] >= 1 && us
->Buffer
[i
] <= 31))
4040 if (us
->Buffer
[0] == '.' && (us
->Length
== sizeof(WCHAR
) || (us
->Length
== 2 * sizeof(WCHAR
) && us
->Buffer
[1] == '.')))
4047 static void STDCALL
init_serial() {
4050 Status
= IoGetDeviceObjectPointer(&log_device
, FILE_WRITE_DATA
, &comfo
, &comdo
);
4051 if (!NT_SUCCESS(Status
)) {
4052 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
4058 static void STDCALL
check_cpu() {
4059 unsigned int cpuInfo
[4];
4061 __get_cpuid(1, &cpuInfo
[0], &cpuInfo
[1], &cpuInfo
[2], &cpuInfo
[3]);
4062 have_sse42
= cpuInfo
[2] & bit_SSE4_2
;
4064 __cpuid(cpuInfo
, 1);
4065 have_sse42
= cpuInfo
[2] & (1 << 20);
4069 TRACE("SSE4.2 is supported\n");
4071 TRACE("SSE4.2 not supported\n");
4075 static void STDCALL
read_registry(PUNICODE_STRING regpath
) {
4078 OBJECT_ATTRIBUTES oa
;
4082 ULONG kvfilen
, retlen
, i
;
4083 KEY_VALUE_FULL_INFORMATION
* kvfi
;
4085 const WCHAR mappings
[] = L
"\\Mappings";
4087 static WCHAR def_log_file
[] = L
"\\??\\C:\\btrfs.log";
4090 path
= ExAllocatePoolWithTag(PagedPool
, regpath
->Length
+ (wcslen(mappings
) * sizeof(WCHAR
)), ALLOC_TAG
);
4092 ERR("out of memory\n");
4096 RtlCopyMemory(path
, regpath
->Buffer
, regpath
->Length
);
4097 RtlCopyMemory((UINT8
*)path
+ regpath
->Length
, mappings
, wcslen(mappings
) * sizeof(WCHAR
));
4100 us
.Length
= us
.MaximumLength
= regpath
->Length
+ ((USHORT
)wcslen(mappings
) * sizeof(WCHAR
));
4102 InitializeObjectAttributes(&oa
, &us
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
4104 // FIXME - keep open and do notify for changes
4105 Status
= ZwCreateKey(&h
, KEY_QUERY_VALUE
, &oa
, 0, NULL
, REG_OPTION_NON_VOLATILE
, &dispos
);
4107 if (!NT_SUCCESS(Status
)) {
4108 ERR("ZwCreateKey returned %08x\n", Status
);
4113 if (dispos
== REG_OPENED_EXISTING_KEY
) {
4114 kvfilen
= sizeof(KEY_VALUE_FULL_INFORMATION
) + 256;
4115 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4118 ERR("out of memory\n");
4126 Status
= ZwEnumerateValueKey(h
, i
, KeyValueFullInformation
, kvfi
, kvfilen
, &retlen
);
4128 if (NT_SUCCESS(Status
) && kvfi
->DataLength
> 0) {
4131 RtlCopyMemory(&val
, (UINT8
*)kvfi
+ kvfi
->DataOffset
, min(kvfi
->DataLength
, sizeof(UINT32
)));
4133 TRACE("entry %u = %.*S = %u\n", i
, kvfi
->NameLength
/ sizeof(WCHAR
), kvfi
->Name
, val
);
4135 add_user_mapping(kvfi
->Name
, kvfi
->NameLength
/ sizeof(WCHAR
), val
);
4139 } while (Status
!= STATUS_NO_MORE_ENTRIES
);
4147 InitializeObjectAttributes(&oa
, regpath
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
4149 Status
= ZwCreateKey(&h
, KEY_QUERY_VALUE
, &oa
, 0, NULL
, REG_OPTION_NON_VOLATILE
, &dispos
);
4151 if (!NT_SUCCESS(Status
)) {
4152 ERR("ZwCreateKey returned %08x\n", Status
);
4156 RtlInitUnicodeString(&us
, L
"DebugLogLevel");
4160 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4162 if ((Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) && kvfilen
> 0) {
4163 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4166 ERR("out of memory\n");
4171 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4173 if (NT_SUCCESS(Status
)) {
4174 if (kvfi
->Type
== REG_DWORD
&& kvfi
->DataLength
>= sizeof(UINT32
)) {
4175 RtlCopyMemory(&debug_log_level
, ((UINT8
*)kvfi
) + kvfi
->DataOffset
, sizeof(UINT32
));
4177 Status
= ZwDeleteValueKey(h
, &us
);
4178 if (!NT_SUCCESS(Status
)) {
4179 ERR("ZwDeleteValueKey returned %08x\n", Status
);
4182 Status
= ZwSetValueKey(h
, &us
, 0, REG_DWORD
, &debug_log_level
, sizeof(debug_log_level
));
4183 if (!NT_SUCCESS(Status
)) {
4184 ERR("ZwSetValueKey reutrned %08x\n", Status
);
4190 } else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) {
4191 Status
= ZwSetValueKey(h
, &us
, 0, REG_DWORD
, &debug_log_level
, sizeof(debug_log_level
));
4193 if (!NT_SUCCESS(Status
)) {
4194 ERR("ZwSetValueKey reutrned %08x\n", Status
);
4197 ERR("ZwQueryValueKey returned %08x\n", Status
);
4200 RtlInitUnicodeString(&us
, L
"LogDevice");
4204 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4206 if ((Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) && kvfilen
> 0) {
4207 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4210 ERR("out of memory\n");
4215 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4217 if (NT_SUCCESS(Status
)) {
4218 if ((kvfi
->Type
== REG_SZ
|| kvfi
->Type
== REG_EXPAND_SZ
) && kvfi
->DataLength
>= sizeof(WCHAR
)) {
4219 log_device
.Length
= log_device
.MaximumLength
= kvfi
->DataLength
;
4220 log_device
.Buffer
= ExAllocatePoolWithTag(PagedPool
, kvfi
->DataLength
, ALLOC_TAG
);
4222 if (!log_device
.Buffer
) {
4223 ERR("out of memory\n");
4229 RtlCopyMemory(log_device
.Buffer
, ((UINT8
*)kvfi
) + kvfi
->DataOffset
, kvfi
->DataLength
);
4231 if (log_device
.Buffer
[(log_device
.Length
/ sizeof(WCHAR
)) - 1] == 0)
4232 log_device
.Length
-= sizeof(WCHAR
);
4234 ERR("LogDevice was type %u, length %u\n", kvfi
->Type
, kvfi
->DataLength
);
4236 Status
= ZwDeleteValueKey(h
, &us
);
4237 if (!NT_SUCCESS(Status
)) {
4238 ERR("ZwDeleteValueKey returned %08x\n", Status
);
4244 } else if (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) {
4245 ERR("ZwQueryValueKey returned %08x\n", Status
);
4248 RtlInitUnicodeString(&us
, L
"LogFile");
4252 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4254 if ((Status
== STATUS_BUFFER_TOO_SMALL
|| Status
== STATUS_BUFFER_OVERFLOW
) && kvfilen
> 0) {
4255 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
4258 ERR("out of memory\n");
4263 Status
= ZwQueryValueKey(h
, &us
, KeyValueFullInformation
, kvfi
, kvfilen
, &kvfilen
);
4265 if (NT_SUCCESS(Status
)) {
4266 if ((kvfi
->Type
== REG_SZ
|| kvfi
->Type
== REG_EXPAND_SZ
) && kvfi
->DataLength
>= sizeof(WCHAR
)) {
4267 log_file
.Length
= log_file
.MaximumLength
= kvfi
->DataLength
;
4268 log_file
.Buffer
= ExAllocatePoolWithTag(PagedPool
, kvfi
->DataLength
, ALLOC_TAG
);
4270 if (!log_file
.Buffer
) {
4271 ERR("out of memory\n");
4277 RtlCopyMemory(log_file
.Buffer
, ((UINT8
*)kvfi
) + kvfi
->DataOffset
, kvfi
->DataLength
);
4279 if (log_file
.Buffer
[(log_file
.Length
/ sizeof(WCHAR
)) - 1] == 0)
4280 log_file
.Length
-= sizeof(WCHAR
);
4282 ERR("LogFile was type %u, length %u\n", kvfi
->Type
, kvfi
->DataLength
);
4284 Status
= ZwDeleteValueKey(h
, &us
);
4285 if (!NT_SUCCESS(Status
)) {
4286 ERR("ZwDeleteValueKey returned %08x\n", Status
);
4292 } else if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
) {
4293 Status
= ZwSetValueKey(h
, &us
, 0, REG_SZ
, def_log_file
, (wcslen(def_log_file
) + 1) * sizeof(WCHAR
));
4295 if (!NT_SUCCESS(Status
)) {
4296 ERR("ZwSetValueKey returned %08x\n", Status
);
4299 ERR("ZwQueryValueKey returned %08x\n", Status
);
4302 if (log_file
.Length
== 0) {
4303 log_file
.Length
= log_file
.MaximumLength
= wcslen(def_log_file
) * sizeof(WCHAR
);
4304 log_file
.Buffer
= ExAllocatePoolWithTag(PagedPool
, log_file
.MaximumLength
, ALLOC_TAG
);
4306 if (!log_file
.Buffer
) {
4307 ERR("out of memory\n");
4312 RtlCopyMemory(log_file
.Buffer
, def_log_file
, log_file
.Length
);
4320 static void init_logging() {
4321 if (log_device
.Length
> 0)
4323 else if (log_file
.Length
> 0) {
4325 OBJECT_ATTRIBUTES oa
;
4326 IO_STATUS_BLOCK iosb
;
4331 InitializeObjectAttributes(&oa
, &log_file
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
4333 Status
= ZwCreateFile(&log_handle
, FILE_WRITE_DATA
, &oa
, &iosb
, NULL
, FILE_ATTRIBUTE_NORMAL
, FILE_SHARE_READ
,
4334 FILE_OPEN_IF
, FILE_NON_DIRECTORY_FILE
| FILE_WRITE_THROUGH
| FILE_SYNCHRONOUS_IO_ALERT
, NULL
, 0);
4336 if (!NT_SUCCESS(Status
)) {
4337 ERR("ZwCreateFile returned %08x\n", Status
);
4341 if (iosb
.Information
== FILE_OPENED
) { // already exists
4342 FILE_STANDARD_INFORMATION fsi
;
4343 FILE_POSITION_INFORMATION fpi
;
4345 static char delim
[] = "\n---\n";
4347 // move to end of file
4349 Status
= ZwQueryInformationFile(log_handle
, &iosb
, &fsi
, sizeof(FILE_STANDARD_INFORMATION
), FileStandardInformation
);
4351 if (!NT_SUCCESS(Status
)) {
4352 ERR("ZwQueryInformationFile returned %08x\n", Status
);
4356 fpi
.CurrentByteOffset
= fsi
.EndOfFile
;
4358 Status
= ZwSetInformationFile(log_handle
, &iosb
, &fpi
, sizeof(FILE_POSITION_INFORMATION
), FilePositionInformation
);
4360 if (!NT_SUCCESS(Status
)) {
4361 ERR("ZwSetInformationFile returned %08x\n", Status
);
4365 Status
= ZwWriteFile(log_handle
, NULL
, NULL
, NULL
, &iosb
, delim
, strlen(delim
), NULL
, NULL
);
4367 if (!NT_SUCCESS(Status
)) {
4368 ERR("ZwWriteFile returned %08x\n", Status
);
4373 dateline
= ExAllocatePoolWithTag(PagedPool
, 256, ALLOC_TAG
);
4376 ERR("out of memory\n");
4380 KeQuerySystemTime(&time
);
4382 RtlTimeToTimeFields(&time
, &tf
);
4384 sprintf(dateline
, "Starting logging at %04u-%02u-%02u %02u:%02u:%02u\n", tf
.Year
, tf
.Month
, tf
.Day
, tf
.Hour
, tf
.Minute
, tf
.Second
);
4386 Status
= ZwWriteFile(log_handle
, NULL
, NULL
, NULL
, &iosb
, dateline
, strlen(dateline
), NULL
, NULL
);
4388 if (!NT_SUCCESS(Status
)) {
4389 ERR("ZwWriteFile returned %08x\n", Status
);
4393 ExFreePool(dateline
);
4398 NTSTATUS STDCALL
DriverEntry(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
) {
4400 PDEVICE_OBJECT DeviceObject
;
4401 UNICODE_STRING device_nameW
;
4402 UNICODE_STRING dosdevice_nameW
;
4404 InitializeListHead(&uid_map_list
);
4406 log_device
.Buffer
= NULL
;
4407 log_device
.Length
= log_device
.MaximumLength
= 0;
4408 log_file
.Buffer
= NULL
;
4409 log_file
.Length
= log_file
.MaximumLength
= 0;
4411 read_registry(RegistryPath
);
4414 if (debug_log_level
> 0)
4420 TRACE("DriverEntry\n");
4426 // TRACE("check CRC32C: %08x\n", calc_crc32c((UINT8*)"123456789", 9)); // should be e3069283
4428 drvobj
= DriverObject
;
4430 DriverObject
->DriverUnload
= DriverUnload
;
4432 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = (PDRIVER_DISPATCH
)drv_create
;
4433 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = (PDRIVER_DISPATCH
)drv_close
;
4434 DriverObject
->MajorFunction
[IRP_MJ_READ
] = (PDRIVER_DISPATCH
)drv_read
;
4435 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = (PDRIVER_DISPATCH
)drv_write
;
4436 DriverObject
->MajorFunction
[IRP_MJ_QUERY_INFORMATION
] = (PDRIVER_DISPATCH
)drv_query_information
;
4437 DriverObject
->MajorFunction
[IRP_MJ_SET_INFORMATION
] = (PDRIVER_DISPATCH
)drv_set_information
;
4438 DriverObject
->MajorFunction
[IRP_MJ_QUERY_EA
] = (PDRIVER_DISPATCH
)drv_query_ea
;
4439 DriverObject
->MajorFunction
[IRP_MJ_SET_EA
] = (PDRIVER_DISPATCH
)drv_set_ea
;
4440 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = (PDRIVER_DISPATCH
)drv_flush_buffers
;
4441 DriverObject
->MajorFunction
[IRP_MJ_QUERY_VOLUME_INFORMATION
] = (PDRIVER_DISPATCH
)drv_query_volume_information
;
4442 DriverObject
->MajorFunction
[IRP_MJ_SET_VOLUME_INFORMATION
] = (PDRIVER_DISPATCH
)drv_set_volume_information
;
4443 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = (PDRIVER_DISPATCH
)drv_cleanup
;
4444 DriverObject
->MajorFunction
[IRP_MJ_DIRECTORY_CONTROL
] = (PDRIVER_DISPATCH
)drv_directory_control
;
4445 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = (PDRIVER_DISPATCH
)drv_file_system_control
;
4446 DriverObject
->MajorFunction
[IRP_MJ_LOCK_CONTROL
] = (PDRIVER_DISPATCH
)drv_lock_control
;
4447 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = (PDRIVER_DISPATCH
)drv_device_control
;
4448 DriverObject
->MajorFunction
[IRP_MJ_SHUTDOWN
] = (PDRIVER_DISPATCH
)drv_shutdown
;
4449 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = (PDRIVER_DISPATCH
)drv_pnp
;
4450 DriverObject
->MajorFunction
[IRP_MJ_QUERY_SECURITY
] = (PDRIVER_DISPATCH
)drv_query_security
;
4451 DriverObject
->MajorFunction
[IRP_MJ_SET_SECURITY
] = (PDRIVER_DISPATCH
)drv_set_security
;
4453 init_fast_io_dispatch(&DriverObject
->FastIoDispatch
);
4455 device_nameW
.Buffer
= device_name
;
4456 device_nameW
.Length
= device_nameW
.MaximumLength
= (USHORT
)wcslen(device_name
) * sizeof(WCHAR
);
4457 dosdevice_nameW
.Buffer
= dosdevice_name
;
4458 dosdevice_nameW
.Length
= dosdevice_nameW
.MaximumLength
= (USHORT
)wcslen(dosdevice_name
) * sizeof(WCHAR
);
4460 Status
= IoCreateDevice(DriverObject
, 0, &device_nameW
, FILE_DEVICE_DISK_FILE_SYSTEM
, 0, FALSE
, &DeviceObject
);
4461 if (!NT_SUCCESS(Status
)) {
4462 ERR("IoCreateDevice returned %08x\n", Status
);
4466 devobj
= DeviceObject
;
4468 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
4470 Status
= IoCreateSymbolicLink(&dosdevice_nameW
, &device_nameW
);
4471 if (!NT_SUCCESS(Status
)) {
4472 ERR("IoCreateSymbolicLink returned %08x\n", Status
);
4476 Status
= init_cache();
4477 if (!NT_SUCCESS(Status
)) {
4478 ERR("init_cache returned %08x\n", Status
);
4482 InitializeListHead(&volumes
);
4483 look_for_vols(&volumes
);
4485 InitializeListHead(&VcbList
);
4486 ExInitializeResourceLite(&global_loading_lock
);
4488 IoRegisterFileSystem(DeviceObject
);
4490 return STATUS_SUCCESS
;