[BTRFS]
[reactos.git] / reactos / drivers / filesystems / btrfs / btrfs.c
1 /* Copyright (c) Mark Harmstone 2016
2 *
3 * This file is part of WinBtrfs.
4 *
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.
9 *
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.
14 *
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/>. */
17
18 #ifdef _DEBUG
19 #define DEBUG
20 #endif
21
22 #include "btrfs_drv.h"
23 #ifndef __REACTOS__
24 #ifndef _MSC_VER
25 #include <cpuid.h>
26 #else
27 #include <intrin.h>
28 #endif
29 #endif
30 #include "btrfs.h"
31 #ifndef __REACTOS__
32 #include <winioctl.h>
33 #else
34 #include <rtlfuncs.h>
35 #endif
36
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
40
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};
43
44 PDRIVER_OBJECT drvobj;
45 PDEVICE_OBJECT devobj;
46 #ifndef __REACTOS__
47 BOOL have_sse42 = FALSE;
48 #endif
49 UINT64 num_reads = 0;
50 LIST_ENTRY uid_map_list;
51 LIST_ENTRY volumes;
52 LIST_ENTRY VcbList;
53 ERESOURCE global_loading_lock;
54 UINT32 debug_log_level = 0;
55 BOOL log_started = FALSE;
56 UNICODE_STRING log_device, log_file;
57
58 #ifdef _DEBUG
59 PFILE_OBJECT comfo = NULL;
60 PDEVICE_OBJECT comdo = NULL;
61 HANDLE log_handle = NULL;
62 #endif
63
64 static NTSTATUS STDCALL close_file(device_extension* Vcb, PFILE_OBJECT FileObject);
65
66 typedef struct {
67 KEVENT Event;
68 IO_STATUS_BLOCK iosb;
69 } read_context;
70
71 #ifdef _DEBUG
72 static NTSTATUS STDCALL dbg_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
73 read_context* context = conptr;
74
75 // DbgPrint("dbg_completion\n");
76
77 context->iosb = Irp->IoStatus;
78 KeSetEvent(&context->Event, 0, FALSE);
79
80 // return STATUS_SUCCESS;
81 return STATUS_MORE_PROCESSING_REQUIRED;
82 }
83
84 #ifdef DEBUG_LONG_MESSAGES
85 void STDCALL _debug_message(const char* func, UINT8 priority, const char* file, unsigned int line, char* s, ...) {
86 #else
87 void STDCALL _debug_message(const char* func, UINT8 priority, char* s, ...) {
88 #endif
89 LARGE_INTEGER offset;
90 PIO_STACK_LOCATION IrpSp;
91 NTSTATUS Status;
92 PIRP Irp;
93 va_list ap;
94 char *buf2 = NULL, *buf;
95 read_context* context = NULL;
96 UINT32 length;
97
98 if (log_started && priority > debug_log_level)
99 return;
100
101 buf2 = ExAllocatePoolWithTag(NonPagedPool, 1024, ALLOC_TAG);
102
103 if (!buf2) {
104 DbgPrint("Couldn't allocate buffer in debug_message\n");
105 return;
106 }
107
108 #ifdef DEBUG_LONG_MESSAGES
109 sprintf(buf2, "%p:%s:%s:%u:", PsGetCurrentThreadId(), func, file, line);
110 #else
111 sprintf(buf2, "%p:%s:", PsGetCurrentThreadId(), func);
112 #endif
113 buf = &buf2[strlen(buf2)];
114
115 va_start(ap, s);
116 vsprintf(buf, s, ap);
117
118 if (!log_started || (log_device.Length == 0 && log_file.Length == 0)) {
119 DbgPrint(buf2);
120 } else if (log_device.Length > 0) {
121 if (!comdo) {
122 DbgPrint("comdo is NULL :-(\n");
123 DbgPrint(buf2);
124 goto exit2;
125 }
126
127 length = (UINT32)strlen(buf2);
128
129 offset.u.LowPart = 0;
130 offset.u.HighPart = 0;
131
132 context = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_context), ALLOC_TAG);
133 if (!context) {
134 DbgPrint("Couldn't allocate context in debug_message\n");
135 return;
136 }
137
138 RtlZeroMemory(context, sizeof(read_context));
139
140 KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
141
142 // status = ZwWriteFile(comh, NULL, NULL, NULL, &io, buf2, strlen(buf2), &offset, NULL);
143
144 Irp = IoAllocateIrp(comdo->StackSize, FALSE);
145
146 if (!Irp) {
147 DbgPrint("IoAllocateIrp failed\n");
148 goto exit2;
149 }
150
151 IrpSp = IoGetNextIrpStackLocation(Irp);
152 IrpSp->MajorFunction = IRP_MJ_WRITE;
153
154 if (comdo->Flags & DO_BUFFERED_IO) {
155 Irp->AssociatedIrp.SystemBuffer = buf2;
156
157 Irp->Flags = IRP_BUFFERED_IO;
158 } else if (comdo->Flags & DO_DIRECT_IO) {
159 Irp->MdlAddress = IoAllocateMdl(buf2, length, FALSE, FALSE, NULL);
160 if (!Irp->MdlAddress) {
161 DbgPrint("IoAllocateMdl failed\n");
162 goto exit;
163 }
164
165 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoWriteAccess);
166 } else {
167 Irp->UserBuffer = buf2;
168 }
169
170 IrpSp->Parameters.Write.Length = length;
171 IrpSp->Parameters.Write.ByteOffset = offset;
172
173 Irp->UserIosb = &context->iosb;
174
175 Irp->UserEvent = &context->Event;
176
177 IoSetCompletionRoutine(Irp, dbg_completion, context, TRUE, TRUE, TRUE);
178
179 Status = IoCallDriver(comdo, Irp);
180
181 if (Status == STATUS_PENDING) {
182 KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
183 Status = context->iosb.Status;
184 }
185
186 if (comdo->Flags & DO_DIRECT_IO) {
187 MmUnlockPages(Irp->MdlAddress);
188 IoFreeMdl(Irp->MdlAddress);
189 }
190
191 if (!NT_SUCCESS(Status)) {
192 DbgPrint("failed to write to COM1 - error %08x\n", Status);
193 goto exit;
194 }
195
196 exit:
197 IoFreeIrp(Irp);
198 } else if (log_handle != NULL) {
199 IO_STATUS_BLOCK iosb;
200
201 length = (UINT32)strlen(buf2);
202
203 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, buf2, length, NULL, NULL);
204
205 if (!NT_SUCCESS(Status)) {
206 DbgPrint("failed to write to file - error %08x\n", Status);
207 }
208 }
209
210 exit2:
211 va_end(ap);
212
213 if (context)
214 ExFreePool(context);
215
216 if (buf2)
217 ExFreePool(buf2);
218 }
219 #endif
220
221 ULONG sector_align( ULONG NumberToBeAligned, ULONG Alignment )
222 {
223 if( Alignment & ( Alignment - 1 ) )
224 {
225 //
226 // Alignment not a power of 2
227 // Just returning
228 //
229 return NumberToBeAligned;
230 }
231 if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 )
232 {
233 NumberToBeAligned = NumberToBeAligned + Alignment;
234 NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) );
235 }
236 return NumberToBeAligned;
237 }
238
239 int keycmp(const KEY* key1, const KEY* key2) {
240 if (key1->obj_id < key2->obj_id) {
241 return -1;
242 } else if (key1->obj_id > key2->obj_id) {
243 return 1;
244 }
245
246 if (key1->obj_type < key2->obj_type) {
247 return -1;
248 } else if (key1->obj_type > key2->obj_type) {
249 return 1;
250 }
251
252 if (key1->offset < key2->offset) {
253 return -1;
254 } else if (key1->offset > key2->offset) {
255 return 1;
256 }
257
258 return 0;
259 }
260
261 BOOL is_top_level(PIRP Irp) {
262 if (!IoGetTopLevelIrp()) {
263 IoSetTopLevelIrp(Irp);
264 return TRUE;
265 }
266
267 return FALSE;
268 }
269
270 static void STDCALL DriverUnload(PDRIVER_OBJECT DriverObject) {
271 UNICODE_STRING dosdevice_nameW;
272
273 ERR("DriverUnload\n");
274
275 free_cache();
276
277 IoUnregisterFileSystem(DriverObject->DeviceObject);
278
279 dosdevice_nameW.Buffer = dosdevice_name;
280 dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR);
281
282 IoDeleteSymbolicLink(&dosdevice_nameW);
283 IoDeleteDevice(DriverObject->DeviceObject);
284
285 while (!IsListEmpty(&uid_map_list)) {
286 LIST_ENTRY* le = RemoveHeadList(&uid_map_list);
287 uid_map* um = CONTAINING_RECORD(le, uid_map, listentry);
288
289 ExFreePool(um->sid);
290
291 ExFreePool(um);
292 }
293
294 // FIXME - free volumes and their devpaths
295
296 #ifdef _DEBUG
297 if (comfo)
298 ObDereferenceObject(comfo);
299
300 if (log_handle)
301 ZwClose(log_handle);
302 #endif
303
304 ExDeleteResourceLite(&global_loading_lock);
305
306 if (log_device.Buffer)
307 ExFreePool(log_device.Buffer);
308
309 if (log_file.Buffer)
310 ExFreePool(log_file.Buffer);
311 }
312
313 BOOL STDCALL get_last_inode(device_extension* Vcb, root* r) {
314 KEY searchkey;
315 traverse_ptr tp, prev_tp;
316 NTSTATUS Status;
317
318 // get last entry
319 searchkey.obj_id = 0xffffffffffffffff;
320 searchkey.obj_type = 0xff;
321 searchkey.offset = 0xffffffffffffffff;
322
323 Status = find_item(Vcb, r, &tp, &searchkey, FALSE);
324 if (!NT_SUCCESS(Status)) {
325 ERR("error - find_item returned %08x\n", Status);
326 return FALSE;
327 }
328
329 while (find_prev_item(Vcb, &tp, &prev_tp, FALSE)) {
330 free_traverse_ptr(&tp);
331 tp = prev_tp;
332
333 TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
334
335 if (tp.item->key.obj_type == TYPE_INODE_ITEM) {
336 r->lastinode = tp.item->key.obj_id;
337 free_traverse_ptr(&tp);
338 TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode);
339 return TRUE;
340 }
341 }
342
343 free_traverse_ptr(&tp);
344
345 r->lastinode = SUBVOL_ROOT_INODE;
346
347 WARN("no INODE_ITEMs in tree %llx\n", r->id);
348
349 return TRUE;
350 }
351
352 BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen) {
353 KEY searchkey;
354 traverse_ptr tp;
355 DIR_ITEM* xa;
356 ULONG size, xasize;
357 NTSTATUS Status;
358
359 TRACE("(%p, %llx, %llx, %s, %08x, %p, %p)\n", Vcb, subvol->id, inode, name, crc32, data, datalen);
360
361 searchkey.obj_id = inode;
362 searchkey.obj_type = TYPE_XATTR_ITEM;
363 searchkey.offset = crc32;
364
365 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
366 if (!NT_SUCCESS(Status)) {
367 ERR("error - find_item returned %08x\n", Status);
368 return FALSE;
369 }
370
371 if (keycmp(&tp.item->key, &searchkey)) {
372 TRACE("could not find item (%llx,%x,%llx)\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
373 free_traverse_ptr(&tp);
374 return FALSE;
375 }
376
377 if (tp.item->size < sizeof(DIR_ITEM)) {
378 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));
379 free_traverse_ptr(&tp);
380 return FALSE;
381 }
382
383 xa = (DIR_ITEM*)tp.item->data;
384 size = tp.item->size;
385
386 while (TRUE) {
387 if (size < sizeof(DIR_ITEM) || size < (sizeof(DIR_ITEM) - 1 + xa->m + xa->n)) {
388 WARN("(%llx,%x,%llx) is truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
389 free_traverse_ptr(&tp);
390 return FALSE;
391 }
392
393 if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) {
394 TRACE("found xattr %s in (%llx,%x,%llx)\n", name, searchkey.obj_id, searchkey.obj_type, searchkey.offset);
395
396 *datalen = xa->m;
397
398 if (xa->m > 0) {
399 *data = ExAllocatePoolWithTag(PagedPool, xa->m, ALLOC_TAG);
400 if (!*data) {
401 ERR("out of memory\n");
402 free_traverse_ptr(&tp);
403 return FALSE;
404 }
405
406 RtlCopyMemory(*data, &xa->name[xa->n], xa->m);
407 } else
408 *data = NULL;
409
410 free_traverse_ptr(&tp);
411 return TRUE;
412 }
413
414 xasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n;
415
416 if (size > xasize) {
417 size -= xasize;
418 xa = (DIR_ITEM*)&xa->name[xa->m + xa->n];
419 } else
420 break;
421 }
422
423 TRACE("xattr %s not found in (%llx,%x,%llx)\n", name, searchkey.obj_id, searchkey.obj_type, searchkey.offset);
424
425 free_traverse_ptr(&tp);
426
427 return FALSE;
428 }
429
430 NTSTATUS STDCALL set_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8* data, UINT16 datalen, LIST_ENTRY* rollback) {
431 KEY searchkey;
432 traverse_ptr tp;
433 ULONG xasize;
434 DIR_ITEM* xa;
435 NTSTATUS Status;
436
437 TRACE("(%p, %llx, %llx, %s, %08x, %p, %u)\n", Vcb, subvol->id, inode, name, crc32, data, datalen);
438
439 searchkey.obj_id = inode;
440 searchkey.obj_type = TYPE_XATTR_ITEM;
441 searchkey.offset = crc32;
442
443 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
444 if (!NT_SUCCESS(Status)) {
445 ERR("error - find_item returned %08x\n", Status);
446 return Status;
447 }
448
449 xasize = sizeof(DIR_ITEM) - 1 + (ULONG)strlen(name) + datalen;
450
451 if (!keycmp(&tp.item->key, &searchkey)) { // key exists
452 UINT8* newdata;
453 ULONG size = tp.item->size;
454
455 xa = (DIR_ITEM*)tp.item->data;
456
457 if (tp.item->size < sizeof(DIR_ITEM)) {
458 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));
459 } else {
460 while (TRUE) {
461 ULONG oldxasize;
462
463 if (size < sizeof(DIR_ITEM) || size < sizeof(DIR_ITEM) - 1 + xa->m + xa->n) {
464 ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
465 break;
466 }
467
468 oldxasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n;
469
470 if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) {
471 UINT64 pos;
472
473 // replace
474 newdata = ExAllocatePoolWithTag(PagedPool, tp.item->size + xasize - oldxasize, ALLOC_TAG);
475 if (!newdata) {
476 ERR("out of memory\n");
477 free_traverse_ptr(&tp);
478 return STATUS_INSUFFICIENT_RESOURCES;
479 }
480
481 pos = (UINT8*)xa - tp.item->data;
482 if (pos + oldxasize < tp.item->size) { // copy after changed xattr
483 RtlCopyMemory(newdata + pos + xasize, tp.item->data + pos + oldxasize, tp.item->size - pos - oldxasize);
484 }
485
486 if (pos > 0) { // copy before changed xattr
487 RtlCopyMemory(newdata, tp.item->data, pos);
488 xa = (DIR_ITEM*)(newdata + pos);
489 } else
490 xa = (DIR_ITEM*)newdata;
491
492 xa->key.obj_id = 0;
493 xa->key.obj_type = 0;
494 xa->key.offset = 0;
495 xa->transid = Vcb->superblock.generation;
496 xa->m = datalen;
497 xa->n = (UINT16)strlen(name);
498 xa->type = BTRFS_TYPE_EA;
499 RtlCopyMemory(xa->name, name, strlen(name));
500 RtlCopyMemory(xa->name + strlen(name), data, datalen);
501
502 delete_tree_item(Vcb, &tp, rollback);
503 insert_tree_item(Vcb, subvol, inode, TYPE_XATTR_ITEM, crc32, newdata, tp.item->size + xasize - oldxasize, NULL, rollback);
504
505 break;
506 }
507
508 if (xa->m + xa->n >= size) { // FIXME - test this works
509 // not found, add to end of data
510 newdata = ExAllocatePoolWithTag(PagedPool, tp.item->size + xasize, ALLOC_TAG);
511 if (!newdata) {
512 ERR("out of memory\n");
513 free_traverse_ptr(&tp);
514 return STATUS_INSUFFICIENT_RESOURCES;
515 }
516
517 RtlCopyMemory(newdata, tp.item->data, tp.item->size);
518
519 xa = (DIR_ITEM*)((UINT8*)newdata + tp.item->size);
520 xa->key.obj_id = 0;
521 xa->key.obj_type = 0;
522 xa->key.offset = 0;
523 xa->transid = Vcb->superblock.generation;
524 xa->m = datalen;
525 xa->n = (UINT16)strlen(name);
526 xa->type = BTRFS_TYPE_EA;
527 RtlCopyMemory(xa->name, name, strlen(name));
528 RtlCopyMemory(xa->name + strlen(name), data, datalen);
529
530 delete_tree_item(Vcb, &tp, rollback);
531 insert_tree_item(Vcb, subvol, inode, TYPE_XATTR_ITEM, crc32, newdata, tp.item->size + xasize, NULL, rollback);
532
533 break;
534 } else {
535 xa = (DIR_ITEM*)&xa->name[xa->m + xa->n];
536 size -= oldxasize;
537 }
538 }
539 }
540 } else {
541 // add new DIR_ITEM struct
542
543 xa = ExAllocatePoolWithTag(PagedPool, xasize, ALLOC_TAG);
544 if (!xa) {
545 ERR("out of memory\n");
546 free_traverse_ptr(&tp);
547 return STATUS_INSUFFICIENT_RESOURCES;
548 }
549
550 xa->key.obj_id = 0;
551 xa->key.obj_type = 0;
552 xa->key.offset = 0;
553 xa->transid = Vcb->superblock.generation;
554 xa->m = datalen;
555 xa->n = (UINT16)strlen(name);
556 xa->type = BTRFS_TYPE_EA;
557 RtlCopyMemory(xa->name, name, strlen(name));
558 RtlCopyMemory(xa->name + strlen(name), data, datalen);
559
560 insert_tree_item(Vcb, subvol, inode, TYPE_XATTR_ITEM, crc32, xa, xasize, NULL, rollback);
561 }
562
563 free_traverse_ptr(&tp);
564
565 return STATUS_SUCCESS;
566 }
567
568 BOOL STDCALL delete_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, LIST_ENTRY* rollback) {
569 KEY searchkey;
570 traverse_ptr tp;
571 DIR_ITEM* xa;
572 NTSTATUS Status;
573
574 TRACE("(%p, %llx, %llx, %s, %08x)\n", Vcb, subvol->id, inode, name, crc32);
575
576 searchkey.obj_id = inode;
577 searchkey.obj_type = TYPE_XATTR_ITEM;
578 searchkey.offset = crc32;
579
580 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
581 if (!NT_SUCCESS(Status)) {
582 ERR("error - find_item returned %08x\n", Status);
583 return FALSE;
584 }
585
586 if (!keycmp(&tp.item->key, &searchkey)) { // key exists
587 ULONG size = tp.item->size;
588
589 if (tp.item->size < sizeof(DIR_ITEM)) {
590 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));
591
592 free_traverse_ptr(&tp);
593 return FALSE;
594 } else {
595 xa = (DIR_ITEM*)tp.item->data;
596
597 while (TRUE) {
598 ULONG oldxasize;
599
600 if (size < sizeof(DIR_ITEM) || size < sizeof(DIR_ITEM) - 1 + xa->m + xa->n) {
601 ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
602 free_traverse_ptr(&tp);
603
604 return FALSE;
605 }
606
607 oldxasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n;
608
609 if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) {
610 ULONG newsize;
611 UINT8 *newdata, *dioff;
612
613 newsize = tp.item->size - (sizeof(DIR_ITEM) - 1 + xa->n + xa->m);
614
615 delete_tree_item(Vcb, &tp, rollback);
616
617 if (newsize == 0) {
618 TRACE("xattr %s deleted\n", name);
619 free_traverse_ptr(&tp);
620
621 return TRUE;
622 }
623
624 // FIXME - deleting collisions almost certainly works, but we should test it properly anyway
625 newdata = ExAllocatePoolWithTag(PagedPool, newsize, ALLOC_TAG);
626 if (!newdata) {
627 ERR("out of memory\n");
628 free_traverse_ptr(&tp);
629 return FALSE;
630 }
631
632 if ((UINT8*)xa > tp.item->data) {
633 RtlCopyMemory(newdata, tp.item->data, (UINT8*)xa - tp.item->data);
634 dioff = newdata + ((UINT8*)xa - tp.item->data);
635 } else {
636 dioff = newdata;
637 }
638
639 if ((UINT8*)&xa->name[xa->n+xa->m] - tp.item->data < tp.item->size)
640 RtlCopyMemory(dioff, &xa->name[xa->n+xa->m], tp.item->size - ((UINT8*)&xa->name[xa->n+xa->m] - tp.item->data));
641
642 insert_tree_item(Vcb, subvol, inode, TYPE_XATTR_ITEM, crc32, newdata, newsize, NULL, rollback);
643
644 free_traverse_ptr(&tp);
645
646 return TRUE;
647 }
648
649 if (xa->m + xa->n >= size) { // FIXME - test this works
650 WARN("xattr %s not found\n", name);
651 free_traverse_ptr(&tp);
652
653 return FALSE;
654 } else {
655 xa = (DIR_ITEM*)&xa->name[xa->m + xa->n];
656 size -= oldxasize;
657 }
658 }
659 }
660 } else {
661 WARN("xattr %s not found\n", name);
662 free_traverse_ptr(&tp);
663
664 return FALSE;
665 }
666 }
667
668 NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, LIST_ENTRY* rollback) {
669 KEY searchkey;
670 traverse_ptr tp;
671 UINT8* di2;
672 NTSTATUS Status;
673
674 searchkey.obj_id = inode;
675 searchkey.obj_type = TYPE_DIR_ITEM;
676 searchkey.offset = crc32;
677
678 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
679 if (!NT_SUCCESS(Status)) {
680 ERR("error - find_item returned %08x\n", Status);
681 return Status;
682 }
683
684 if (!keycmp(&tp.item->key, &searchkey)) {
685 ULONG maxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node);
686
687 if (tp.item->size + disize > maxlen) {
688 WARN("DIR_ITEM was longer than maxlen (%u + %u > %u)\n", tp.item->size, disize, maxlen);
689 free_traverse_ptr(&tp);
690 return STATUS_INTERNAL_ERROR;
691 }
692
693 di2 = ExAllocatePoolWithTag(PagedPool, tp.item->size + disize, ALLOC_TAG);
694 if (!di2) {
695 ERR("out of memory\n");
696 free_traverse_ptr(&tp);
697 return STATUS_INSUFFICIENT_RESOURCES;
698 }
699
700 if (tp.item->size > 0)
701 RtlCopyMemory(di2, tp.item->data, tp.item->size);
702
703 RtlCopyMemory(di2 + tp.item->size, di, disize);
704
705 delete_tree_item(Vcb, &tp, rollback);
706
707 insert_tree_item(Vcb, subvol, inode, TYPE_DIR_ITEM, crc32, di2, tp.item->size + disize, NULL, rollback);
708
709 ExFreePool(di);
710 } else {
711 insert_tree_item(Vcb, subvol, inode, TYPE_DIR_ITEM, crc32, di, disize, NULL, rollback);
712 }
713
714 free_traverse_ptr(&tp);
715
716 return STATUS_SUCCESS;
717 }
718
719 UINT64 find_next_dir_index(device_extension* Vcb, root* subvol, UINT64 inode) {
720 KEY searchkey;
721 traverse_ptr tp, prev_tp;
722 UINT64 dirpos;
723 NTSTATUS Status;
724
725 searchkey.obj_id = inode;
726 searchkey.obj_type = TYPE_DIR_INDEX + 1;
727 searchkey.offset = 0;
728
729 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
730 if (!NT_SUCCESS(Status)) {
731 ERR("error - find_item returned %08x\n", Status);
732 return 0;
733 }
734
735 if (!keycmp(&searchkey, &tp.item->key)) {
736 if (!find_prev_item(Vcb, &tp, &prev_tp, FALSE)) {
737 free_traverse_ptr(&tp);
738 tp = prev_tp;
739
740 TRACE("moving back to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
741 }
742 }
743
744 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == TYPE_DIR_INDEX) {
745 dirpos = tp.item->key.offset + 1;
746 } else
747 dirpos = 2;
748
749 free_traverse_ptr(&tp);
750
751 return dirpos;
752 }
753
754 static NTSTATUS STDCALL drv_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
755 NTSTATUS Status;
756 PIO_STACK_LOCATION IrpSp;
757 BOOL top_level;
758
759 TRACE("close\n");
760
761 FsRtlEnterFileSystem();
762
763 top_level = is_top_level(Irp);
764
765 if (DeviceObject == devobj) {
766 TRACE("Closing file system\n");
767 Status = STATUS_SUCCESS;
768 goto exit;
769 }
770
771 IrpSp = IoGetCurrentIrpStackLocation(Irp);
772
773 // FIXME - unmount if called for volume
774 // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
775
776 Status = close_file(DeviceObject->DeviceExtension, IrpSp->FileObject);
777
778 exit:
779 Irp->IoStatus.Status = Status;
780 Irp->IoStatus.Information = 0;
781
782 IoCompleteRequest( Irp, IO_DISK_INCREMENT );
783
784 if (top_level)
785 IoSetTopLevelIrp(NULL);
786
787 FsRtlExitFileSystem();
788
789 TRACE("returning %08x\n", Status);
790
791 return Status;
792 }
793
794 static NTSTATUS STDCALL drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
795 NTSTATUS Status;
796 BOOL top_level;
797
798 FsRtlEnterFileSystem();
799
800 top_level = is_top_level(Irp);
801
802 // ERR("recursive = %s\n", Irp != IoGetTopLevelIrp() ? "TRUE" : "FALSE");
803
804 Status = write_file(DeviceObject, Irp);
805
806 Irp->IoStatus.Status = Status;
807
808 TRACE("wrote %u bytes\n", Irp->IoStatus.Information);
809
810 if (Status != STATUS_PENDING)
811 IoCompleteRequest(Irp, IO_NO_INCREMENT);
812
813 if (top_level)
814 IoSetTopLevelIrp(NULL);
815
816 FsRtlExitFileSystem();
817
818 TRACE("returning %08x\n", Status);
819
820 return Status;
821 }
822
823 static NTSTATUS STDCALL drv_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
824 NTSTATUS Status;
825 BOOL top_level;
826
827 FsRtlEnterFileSystem();
828
829 top_level = is_top_level(Irp);
830
831 FIXME("STUB: query ea\n");
832 Status = STATUS_NOT_IMPLEMENTED;
833
834 Irp->IoStatus.Status = Status;
835 Irp->IoStatus.Information = 0;
836
837 IoCompleteRequest( Irp, IO_NO_INCREMENT );
838
839 if (top_level)
840 IoSetTopLevelIrp(NULL);
841
842 FsRtlExitFileSystem();
843
844 return Status;
845 }
846
847 static NTSTATUS STDCALL drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
848 NTSTATUS Status;
849 device_extension* Vcb = DeviceObject->DeviceExtension;
850 BOOL top_level;
851
852 FsRtlEnterFileSystem();
853
854 top_level = is_top_level(Irp);
855
856 FIXME("STUB: set ea\n");
857 Status = STATUS_NOT_IMPLEMENTED;
858
859 if (Vcb->readonly)
860 Status = STATUS_MEDIA_WRITE_PROTECTED;
861
862 // FIXME - return STATUS_ACCESS_DENIED if subvol readonly
863
864 Irp->IoStatus.Status = Status;
865 Irp->IoStatus.Information = 0;
866
867 IoCompleteRequest( Irp, IO_NO_INCREMENT );
868
869 if (top_level)
870 IoSetTopLevelIrp(NULL);
871
872 FsRtlExitFileSystem();
873
874 return Status;
875 }
876
877 static NTSTATUS STDCALL drv_flush_buffers(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
878 NTSTATUS Status;
879 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
880 PFILE_OBJECT FileObject = IrpSp->FileObject;
881 fcb* fcb = FileObject->FsContext;
882 BOOL top_level;
883
884 TRACE("flush buffers\n");
885
886 FsRtlEnterFileSystem();
887
888 top_level = is_top_level(Irp);
889
890 Status = STATUS_SUCCESS;
891 Irp->IoStatus.Status = Status;
892 Irp->IoStatus.Information = 0;
893
894 if (fcb->type != BTRFS_TYPE_DIRECTORY) {
895 CcFlushCache(&fcb->nonpaged->segment_object, NULL, 0, &Irp->IoStatus);
896
897 if (fcb->Header.PagingIoResource) {
898 ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
899 ExReleaseResourceLite(fcb->Header.PagingIoResource);
900 }
901
902 Status = Irp->IoStatus.Status;
903 }
904
905 IoCompleteRequest(Irp, IO_NO_INCREMENT);
906
907 if (top_level)
908 IoSetTopLevelIrp(NULL);
909
910 FsRtlExitFileSystem();
911
912 return Status;
913 }
914
915 static NTSTATUS STDCALL drv_query_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
916 PIO_STACK_LOCATION IrpSp;
917 NTSTATUS Status;
918 ULONG BytesCopied = 0;
919 device_extension* Vcb = DeviceObject->DeviceExtension;
920 BOOL top_level;
921
922 #ifndef __REACTOS__
923 // An unfortunate necessity - we have to lie about our FS type. MPR!MprGetConnection polls for this,
924 // and compares it to a whitelist. If it doesn't match, it will return ERROR_NO_NET_OR_BAD_PATH,
925 // which prevents UAC from working.
926 // FIXME - only lie if we detect that we're being called by mpr.dll
927
928 WCHAR* fs_name = L"NTFS";
929 ULONG fs_name_len = 4 * sizeof(WCHAR);
930 #else
931 WCHAR* fs_name = L"Btrfs";
932 ULONG fs_name_len = 5 * sizeof(WCHAR);
933 #endif
934
935 TRACE("query volume information\n");
936
937 FsRtlEnterFileSystem();
938 top_level = is_top_level(Irp);
939
940 IrpSp = IoGetCurrentIrpStackLocation(Irp);
941
942 Status = STATUS_NOT_IMPLEMENTED;
943
944 switch (IrpSp->Parameters.QueryVolume.FsInformationClass) {
945 case FileFsAttributeInformation:
946 {
947 FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
948 BOOL overflow = FALSE;
949 ULONG orig_fs_name_len = fs_name_len;
950
951 TRACE("FileFsAttributeInformation\n");
952
953 if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len) {
954 if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR))
955 fs_name_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + sizeof(WCHAR);
956 else
957 fs_name_len = 0;
958
959 overflow = TRUE;
960 }
961
962 data->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH |
963 FILE_UNICODE_ON_DISK | FILE_NAMED_STREAMS | FILE_SUPPORTS_HARD_LINKS | FILE_PERSISTENT_ACLS |
964 FILE_SUPPORTS_REPARSE_POINTS;
965 if (Vcb->readonly)
966 data->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
967
968 // should also be FILE_FILE_COMPRESSION when supported
969 data->MaximumComponentNameLength = 255; // FIXME - check
970 data->FileSystemNameLength = orig_fs_name_len;
971 RtlCopyMemory(data->FileSystemName, fs_name, fs_name_len);
972
973 BytesCopied = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len;
974 Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
975 break;
976 }
977
978 case FileFsControlInformation:
979 FIXME("STUB: FileFsControlInformation\n");
980 break;
981
982 case FileFsDeviceInformation:
983 FIXME("STUB: FileFsDeviceInformation\n");
984 break;
985
986 case FileFsDriverPathInformation:
987 FIXME("STUB: FileFsDriverPathInformation\n");
988 break;
989
990 case FileFsFullSizeInformation:
991 {
992 FILE_FS_FULL_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer;
993 UINT64 totalsize, freespace;
994
995 TRACE("FileFsFullSizeInformation\n");
996
997 // FIXME - calculate correctly for RAID
998 totalsize = Vcb->superblock.total_bytes / Vcb->superblock.sector_size;
999 freespace = (Vcb->superblock.total_bytes - Vcb->superblock.bytes_used) / Vcb->superblock.sector_size;
1000
1001 ffsi->TotalAllocationUnits.QuadPart = totalsize;
1002 ffsi->ActualAvailableAllocationUnits.QuadPart = freespace;
1003 ffsi->CallerAvailableAllocationUnits.QuadPart = ffsi->ActualAvailableAllocationUnits.QuadPart;
1004 ffsi->SectorsPerAllocationUnit = 1;
1005 ffsi->BytesPerSector = Vcb->superblock.sector_size;
1006
1007 BytesCopied = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
1008 Status = STATUS_SUCCESS;
1009
1010 break;
1011 }
1012
1013 case FileFsObjectIdInformation:
1014 FIXME("STUB: FileFsObjectIdInformation\n");
1015 break;
1016
1017 case FileFsSizeInformation:
1018 {
1019 FILE_FS_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer;
1020 UINT64 totalsize, freespace;
1021
1022 TRACE("FileFsSizeInformation\n");
1023
1024 // FIXME - calculate correctly for RAID
1025 // FIXME - is this returning the right free space?
1026 totalsize = Vcb->superblock.dev_item.num_bytes / Vcb->superblock.sector_size;
1027 freespace = (Vcb->superblock.dev_item.num_bytes - Vcb->superblock.dev_item.bytes_used) / Vcb->superblock.sector_size;
1028
1029 ffsi->TotalAllocationUnits.QuadPart = totalsize;
1030 ffsi->AvailableAllocationUnits.QuadPart = freespace;
1031 ffsi->SectorsPerAllocationUnit = 1;
1032 ffsi->BytesPerSector = Vcb->superblock.sector_size;
1033
1034 BytesCopied = sizeof(FILE_FS_SIZE_INFORMATION);
1035 Status = STATUS_SUCCESS;
1036
1037 break;
1038 }
1039
1040 case FileFsVolumeInformation:
1041 {
1042 FILE_FS_VOLUME_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
1043 FILE_FS_VOLUME_INFORMATION ffvi;
1044 BOOL overflow = FALSE;
1045 ULONG label_len, orig_label_len;
1046
1047 TRACE("FileFsVolumeInformation\n");
1048 TRACE("max length = %u\n", IrpSp->Parameters.QueryVolume.Length);
1049
1050 acquire_tree_lock(Vcb, FALSE);
1051
1052 // orig_label_len = label_len = (ULONG)(wcslen(Vcb->label) * sizeof(WCHAR));
1053 RtlUTF8ToUnicodeN(NULL, 0, &label_len, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
1054 orig_label_len = label_len;
1055
1056 if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len) {
1057 if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR))
1058 label_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_VOLUME_INFORMATION) + sizeof(WCHAR);
1059 else
1060 label_len = 0;
1061
1062 overflow = TRUE;
1063 }
1064
1065 TRACE("label_len = %u\n", label_len);
1066
1067 ffvi.VolumeCreationTime.QuadPart = 0; // FIXME
1068 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];
1069 ffvi.VolumeLabelLength = orig_label_len;
1070 ffvi.SupportsObjects = FALSE;
1071
1072 RtlCopyMemory(data, &ffvi, min(sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR), IrpSp->Parameters.QueryVolume.Length));
1073
1074 if (label_len > 0) {
1075 ULONG bytecount;
1076
1077 // RtlCopyMemory(&data->VolumeLabel[0], Vcb->label, label_len);
1078 RtlUTF8ToUnicodeN(&data->VolumeLabel[0], label_len, &bytecount, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
1079 TRACE("label = %.*S\n", label_len / sizeof(WCHAR), data->VolumeLabel);
1080 }
1081
1082 release_tree_lock(Vcb, FALSE);
1083
1084 BytesCopied = sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len;
1085 Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
1086 break;
1087 }
1088
1089 default:
1090 Status = STATUS_INVALID_PARAMETER;
1091 WARN("unknown FsInformatClass %u\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
1092 break;
1093 }
1094
1095 // if (NT_SUCCESS(Status) && IrpSp->Parameters.QueryVolume.Length < BytesCopied) { // FIXME - should not copy anything if overflow
1096 // WARN("overflow: %u < %u\n", IrpSp->Parameters.QueryVolume.Length, BytesCopied);
1097 // BytesCopied = IrpSp->Parameters.QueryVolume.Length;
1098 // Status = STATUS_BUFFER_OVERFLOW;
1099 // }
1100
1101 Irp->IoStatus.Status = Status;
1102
1103 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
1104 Irp->IoStatus.Information = 0;
1105 else
1106 Irp->IoStatus.Information = BytesCopied;
1107
1108 IoCompleteRequest( Irp, IO_DISK_INCREMENT );
1109
1110 if (top_level)
1111 IoSetTopLevelIrp(NULL);
1112
1113 FsRtlExitFileSystem();
1114
1115 TRACE("query volume information returning %08x\n", Status);
1116
1117 return Status;
1118 }
1119
1120 static NTSTATUS STDCALL read_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
1121 read_context* context = conptr;
1122
1123 // DbgPrint("read_completion\n");
1124
1125 context->iosb = Irp->IoStatus;
1126 KeSetEvent(&context->Event, 0, FALSE);
1127
1128 // return STATUS_SUCCESS;
1129 return STATUS_MORE_PROCESSING_REQUIRED;
1130 }
1131
1132 // static void test_tree_deletion(device_extension* Vcb) {
1133 // KEY searchkey/*, endkey*/;
1134 // traverse_ptr tp, next_tp;
1135 // root* r;
1136 //
1137 // searchkey.obj_id = 0x100;
1138 // searchkey.obj_type = 0x54;
1139 // searchkey.offset = 0xca4ab2f5;
1140 //
1141 // // endkey.obj_id = 0x100;
1142 // // endkey.obj_type = 0x60;
1143 // // endkey.offset = 0x15a;
1144 //
1145 // r = Vcb->roots;
1146 // while (r && r->id != 0x102)
1147 // r = r->next;
1148 //
1149 // if (!r) {
1150 // ERR("error - could not find root\n");
1151 // return;
1152 // }
1153 //
1154 // if (!find_item(Vcb, r, &tp, &searchkey, NULL, FALSE)) {
1155 // ERR("error - could not find key\n");
1156 // return;
1157 // }
1158 //
1159 // while (TRUE/*keycmp(&tp.item->key, &endkey) < 1*/) {
1160 // tp.item->ignore = TRUE;
1161 // add_to_tree_cache(tc, tp.tree);
1162 //
1163 // if (find_next_item(Vcb, &tp, &next_tp, NULL, FALSE)) {
1164 // free_traverse_ptr(&tp);
1165 // tp = next_tp;
1166 // } else
1167 // break;
1168 // }
1169 //
1170 // free_traverse_ptr(&tp);
1171 // }
1172
1173 // static void test_tree_splitting(device_extension* Vcb) {
1174 // int i;
1175 //
1176 // for (i = 0; i < 1000; i++) {
1177 // char* data = ExAllocatePoolWithTag(PagedPool, 4, ALLOC_TAG);
1178 //
1179 // insert_tree_item(Vcb, Vcb->extent_root, 0, 0xfd, i, data, 4, NULL);
1180 // }
1181 // }
1182
1183 static NTSTATUS STDCALL set_label(device_extension* Vcb, FILE_FS_LABEL_INFORMATION* ffli) {
1184 ULONG utf8len;
1185 NTSTATUS Status;
1186
1187 TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel);
1188
1189 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, ffli->VolumeLabelLength);
1190 if (!NT_SUCCESS(Status))
1191 goto end;
1192
1193 if (utf8len > MAX_LABEL_SIZE) {
1194 Status = STATUS_INVALID_VOLUME_LABEL;
1195 goto end;
1196 }
1197
1198 // FIXME - check for '/' and '\\' and reject
1199
1200 acquire_tree_lock(Vcb, TRUE);
1201
1202 // utf8 = ExAllocatePoolWithTag(PagedPool, utf8len + 1, ALLOC_TAG);
1203
1204 Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE * sizeof(WCHAR), &utf8len, ffli->VolumeLabel, ffli->VolumeLabelLength);
1205 if (!NT_SUCCESS(Status))
1206 goto release;
1207
1208 if (utf8len < MAX_LABEL_SIZE * sizeof(WCHAR))
1209 RtlZeroMemory(Vcb->superblock.label + utf8len, (MAX_LABEL_SIZE * sizeof(WCHAR)) - utf8len);
1210
1211 // test_tree_deletion(Vcb); // TESTING
1212 // test_tree_splitting(Vcb);
1213
1214 Status = consider_write(Vcb);
1215
1216 release:
1217 release_tree_lock(Vcb, TRUE);
1218
1219 end:
1220 TRACE("returning %08x\n", Status);
1221
1222 return Status;
1223 }
1224
1225 static NTSTATUS STDCALL drv_set_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
1226 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
1227 device_extension* Vcb = DeviceObject->DeviceExtension;
1228 NTSTATUS Status;
1229 BOOL top_level;
1230
1231 TRACE("set volume information\n");
1232
1233 FsRtlEnterFileSystem();
1234
1235 top_level = is_top_level(Irp);
1236
1237 Status = STATUS_NOT_IMPLEMENTED;
1238
1239 if (Vcb->readonly) {
1240 Status = STATUS_MEDIA_WRITE_PROTECTED;
1241 goto end;
1242 }
1243
1244 switch (IrpSp->Parameters.SetVolume.FsInformationClass) {
1245 case FileFsControlInformation:
1246 FIXME("STUB: FileFsControlInformation\n");
1247 break;
1248
1249 case FileFsLabelInformation:
1250 TRACE("FileFsLabelInformation\n");
1251
1252 Status = set_label(Vcb, Irp->AssociatedIrp.SystemBuffer);
1253 break;
1254
1255 case FileFsObjectIdInformation:
1256 FIXME("STUB: FileFsObjectIdInformation\n");
1257 break;
1258
1259 default:
1260 WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp->Parameters.SetVolume.FsInformationClass);
1261 break;
1262 }
1263
1264 end:
1265 Irp->IoStatus.Status = Status;
1266 Irp->IoStatus.Information = 0;
1267
1268 IoCompleteRequest( Irp, IO_NO_INCREMENT );
1269
1270 if (top_level)
1271 IoSetTopLevelIrp(NULL);
1272
1273 FsRtlExitFileSystem();
1274
1275 return Status;
1276 }
1277
1278 NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, LIST_ENTRY* rollback) {
1279 KEY searchkey;
1280 traverse_ptr tp;
1281 NTSTATUS Status;
1282
1283 searchkey.obj_id = parinode;
1284 searchkey.obj_type = TYPE_DIR_ITEM;
1285 searchkey.offset = crc32;
1286
1287 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
1288 if (!NT_SUCCESS(Status)) {
1289 ERR("error - find_item returned %08x\n", Status);
1290 return Status;
1291 }
1292
1293 if (!keycmp(&searchkey, &tp.item->key)) {
1294 if (tp.item->size < sizeof(DIR_ITEM)) {
1295 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));
1296 } else {
1297 DIR_ITEM* di;
1298 LONG len;
1299
1300 di = (DIR_ITEM*)tp.item->data;
1301 len = tp.item->size;
1302
1303 do {
1304 if (di->n == utf8->Length && RtlCompareMemory(di->name, utf8->Buffer, di->n) == di->n) {
1305 ULONG newlen = tp.item->size - (sizeof(DIR_ITEM) - sizeof(char) + di->n + di->m);
1306
1307 delete_tree_item(Vcb, &tp, rollback);
1308
1309 if (newlen == 0) {
1310 TRACE("deleting (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1311 } else {
1312 UINT8 *newdi = ExAllocatePoolWithTag(PagedPool, newlen, ALLOC_TAG), *dioff;
1313
1314 if (!newdi) {
1315 ERR("out of memory\n");
1316 free_traverse_ptr(&tp);
1317 return STATUS_INSUFFICIENT_RESOURCES;
1318 }
1319
1320 TRACE("modifying (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1321
1322 if ((UINT8*)di > tp.item->data) {
1323 RtlCopyMemory(newdi, tp.item->data, (UINT8*)di - tp.item->data);
1324 dioff = newdi + ((UINT8*)di - tp.item->data);
1325 } else {
1326 dioff = newdi;
1327 }
1328
1329 if ((UINT8*)&di->name[di->n + di->m] - tp.item->data < tp.item->size)
1330 RtlCopyMemory(dioff, &di->name[di->n + di->m], tp.item->size - ((UINT8*)&di->name[di->n + di->m] - tp.item->data));
1331
1332 insert_tree_item(Vcb, subvol, parinode, TYPE_DIR_ITEM, crc32, newdi, newlen, NULL, rollback);
1333 }
1334
1335 break;
1336 }
1337
1338 len -= sizeof(DIR_ITEM) - sizeof(char) + di->n + di->m;
1339 di = (DIR_ITEM*)&di->name[di->n + di->m];
1340 } while (len > 0);
1341 }
1342 } else {
1343 WARN("could not find DIR_ITEM for crc32 %08x\n", crc32);
1344 }
1345
1346 free_traverse_ptr(&tp);
1347
1348 return STATUS_SUCCESS;
1349 }
1350
1351 NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, UINT64* index, LIST_ENTRY* rollback) {
1352 KEY searchkey;
1353 traverse_ptr tp;
1354 BOOL changed = FALSE;
1355 NTSTATUS Status;
1356
1357 searchkey.obj_id = inode;
1358 searchkey.obj_type = TYPE_INODE_REF;
1359 searchkey.offset = parinode;
1360
1361 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
1362 if (!NT_SUCCESS(Status)) {
1363 ERR("error - find_item returned %08x\n", Status);
1364 return Status;
1365 }
1366
1367 if (!keycmp(&searchkey, &tp.item->key)) {
1368 if (tp.item->size < sizeof(INODE_REF)) {
1369 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));
1370 } else {
1371 INODE_REF* ir;
1372 ULONG len;
1373
1374 ir = (INODE_REF*)tp.item->data;
1375 len = tp.item->size;
1376
1377 do {
1378 ULONG itemlen;
1379
1380 if (len < sizeof(INODE_REF) || len < sizeof(INODE_REF) - 1 + ir->n) {
1381 ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1382 break;
1383 }
1384
1385 itemlen = sizeof(INODE_REF) - sizeof(char) + ir->n;
1386
1387 if (ir->n == utf8->Length && RtlCompareMemory(ir->name, utf8->Buffer, ir->n) == ir->n) {
1388 ULONG newlen = tp.item->size - itemlen;
1389
1390 delete_tree_item(Vcb, &tp, rollback);
1391 changed = TRUE;
1392
1393 if (newlen == 0) {
1394 TRACE("deleting (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1395 } else {
1396 UINT8 *newir = ExAllocatePoolWithTag(PagedPool, newlen, ALLOC_TAG), *iroff;
1397
1398 if (!newir) {
1399 ERR("out of memory\n");
1400 free_traverse_ptr(&tp);
1401 return STATUS_INSUFFICIENT_RESOURCES;
1402 }
1403
1404 TRACE("modifying (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1405
1406 if ((UINT8*)ir > tp.item->data) {
1407 RtlCopyMemory(newir, tp.item->data, (UINT8*)ir - tp.item->data);
1408 iroff = newir + ((UINT8*)ir - tp.item->data);
1409 } else {
1410 iroff = newir;
1411 }
1412
1413 if ((UINT8*)&ir->name[ir->n] - tp.item->data < tp.item->size)
1414 RtlCopyMemory(iroff, &ir->name[ir->n], tp.item->size - ((UINT8*)&ir->name[ir->n] - tp.item->data));
1415
1416 insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newir, newlen, NULL, rollback);
1417 }
1418
1419 if (index)
1420 *index = ir->index;
1421
1422 break;
1423 }
1424
1425 if (len > itemlen) {
1426 len -= itemlen;
1427 ir = (INODE_REF*)&ir->name[ir->n];
1428 } else
1429 break;
1430 } while (len > 0);
1431
1432 if (!changed) {
1433 WARN("found INODE_REF entry, but couldn't find filename\n");
1434 }
1435 }
1436 } else {
1437 WARN("could not find INODE_REF entry for inode %llx in %llx\n", searchkey.obj_id, searchkey.offset);
1438 }
1439
1440 free_traverse_ptr(&tp);
1441
1442 if (changed)
1443 return STATUS_SUCCESS;
1444
1445 if (!(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF))
1446 return STATUS_INTERNAL_ERROR;
1447
1448 searchkey.obj_id = inode;
1449 searchkey.obj_type = TYPE_INODE_EXTREF;
1450 searchkey.offset = calc_crc32c((UINT32)parinode, (UINT8*)utf8->Buffer, utf8->Length);
1451
1452 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
1453 if (!NT_SUCCESS(Status)) {
1454 ERR("error - find_item returned %08x\n", Status);
1455 return Status;
1456 }
1457
1458 if (!keycmp(&searchkey, &tp.item->key)) {
1459 if (tp.item->size < sizeof(INODE_EXTREF)) {
1460 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));
1461 } else {
1462 INODE_EXTREF* ier;
1463 ULONG len;
1464
1465 ier = (INODE_EXTREF*)tp.item->data;
1466 len = tp.item->size;
1467
1468 do {
1469 ULONG itemlen;
1470
1471 if (len < sizeof(INODE_EXTREF) || len < sizeof(INODE_EXTREF) - 1 + ier->n) {
1472 ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1473 break;
1474 }
1475
1476 itemlen = sizeof(INODE_EXTREF) - sizeof(char) + ier->n;
1477
1478 if (ier->dir == parinode && ier->n == utf8->Length && RtlCompareMemory(ier->name, utf8->Buffer, ier->n) == ier->n) {
1479 ULONG newlen = tp.item->size - itemlen;
1480
1481 delete_tree_item(Vcb, &tp, rollback);
1482 changed = TRUE;
1483
1484 if (newlen == 0) {
1485 TRACE("deleting (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1486 } else {
1487 UINT8 *newier = ExAllocatePoolWithTag(PagedPool, newlen, ALLOC_TAG), *ieroff;
1488
1489 if (!newier) {
1490 ERR("out of memory\n");
1491 free_traverse_ptr(&tp);
1492 return STATUS_INSUFFICIENT_RESOURCES;
1493 }
1494
1495 TRACE("modifying (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1496
1497 if ((UINT8*)ier > tp.item->data) {
1498 RtlCopyMemory(newier, tp.item->data, (UINT8*)ier - tp.item->data);
1499 ieroff = newier + ((UINT8*)ier - tp.item->data);
1500 } else {
1501 ieroff = newier;
1502 }
1503
1504 if ((UINT8*)&ier->name[ier->n] - tp.item->data < tp.item->size)
1505 RtlCopyMemory(ieroff, &ier->name[ier->n], tp.item->size - ((UINT8*)&ier->name[ier->n] - tp.item->data));
1506
1507 insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newier, newlen, NULL, rollback);
1508 }
1509
1510 if (index)
1511 *index = ier->index;
1512
1513 break;
1514 }
1515
1516 if (len > itemlen) {
1517 len -= itemlen;
1518 ier = (INODE_EXTREF*)&ier->name[ier->n];
1519 } else
1520 break;
1521 } while (len > 0);
1522 }
1523 } else {
1524 WARN("couldn't find INODE_EXTREF entry either (offset = %08x)\n", (UINT32)searchkey.offset);
1525 }
1526
1527 free_traverse_ptr(&tp);
1528
1529 return changed ? STATUS_SUCCESS : STATUS_INTERNAL_ERROR;
1530 }
1531
1532 NTSTATUS delete_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback) {
1533 ULONG bytecount;
1534 NTSTATUS Status;
1535 char* utf8 = NULL;
1536 UINT32 crc32;
1537 KEY searchkey;
1538 traverse_ptr tp, tp2;
1539 UINT64 parinode, index;
1540 INODE_ITEM *ii, *dirii;
1541 LARGE_INTEGER time;
1542 BTRFS_TIME now;
1543 LIST_ENTRY changed_sector_list;
1544 #ifdef _DEBUG
1545 LARGE_INTEGER freq, time1, time2;
1546 #endif
1547
1548 // FIXME - throw error if try to delete subvol root(?)
1549
1550 // FIXME - delete all children if deleting directory
1551
1552 if (fcb->deleted) {
1553 WARN("trying to delete already-deleted file\n");
1554 return STATUS_SUCCESS;
1555 }
1556
1557 if (!fcb->par) {
1558 ERR("error - trying to delete root FCB\n");
1559 return STATUS_INTERNAL_ERROR;
1560 }
1561
1562 #ifdef _DEBUG
1563 time1 = KeQueryPerformanceCounter(&freq);
1564 #endif
1565
1566 KeQuerySystemTime(&time);
1567 win_time_to_unix(time, &now);
1568
1569 if (fcb->ads) {
1570 char* s;
1571 TRACE("deleting ADS\n");
1572
1573 s = ExAllocatePoolWithTag(PagedPool, fcb->adsxattr.Length + 1, ALLOC_TAG);
1574 if (!s) {
1575 ERR("out of memory\n");
1576 Status = STATUS_INSUFFICIENT_RESOURCES;
1577 goto exit;
1578 }
1579
1580 RtlCopyMemory(s, fcb->adsxattr.Buffer, fcb->adsxattr.Length);
1581 s[fcb->adsxattr.Length] = 0;
1582
1583 if (!delete_xattr(fcb->Vcb, fcb->par->subvol, fcb->par->inode, s, fcb->adshash, rollback)) {
1584 ERR("failed to delete xattr %s\n", s);
1585 }
1586
1587 ExFreePool(s);
1588
1589 fcb->par->inode_item.transid = fcb->Vcb->superblock.generation;
1590 fcb->par->inode_item.sequence++;
1591 fcb->par->inode_item.st_ctime = now;
1592
1593 searchkey.obj_id = fcb->par->inode;
1594 searchkey.obj_type = TYPE_INODE_ITEM;
1595 searchkey.offset = 0xffffffffffffffff;
1596
1597 Status = find_item(fcb->Vcb, fcb->par->subvol, &tp, &searchkey, FALSE);
1598 if (!NT_SUCCESS(Status)) {
1599 ERR("error - find_item returned %08x\n", Status);
1600 goto exit;
1601 }
1602
1603 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
1604 ERR("error - could not find INODE_ITEM for inode %llx in subvol %llx\n", fcb->par->inode, fcb->par->subvol->id);
1605 free_traverse_ptr(&tp);
1606 Status = STATUS_INTERNAL_ERROR;
1607 goto exit;
1608 }
1609
1610 ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
1611 if (!ii) {
1612 ERR("out of memory\n");
1613 free_traverse_ptr(&tp);
1614 Status = STATUS_INSUFFICIENT_RESOURCES;
1615 goto exit;
1616 }
1617
1618 RtlCopyMemory(ii, &fcb->par->inode_item, sizeof(INODE_ITEM));
1619 delete_tree_item(fcb->Vcb, &tp, rollback);
1620
1621 insert_tree_item(fcb->Vcb, fcb->par->subvol, searchkey.obj_id, searchkey.obj_type, 0, ii, sizeof(INODE_ITEM), NULL, rollback);
1622
1623 free_traverse_ptr(&tp);
1624
1625 fcb->par->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
1626 fcb->par->subvol->root_item.ctime = now;
1627
1628 goto success;
1629 }
1630
1631 Status = RtlUnicodeToUTF8N(NULL, 0, &bytecount, fcb->filepart.Buffer, fcb->filepart.Length);
1632 if (!NT_SUCCESS(Status)) {
1633 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status);
1634 return Status;
1635 }
1636
1637 utf8 = ExAllocatePoolWithTag(PagedPool, bytecount + 1, ALLOC_TAG);
1638 if (!utf8) {
1639 ERR("out of memory\n");
1640 return STATUS_INSUFFICIENT_RESOURCES;
1641 }
1642
1643 RtlUnicodeToUTF8N(utf8, bytecount, &bytecount, fcb->filepart.Buffer, fcb->filepart.Length);
1644 utf8[bytecount] = 0;
1645
1646 crc32 = calc_crc32c(0xfffffffe, (UINT8*)utf8, bytecount);
1647
1648 TRACE("deleting %.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1649
1650 if (fcb->par->subvol == fcb->subvol)
1651 parinode = fcb->par->inode;
1652 else
1653 parinode = SUBVOL_ROOT_INODE;
1654
1655 // delete DIR_ITEM (0x54)
1656
1657 Status = delete_dir_item(fcb->Vcb, fcb->subvol, parinode, crc32, &fcb->utf8, rollback);
1658 if (!NT_SUCCESS(Status)) {
1659 ERR("delete_dir_item returned %08x\n", Status);
1660 return Status;
1661 }
1662
1663 // delete INODE_REF (0xc)
1664
1665 index = 0;
1666
1667 Status = delete_inode_ref(fcb->Vcb, fcb->subvol, fcb->inode, parinode, &fcb->utf8, &index, rollback);
1668
1669 // delete DIR_INDEX (0x60)
1670
1671 searchkey.obj_id = parinode;
1672 searchkey.obj_type = TYPE_DIR_INDEX;
1673 searchkey.offset = index;
1674
1675 Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
1676 if (!NT_SUCCESS(Status)) {
1677 ERR("error - find_item returned %08x\n", Status);
1678 free_traverse_ptr(&tp);
1679 Status = STATUS_INTERNAL_ERROR;
1680 goto exit;
1681 }
1682
1683 if (!keycmp(&searchkey, &tp.item->key)) {
1684 delete_tree_item(fcb->Vcb, &tp, rollback);
1685 TRACE("deleting (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1686 }
1687
1688 // delete INODE_ITEM (0x1)
1689
1690 searchkey.obj_id = fcb->inode;
1691 searchkey.obj_type = TYPE_INODE_ITEM;
1692 searchkey.offset = 0;
1693
1694 Status = find_item(fcb->Vcb, fcb->subvol, &tp2, &searchkey, FALSE);
1695 if (!NT_SUCCESS(Status)) {
1696 ERR("error - find_item returned %08x\n", Status);
1697 free_traverse_ptr(&tp);
1698 goto exit;
1699 }
1700
1701 free_traverse_ptr(&tp);
1702 tp = tp2;
1703
1704 if (keycmp(&searchkey, &tp.item->key)) {
1705 ERR("error - INODE_ITEM not found\n");
1706 free_traverse_ptr(&tp);
1707 Status = STATUS_INTERNAL_ERROR;
1708 goto exit;
1709 }
1710
1711 if (tp.item->size < sizeof(INODE_ITEM)) {
1712 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));
1713 free_traverse_ptr(&tp);
1714 Status = STATUS_INTERNAL_ERROR;
1715 goto exit;
1716 }
1717
1718 ii = (INODE_ITEM*)tp.item->data;
1719 TRACE("nlink = %u\n", ii->st_nlink);
1720
1721 if (ii->st_nlink > 1) {
1722 INODE_ITEM* newii;
1723
1724 newii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
1725 if (!newii) {
1726 ERR("out of memory\n");
1727 free_traverse_ptr(&tp);
1728 Status = STATUS_INSUFFICIENT_RESOURCES;
1729 goto exit;
1730 }
1731
1732 RtlCopyMemory(newii, ii, sizeof(INODE_ITEM));
1733 newii->st_nlink--;
1734 newii->transid = fcb->Vcb->superblock.generation;
1735 newii->sequence++;
1736 newii->st_ctime = now;
1737
1738 TRACE("replacing (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1739
1740 delete_tree_item(fcb->Vcb, &tp, rollback);
1741
1742 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))
1743 ERR("error - failed to insert item\n");
1744
1745 free_traverse_ptr(&tp);
1746
1747 goto success2;
1748 }
1749
1750 delete_tree_item(fcb->Vcb, &tp, rollback);
1751 TRACE("deleting (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1752
1753 // delete XATTR_ITEM (0x18)
1754
1755 while (find_next_item(fcb->Vcb, &tp, &tp2, FALSE)) {
1756 free_traverse_ptr(&tp);
1757 tp = tp2;
1758
1759 if (tp.item->key.obj_id == fcb->inode) {
1760 // FIXME - do metadata thing here too?
1761 if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
1762 delete_tree_item(fcb->Vcb, &tp, rollback);
1763 TRACE("deleting (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1764 }
1765 } else
1766 break;
1767 }
1768
1769 free_traverse_ptr(&tp);
1770
1771 // excise extents
1772
1773 InitializeListHead(&changed_sector_list);
1774
1775 if (fcb->type != BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0) {
1776 Status = excise_extents(fcb->Vcb, fcb, 0, sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size), &changed_sector_list, rollback);
1777 if (!NT_SUCCESS(Status)) {
1778 ERR("excise_extents returned %08x\n", Status);
1779 goto exit;
1780 }
1781
1782 if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM))
1783 update_checksum_tree(fcb->Vcb, &changed_sector_list, rollback);
1784 }
1785
1786 success2:
1787 // update INODE_ITEM of parent
1788
1789 searchkey.obj_id = parinode;
1790 searchkey.obj_type = TYPE_INODE_ITEM;
1791 searchkey.offset = 0;
1792
1793 Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
1794 if (!NT_SUCCESS(Status)) {
1795 ERR("error - find_tree returned %08x\n", Status);
1796 goto exit;
1797 }
1798
1799 if (keycmp(&searchkey, &tp.item->key)) {
1800 ERR("error - could not find INODE_ITEM for parent directory %llx in subvol %llx\n", parinode, fcb->subvol->id);
1801 free_traverse_ptr(&tp);
1802 Status = STATUS_INTERNAL_ERROR;
1803 goto exit;
1804 }
1805
1806 TRACE("fcb->par->inode_item.st_size was %llx\n", fcb->par->inode_item.st_size);
1807 fcb->par->inode_item.st_size -= bytecount * 2;
1808 TRACE("fcb->par->inode_item.st_size now %llx\n", fcb->par->inode_item.st_size);
1809 fcb->par->inode_item.transid = fcb->Vcb->superblock.generation;
1810 fcb->par->inode_item.sequence++;
1811 fcb->par->inode_item.st_ctime = now;
1812 fcb->par->inode_item.st_mtime = now;
1813
1814 dirii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
1815 if (!dirii) {
1816 ERR("out of memory\n");
1817 free_traverse_ptr(&tp);
1818 Status = STATUS_INSUFFICIENT_RESOURCES;
1819 goto exit;
1820 }
1821
1822 RtlCopyMemory(dirii, &fcb->par->inode_item, sizeof(INODE_ITEM));
1823 delete_tree_item(fcb->Vcb, &tp, rollback);
1824
1825 insert_tree_item(fcb->Vcb, fcb->subvol, searchkey.obj_id, searchkey.obj_type, searchkey.offset, dirii, sizeof(INODE_ITEM), NULL, rollback);
1826
1827 free_traverse_ptr(&tp);
1828
1829 fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
1830 fcb->subvol->root_item.ctime = now;
1831
1832 success:
1833 consider_write(fcb->Vcb);
1834
1835 fcb->deleted = TRUE;
1836
1837 fcb->Header.AllocationSize.QuadPart = 0;
1838 fcb->Header.FileSize.QuadPart = 0;
1839 fcb->Header.ValidDataLength.QuadPart = 0;
1840
1841 if (FileObject && FileObject->PrivateCacheMap) {
1842 CC_FILE_SIZES ccfs;
1843
1844 ccfs.AllocationSize = fcb->Header.AllocationSize;
1845 ccfs.FileSize = fcb->Header.FileSize;
1846 ccfs.ValidDataLength = fcb->Header.ValidDataLength;
1847
1848 CcSetFileSizes(FileObject, &ccfs);
1849 }
1850
1851 // FIXME - set deleted flag of any open FCBs for ADS
1852
1853 TRACE("sending notification for deletion of %.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1854
1855 FsRtlNotifyFullReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fcb->full_filename, fcb->name_offset * sizeof(WCHAR), NULL, NULL,
1856 fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
1857 FILE_ACTION_REMOVED, NULL);
1858
1859 #ifdef _DEBUG
1860 time2 = KeQueryPerformanceCounter(NULL);
1861 #endif
1862
1863 TRACE("time = %u (freq = %u)\n", (UINT32)(time2.QuadPart - time1.QuadPart), (UINT32)freq.QuadPart);
1864
1865 Status = STATUS_SUCCESS;
1866
1867 exit:
1868 if (utf8)
1869 ExFreePool(utf8);
1870
1871 return Status;
1872 }
1873
1874 void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line) {
1875 ULONG rc;
1876
1877 rc = InterlockedDecrement(&fcb->refcount);
1878
1879 #ifdef DEBUG_FCB_REFCOUNTS
1880 // WARN("fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1881 #ifdef DEBUG_LONG_MESSAGES
1882 _debug_message(func, 1, file, line, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1883 #else
1884 _debug_message(func, 1, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1885 #endif
1886 #endif
1887
1888 if (rc > 0)
1889 return;
1890
1891 ExAcquireResourceExclusiveLite(&fcb->Vcb->fcb_lock, TRUE);
1892
1893 if (fcb->filepart.Buffer)
1894 RtlFreeUnicodeString(&fcb->filepart);
1895
1896 ExDeleteResourceLite(&fcb->nonpaged->resource);
1897 ExDeleteResourceLite(&fcb->nonpaged->paging_resource);
1898 ExFreePool(fcb->nonpaged);
1899
1900 if (fcb->par/* && fcb->par != fcb->par->Vcb->root_fcb*/) {
1901 RemoveEntryList(&fcb->list_entry);
1902 _free_fcb(fcb->par, func, file, line);
1903 }
1904
1905 if (fcb->prev)
1906 fcb->prev->next = fcb->next;
1907
1908 if (fcb->next)
1909 fcb->next->prev = fcb->prev;
1910
1911 if (fcb->Vcb->fcbs == fcb)
1912 fcb->Vcb->fcbs = fcb->next;
1913
1914 if (fcb->full_filename.Buffer)
1915 ExFreePool(fcb->full_filename.Buffer);
1916
1917 if (fcb->sd)
1918 ExFreePool(fcb->sd);
1919
1920 if (fcb->adsxattr.Buffer)
1921 ExFreePool(fcb->adsxattr.Buffer);
1922
1923 if (fcb->utf8.Buffer)
1924 ExFreePool(fcb->utf8.Buffer);
1925
1926 FsRtlUninitializeFileLock(&fcb->lock);
1927
1928 ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
1929
1930 ExFreePool(fcb);
1931 #ifdef DEBUG_FCB_REFCOUNTS
1932 #ifdef DEBUG_LONG_MESSAGES
1933 _debug_message(func, 1, file, line, "freeing fcb %p\n", fcb);
1934 #else
1935 _debug_message(func, 1, "freeing fcb %p\n", fcb);
1936 #endif
1937 #endif
1938 }
1939
1940 static NTSTATUS STDCALL close_file(device_extension* Vcb, PFILE_OBJECT FileObject) {
1941 fcb* fcb;
1942 ccb* ccb;
1943
1944 TRACE("FileObject = %p\n", FileObject);
1945
1946 fcb = FileObject->FsContext;
1947 if (!fcb) {
1948 TRACE("FCB was NULL, returning success\n");
1949 return STATUS_SUCCESS;
1950 }
1951
1952 ccb = FileObject->FsContext2;
1953
1954 TRACE("close called for %.*S (fcb == %p)\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb);
1955
1956 FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->DirNotifyList, ccb);
1957
1958 // FIXME - make sure notification gets sent if file is being deleted
1959
1960 if (ccb) {
1961 if (ccb->query_string.Buffer)
1962 RtlFreeUnicodeString(&ccb->query_string);
1963
1964 ExFreePool(ccb);
1965 }
1966
1967 CcUninitializeCacheMap(FileObject, NULL, NULL);
1968
1969 free_fcb(fcb);
1970
1971 return STATUS_SUCCESS;
1972 }
1973
1974 static void STDCALL uninit(device_extension* Vcb) {
1975 chunk* c;
1976 space* s;
1977 UINT64 i;
1978 LIST_ENTRY rollback;
1979
1980 InitializeListHead(&rollback);
1981
1982 acquire_tree_lock(Vcb, TRUE);
1983
1984 if (Vcb->write_trees > 0)
1985 do_write(Vcb, &rollback);
1986
1987 free_tree_cache(&Vcb->tree_cache);
1988
1989 clear_rollback(&rollback);
1990
1991 release_tree_lock(Vcb, TRUE);
1992
1993 while (Vcb->roots) {
1994 root* r = Vcb->roots->next;
1995
1996 ExDeleteResourceLite(&Vcb->roots->nonpaged->load_tree_lock);
1997 ExFreePool(Vcb->roots->nonpaged);
1998 ExFreePool(Vcb->roots);
1999
2000 Vcb->roots = r;
2001 }
2002
2003 while (!IsListEmpty(&Vcb->chunks)) {
2004 LIST_ENTRY* le = RemoveHeadList(&Vcb->chunks);
2005 c = CONTAINING_RECORD(le, chunk, list_entry);
2006
2007 while (!IsListEmpty(&c->space)) {
2008 LIST_ENTRY* le2 = RemoveHeadList(&c->space);
2009 s = CONTAINING_RECORD(le2, space, list_entry);
2010
2011 ExFreePool(s);
2012 }
2013
2014 if (c->devices)
2015 ExFreePool(c->devices);
2016
2017 ExFreePool(c->chunk_item);
2018 ExFreePool(c);
2019 }
2020
2021 free_fcb(Vcb->volume_fcb);
2022 free_fcb(Vcb->root_fcb);
2023
2024 for (i = 0; i < Vcb->superblock.num_devices; i++) {
2025 while (!IsListEmpty(&Vcb->devices[i].disk_holes)) {
2026 LIST_ENTRY* le = RemoveHeadList(&Vcb->devices[i].disk_holes);
2027 disk_hole* dh = CONTAINING_RECORD(le, disk_hole, listentry);
2028
2029 ExFreePool(dh);
2030 }
2031 }
2032
2033 ExFreePool(Vcb->devices);
2034
2035 ExDeleteResourceLite(&Vcb->fcb_lock);
2036 ExDeleteResourceLite(&Vcb->load_lock);
2037 ExDeleteResourceLite(&Vcb->tree_lock);
2038
2039 ZwClose(Vcb->flush_thread_handle);
2040 }
2041
2042 static NTSTATUS STDCALL drv_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
2043 NTSTATUS Status;
2044 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
2045 PFILE_OBJECT FileObject = IrpSp->FileObject;
2046 fcb* fcb;
2047 BOOL top_level;
2048
2049 TRACE("cleanup\n");
2050
2051 FsRtlEnterFileSystem();
2052
2053 top_level = is_top_level(Irp);
2054
2055 if (DeviceObject == devobj) {
2056 TRACE("closing file system\n");
2057 Status = STATUS_SUCCESS;
2058 goto exit;
2059 }
2060
2061 if (FileObject) {
2062 LONG oc;
2063
2064 fcb = FileObject->FsContext;
2065
2066 TRACE("cleanup called for FileObject %p\n", FileObject);
2067 TRACE("fcb %p (%.*S), refcount = %u, open_count = %u\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb->refcount, fcb->open_count);
2068
2069 IoRemoveShareAccess(FileObject, &fcb->share_access);
2070
2071 oc = InterlockedDecrement(&fcb->open_count);
2072 #ifdef DEBUG_FCB_REFCOUNTS
2073 ERR("fcb %p: open_count now %i\n", fcb, oc);
2074 #endif
2075
2076 if (oc == 0) {
2077 if (fcb->delete_on_close && fcb != fcb->Vcb->root_fcb && fcb != fcb->Vcb->volume_fcb) {
2078 LIST_ENTRY rollback;
2079 InitializeListHead(&rollback);
2080
2081 acquire_tree_lock(fcb->Vcb, TRUE);
2082
2083 Status = delete_fcb(fcb, FileObject, &rollback);
2084
2085 if (NT_SUCCESS(Status)) {
2086 LARGE_INTEGER newlength;
2087
2088 if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject)
2089 CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE);
2090
2091 newlength.QuadPart = 0;
2092
2093 if (!CcUninitializeCacheMap(FileObject, &newlength, NULL)) {
2094 TRACE("CcUninitializeCacheMap failed\n");
2095 }
2096
2097 clear_rollback(&rollback);
2098 } else
2099 do_rollback(fcb->Vcb, &rollback);
2100
2101 release_tree_lock(fcb->Vcb, TRUE);
2102 } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) {
2103 IO_STATUS_BLOCK iosb;
2104 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2105
2106 if (!NT_SUCCESS(iosb.Status)) {
2107 ERR("CcFlushCache returned %08x\n", iosb.Status);
2108 }
2109
2110 ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
2111 ExReleaseResourceLite(fcb->Header.PagingIoResource);
2112
2113 CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE);
2114
2115 TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n",
2116 FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
2117 }
2118
2119 if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb)
2120 CcUninitializeCacheMap(FileObject, NULL, NULL);
2121 }
2122
2123 FileObject->Flags |= FO_CLEANUP_COMPLETE;
2124 }
2125
2126 Status = STATUS_SUCCESS;
2127
2128 exit:
2129 Irp->IoStatus.Status = Status;
2130 Irp->IoStatus.Information = 0;
2131
2132 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2133
2134 if (top_level)
2135 IoSetTopLevelIrp(NULL);
2136
2137 FsRtlExitFileSystem();
2138
2139 return Status;
2140 }
2141
2142 ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa) {
2143 ULONG att;
2144 char* eaval;
2145 UINT16 ealen;
2146
2147 if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen)) {
2148 if (ealen > 2) {
2149 if (eaval[0] == '0' && eaval[1] == 'x') {
2150 int i;
2151 ULONG dosnum = 0;
2152
2153 for (i = 2; i < ealen; i++) {
2154 dosnum *= 0x10;
2155
2156 if (eaval[i] >= '0' && eaval[i] <= '9')
2157 dosnum |= eaval[i] - '0';
2158 else if (eaval[i] >= 'a' && eaval[i] <= 'f')
2159 dosnum |= eaval[i] + 10 - 'a';
2160 else if (eaval[i] >= 'A' && eaval[i] <= 'F')
2161 dosnum |= eaval[i] + 10 - 'a';
2162 }
2163
2164 TRACE("DOSATTRIB: %08x\n", dosnum);
2165
2166 ExFreePool(eaval);
2167
2168 return dosnum;
2169 }
2170 }
2171
2172 ExFreePool(eaval);
2173 }
2174
2175 switch (type) {
2176 case BTRFS_TYPE_DIRECTORY:
2177 att = FILE_ATTRIBUTE_DIRECTORY;
2178 break;
2179
2180 case BTRFS_TYPE_SYMLINK:
2181 att = FILE_ATTRIBUTE_REPARSE_POINT;
2182 break;
2183
2184 default:
2185 att = 0;
2186 break;
2187 }
2188
2189 if (dotfile) {
2190 att |= FILE_ATTRIBUTE_HIDDEN;
2191 }
2192
2193 att |= FILE_ATTRIBUTE_ARCHIVE;
2194
2195 // FIXME - get READONLY from ii->st_mode
2196 // FIXME - return SYSTEM for block/char devices?
2197
2198 if (att == 0)
2199 att = FILE_ATTRIBUTE_NORMAL;
2200
2201 return att;
2202 }
2203
2204 // static int STDCALL utf8icmp(char* a, char* b) {
2205 // return strcmp(a, b); // FIXME - don't treat as ASCII
2206 // }
2207
2208 NTSTATUS sync_read_phys(PDEVICE_OBJECT DeviceObject, LONGLONG StartingOffset, ULONG Length, PUCHAR Buffer) {
2209 IO_STATUS_BLOCK* IoStatus;
2210 LARGE_INTEGER Offset;
2211 PIRP Irp;
2212 PIO_STACK_LOCATION IrpSp;
2213 NTSTATUS Status;
2214 read_context* context;
2215
2216 num_reads++;
2217
2218 context = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_context), ALLOC_TAG);
2219 if (!context) {
2220 ERR("out of memory\n");
2221 return STATUS_INSUFFICIENT_RESOURCES;
2222 }
2223
2224 RtlZeroMemory(context, sizeof(read_context));
2225 KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
2226
2227 IoStatus = ExAllocatePoolWithTag(NonPagedPool, sizeof(IO_STATUS_BLOCK), ALLOC_TAG);
2228 if (!IoStatus) {
2229 ERR("out of memory\n");
2230 ExFreePool(context);
2231 return STATUS_INSUFFICIENT_RESOURCES;
2232 }
2233
2234 Offset.QuadPart = StartingOffset;
2235
2236 // Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, Buffer, Length, &Offset, /*&Event*/NULL, IoStatus);
2237 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2238
2239 if (!Irp) {
2240 ERR("IoAllocateIrp failed\n");
2241 Status = STATUS_INSUFFICIENT_RESOURCES;
2242 goto exit;
2243 }
2244
2245 IrpSp = IoGetNextIrpStackLocation(Irp);
2246 IrpSp->MajorFunction = IRP_MJ_READ;
2247
2248 if (DeviceObject->Flags & DO_BUFFERED_IO) {
2249 FIXME("FIXME - buffered IO\n");
2250 } else if (DeviceObject->Flags & DO_DIRECT_IO) {
2251 // TRACE("direct IO\n");
2252
2253 Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);
2254 if (!Irp->MdlAddress) {
2255 ERR("IoAllocateMdl failed\n");
2256 Status = STATUS_INSUFFICIENT_RESOURCES;
2257 // IoFreeIrp(Irp);
2258 goto exit;
2259 // } else {
2260 // TRACE("got MDL %p from buffer %p\n", Irp->MdlAddress, Buffer);
2261 }
2262
2263 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoWriteAccess);
2264 } else {
2265 // TRACE("neither buffered nor direct IO\n");
2266 Irp->UserBuffer = Buffer;
2267 }
2268
2269 IrpSp->Parameters.Read.Length = Length;
2270 IrpSp->Parameters.Read.ByteOffset = Offset;
2271
2272 Irp->UserIosb = IoStatus;
2273 // Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2274
2275 Irp->UserEvent = &context->Event;
2276
2277 // IoQueueThreadIrp(Irp);
2278
2279 IoSetCompletionRoutine(Irp, read_completion, context, TRUE, TRUE, TRUE);
2280
2281 // if (Override)
2282 // {
2283 // Stack = IoGetNextIrpStackLocation(Irp);
2284 // Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2285 // }
2286
2287 // TRACE("Calling IO Driver... with irp %p\n", Irp);
2288 Status = IoCallDriver(DeviceObject, Irp);
2289
2290 // TRACE("Waiting for IO Operation for %p\n", Irp);
2291 if (Status == STATUS_PENDING) {
2292 // TRACE("Operation pending\n");
2293 KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
2294 // TRACE("Getting IO Status... for %p\n", Irp);
2295 Status = context->iosb.Status;
2296 }
2297
2298 if (DeviceObject->Flags & DO_DIRECT_IO) {
2299 MmUnlockPages(Irp->MdlAddress);
2300 IoFreeMdl(Irp->MdlAddress);
2301 }
2302
2303 exit:
2304 IoFreeIrp(Irp);
2305
2306 ExFreePool(IoStatus);
2307 ExFreePool(context);
2308
2309 return Status;
2310 }
2311
2312 static NTSTATUS STDCALL read_superblock(device_extension* Vcb, PDEVICE_OBJECT device) {
2313 NTSTATUS Status;
2314 superblock* sb;
2315 unsigned int i, to_read;
2316 UINT32 crc32;
2317
2318 to_read = sector_align(sizeof(superblock), device->SectorSize);
2319
2320 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG);
2321 if (!sb) {
2322 ERR("out of memory\n");
2323 return STATUS_INSUFFICIENT_RESOURCES;
2324 }
2325
2326 i = 0;
2327
2328 while (superblock_addrs[i] > 0) {
2329 if (i > 0 && superblock_addrs[i] + sizeof(superblock) > Vcb->length)
2330 break;
2331
2332 Status = sync_read_phys(device, superblock_addrs[i], to_read, (PUCHAR)sb);
2333 if (!NT_SUCCESS(Status)) {
2334 ERR("Failed to read superblock %u: %08x\n", i, Status);
2335 ExFreePool(sb);
2336 return Status;
2337 }
2338
2339 TRACE("got superblock %u!\n", i);
2340
2341 if (i == 0 || sb->generation > Vcb->superblock.generation)
2342 RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock));
2343
2344 i++;
2345 }
2346
2347 ExFreePool(sb);
2348
2349 crc32 = calc_crc32c(0xffffffff, (UINT8*)&Vcb->superblock.uuid, (ULONG)sizeof(superblock) - sizeof(Vcb->superblock.checksum));
2350 crc32 = ~crc32;
2351 TRACE("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)Vcb->superblock.checksum));
2352
2353 if (crc32 != *((UINT32*)Vcb->superblock.checksum))
2354 return STATUS_INTERNAL_ERROR; // FIXME - correct error?
2355
2356 TRACE("label is %s\n", Vcb->superblock.label);
2357 // utf8_to_utf16(Vcb->superblock.label, Vcb->label, MAX_LABEL_SIZE * sizeof(WCHAR));
2358
2359 return STATUS_SUCCESS;
2360 }
2361
2362 static NTSTATUS STDCALL dev_ioctl(PDEVICE_OBJECT DeviceObject, ULONG ControlCode, PVOID InputBuffer,
2363 ULONG InputBufferSize, PVOID OutputBuffer, ULONG OutputBufferSize, BOOLEAN Override)
2364 {
2365 PIRP Irp;
2366 KEVENT Event;
2367 NTSTATUS Status;
2368 PIO_STACK_LOCATION Stack;
2369 IO_STATUS_BLOCK IoStatus;
2370
2371 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2372
2373 Irp = IoBuildDeviceIoControlRequest(ControlCode,
2374 DeviceObject,
2375 InputBuffer,
2376 InputBufferSize,
2377 OutputBuffer,
2378 OutputBufferSize,
2379 FALSE,
2380 &Event,
2381 &IoStatus);
2382
2383 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
2384
2385 if (Override) {
2386 Stack = IoGetNextIrpStackLocation(Irp);
2387 Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2388 }
2389
2390 Status = IoCallDriver(DeviceObject, Irp);
2391
2392 if (Status == STATUS_PENDING) {
2393 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
2394 Status = IoStatus.Status;
2395 }
2396
2397 return Status;
2398 }
2399
2400 // static void STDCALL find_chunk_root(device_extension* Vcb) {
2401 // UINT32 i;
2402 // KEY* key;
2403 //
2404 // i = 0;
2405 // while (i < Vcb->superblock.n) {
2406 // key = &Vcb->superblock.sys_chunk_array[i];
2407 // i += sizeof(KEY);
2408 // }
2409 //
2410 // // FIXME
2411 // }
2412
2413 // static void STDCALL insert_ltp(device_extension* Vcb, log_to_phys* ltp) {
2414 // if (!Vcb->log_to_phys) {
2415 // Vcb->log_to_phys = ltp;
2416 // ltp->next = NULL;
2417 // return;
2418 // }
2419 //
2420 // // FIXME - these should be ordered
2421 // ltp->next = Vcb->log_to_phys;
2422 // Vcb->log_to_phys = ltp;
2423 // }
2424
2425 static NTSTATUS STDCALL add_root(device_extension* Vcb, UINT64 id, UINT64 addr, traverse_ptr* tp) {
2426 root* r = ExAllocatePoolWithTag(PagedPool, sizeof(root), ALLOC_TAG);
2427 if (!r) {
2428 ERR("out of memory\n");
2429 return STATUS_INSUFFICIENT_RESOURCES;
2430 }
2431
2432 r->id = id;
2433 r->treeholder.address = addr;
2434 r->treeholder.tree = NULL;
2435 init_tree_holder(&r->treeholder);
2436 r->prev = NULL;
2437 r->next = Vcb->roots;
2438
2439 r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG);
2440 if (!r->nonpaged) {
2441 ERR("out of memory\n");
2442 ExFreePool(r);
2443 return STATUS_INSUFFICIENT_RESOURCES;
2444 }
2445
2446 ExInitializeResourceLite(&r->nonpaged->load_tree_lock);
2447
2448 r->lastinode = 0;
2449
2450 if (tp) {
2451 RtlCopyMemory(&r->root_item, tp->item->data, min(sizeof(ROOT_ITEM), tp->item->size));
2452 if (tp->item->size < sizeof(ROOT_ITEM))
2453 RtlZeroMemory(((UINT8*)&r->root_item) + tp->item->size, sizeof(ROOT_ITEM) - tp->item->size);
2454 }
2455
2456 if (Vcb->roots)
2457 Vcb->roots->prev = r;
2458
2459 Vcb->roots = r;
2460
2461 switch (r->id) {
2462 case BTRFS_ROOT_ROOT:
2463 Vcb->root_root = r;
2464 break;
2465
2466 case BTRFS_ROOT_EXTENT:
2467 Vcb->extent_root = r;
2468 break;
2469
2470 case BTRFS_ROOT_CHUNK:
2471 Vcb->chunk_root = r;
2472 break;
2473
2474 case BTRFS_ROOT_DEVTREE:
2475 Vcb->dev_root = r;
2476 break;
2477
2478 case BTRFS_ROOT_CHECKSUM:
2479 Vcb->checksum_root = r;
2480 break;
2481 }
2482
2483 return STATUS_SUCCESS;
2484 }
2485
2486 static NTSTATUS STDCALL look_for_roots(device_extension* Vcb) {
2487 traverse_ptr tp, next_tp;
2488 KEY searchkey;
2489 BOOL b;
2490 NTSTATUS Status;
2491
2492 searchkey.obj_id = 0;
2493 searchkey.obj_type = 0;
2494 searchkey.offset = 0;
2495
2496 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
2497 if (!NT_SUCCESS(Status)) {
2498 ERR("error - find_tree returned %08x\n", Status);
2499 return Status;
2500 }
2501
2502 do {
2503 TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
2504
2505 if (tp.item->key.obj_type == TYPE_ROOT_ITEM) {
2506 ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data;
2507
2508 if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) {
2509 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));
2510 } else {
2511 TRACE("root %llx - address %llx\n", tp.item->key.obj_id, ri->block_number);
2512
2513 Status = add_root(Vcb, tp.item->key.obj_id, ri->block_number, &tp);
2514 if (!NT_SUCCESS(Status)) {
2515 ERR("add_root returned %08x\n", Status);
2516 return Status;
2517 }
2518 }
2519 }
2520
2521 b = find_next_item(Vcb, &tp, &next_tp, FALSE);
2522
2523 if (b) {
2524 free_traverse_ptr(&tp);
2525 tp = next_tp;
2526 }
2527 } while (b);
2528
2529 free_traverse_ptr(&tp);
2530
2531 return STATUS_SUCCESS;
2532 }
2533
2534 static NTSTATUS add_disk_hole(LIST_ENTRY* disk_holes, UINT64 address, UINT64 size) {
2535 disk_hole* dh = ExAllocatePoolWithTag(PagedPool, sizeof(disk_hole), ALLOC_TAG);
2536
2537 if (!dh) {
2538 ERR("out of memory\n");
2539 return STATUS_INSUFFICIENT_RESOURCES;
2540 }
2541
2542 dh->address = address;
2543 dh->size = size;
2544 dh->provisional = FALSE;
2545
2546 InsertTailList(disk_holes, &dh->listentry);
2547
2548 return STATUS_SUCCESS;
2549 }
2550
2551 static NTSTATUS find_disk_holes(device_extension* Vcb, device* dev) {
2552 KEY searchkey;
2553 traverse_ptr tp, next_tp;
2554 BOOL b;
2555 UINT64 lastaddr;
2556 NTSTATUS Status;
2557
2558 InitializeListHead(&dev->disk_holes);
2559
2560 searchkey.obj_id = dev->devitem.dev_id;
2561 searchkey.obj_type = TYPE_DEV_EXTENT;
2562 searchkey.offset = 0;
2563
2564 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE);
2565 if (!NT_SUCCESS(Status)) {
2566 ERR("error - find_tree returned %08x\n", Status);
2567 return Status;
2568 }
2569
2570 lastaddr = 0;
2571
2572 do {
2573 if (tp.item->key.obj_id == dev->devitem.dev_id && tp.item->key.obj_type == TYPE_DEV_EXTENT) {
2574 if (tp.item->size >= sizeof(DEV_EXTENT)) {
2575 DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data;
2576
2577 if (tp.item->key.offset > lastaddr) {
2578 Status = add_disk_hole(&dev->disk_holes, lastaddr, tp.item->key.offset - lastaddr);
2579 if (!NT_SUCCESS(Status)) {
2580 ERR("add_disk_hole returned %08x\n", Status);
2581 return Status;
2582 }
2583 }
2584
2585 lastaddr = tp.item->key.offset + de->length;
2586 } else {
2587 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));
2588 }
2589 }
2590
2591 b = find_next_item(Vcb, &tp, &next_tp, FALSE);
2592
2593 if (b) {
2594 free_traverse_ptr(&tp);
2595 tp = next_tp;
2596 if (tp.item->key.obj_id > searchkey.obj_id || tp.item->key.obj_type > searchkey.obj_type)
2597 break;
2598 }
2599 } while (b);
2600
2601 free_traverse_ptr(&tp);
2602
2603 if (lastaddr < dev->devitem.num_bytes) {
2604 Status = add_disk_hole(&dev->disk_holes, lastaddr, dev->devitem.num_bytes - lastaddr);
2605 if (!NT_SUCCESS(Status)) {
2606 ERR("add_disk_hole returned %08x\n", Status);
2607 return Status;
2608 }
2609 }
2610
2611 // FIXME - free disk_holes when unmounting
2612
2613 return STATUS_SUCCESS;
2614 }
2615
2616 device* find_device_from_uuid(device_extension* Vcb, BTRFS_UUID* uuid) {
2617 UINT64 i;
2618
2619 for (i = 0; i < Vcb->superblock.num_devices; i++) {
2620 TRACE("device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", i,
2621 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],
2622 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]);
2623
2624 if (Vcb->devices[i].devobj && RtlCompareMemory(&Vcb->devices[i].devitem.device_uuid, uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2625 TRACE("returning device %llx\n", i);
2626 return &Vcb->devices[i];
2627 }
2628 }
2629
2630 WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
2631 uuid->uuid[0], uuid->uuid[1], uuid->uuid[2], uuid->uuid[3], uuid->uuid[4], uuid->uuid[5], uuid->uuid[6], uuid->uuid[7],
2632 uuid->uuid[8], uuid->uuid[9], uuid->uuid[10], uuid->uuid[11], uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]);
2633
2634 return NULL;
2635 }
2636
2637 static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
2638 traverse_ptr tp, next_tp;
2639 KEY searchkey;
2640 BOOL b;
2641 chunk* c;
2642 UINT64 i;
2643 NTSTATUS Status;
2644
2645 searchkey.obj_id = 0;
2646 searchkey.obj_type = 0;
2647 searchkey.offset = 0;
2648
2649 Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE);
2650 if (!NT_SUCCESS(Status)) {
2651 ERR("error - find_item returned %08x\n", Status);
2652 return Status;
2653 }
2654
2655 do {
2656 TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
2657
2658 if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM && tp.item->key.offset == 1) {
2659 // FIXME - this is a hack; make this work with multiple devices!
2660 if (tp.item->size > 0)
2661 RtlCopyMemory(&Vcb->devices[0].devitem, tp.item->data, min(tp.item->size, sizeof(DEV_ITEM)));
2662 } else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) {
2663 if (tp.item->size < sizeof(CHUNK_ITEM)) {
2664 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));
2665 } else {
2666 c = ExAllocatePoolWithTag(PagedPool, sizeof(chunk), ALLOC_TAG);
2667
2668 if (!c) {
2669 ERR("out of memory\n");
2670 return STATUS_INSUFFICIENT_RESOURCES;
2671 }
2672
2673 c->size = tp.item->size;
2674 c->offset = tp.item->key.offset;
2675 c->used = c->oldused = 0;
2676 c->space_changed = FALSE;
2677
2678 c->chunk_item = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
2679
2680 if (!c->chunk_item) {
2681 ERR("out of memory\n");
2682 return STATUS_INSUFFICIENT_RESOURCES;
2683 }
2684
2685 RtlCopyMemory(c->chunk_item, tp.item->data, tp.item->size);
2686
2687 if (c->chunk_item->num_stripes > 0) {
2688 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
2689
2690 c->devices = ExAllocatePoolWithTag(PagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG);
2691
2692 if (!c->devices) {
2693 ERR("out of memory\n");
2694 return STATUS_INSUFFICIENT_RESOURCES;
2695 }
2696
2697 for (i = 0; i < c->chunk_item->num_stripes; i++) {
2698 c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid);
2699 TRACE("device %llu = %p\n", i, c->devices[i]);
2700 }
2701 } else
2702 c->devices = NULL;
2703
2704 InitializeListHead(&c->space);
2705
2706 InsertTailList(&Vcb->chunks, &c->list_entry);
2707 }
2708 }
2709
2710 b = find_next_item(Vcb, &tp, &next_tp, FALSE);
2711
2712 if (b) {
2713 free_traverse_ptr(&tp);
2714 tp = next_tp;
2715 }
2716 } while (b);
2717
2718 free_traverse_ptr(&tp);
2719
2720 Vcb->log_to_phys_loaded = TRUE;
2721
2722 return STATUS_SUCCESS;
2723 }
2724
2725 static BOOL load_stored_free_space_cache(device_extension* Vcb, chunk* c) {
2726 KEY searchkey;
2727 traverse_ptr tp, tp2;
2728 FREE_SPACE_ITEM* fsi;
2729 UINT64 inode, num_sectors, i, generation;
2730 INODE_ITEM* ii;
2731 UINT8* data;
2732 NTSTATUS Status;
2733 UINT32 *checksums, crc32;
2734 #ifdef _DEBUG
2735 FREE_SPACE_ENTRY* fse;
2736 UINT64 num_entries;
2737 #endif
2738
2739 TRACE("(%p, %llx)\n", Vcb, c->offset);
2740
2741 if (Vcb->superblock.generation != Vcb->superblock.cache_generation)
2742 return FALSE;
2743
2744 searchkey.obj_id = FREE_SPACE_CACHE_ID;
2745 searchkey.obj_type = 0;
2746 searchkey.offset = c->offset;
2747
2748 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
2749 if (!NT_SUCCESS(Status)) {
2750 ERR("error - find_item returned %08x\n", Status);
2751 return FALSE;
2752 }
2753
2754 if (keycmp(&tp.item->key, &searchkey)) {
2755 WARN("(%llx,%x,%llx) not found\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
2756 free_traverse_ptr(&tp);
2757 return FALSE;
2758 }
2759
2760 if (tp.item->size < sizeof(FREE_SPACE_ITEM)) {
2761 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(FREE_SPACE_ITEM));
2762 free_traverse_ptr(&tp);
2763 return FALSE;
2764 }
2765
2766 fsi = (FREE_SPACE_ITEM*)tp.item->data;
2767
2768 if (fsi->generation != Vcb->superblock.cache_generation) {
2769 WARN("cache had generation %llx, expecting %llx\n", fsi->generation, Vcb->superblock.cache_generation);
2770 free_traverse_ptr(&tp);
2771 return FALSE;
2772 }
2773
2774 if (fsi->key.obj_type != TYPE_INODE_ITEM) {
2775 WARN("cache pointed to something other than an INODE_ITEM\n");
2776 free_traverse_ptr(&tp);
2777 return FALSE;
2778 }
2779
2780 if (fsi->num_bitmaps > 0) {
2781 WARN("cache had bitmaps, unsure of how to deal with these\n");
2782 free_traverse_ptr(&tp);
2783 return FALSE;
2784 }
2785
2786 inode = fsi->key.obj_id;
2787
2788 searchkey = fsi->key;
2789 #ifdef _DEBUG
2790 num_entries = fsi->num_entries;
2791 #endif
2792
2793 Status = find_item(Vcb, Vcb->root_root, &tp2, &searchkey, FALSE);
2794 if (!NT_SUCCESS(Status)) {
2795 ERR("error - find_item returned %08x\n", Status);
2796 free_traverse_ptr(&tp);
2797 return FALSE;
2798 }
2799
2800 free_traverse_ptr(&tp);
2801
2802 if (keycmp(&tp2.item->key, &searchkey)) {
2803 WARN("(%llx,%x,%llx) not found\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
2804 free_traverse_ptr(&tp2);
2805 return FALSE;
2806 }
2807
2808 if (tp2.item->size < sizeof(INODE_ITEM)) {
2809 WARN("(%llx,%x,%llx) was %u bytes, expected %u\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, tp2.item->size, sizeof(INODE_ITEM));
2810 free_traverse_ptr(&tp2);
2811 return FALSE;
2812 }
2813
2814 ii = (INODE_ITEM*)tp2.item->data;
2815
2816 data = ExAllocatePoolWithTag(PagedPool, ii->st_size, ALLOC_TAG);
2817
2818 if (!data) {
2819 ERR("out of memory\n");
2820 free_traverse_ptr(&tp2);
2821 return FALSE;
2822 }
2823
2824 Status = read_file(Vcb, Vcb->root_root, inode, data, 0, ii->st_size, NULL);
2825 if (!NT_SUCCESS(Status)) {
2826 ERR("read_file returned %08x\n", Status);
2827 ExFreePool(data);
2828 free_traverse_ptr(&tp2);
2829 return FALSE;
2830 }
2831
2832 num_sectors = ii->st_size / Vcb->superblock.sector_size;
2833
2834 generation = *(data + (num_sectors * sizeof(UINT32)));
2835
2836 if (generation != Vcb->superblock.cache_generation) {
2837 ERR("generation was %llx, expected %llx\n", generation, Vcb->superblock.cache_generation);
2838 ExFreePool(data);
2839 free_traverse_ptr(&tp2);
2840 return FALSE;
2841 }
2842
2843 checksums = ExAllocatePoolWithTag(PagedPool, sizeof(UINT32) * num_sectors, ALLOC_TAG); // FIXME - get rid of this
2844
2845 if (!checksums) {
2846 ERR("out of memory\n");
2847 ExFreePool(data);
2848 free_traverse_ptr(&tp2);
2849 return FALSE;
2850 }
2851
2852 RtlCopyMemory(checksums, data, sizeof(UINT32) * num_sectors);
2853
2854 for (i = 0; i < num_sectors; i++) {
2855 if (i * Vcb->superblock.sector_size > sizeof(UINT32) * num_sectors)
2856 crc32 = ~calc_crc32c(0xffffffff, &data[i * Vcb->superblock.sector_size], Vcb->superblock.sector_size);
2857 else if ((i + 1) * Vcb->superblock.sector_size < sizeof(UINT32) * num_sectors)
2858 crc32 = 0; // FIXME - test this
2859 else
2860 crc32 = ~calc_crc32c(0xffffffff, &data[sizeof(UINT32) * num_sectors], ((i + 1) * Vcb->superblock.sector_size) - (sizeof(UINT32) * num_sectors));
2861
2862 if (crc32 != checksums[i]) {
2863 WARN("checksum %llu was %08x, expected %08x\n", i, crc32, checksums[i]);
2864 ExFreePool(checksums);
2865 ExFreePool(data);
2866 free_traverse_ptr(&tp2);
2867 return FALSE;
2868 }
2869 }
2870
2871 ExFreePool(checksums);
2872
2873 #ifdef _DEBUG
2874 fse = (FREE_SPACE_ENTRY*)&data[(sizeof(UINT32) * num_sectors) + sizeof(UINT64)];
2875
2876 for (i = 0; i < num_entries; i++) {
2877 TRACE("(%llx,%llx,%x)\n", fse[i].offset, fse[i].size, fse[i].type);
2878 }
2879 #endif
2880
2881 FIXME("FIXME - read cache\n");
2882
2883 ExFreePool(data);
2884 free_traverse_ptr(&tp2);
2885
2886 return FALSE;
2887 }
2888
2889 static NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c) {
2890 traverse_ptr tp, next_tp;
2891 KEY searchkey;
2892 UINT64 lastaddr;
2893 BOOL b;
2894 space *s, *s2;
2895 LIST_ENTRY* le;
2896 NTSTATUS Status;
2897
2898 load_stored_free_space_cache(Vcb, c);
2899
2900 TRACE("generating free space cache for chunk %llx\n", c->offset);
2901
2902 searchkey.obj_id = c->offset;
2903 searchkey.obj_type = TYPE_EXTENT_ITEM;
2904 searchkey.offset = 0;
2905
2906 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
2907 if (!NT_SUCCESS(Status)) {
2908 ERR("error - find_item returned %08x\n", Status);
2909 return Status;
2910 }
2911
2912 lastaddr = c->offset;
2913
2914 do {
2915 if (tp.item->key.obj_id >= c->offset + c->chunk_item->size)
2916 break;
2917
2918 if (tp.item->key.obj_id >= c->offset && (tp.item->key.obj_type == TYPE_EXTENT_ITEM || tp.item->key.obj_type == TYPE_METADATA_ITEM)) {
2919 if (tp.item->key.obj_id > lastaddr) {
2920 s = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
2921
2922 if (!s) {
2923 ERR("out of memory\n");
2924 return STATUS_INSUFFICIENT_RESOURCES;
2925 }
2926
2927 s->offset = lastaddr;
2928 s->size = tp.item->key.obj_id - lastaddr;
2929 s->type = SPACE_TYPE_FREE;
2930 InsertTailList(&c->space, &s->list_entry);
2931
2932 TRACE("(%llx,%llx)\n", s->offset, s->size);
2933 }
2934
2935 if (tp.item->key.obj_type == TYPE_METADATA_ITEM)
2936 lastaddr = tp.item->key.obj_id + Vcb->superblock.node_size;
2937 else
2938 lastaddr = tp.item->key.obj_id + tp.item->key.offset;
2939 }
2940
2941 b = find_next_item(Vcb, &tp, &next_tp, FALSE);
2942 if (b) {
2943 free_traverse_ptr(&tp);
2944 tp = next_tp;
2945 }
2946 } while (b);
2947
2948 if (lastaddr < c->offset + c->chunk_item->size) {
2949 s = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
2950
2951 if (!s) {
2952 ERR("out of memory\n");
2953 return STATUS_INSUFFICIENT_RESOURCES;
2954 }
2955
2956 s->offset = lastaddr;
2957 s->size = c->offset + c->chunk_item->size - lastaddr;
2958 s->type = SPACE_TYPE_FREE;
2959 InsertTailList(&c->space, &s->list_entry);
2960
2961 TRACE("(%llx,%llx)\n", s->offset, s->size);
2962 }
2963
2964 free_traverse_ptr(&tp);
2965
2966 // add allocated space
2967
2968 lastaddr = c->offset;
2969
2970 le = c->space.Flink;
2971 while (le != &c->space) {
2972 s = CONTAINING_RECORD(le, space, list_entry);
2973
2974 if (s->offset > lastaddr) {
2975 s2 = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
2976
2977 if (!s2) {
2978 ERR("out of memory\n");
2979 return STATUS_INSUFFICIENT_RESOURCES;
2980 }
2981
2982 s2->offset = lastaddr;
2983 s2->size = s->offset - lastaddr;
2984 s2->type = SPACE_TYPE_USED;
2985
2986 InsertTailList(&s->list_entry, &s2->list_entry);
2987 }
2988
2989 lastaddr = s->offset + s->size;
2990
2991 le = le->Flink;
2992 }
2993
2994 if (lastaddr < c->offset + c->chunk_item->size) {
2995 s = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
2996
2997 if (!s) {
2998 ERR("out of memory\n");
2999 return STATUS_INSUFFICIENT_RESOURCES;
3000 }
3001
3002 s->offset = lastaddr;
3003 s->size = c->offset + c->chunk_item->size - lastaddr;
3004 s->type = SPACE_TYPE_USED;
3005 InsertTailList(&c->space, &s->list_entry);
3006 }
3007
3008 le = c->space.Flink;
3009 while (le != &c->space) {
3010 s = CONTAINING_RECORD(le, space, list_entry);
3011
3012 TRACE("%llx,%llx,%u\n", s->offset, s->size, s->type);
3013
3014 le = le->Flink;
3015 }
3016
3017 return STATUS_SUCCESS;
3018 }
3019
3020 void protect_superblocks(device_extension* Vcb, chunk* c) {
3021 int i = 0, j;
3022 UINT64 addr;
3023
3024 // FIXME - this will need modifying for RAID
3025
3026 while (superblock_addrs[i] != 0) {
3027 CHUNK_ITEM* ci = c->chunk_item;
3028 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
3029
3030 for (j = 0; j < ci->num_stripes; j++) {
3031 if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3032 UINT32 size;
3033
3034 TRACE("cut out superblock in chunk %llx\n", c->offset);
3035
3036 addr = (superblock_addrs[i] - cis[j].offset) + c->offset;
3037 TRACE("addr %llx\n", addr);
3038
3039 // This prevents trees from spanning a stripe boundary, which btrfs check complains
3040 // about. It also prevents the chunk tree being placed at 0x11000, which for some
3041 // reason makes the FS unmountable on Linux (it tries to read 0x10000, i.e. the
3042 // superblock, instead).
3043 if (ci->type & BLOCK_FLAG_SYSTEM || ci->type & BLOCK_FLAG_METADATA)
3044 size = max(sizeof(superblock), Vcb->superblock.node_size);
3045 else
3046 size = sizeof(superblock);
3047
3048 add_to_space_list(c, addr, size, SPACE_TYPE_USED);
3049 }
3050 }
3051
3052 i++;
3053 }
3054 }
3055
3056 static NTSTATUS STDCALL find_chunk_usage(device_extension* Vcb) {
3057 LIST_ENTRY* le = Vcb->chunks.Flink;
3058 chunk* c;
3059 KEY searchkey;
3060 traverse_ptr tp;
3061 BLOCK_GROUP_ITEM* bgi;
3062 NTSTATUS Status;
3063
3064 // c00000,c0,800000
3065 // block_group_item size=7f0000 chunktreeid=100 flags=1
3066
3067 searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM;
3068
3069 while (le != &Vcb->chunks) {
3070 c = CONTAINING_RECORD(le, chunk, list_entry);
3071
3072 searchkey.obj_id = c->offset;
3073 searchkey.offset = c->chunk_item->size;
3074
3075 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
3076 if (!NT_SUCCESS(Status)) {
3077 ERR("error - find_item returned %08x\n", Status);
3078 return Status;
3079 }
3080
3081 if (!keycmp(&searchkey, &tp.item->key)) {
3082 if (tp.item->size >= sizeof(BLOCK_GROUP_ITEM)) {
3083 bgi = (BLOCK_GROUP_ITEM*)tp.item->data;
3084
3085 c->used = c->oldused = bgi->used;
3086
3087 TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used);
3088 } else {
3089 ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n",
3090 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));
3091 }
3092 }
3093
3094 free_traverse_ptr(&tp);
3095 // if (addr >= c->offset && (addr - c->offset) < c->chunk_item->size && c->chunk_item->num_stripes > 0) {
3096 // cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
3097 //
3098 // return (addr - c->offset) + cis->offset;
3099 // }
3100
3101 // FIXME - make sure we free occasionally after doing one of these, or we
3102 // might use up a lot of memory with a big disk.
3103
3104 Status = load_free_space_cache(Vcb, c);
3105 if (!NT_SUCCESS(Status)) {
3106 ERR("load_free_space_cache returned %08x\n", Status);
3107 return Status;
3108 }
3109
3110 protect_superblocks(Vcb, c);
3111
3112 le = le->Flink;
3113 }
3114
3115 return STATUS_SUCCESS;
3116 }
3117
3118 // static void STDCALL root_test(device_extension* Vcb) {
3119 // root* r;
3120 // KEY searchkey;
3121 // traverse_ptr tp, next_tp;
3122 // BOOL b;
3123 //
3124 // r = Vcb->roots;
3125 // while (r) {
3126 // if (r->id == 0x102)
3127 // break;
3128 // r = r->next;
3129 // }
3130 //
3131 // if (!r) {
3132 // ERR("Could not find root tree.\n");
3133 // return;
3134 // }
3135 //
3136 // searchkey.obj_id = 0x1b6;
3137 // searchkey.obj_type = 0xb;
3138 // searchkey.offset = 0;
3139 //
3140 // if (!find_item(Vcb, r, &tp, &searchkey, NULL, FALSE)) {
3141 // ERR("Could not find first item.\n");
3142 // return;
3143 // }
3144 //
3145 // b = TRUE;
3146 // do {
3147 // TRACE("%x,%x,%x\n", (UINT32)tp.item->key.obj_id, tp.item->key.obj_type, (UINT32)tp.item->key.offset);
3148 //
3149 // b = find_prev_item(Vcb, &tp, &next_tp, NULL, FALSE);
3150 //
3151 // if (b) {
3152 // free_traverse_ptr(&tp);
3153 // tp = next_tp;
3154 // }
3155 // } while (b);
3156 //
3157 // free_traverse_ptr(&tp);
3158 // }
3159
3160 static NTSTATUS load_sys_chunks(device_extension* Vcb) {
3161 KEY key;
3162 ULONG n = Vcb->superblock.n;
3163
3164 while (n > 0) {
3165 if (n > sizeof(KEY)) {
3166 RtlCopyMemory(&key, &Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n], sizeof(KEY));
3167 n -= sizeof(KEY);
3168 } else
3169 return STATUS_SUCCESS;
3170
3171 TRACE("bootstrap: %llx,%x,%llx\n", key.obj_id, key.obj_type, key.offset);
3172
3173 if (key.obj_type == TYPE_CHUNK_ITEM) {
3174 CHUNK_ITEM* ci;
3175 ULONG cisize;
3176 sys_chunk* sc;
3177
3178 if (n < sizeof(CHUNK_ITEM))
3179 return STATUS_SUCCESS;
3180
3181 ci = (CHUNK_ITEM*)&Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n];
3182 cisize = sizeof(CHUNK_ITEM) + (ci->num_stripes * sizeof(CHUNK_ITEM_STRIPE));
3183
3184 if (n < cisize)
3185 return STATUS_SUCCESS;
3186
3187 sc = ExAllocatePoolWithTag(PagedPool, sizeof(sys_chunk), ALLOC_TAG);
3188
3189 if (!sc) {
3190 ERR("out of memory\n");
3191 return STATUS_INSUFFICIENT_RESOURCES;
3192 }
3193
3194 sc->key = key;
3195 sc->size = cisize;
3196 sc->data = ExAllocatePoolWithTag(PagedPool, sc->size, ALLOC_TAG);
3197
3198 if (!sc->data) {
3199 ERR("out of memory\n");
3200 return STATUS_INSUFFICIENT_RESOURCES;
3201 }
3202
3203 RtlCopyMemory(sc->data, ci, sc->size);
3204 InsertTailList(&Vcb->sys_chunks, &sc->list_entry);
3205
3206 n -= cisize;
3207 } else {
3208 ERR("unexpected item %llx,%x,%llx in bootstrap\n", key.obj_id, key.obj_type, key.offset);
3209 return STATUS_INTERNAL_ERROR;
3210 }
3211 }
3212
3213 return STATUS_SUCCESS;
3214 }
3215
3216 static root* find_default_subvol(device_extension* Vcb) {
3217 root* subvol;
3218 UINT64 inode;
3219 UINT8 type;
3220 UNICODE_STRING filename;
3221
3222 static WCHAR fn[] = L"default";
3223 static UINT32 crc32 = 0x8dbfc2d2;
3224
3225 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL) {
3226 filename.Buffer = fn;
3227 filename.Length = filename.MaximumLength = (USHORT)wcslen(fn) * sizeof(WCHAR);
3228
3229 if (!find_file_in_dir_with_crc32(Vcb, &filename, crc32, Vcb->root_root, Vcb->superblock.root_dir_objectid, &subvol, &inode, &type, NULL))
3230 WARN("couldn't find default subvol DIR_ITEM, using default tree\n");
3231 else
3232 return subvol;
3233 }
3234
3235 subvol = Vcb->roots;
3236 while (subvol && subvol->id != BTRFS_ROOT_FSTREE)
3237 subvol = subvol->next;
3238
3239 return subvol;
3240 }
3241
3242 static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
3243 PIO_STACK_LOCATION Stack;
3244 PDEVICE_OBJECT NewDeviceObject = NULL;
3245 PDEVICE_OBJECT DeviceToMount;
3246 NTSTATUS Status;
3247 device_extension* Vcb = NULL;
3248 PARTITION_INFORMATION_EX piex;
3249 UINT64 i;
3250 LIST_ENTRY* le;
3251 KEY searchkey;
3252 traverse_ptr tp;
3253
3254 TRACE("mount_vol called\n");
3255
3256 if (DeviceObject != devobj)
3257 {
3258 Status = STATUS_INVALID_DEVICE_REQUEST;
3259 goto exit;
3260 }
3261
3262 Stack = IoGetCurrentIrpStackLocation(Irp);
3263 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
3264
3265 // Status = NtfsHasFileSystem(DeviceToMount);
3266 // if (!NT_SUCCESS(Status))
3267 // {
3268 // goto ByeBye;
3269 // }
3270
3271 Status = dev_ioctl(DeviceToMount, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
3272 &piex, sizeof(piex), TRUE);
3273 if (!NT_SUCCESS(Status)) {
3274 ERR("error reading partition information: %08x\n", Status);
3275 goto exit;
3276 }
3277
3278 Status = IoCreateDevice(drvobj,
3279 sizeof(device_extension),
3280 NULL,
3281 FILE_DEVICE_DISK_FILE_SYSTEM,
3282 0,
3283 FALSE,
3284 &NewDeviceObject);
3285 if (!NT_SUCCESS(Status))
3286 goto exit;
3287
3288 // TRACE("DEV_ITEM = %x, superblock = %x\n", sizeof(DEV_ITEM), sizeof(superblock));
3289
3290 NewDeviceObject->Flags |= DO_DIRECT_IO;
3291 Vcb = (PVOID)NewDeviceObject->DeviceExtension;
3292 RtlZeroMemory(Vcb, sizeof(device_extension));
3293
3294 InitializeListHead(&Vcb->tree_cache);
3295
3296 ExInitializeResourceLite(&Vcb->tree_lock);
3297 Vcb->tree_lock_counter = 0;
3298 Vcb->open_trees = 0;
3299 Vcb->write_trees = 0;
3300
3301 ExInitializeResourceLite(&Vcb->fcb_lock);
3302 ExInitializeResourceLite(&Vcb->DirResource);
3303
3304 ExAcquireResourceExclusiveLite(&global_loading_lock, TRUE);
3305 InsertTailList(&VcbList, &Vcb->list_entry);
3306 ExReleaseResourceLite(&global_loading_lock);
3307
3308 ExInitializeResourceLite(&Vcb->load_lock);
3309 ExAcquireResourceExclusiveLite(&Vcb->load_lock, TRUE);
3310
3311 // Vcb->Identifier.Type = NTFS_TYPE_VCB;
3312 // Vcb->Identifier.Size = sizeof(NTFS_TYPE_VCB);
3313 //
3314 // Status = NtfsGetVolumeData(DeviceToMount,
3315 // Vcb);
3316 // if (!NT_SUCCESS(Status))
3317 // goto ByeBye;
3318
3319 // Vcb->device = DeviceToMount;
3320 DeviceToMount->Flags |= DO_DIRECT_IO;
3321
3322 // Status = dev_ioctl(DeviceToMount, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
3323 // &Vcb->geometry, sizeof(DISK_GEOMETRY), TRUE);
3324 // if (!NT_SUCCESS(Status)) {
3325 // ERR("error reading disk geometry: %08x\n", Status);
3326 // goto exit;
3327 // } else {
3328 // TRACE("media type = %u, cylinders = %u, tracks per cylinder = %u, sectors per track = %u, bytes per sector = %u\n",
3329 // Vcb->geometry.MediaType, Vcb->geometry.Cylinders, Vcb->geometry.TracksPerCylinder,
3330 // Vcb->geometry.SectorsPerTrack, Vcb->geometry.BytesPerSector);
3331 // }
3332
3333 Vcb->length = piex.PartitionLength.QuadPart;
3334 TRACE("partition length = %u\n", piex.PartitionLength);
3335
3336 Status = read_superblock(Vcb, DeviceToMount);
3337 if (!NT_SUCCESS(Status)) {
3338 Status = STATUS_UNRECOGNIZED_VOLUME;
3339 goto exit;
3340 }
3341
3342 if (Vcb->superblock.magic != BTRFS_MAGIC) {
3343 ERR("not a BTRFS volume\n");
3344 Status = STATUS_UNRECOGNIZED_VOLUME;
3345 goto exit;
3346 } else {
3347 TRACE("btrfs magic found\n");
3348 }
3349
3350 if (Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED) {
3351 WARN("cannot mount because of unsupported incompat flags (%llx)\n", Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED);
3352 Status = STATUS_UNRECOGNIZED_VOLUME;
3353 goto exit;
3354 }
3355
3356 le = volumes.Flink;
3357 while (le != &volumes) {
3358 volume* v = CONTAINING_RECORD(le, volume, list_entry);
3359
3360 if (RtlCompareMemory(&Vcb->superblock.uuid, &v->fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID) && v->devnum < Vcb->superblock.dev_item.dev_id) {
3361 // skipping over device in RAID which isn't the first one
3362 // FIXME - hide this in My Computer
3363 Status = STATUS_UNRECOGNIZED_VOLUME;
3364 goto exit;
3365 }
3366
3367 le = le->Flink;
3368 }
3369
3370 // FIXME - remove this when we can
3371 if (Vcb->superblock.num_devices > 1) {
3372 WARN("not mounting - multiple devices not yet implemented\n");
3373 Status = STATUS_UNRECOGNIZED_VOLUME;
3374 goto exit;
3375 }
3376
3377 Vcb->readonly = FALSE;
3378 if (Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED) {
3379 WARN("mounting read-only because of unsupported flags (%llx)\n", Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED);
3380 Vcb->readonly = TRUE;
3381 }
3382
3383 Vcb->superblock.generation++;
3384 Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF;
3385
3386 Vcb->devices = ExAllocatePoolWithTag(PagedPool, sizeof(device) * Vcb->superblock.num_devices, ALLOC_TAG);
3387 if (!Vcb->devices) {
3388 ERR("out of memory\n");
3389 Status = STATUS_INSUFFICIENT_RESOURCES;
3390 goto exit;
3391 }
3392
3393 Vcb->devices[0].devobj = DeviceToMount;
3394 RtlCopyMemory(&Vcb->devices[0].devitem, &Vcb->superblock.dev_item, sizeof(DEV_ITEM));
3395
3396 if (Vcb->superblock.num_devices > 1)
3397 RtlZeroMemory(&Vcb->devices[1], sizeof(DEV_ITEM) * (Vcb->superblock.num_devices - 1));
3398
3399 // FIXME - find other devices, if there are any
3400
3401 TRACE("DeviceToMount = %p\n", DeviceToMount);
3402 TRACE("Stack->Parameters.MountVolume.Vpb = %p\n", Stack->Parameters.MountVolume.Vpb);
3403
3404 NewDeviceObject->StackSize = DeviceToMount->StackSize + 1;
3405 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3406
3407 // find_chunk_root(Vcb);
3408 // Vcb->chunk_root_phys_addr = Vcb->superblock.chunk_tree_addr; // FIXME - map from logical to physical (bootstrapped)
3409
3410 // Vcb->root_tree_phys_addr = logical_to_physical(Vcb, Vcb->superblock.root_tree_addr);
3411
3412 Vcb->roots = NULL;
3413 Vcb->log_to_phys_loaded = FALSE;
3414
3415 Vcb->max_inline = Vcb->superblock.node_size / 2;
3416
3417 // Vcb->write_trees = NULL;
3418
3419 add_root(Vcb, BTRFS_ROOT_CHUNK, Vcb->superblock.chunk_tree_addr, NULL);
3420
3421 if (!Vcb->chunk_root) {
3422 ERR("Could not load chunk root.\n");
3423 Status = STATUS_INTERNAL_ERROR;
3424 goto exit;
3425 }
3426
3427 InitializeListHead(&Vcb->sys_chunks);
3428 Status = load_sys_chunks(Vcb);
3429 if (!NT_SUCCESS(Status)) {
3430 ERR("load_sys_chunks returned %08x\n", Status);
3431 goto exit;
3432 }
3433
3434 InitializeListHead(&Vcb->chunks);
3435 InitializeListHead(&Vcb->trees);
3436
3437 InitializeListHead(&Vcb->DirNotifyList);
3438
3439 FsRtlNotifyInitializeSync(&Vcb->NotifySync);
3440
3441 Status = load_chunk_root(Vcb);
3442 if (!NT_SUCCESS(Status)) {
3443 ERR("load_chunk_root returned %08x\n", Status);
3444 goto exit;
3445 }
3446
3447 add_root(Vcb, BTRFS_ROOT_ROOT, Vcb->superblock.root_tree_addr, NULL);
3448
3449 if (!Vcb->root_root) {
3450 ERR("Could not load root of roots.\n");
3451 Status = STATUS_INTERNAL_ERROR;
3452 goto exit;
3453 }
3454
3455 Status = look_for_roots(Vcb);
3456 if (!NT_SUCCESS(Status)) {
3457 ERR("look_for_roots returned %08x\n", Status);
3458 goto exit;
3459 }
3460
3461 Status = find_chunk_usage(Vcb);
3462 if (!NT_SUCCESS(Status)) {
3463 ERR("find_chunk_usage returned %08x\n", Status);
3464 goto exit;
3465 }
3466
3467 Vcb->volume_fcb = create_fcb();
3468 if (!Vcb->volume_fcb) {
3469 ERR("out of memory\n");
3470 Status = STATUS_INSUFFICIENT_RESOURCES;
3471 goto exit;
3472 }
3473
3474 Vcb->volume_fcb->Vcb = Vcb;
3475 Vcb->volume_fcb->sd = NULL;
3476
3477 Vcb->root_fcb = create_fcb();
3478 if (!Vcb->root_fcb) {
3479 ERR("out of memory\n");
3480 Status = STATUS_INSUFFICIENT_RESOURCES;
3481 goto exit;
3482 }
3483
3484 Vcb->root_fcb->Vcb = Vcb;
3485 Vcb->root_fcb->inode = SUBVOL_ROOT_INODE;
3486 Vcb->root_fcb->type = BTRFS_TYPE_DIRECTORY;
3487
3488 Vcb->root_fcb->full_filename.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(WCHAR), ALLOC_TAG);
3489
3490 if (!Vcb->root_fcb->full_filename.Buffer) {
3491 ERR("out of memory\n");
3492 Status = STATUS_INSUFFICIENT_RESOURCES;
3493 goto exit;
3494 }
3495
3496 Vcb->root_fcb->full_filename.Buffer[0] = '\\';
3497 Vcb->root_fcb->full_filename.Length = Vcb->root_fcb->full_filename.MaximumLength = sizeof(WCHAR);
3498
3499 #ifdef DEBUG_FCB_REFCOUNTS
3500 WARN("volume FCB = %p\n", Vcb->volume_fcb);
3501 WARN("root FCB = %p\n", Vcb->root_fcb);
3502 #endif
3503
3504 Vcb->root_fcb->subvol = find_default_subvol(Vcb);
3505
3506 if (!Vcb->root_fcb->subvol) {
3507 ERR("could not find top subvol\n");
3508 Status = STATUS_INTERNAL_ERROR;
3509 goto exit;
3510 }
3511
3512 Vcb->fcbs = Vcb->root_fcb;
3513
3514 searchkey.obj_id = Vcb->root_fcb->inode;
3515 searchkey.obj_type = TYPE_INODE_ITEM;
3516 searchkey.offset = 0xffffffffffffffff;
3517
3518 Status = find_item(Vcb, Vcb->root_fcb->subvol, &tp, &searchkey, FALSE);
3519 if (!NT_SUCCESS(Status)) {
3520 ERR("error - find_item returned %08x\n", Status);
3521 goto exit;
3522 }
3523
3524 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
3525 ERR("couldn't find INODE_ITEM for root directory\n");
3526 Status = STATUS_INTERNAL_ERROR;
3527 free_traverse_ptr(&tp);
3528 goto exit;
3529 }
3530
3531 if (tp.item->size > 0)
3532 RtlCopyMemory(&Vcb->root_fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
3533
3534 free_traverse_ptr(&tp);
3535
3536 fcb_get_sd(Vcb->root_fcb);
3537
3538 Vcb->root_fcb->atts = get_file_attributes(Vcb, &Vcb->root_fcb->inode_item, Vcb->root_fcb->subvol, Vcb->root_fcb->inode, Vcb->root_fcb->type,
3539 FALSE, FALSE);
3540
3541 for (i = 0; i < Vcb->superblock.num_devices; i++) {
3542 Status = find_disk_holes(Vcb, &Vcb->devices[i]);
3543 if (!NT_SUCCESS(Status)) {
3544 ERR("find_disk_holes returned %08x\n", Status);
3545 goto exit;
3546 }
3547 }
3548
3549 // root_test(Vcb);
3550
3551 // Vcb->StreamFileObject = IoCreateStreamFileObject(NULL,
3552 // Vcb->StorageDevice);
3553 //
3554 // InitializeListHead(&Vcb->FcbListHead);
3555 //
3556 // Fcb = NtfsCreateFCB(NULL, Vcb);
3557 // if (Fcb == NULL)
3558 // {
3559 // Status = STATUS_INSUFFICIENT_RESOURCES;
3560 // goto ByeBye;
3561 // }
3562 //
3563 // Ccb = ExAllocatePoolWithTag(NonPagedPool,
3564 // sizeof(NTFS_CCB),
3565 // TAG_CCB);
3566 // if (Ccb == NULL)
3567 // {
3568 // Status = STATUS_INSUFFICIENT_RESOURCES;
3569 // goto ByeBye;
3570 // }
3571 //
3572 // RtlZeroMemory(Ccb, sizeof(NTFS_CCB));
3573 //
3574 // Ccb->Identifier.Type = NTFS_TYPE_CCB;
3575 // Ccb->Identifier.Size = sizeof(NTFS_TYPE_CCB);
3576 //
3577 // Vcb->StreamFileObject->FsContext = Fcb;
3578 // Vcb->StreamFileObject->FsContext2 = Ccb;
3579 // Vcb->StreamFileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
3580 // Vcb->StreamFileObject->PrivateCacheMap = NULL;
3581 // Vcb->StreamFileObject->Vpb = Vcb->Vpb;
3582 // Ccb->PtrFileObject = Vcb->StreamFileObject;
3583 // Fcb->FileObject = Vcb->StreamFileObject;
3584 // Fcb->Vcb = (PDEVICE_EXTENSION)Vcb->StorageDevice;
3585 //
3586 // Fcb->Flags = FCB_IS_VOLUME_STREAM;
3587 //
3588 // Fcb->RFCB.FileSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
3589 // Fcb->RFCB.ValidDataLength.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector;
3590 // Fcb->RFCB.AllocationSize.QuadPart = Vcb->NtfsInfo.SectorCount * Vcb->NtfsInfo.BytesPerSector; /* Correct? */
3591 //
3592 // CcInitializeCacheMap(Vcb->StreamFileObject,
3593 // (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
3594 // FALSE,
3595 // &(NtfsGlobalData->CacheMgrCallbacks),
3596 // Fcb);
3597 //
3598 // ExInitializeResourceLite(&Vcb->LogToPhysLock);
3599
3600 KeInitializeSpinLock(&Vcb->FcbListLock);
3601 //
3602 // /* Get serial number */
3603 // NewDeviceObject->Vpb->SerialNumber = Vcb->NtfsInfo.SerialNumber;
3604 //
3605 // /* Get volume label */
3606 // NewDeviceObject->Vpb->VolumeLabelLength = Vcb->NtfsInfo.VolumeLabelLength;
3607 // RtlCopyMemory(NewDeviceObject->Vpb->VolumeLabel,
3608 // Vcb->NtfsInfo.VolumeLabel,
3609 // Vcb->NtfsInfo.VolumeLabelLength);
3610
3611 Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, NULL, NULL, NULL, flush_thread, Vcb);
3612 if (!NT_SUCCESS(Status)) {
3613 ERR("PsCreateSystemThread returned %08x\n", Status);
3614 goto exit;
3615 }
3616
3617 NewDeviceObject->Vpb = Stack->Parameters.MountVolume.Vpb;
3618 Stack->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject;
3619 Stack->Parameters.MountVolume.Vpb->RealDevice = DeviceToMount;
3620 Stack->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED;
3621 NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME
3622 NewDeviceObject->Vpb->VolumeLabel[0] = '?';
3623 NewDeviceObject->Vpb->VolumeLabel[1] = 0;
3624 NewDeviceObject->Vpb->ReferenceCount++; // FIXME - should we deref this at any point?
3625
3626 Status = STATUS_SUCCESS;
3627
3628 exit:
3629 // if (!NT_SUCCESS(Status))
3630 // {
3631 // /* Cleanup */
3632 // if (Vcb && Vcb->StreamFileObject)
3633 // ObDereferenceObject(Vcb->StreamFileObject);
3634 //
3635 // if (Fcb)
3636 // ExFreePool(Fcb);
3637 //
3638 // if (Ccb)
3639 // ExFreePool(Ccb);
3640 //
3641 // if (NewDeviceObject)
3642 // IoDeleteDevice(NewDeviceObject);
3643 // }
3644
3645 if (Vcb) {
3646 ExReleaseResourceLite(&Vcb->load_lock);
3647 }
3648
3649 if (!NT_SUCCESS(Status)) {
3650 if (Vcb) {
3651 if (Vcb->root_fcb)
3652 free_fcb(Vcb->root_fcb);
3653
3654 if (Vcb->volume_fcb)
3655 free_fcb(Vcb->volume_fcb);
3656
3657 ExDeleteResourceLite(&Vcb->tree_lock);
3658 ExDeleteResourceLite(&Vcb->load_lock);
3659 ExDeleteResourceLite(&Vcb->fcb_lock);
3660 ExDeleteResourceLite(&Vcb->DirResource);
3661
3662 if (Vcb->devices)
3663 ExFreePoolWithTag(Vcb->devices, ALLOC_TAG);
3664
3665 RemoveEntryList(&Vcb->list_entry);
3666 }
3667
3668 if (NewDeviceObject)
3669 IoDeleteDevice(NewDeviceObject);
3670 }
3671
3672 TRACE("mount_vol done (status: %lx)\n", Status);
3673
3674 return Status;
3675 }
3676
3677 static NTSTATUS STDCALL drv_file_system_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
3678 PIO_STACK_LOCATION IrpSp;
3679 NTSTATUS status;
3680 BOOL top_level;
3681
3682 TRACE("file system control\n");
3683
3684 FsRtlEnterFileSystem();
3685
3686 top_level = is_top_level(Irp);
3687
3688 status = STATUS_NOT_IMPLEMENTED;
3689
3690 IrpSp = IoGetCurrentIrpStackLocation( Irp );
3691
3692 Irp->IoStatus.Information = 0;
3693
3694 switch (IrpSp->MinorFunction) {
3695 case IRP_MN_MOUNT_VOLUME:
3696 TRACE("IRP_MN_MOUNT_VOLUME\n");
3697
3698 // Irp->IoStatus.Status = STATUS_SUCCESS;
3699 status = mount_vol(DeviceObject, Irp);
3700 // IrpSp->Parameters.MountVolume.DeviceObject = 0x0badc0de;
3701 // IrpSp->Parameters.MountVolume.Vpb = 0xdeadbeef;
3702
3703 // IoCompleteRequest( Irp, IO_DISK_INCREMENT );
3704
3705 // return Irp->IoStatus.Status;
3706 break;
3707
3708 case IRP_MN_KERNEL_CALL:
3709 TRACE("IRP_MN_KERNEL_CALL\n");
3710 break;
3711
3712 case IRP_MN_LOAD_FILE_SYSTEM:
3713 TRACE("IRP_MN_LOAD_FILE_SYSTEM\n");
3714 break;
3715
3716 case IRP_MN_USER_FS_REQUEST:
3717 TRACE("IRP_MN_USER_FS_REQUEST\n");
3718
3719 status = fsctl_request(DeviceObject, Irp, IrpSp->Parameters.FileSystemControl.FsControlCode, TRUE);
3720 break;
3721
3722 case IRP_MN_VERIFY_VOLUME:
3723 TRACE("IRP_MN_VERIFY_VOLUME\n");
3724 break;
3725
3726 default:
3727 WARN("unknown minor %u\n", IrpSp->MinorFunction);
3728 break;
3729
3730 }
3731
3732 Irp->IoStatus.Status = status;
3733
3734 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3735
3736 if (top_level)
3737 IoSetTopLevelIrp(NULL);
3738
3739 FsRtlExitFileSystem();
3740
3741 return status;
3742 }
3743
3744 static NTSTATUS STDCALL drv_lock_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
3745 NTSTATUS Status;
3746 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3747 fcb* fcb = IrpSp->FileObject->FsContext;
3748 BOOL top_level;
3749
3750 FsRtlEnterFileSystem();
3751
3752 top_level = is_top_level(Irp);
3753
3754 TRACE("lock control\n");
3755
3756 Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL);
3757
3758 if (top_level)
3759 IoSetTopLevelIrp(NULL);
3760
3761 FsRtlExitFileSystem();
3762
3763 return Status;
3764 }
3765
3766 static NTSTATUS STDCALL drv_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
3767 NTSTATUS Status;
3768 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3769 PFILE_OBJECT FileObject = IrpSp->FileObject;
3770 device_extension* Vcb = DeviceObject->DeviceExtension;
3771 fcb* fcb;
3772 BOOL top_level;
3773
3774 FIXME("STUB: device control\n");
3775
3776 FsRtlEnterFileSystem();
3777
3778 top_level = is_top_level(Irp);
3779
3780 Irp->IoStatus.Information = 0;
3781
3782 WARN("control code = %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
3783
3784 if (!FileObject) {
3785 ERR("FileObject was NULL\n");
3786 Status = STATUS_INVALID_PARAMETER;
3787 goto end;
3788
3789 }
3790
3791 fcb = FileObject->FsContext;
3792
3793 if (!fcb) {
3794 ERR("FCB was NULL\n");
3795 Status = STATUS_INVALID_PARAMETER;
3796 goto end;
3797 }
3798
3799 if (fcb == Vcb->volume_fcb) {
3800 FIXME("FIXME - pass through\n");
3801 Status = STATUS_NOT_IMPLEMENTED;
3802 } else {
3803 TRACE("filename = %.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
3804
3805 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
3806 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
3807 TRACE("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
3808 Status = STATUS_INVALID_PARAMETER;
3809 break;
3810
3811 default:
3812 WARN("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",
3813 IrpSp->Parameters.DeviceIoControl.IoControlCode, (IrpSp->Parameters.DeviceIoControl.IoControlCode & 0xff0000) >> 16,
3814 (IrpSp->Parameters.DeviceIoControl.IoControlCode & 0xc000) >> 14, (IrpSp->Parameters.DeviceIoControl.IoControlCode & 0x3ffc) >> 2,
3815 IrpSp->Parameters.DeviceIoControl.IoControlCode & 0x3);
3816 Status = STATUS_INVALID_PARAMETER;
3817 break;
3818 }
3819 }
3820
3821 end:
3822 Irp->IoStatus.Status = Status;
3823
3824 IoCompleteRequest( Irp, IO_NO_INCREMENT );
3825
3826 if (top_level)
3827 IoSetTopLevelIrp(NULL);
3828
3829 FsRtlExitFileSystem();
3830
3831 return Status;
3832 }
3833
3834 static NTSTATUS STDCALL drv_shutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
3835 NTSTATUS Status;
3836 BOOL top_level;
3837
3838 ERR("shutdown\n");
3839
3840 FsRtlEnterFileSystem();
3841
3842 top_level = is_top_level(Irp);
3843
3844 Status = STATUS_SUCCESS;
3845
3846 while (!IsListEmpty(&VcbList)) {
3847 LIST_ENTRY* le = RemoveHeadList(&VcbList);
3848 device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
3849
3850 TRACE("shutting down Vcb %p\n", Vcb);
3851
3852 uninit(Vcb);
3853 }
3854
3855 Irp->IoStatus.Status = Status;
3856 Irp->IoStatus.Information = 0;
3857
3858 IoCompleteRequest( Irp, IO_NO_INCREMENT );
3859
3860 if (top_level)
3861 IoSetTopLevelIrp(NULL);
3862
3863 FsRtlExitFileSystem();
3864
3865 return Status;
3866 }
3867
3868 static NTSTATUS STDCALL drv_pnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
3869 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3870 device_extension* Vcb = DeviceObject->DeviceExtension;
3871 NTSTATUS Status;
3872 BOOL top_level;
3873
3874 FIXME("STUB: pnp\n");
3875
3876 FsRtlEnterFileSystem();
3877
3878 top_level = is_top_level(Irp);
3879
3880 Status = STATUS_NOT_IMPLEMENTED;
3881
3882 switch (IrpSp->MinorFunction) {
3883 case IRP_MN_CANCEL_REMOVE_DEVICE:
3884 TRACE(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
3885 break;
3886
3887 case IRP_MN_QUERY_REMOVE_DEVICE:
3888 TRACE(" IRP_MN_QUERY_REMOVE_DEVICE\n");
3889 break;
3890
3891 case IRP_MN_REMOVE_DEVICE:
3892 TRACE(" IRP_MN_REMOVE_DEVICE\n");
3893 break;
3894
3895 case IRP_MN_START_DEVICE:
3896 TRACE(" IRP_MN_START_DEVICE\n");
3897 break;
3898
3899 case IRP_MN_SURPRISE_REMOVAL:
3900 TRACE(" IRP_MN_SURPRISE_REMOVAL\n");
3901 break;
3902
3903 case IRP_MN_QUERY_DEVICE_RELATIONS:
3904 TRACE(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
3905 break;
3906
3907 default:
3908 WARN("Unrecognized minor function 0x%x\n", IrpSp->MinorFunction);
3909 break;
3910 }
3911
3912 // Irp->IoStatus.Status = Status;
3913 // Irp->IoStatus.Information = 0;
3914
3915 IoSkipCurrentIrpStackLocation(Irp);
3916
3917 Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
3918
3919 // IoCompleteRequest(Irp, IO_NO_INCREMENT);
3920
3921 if (top_level)
3922 IoSetTopLevelIrp(NULL);
3923
3924 FsRtlExitFileSystem();
3925
3926 return Status;
3927 }
3928
3929 #ifdef _DEBUG
3930 static void STDCALL init_serial() {
3931 NTSTATUS Status;
3932
3933 Status = IoGetDeviceObjectPointer(&log_device, FILE_WRITE_DATA, &comfo, &comdo);
3934 if (!NT_SUCCESS(Status)) {
3935 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
3936 }
3937 }
3938 #endif
3939
3940 #ifndef __REACTOS__
3941 static void STDCALL check_cpu() {
3942 unsigned int cpuInfo[4];
3943 #ifndef _MSC_VER
3944 __get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]);
3945 have_sse42 = cpuInfo[2] & bit_SSE4_2;
3946 #else
3947 __cpuid(cpuInfo, 1);
3948 have_sse42 = cpuInfo[2] & (1 << 20);
3949 #endif
3950
3951 if (have_sse42)
3952 TRACE("SSE4.2 is supported\n");
3953 else
3954 TRACE("SSE4.2 not supported\n");
3955 }
3956 #endif
3957
3958 static void STDCALL read_registry(PUNICODE_STRING regpath) {
3959 HANDLE h;
3960 UNICODE_STRING us;
3961 OBJECT_ATTRIBUTES oa;
3962 ULONG dispos;
3963 NTSTATUS Status;
3964 WCHAR* path;
3965 ULONG kvfilen, retlen, i;
3966 KEY_VALUE_FULL_INFORMATION* kvfi;
3967
3968 const WCHAR mappings[] = L"\\Mappings";
3969 #ifndef __REACTOS__
3970 static WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
3971 #endif
3972
3973 path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) * sizeof(WCHAR)), ALLOC_TAG);
3974 if (!path) {
3975 ERR("out of memory\n");
3976 return;
3977 }
3978
3979 RtlCopyMemory(path, regpath->Buffer, regpath->Length);
3980 RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) * sizeof(WCHAR));
3981
3982 us.Buffer = path;
3983 us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) * sizeof(WCHAR));
3984
3985 InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
3986
3987 // FIXME - keep open and do notify for changes
3988 Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
3989
3990 if (!NT_SUCCESS(Status)) {
3991 ERR("ZwCreateKey returned %08x\n", Status);
3992 ExFreePool(path);
3993 return;
3994 }
3995
3996 if (dispos == REG_OPENED_EXISTING_KEY) {
3997 kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
3998 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
3999
4000 if (!kvfi) {
4001 ERR("out of memory\n");
4002 ExFreePool(path);
4003 ZwClose(h);
4004 return;
4005 }
4006
4007 i = 0;
4008 do {
4009 Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
4010
4011 if (NT_SUCCESS(Status) && kvfi->DataLength > 0) {
4012 UINT32 val = 0;
4013
4014 RtlCopyMemory(&val, (UINT8*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(UINT32)));
4015
4016 TRACE("entry %u = %.*S = %u\n", i, kvfi->NameLength / sizeof(WCHAR), kvfi->Name, val);
4017
4018 add_user_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
4019 }
4020
4021 i = i + 1;
4022 } while (Status != STATUS_NO_MORE_ENTRIES);
4023 }
4024
4025 ZwClose(h);
4026
4027 ExFreePool(path);
4028
4029 #ifdef _DEBUG
4030 InitializeObjectAttributes(&oa, regpath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
4031
4032 Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
4033
4034 if (!NT_SUCCESS(Status)) {
4035 ERR("ZwCreateKey returned %08x\n", Status);
4036 return;
4037 }
4038
4039 RtlInitUnicodeString(&us, L"DebugLogLevel");
4040
4041 kvfi = NULL;
4042 kvfilen = 0;
4043 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
4044
4045 if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
4046 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
4047
4048 if (!kvfi) {
4049 ERR("out of memory\n");
4050 ZwClose(h);
4051 return;
4052 }
4053
4054 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
4055
4056 if (NT_SUCCESS(Status)) {
4057 if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) {
4058 RtlCopyMemory(&debug_log_level, ((UINT8*)kvfi) + kvfi->DataOffset, sizeof(UINT32));
4059 } else {
4060 Status = ZwDeleteValueKey(h, &us);
4061 if (!NT_SUCCESS(Status)) {
4062 ERR("ZwDeleteValueKey returned %08x\n", Status);
4063 }
4064
4065 Status = ZwSetValueKey(h, &us, 0, REG_DWORD, &debug_log_level, sizeof(debug_log_level));
4066 if (!NT_SUCCESS(Status)) {
4067 ERR("ZwSetValueKey reutrned %08x\n", Status);
4068 }
4069 }
4070 }
4071
4072 ExFreePool(kvfi);
4073 } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
4074 Status = ZwSetValueKey(h, &us, 0, REG_DWORD, &debug_log_level, sizeof(debug_log_level));
4075
4076 if (!NT_SUCCESS(Status)) {
4077 ERR("ZwSetValueKey reutrned %08x\n", Status);
4078 }
4079 } else {
4080 ERR("ZwQueryValueKey returned %08x\n", Status);
4081 }
4082
4083 RtlInitUnicodeString(&us, L"LogDevice");
4084
4085 kvfi = NULL;
4086 kvfilen = 0;
4087 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
4088
4089 if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
4090 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
4091
4092 if (!kvfi) {
4093 ERR("out of memory\n");
4094 ZwClose(h);
4095 return;
4096 }
4097
4098 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
4099
4100 if (NT_SUCCESS(Status)) {
4101 if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
4102 log_device.Length = log_device.MaximumLength = kvfi->DataLength;
4103 log_device.Buffer = ExAllocatePoolWithTag(PagedPool, kvfi->DataLength, ALLOC_TAG);
4104
4105 if (!log_device.Buffer) {
4106 ERR("out of memory\n");
4107 ExFreePool(kvfi);
4108 ZwClose(h);
4109 return;
4110 }
4111
4112 RtlCopyMemory(log_device.Buffer, ((UINT8*)kvfi) + kvfi->DataOffset, kvfi->DataLength);
4113
4114 if (log_device.Buffer[(log_device.Length / sizeof(WCHAR)) - 1] == 0)
4115 log_device.Length -= sizeof(WCHAR);
4116 } else {
4117 ERR("LogDevice was type %u, length %u\n", kvfi->Type, kvfi->DataLength);
4118
4119 Status = ZwDeleteValueKey(h, &us);
4120 if (!NT_SUCCESS(Status)) {
4121 ERR("ZwDeleteValueKey returned %08x\n", Status);
4122 }
4123 }
4124 }
4125
4126 ExFreePool(kvfi);
4127 } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
4128 ERR("ZwQueryValueKey returned %08x\n", Status);
4129 }
4130
4131 RtlInitUnicodeString(&us, L"LogFile");
4132
4133 kvfi = NULL;
4134 kvfilen = 0;
4135 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
4136
4137 if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
4138 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
4139
4140 if (!kvfi) {
4141 ERR("out of memory\n");
4142 ZwClose(h);
4143 return;
4144 }
4145
4146 Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
4147
4148 if (NT_SUCCESS(Status)) {
4149 if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
4150 log_file.Length = log_file.MaximumLength = kvfi->DataLength;
4151 log_file.Buffer = ExAllocatePoolWithTag(PagedPool, kvfi->DataLength, ALLOC_TAG);
4152
4153 if (!log_file.Buffer) {
4154 ERR("out of memory\n");
4155 ExFreePool(kvfi);
4156 ZwClose(h);
4157 return;
4158 }
4159
4160 RtlCopyMemory(log_file.Buffer, ((UINT8*)kvfi) + kvfi->DataOffset, kvfi->DataLength);
4161
4162 if (log_file.Buffer[(log_file.Length / sizeof(WCHAR)) - 1] == 0)
4163 log_file.Length -= sizeof(WCHAR);
4164 } else {
4165 ERR("LogFile was type %u, length %u\n", kvfi->Type, kvfi->DataLength);
4166
4167 Status = ZwDeleteValueKey(h, &us);
4168 if (!NT_SUCCESS(Status)) {
4169 ERR("ZwDeleteValueKey returned %08x\n", Status);
4170 }
4171 }
4172 }
4173
4174 ExFreePool(kvfi);
4175 } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
4176 Status = ZwSetValueKey(h, &us, 0, REG_SZ, def_log_file, (wcslen(def_log_file) + 1) * sizeof(WCHAR));
4177
4178 if (!NT_SUCCESS(Status)) {
4179 ERR("ZwSetValueKey returned %08x\n", Status);
4180 }
4181 } else {
4182 ERR("ZwQueryValueKey returned %08x\n", Status);
4183 }
4184
4185 if (log_file.Length == 0) {
4186 log_file.Length = log_file.MaximumLength = wcslen(def_log_file) * sizeof(WCHAR);
4187 log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength, ALLOC_TAG);
4188
4189 if (!log_file.Buffer) {
4190 ERR("out of memory\n");
4191 ZwClose(h);
4192 return;
4193 }
4194
4195 RtlCopyMemory(log_file.Buffer, def_log_file, log_file.Length);
4196 }
4197
4198 ZwClose(h);
4199 #endif
4200 }
4201
4202 #ifdef _DEBUG
4203 static void init_logging() {
4204 if (log_device.Length > 0)
4205 init_serial();
4206 else if (log_file.Length > 0) {
4207 NTSTATUS Status;
4208 OBJECT_ATTRIBUTES oa;
4209 IO_STATUS_BLOCK iosb;
4210 char* dateline;
4211 LARGE_INTEGER time;
4212 TIME_FIELDS tf;
4213
4214 InitializeObjectAttributes(&oa, &log_file, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
4215
4216 Status = ZwCreateFile(&log_handle, FILE_WRITE_DATA, &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
4217 FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT, NULL, 0);
4218
4219 if (!NT_SUCCESS(Status)) {
4220 ERR("ZwCreateFile returned %08x\n", Status);
4221 return;
4222 }
4223
4224 if (iosb.Information == FILE_OPENED) { // already exists
4225 FILE_STANDARD_INFORMATION fsi;
4226 FILE_POSITION_INFORMATION fpi;
4227
4228 static char delim[] = "\n---\n";
4229
4230 // move to end of file
4231
4232 Status = ZwQueryInformationFile(log_handle, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
4233
4234 if (!NT_SUCCESS(Status)) {
4235 ERR("ZwQueryInformationFile returned %08x\n", Status);
4236 return;
4237 }
4238
4239 fpi.CurrentByteOffset = fsi.EndOfFile;
4240
4241 Status = ZwSetInformationFile(log_handle, &iosb, &fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
4242
4243 if (!NT_SUCCESS(Status)) {
4244 ERR("ZwSetInformationFile returned %08x\n", Status);
4245 return;
4246 }
4247
4248 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, delim, strlen(delim), NULL, NULL);
4249
4250 if (!NT_SUCCESS(Status)) {
4251 ERR("ZwWriteFile returned %08x\n", Status);
4252 return;
4253 }
4254 }
4255
4256 dateline = ExAllocatePoolWithTag(PagedPool, 256, ALLOC_TAG);
4257
4258 if (!dateline) {
4259 ERR("out of memory\n");
4260 return;
4261 }
4262
4263 KeQuerySystemTime(&time);
4264
4265 RtlTimeToTimeFields(&time, &tf);
4266
4267 sprintf(dateline, "Starting logging at %04u-%02u-%02u %02u:%02u:%02u\n", tf.Year, tf.Month, tf.Day, tf.Hour, tf.Minute, tf.Second);
4268
4269 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, dateline, strlen(dateline), NULL, NULL);
4270
4271 if (!NT_SUCCESS(Status)) {
4272 ERR("ZwWriteFile returned %08x\n", Status);
4273 return;
4274 }
4275
4276 ExFreePool(dateline);
4277 }
4278 }
4279 #endif
4280
4281 NTSTATUS STDCALL DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
4282 NTSTATUS Status;
4283 PDEVICE_OBJECT DeviceObject;
4284 UNICODE_STRING device_nameW;
4285 UNICODE_STRING dosdevice_nameW;
4286
4287 InitializeListHead(&uid_map_list);
4288
4289 log_device.Buffer = NULL;
4290 log_device.Length = log_device.MaximumLength = 0;
4291 log_file.Buffer = NULL;
4292 log_file.Length = log_file.MaximumLength = 0;
4293
4294 read_registry(RegistryPath);
4295
4296 #ifdef _DEBUG
4297 if (debug_log_level > 0)
4298 init_logging();
4299
4300 log_started = TRUE;
4301 #endif
4302
4303 TRACE("DriverEntry\n");
4304
4305 #ifndef __REACTOS__
4306 check_cpu();
4307 #endif
4308
4309 // TRACE("check CRC32C: %08x\n", calc_crc32c((UINT8*)"123456789", 9)); // should be e3069283
4310
4311 drvobj = DriverObject;
4312
4313 DriverObject->DriverUnload = DriverUnload;
4314
4315 DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)drv_create;
4316 DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)drv_close;
4317 DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)drv_read;
4318 DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)drv_write;
4319 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)drv_query_information;
4320 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)drv_set_information;
4321 DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)drv_query_ea;
4322 DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)drv_set_ea;
4323 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)drv_flush_buffers;
4324 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)drv_query_volume_information;
4325 DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)drv_set_volume_information;
4326 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)drv_cleanup;
4327 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)drv_directory_control;
4328 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)drv_file_system_control;
4329 DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)drv_lock_control;
4330 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)drv_device_control;
4331 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)drv_shutdown;
4332 DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)drv_pnp;
4333 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = (PDRIVER_DISPATCH)drv_query_security;
4334 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = (PDRIVER_DISPATCH)drv_set_security;
4335
4336 init_fast_io_dispatch(&DriverObject->FastIoDispatch);
4337
4338 device_nameW.Buffer = device_name;
4339 device_nameW.Length = device_nameW.MaximumLength = (USHORT)wcslen(device_name) * sizeof(WCHAR);
4340 dosdevice_nameW.Buffer = dosdevice_name;
4341 dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR);
4342
4343 Status = IoCreateDevice(DriverObject, 0, &device_nameW, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &DeviceObject);
4344 if (!NT_SUCCESS(Status)) {
4345 ERR("IoCreateDevice returned %08x\n", Status);
4346 return Status;
4347 }
4348
4349 devobj = DeviceObject;
4350
4351 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
4352
4353 Status = IoCreateSymbolicLink(&dosdevice_nameW, &device_nameW);
4354 if (!NT_SUCCESS(Status)) {
4355 ERR("IoCreateSymbolicLink returned %08x\n", Status);
4356 return Status;
4357 }
4358
4359 Status = init_cache();
4360 if (!NT_SUCCESS(Status)) {
4361 ERR("init_cache returned %08x\n", Status);
4362 return Status;
4363 }
4364
4365 InitializeListHead(&volumes);
4366 look_for_vols(&volumes);
4367
4368 InitializeListHead(&VcbList);
4369 ExInitializeResourceLite(&global_loading_lock);
4370
4371 IoRegisterFileSystem(DeviceObject);
4372
4373 return STATUS_SUCCESS;
4374 }