ReactOS  0.4.13-dev-257-gfabbd7c
btrfs.c
Go to the documentation of this file.
1 /* Copyright (c) Mark Harmstone 2016-17
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 <ntddscsi.h>
31 #include "btrfs.h"
32 #include <ata.h>
33 
34 #ifndef _MSC_VER
35 #include <initguid.h>
36 #include <ntddstor.h>
37 #undef INITGUID
38 #endif
39 
40 #include <ntdddisk.h>
41 #include <ntddvol.h>
42 
43 #ifdef _MSC_VER
44 #include <initguid.h>
45 #include <ntddstor.h>
46 #undef INITGUID
47 #endif
48 
49 #define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \
50  BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \
51  BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES | \
52  BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD)
53 #define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)
54 
55 static const WCHAR device_name[] = {'\\','B','t','r','f','s',0};
56 static const WCHAR dosdevice_name[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0};
57 
58 DEFINE_GUID(BtrfsBusInterface, 0x4d414874, 0x6865, 0x6761, 0x6d, 0x65, 0x83, 0x69, 0x17, 0x9a, 0x7d, 0x1d);
59 
62 #ifndef __REACTOS__
64 #endif
100 
101 #ifdef _DEBUG
102 PFILE_OBJECT comfo = NULL;
103 PDEVICE_OBJECT comdo = NULL;
104 HANDLE log_handle = NULL;
105 ERESOURCE log_lock;
106 HANDLE serial_thread_handle = NULL;
107 
108 static void init_serial(BOOL first_time);
109 #endif
110 
112 
113 typedef struct {
116 } read_context;
117 
118 #ifdef _DEBUG
119 _Function_class_(IO_COMPLETION_ROUTINE)
120 static NTSTATUS dbg_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) {
121  read_context* context = conptr;
122 
124 
125  context->iosb = Irp->IoStatus;
126  KeSetEvent(&context->Event, 0, FALSE);
127 
129 }
130 
131 #ifdef DEBUG_LONG_MESSAGES
132 void _debug_message(_In_ const char* func, _In_ const char* file, _In_ unsigned int line, _In_ char* s, ...) {
133 #else
134 void _debug_message(_In_ const char* func, _In_ char* s, ...) {
135 #endif
139  PIRP Irp;
140  va_list ap;
141  char *buf2, *buf;
143  UINT32 length;
144 
146 
147  if (!buf2) {
148  DbgPrint("Couldn't allocate buffer in debug_message\n");
149  return;
150  }
151 
152 #ifdef DEBUG_LONG_MESSAGES
153  sprintf(buf2, "%p:%s:%s:%u:", PsGetCurrentThread(), func, file, line);
154 #else
155  sprintf(buf2, "%p:%s:", PsGetCurrentThread(), func);
156 #endif
157  buf = &buf2[strlen(buf2)];
158 
159  va_start(ap, s);
160  vsprintf(buf, s, ap);
161 
162  ExAcquireResourceSharedLite(&log_lock, TRUE);
163 
164  if (!log_started || (log_device.Length == 0 && log_file.Length == 0)) {
165  DbgPrint(buf2);
166  } else if (log_device.Length > 0) {
167  if (!comdo) {
168  DbgPrint("comdo is NULL :-(\n");
169  DbgPrint(buf2);
170  goto exit2;
171  }
172 
173  length = (UINT32)strlen(buf2);
174 
175  offset.u.LowPart = 0;
176  offset.u.HighPart = 0;
177 
179 
181 
182  Irp = IoAllocateIrp(comdo->StackSize, FALSE);
183 
184  if (!Irp) {
185  DbgPrint("IoAllocateIrp failed\n");
186  goto exit2;
187  }
188 
191 
192  if (comdo->Flags & DO_BUFFERED_IO) {
193  Irp->AssociatedIrp.SystemBuffer = buf2;
194 
195  Irp->Flags = IRP_BUFFERED_IO;
196  } else if (comdo->Flags & DO_DIRECT_IO) {
197  Irp->MdlAddress = IoAllocateMdl(buf2, length, FALSE, FALSE, NULL);
198  if (!Irp->MdlAddress) {
199  DbgPrint("IoAllocateMdl failed\n");
200  goto exit;
201  }
202 
203  MmBuildMdlForNonPagedPool(Irp->MdlAddress);
204  } else {
205  Irp->UserBuffer = buf2;
206  }
207 
208  IrpSp->Parameters.Write.Length = length;
209  IrpSp->Parameters.Write.ByteOffset = offset;
210 
211  Irp->UserIosb = &context.iosb;
212 
213  Irp->UserEvent = &context.Event;
214 
215  IoSetCompletionRoutine(Irp, dbg_completion, &context, TRUE, TRUE, TRUE);
216 
217  Status = IoCallDriver(comdo, Irp);
218 
219  if (Status == STATUS_PENDING) {
221  Status = context.iosb.Status;
222  }
223 
224  if (comdo->Flags & DO_DIRECT_IO)
225  IoFreeMdl(Irp->MdlAddress);
226 
227  if (!NT_SUCCESS(Status)) {
228  DbgPrint("failed to write to COM1 - error %08x\n", Status);
229  goto exit;
230  }
231 
232 exit:
233  IoFreeIrp(Irp);
234  } else if (log_handle != NULL) {
236 
237  length = (UINT32)strlen(buf2);
238 
239  Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, buf2, length, NULL, NULL);
240 
241  if (!NT_SUCCESS(Status)) {
242  DbgPrint("failed to write to file - error %08x\n", Status);
243  }
244  }
245 
246 exit2:
247  ExReleaseResourceLite(&log_lock);
248 
249  va_end(ap);
250 
251  if (buf2)
252  ExFreePool(buf2);
253 }
254 #endif
255 
257  if (!IoGetTopLevelIrp()) {
259  return TRUE;
260  }
261 
262  return FALSE;
263 }
264 
265 _Function_class_(DRIVER_UNLOAD)
266 #ifdef __REACTOS__
268 #else
270 #endif
271  UNICODE_STRING dosdevice_nameW;
272 
273  TRACE("(%p)\n");
274 
275  free_cache();
276 
278 
280 #ifdef __REACTOS__
282 #else
283  IoUnregisterPlugPlayNotificationEx(notification_entry2);
284 #endif
285 
287 #ifdef __REACTOS__
289 #else
290  IoUnregisterPlugPlayNotificationEx(notification_entry3);
291 #endif
292 
293  if (notification_entry)
294 #ifdef __REACTOS__
296 #else
297  IoUnregisterPlugPlayNotificationEx(notification_entry);
298 #endif
299 
300  dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name;
301  dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR);
302 
303  IoDeleteSymbolicLink(&dosdevice_nameW);
305 
306  while (!IsListEmpty(&uid_map_list)) {
308  uid_map* um = CONTAINING_RECORD(le, uid_map, listentry);
309 
310  ExFreePool(um->sid);
311 
312  ExFreePool(um);
313  }
314 
315  while (!IsListEmpty(&gid_map_list)) {
317 
318  ExFreePool(gm->sid);
319  ExFreePool(gm);
320  }
321 
322  // FIXME - free volumes and their devpaths
323 
324 #ifdef _DEBUG
325  if (comfo)
326  ObDereferenceObject(comfo);
327 
328  if (log_handle)
329  ZwClose(log_handle);
330 #endif
331 
334 
335  if (log_device.Buffer)
337 
338  if (log_file.Buffer)
340 
341  if (registry_path.Buffer)
343 
344 #ifdef _DEBUG
345  ExDeleteResourceLite(&log_lock);
346 #endif
348 }
349 
351  KEY searchkey;
352  traverse_ptr tp, prev_tp;
354 
355  // get last entry
356  searchkey.obj_id = 0xffffffffffffffff;
357  searchkey.obj_type = 0xff;
358  searchkey.offset = 0xffffffffffffffff;
359 
360  Status = find_item(Vcb, r, &tp, &searchkey, FALSE, Irp);
361  if (!NT_SUCCESS(Status)) {
362  ERR("error - find_item returned %08x\n", Status);
363  return FALSE;
364  }
365 
366  if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) {
367  r->lastinode = tp.item->key.obj_id;
368  TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode);
369  return TRUE;
370  }
371 
372  while (find_prev_item(Vcb, &tp, &prev_tp, Irp)) {
373  tp = prev_tp;
374 
375  TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
376 
377  if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) {
378  r->lastinode = tp.item->key.obj_id;
379  TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode);
380  return TRUE;
381  }
382  }
383 
384  r->lastinode = SUBVOL_ROOT_INODE;
385 
386  WARN("no INODE_ITEMs in tree %llx\n", r->id);
387 
388  return TRUE;
389 }
390 
391 _Success_(return)
392 static BOOL extract_xattr(_In_reads_bytes_(size) void* item, _In_ USHORT size, _In_z_ char* name, _Out_ UINT8** data, _Out_ UINT16* datalen) {
393  DIR_ITEM* xa = (DIR_ITEM*)item;
394  USHORT xasize;
395 
396  while (TRUE) {
397  if (size < sizeof(DIR_ITEM) || size < (sizeof(DIR_ITEM) - 1 + xa->m + xa->n)) {
398  WARN("DIR_ITEM is truncated\n");
399  return FALSE;
400  }
401 
402  if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) {
403  TRACE("found xattr %s\n", name);
404 
405  *datalen = xa->m;
406 
407  if (xa->m > 0) {
409  if (!*data) {
410  ERR("out of memory\n");
411  return FALSE;
412  }
413 
414  RtlCopyMemory(*data, &xa->name[xa->n], xa->m);
415  } else
416  *data = NULL;
417 
418  return TRUE;
419  }
420 
421  xasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n;
422 
423  if (size > xasize) {
424  size -= xasize;
425  xa = (DIR_ITEM*)&xa->name[xa->m + xa->n];
426  } else
427  break;
428  }
429 
430  TRACE("xattr %s not found\n", name);
431 
432  return FALSE;
433 }
434 
435 _Success_(return)
436 BOOL get_xattr(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* subvol, _In_ UINT64 inode, _In_z_ char* name, _In_ UINT32 crc32,
438  KEY searchkey;
441 
442  TRACE("(%p, %llx, %llx, %s, %08x, %p, %p)\n", Vcb, subvol->id, inode, name, crc32, data, datalen);
443 
444  searchkey.obj_id = inode;
445  searchkey.obj_type = TYPE_XATTR_ITEM;
446  searchkey.offset = crc32;
447 
448  Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
449  if (!NT_SUCCESS(Status)) {
450  ERR("error - find_item returned %08x\n", Status);
451  return FALSE;
452  }
453 
454  if (keycmp(tp.item->key, searchkey)) {
455  TRACE("could not find item (%llx,%x,%llx)\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
456  return FALSE;
457  }
458 
459  if (tp.item->size < sizeof(DIR_ITEM)) {
460  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));
461  return FALSE;
462  }
463 
464  return extract_xattr(tp.item->data, tp.item->size, name, data, datalen);
465 }
466 
469 #ifdef __REACTOS__
471 #else
472 static NTSTATUS drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
473 #endif
477  BOOL top_level;
478 
480 
481  TRACE("close\n");
482 
483  top_level = is_top_level(Irp);
484 
485  if (DeviceObject == master_devobj) {
486  TRACE("Closing file system\n");
488  goto end;
489  } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
491  goto end;
492  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
494  goto end;
495  }
496 
498 
499  // FIXME - unmount if called for volume
500  // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
501 
503 
504 end:
505  Irp->IoStatus.Status = Status;
506  Irp->IoStatus.Information = 0;
507 
509 
510  if (top_level)
512 
513  TRACE("returning %08x\n", Status);
514 
516 
517  return Status;
518 }
519 
522 #ifdef __REACTOS__
523 static NTSTATUS NTAPI drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
524 #else
525 static NTSTATUS drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
526 #endif
530  fcb* fcb = FileObject->FsContext;
532  BOOL top_level;
533 
535 
536  TRACE("flush buffers\n");
537 
538  top_level = is_top_level(Irp);
539 
540  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
542  goto end;
543  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
545  goto end;
546  }
547 
548  if (!fcb) {
549  ERR("fcb was NULL\n");
551  goto end;
552  }
553 
554  if (fcb == Vcb->volume_fcb) {
556  goto end;
557  }
558 
559  Irp->IoStatus.Information = 0;
560 
561  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
562 
564  Irp->IoStatus.Status = Status;
565 
566  if (fcb->type != BTRFS_TYPE_DIRECTORY) {
567  CcFlushCache(&fcb->nonpaged->segment_object, NULL, 0, &Irp->IoStatus);
568 
569  if (fcb->Header.PagingIoResource) {
570  ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
571  ExReleaseResourceLite(fcb->Header.PagingIoResource);
572  }
573 
574  Status = Irp->IoStatus.Status;
575  }
576 
577 end:
579 
580  TRACE("returning %08x\n", Status);
581 
582  if (top_level)
584 
586 
587  return Status;
588 }
589 
591  UINT64 nfactor, dfactor, sectors_used;
592 
593  if (Vcb->data_flags & BLOCK_FLAG_DUPLICATE || Vcb->data_flags & BLOCK_FLAG_RAID1 || Vcb->data_flags & BLOCK_FLAG_RAID10) {
594  nfactor = 1;
595  dfactor = 2;
596  } else if (Vcb->data_flags & BLOCK_FLAG_RAID5) {
597  nfactor = Vcb->superblock.num_devices - 1;
598  dfactor = Vcb->superblock.num_devices;
599  } else if (Vcb->data_flags & BLOCK_FLAG_RAID6) {
600  nfactor = Vcb->superblock.num_devices - 2;
601  dfactor = Vcb->superblock.num_devices;
602  } else {
603  nfactor = 1;
604  dfactor = 1;
605  }
606 
607  sectors_used = Vcb->superblock.bytes_used / Vcb->superblock.sector_size;
608 
609  *totalsize = (Vcb->superblock.total_bytes / Vcb->superblock.sector_size) * nfactor / dfactor;
610  *freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used);
611 }
612 
613 #ifndef __REACTOS__
614 // This function exists because we have to lie about our FS type in certain situations.
615 // MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match,
616 // it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
617 // The command mklink refuses to create hard links on anything other than NTFS, so we have to
618 // blacklist cmd.exe too.
619 
623  PPEB peb;
624  LIST_ENTRY* le;
625  ULONG retlen;
626 #ifdef _AMD64_
627  ULONG_PTR wow64info;
628 #endif
629 
630  static const WCHAR mpr[] = L"MPR.DLL";
631  static const WCHAR cmd[] = L"CMD.EXE";
632  static const WCHAR fsutil[] = L"FSUTIL.EXE";
633  UNICODE_STRING mprus, cmdus, fsutilus;
634 
635  mprus.Buffer = (WCHAR*)mpr;
636  mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR);
637  cmdus.Buffer = (WCHAR*)cmd;
638  cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR);
639  fsutilus.Buffer = (WCHAR*)fsutil;
640  fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR);
641 
642  if (!PsGetCurrentProcess())
643  return FALSE;
644 
645 #ifdef _AMD64_
646  Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64info, sizeof(wow64info), NULL);
647 
648  if (NT_SUCCESS(Status) && wow64info != 0)
649  return TRUE;
650 #endif
651 
653 
654  if (!NT_SUCCESS(Status)) {
655  ERR("ZwQueryInformationProcess returned %08x\n", Status);
656  return FALSE;
657  }
658 
659  if (!pbi.PebBaseAddress)
660  return FALSE;
661 
662  peb = pbi.PebBaseAddress;
663 
664  if (!peb->Ldr)
665  return FALSE;
666 
667  le = peb->Ldr->InMemoryOrderModuleList.Flink;
668  while (le != &peb->Ldr->InMemoryOrderModuleList) {
670  BOOL blacklist = FALSE;
671 
672  if (entry->FullDllName.Length >= mprus.Length) {
674 
675  name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - mprus.Length) / sizeof(WCHAR)];
676  name.Length = name.MaximumLength = mprus.Length;
677 
678  blacklist = FsRtlAreNamesEqual(&name, &mprus, TRUE, NULL);
679  }
680 
681  if (!blacklist && entry->FullDllName.Length >= cmdus.Length) {
683 
684  name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - cmdus.Length) / sizeof(WCHAR)];
685  name.Length = name.MaximumLength = cmdus.Length;
686 
687  blacklist = FsRtlAreNamesEqual(&name, &cmdus, TRUE, NULL);
688  }
689 
690  if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) {
692 
693  name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - fsutilus.Length) / sizeof(WCHAR)];
694  name.Length = name.MaximumLength = fsutilus.Length;
695 
696  blacklist = FsRtlAreNamesEqual(&name, &fsutilus, TRUE, NULL);
697  }
698 
699  if (blacklist) {
700  void** frames;
701  ULONG i, num_frames;
702 
703  frames = ExAllocatePoolWithTag(PagedPool, 256 * sizeof(void*), ALLOC_TAG);
704  if (!frames) {
705  ERR("out of memory\n");
706  return FALSE;
707  }
708 
709  num_frames = RtlWalkFrameChain(frames, 256, 1);
710 
711  for (i = 0; i < num_frames; i++) {
712  // entry->Reserved3[1] appears to be the image size
713  if (frames[i] >= entry->DllBase && (ULONG_PTR)frames[i] <= (ULONG_PTR)entry->DllBase + (ULONG_PTR)entry->Reserved3[1]) {
714  ExFreePool(frames);
715  return TRUE;
716  }
717  }
718 
719  ExFreePool(frames);
720  }
721 
722  le = le->Flink;
723  }
724 
725  return FALSE;
726 }
727 #endif
728 
731 #ifdef __REACTOS__
732 static NTSTATUS NTAPI drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
733 #else
734 static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
735 #endif
738  ULONG BytesCopied = 0;
740  BOOL top_level;
741 
743 
744  TRACE("query volume information\n");
745  top_level = is_top_level(Irp);
746 
747  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
749  goto end;
750  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
752  goto end;
753  }
754 
756 
758 
759  switch (IrpSp->Parameters.QueryVolume.FsInformationClass) {
761  {
762  FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
763  BOOL overflow = FALSE;
764 #ifndef __REACTOS__
765  static const WCHAR ntfs[] = L"NTFS";
766 #endif
767  static const WCHAR btrfs[] = L"Btrfs";
768  const WCHAR* fs_name;
769  ULONG fs_name_len, orig_fs_name_len;
770 
771 #ifndef __REACTOS__
772  if (Irp->RequestorMode == UserMode && lie_about_fs_type()) {
773  fs_name = ntfs;
774  orig_fs_name_len = fs_name_len = sizeof(ntfs) - sizeof(WCHAR);
775  } else {
776  fs_name = btrfs;
777  orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR);
778  }
779 #else
780  fs_name = btrfs;
781  orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR);
782 #endif
783 
784  TRACE("FileFsAttributeInformation\n");
785 
786  if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len) {
787  if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR))
788  fs_name_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + sizeof(WCHAR);
789  else
790  fs_name_len = 0;
791 
792  overflow = TRUE;
793  }
794 
795  data->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH |
799  if (Vcb->readonly)
800  data->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
801 
802  // should also be FILE_FILE_COMPRESSION when supported
803  data->MaximumComponentNameLength = 255; // FIXME - check
804  data->FileSystemNameLength = orig_fs_name_len;
805  RtlCopyMemory(data->FileSystemName, fs_name, fs_name_len);
806 
807  BytesCopied = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len;
809  break;
810  }
811 
813  {
814  FILE_FS_DEVICE_INFORMATION* ffdi = Irp->AssociatedIrp.SystemBuffer;
815 
816  TRACE("FileFsDeviceInformation\n");
817 
819 
820  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
821  ffdi->Characteristics = Vcb->Vpb->RealDevice->Characteristics;
822  ExReleaseResourceLite(&Vcb->tree_lock);
823 
824  if (Vcb->readonly)
826  else
828 
831 
832  break;
833  }
834 
836  {
837  FILE_FS_FULL_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer;
838 
839  TRACE("FileFsFullSizeInformation\n");
840 
843  ffsi->SectorsPerAllocationUnit = 1;
844  ffsi->BytesPerSector = Vcb->superblock.sector_size;
845 
848 
849  break;
850  }
851 
853  {
854  FILE_FS_OBJECTID_INFORMATION* ffoi = Irp->AssociatedIrp.SystemBuffer;
855 
856  TRACE("FileFsObjectIdInformation\n");
857 
858  RtlCopyMemory(ffoi->ObjectId, &Vcb->superblock.uuid.uuid[0], sizeof(UCHAR) * 16);
859  RtlZeroMemory(ffoi->ExtendedInfo, sizeof(ffoi->ExtendedInfo));
860 
863 
864  break;
865  }
866 
868  {
869  FILE_FS_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer;
870 
871  TRACE("FileFsSizeInformation\n");
872 
874  ffsi->SectorsPerAllocationUnit = 1;
875  ffsi->BytesPerSector = Vcb->superblock.sector_size;
876 
879 
880  break;
881  }
882 
884  {
885  FILE_FS_VOLUME_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
887  BOOL overflow = FALSE;
888  ULONG label_len, orig_label_len;
889 
890  TRACE("FileFsVolumeInformation\n");
891  TRACE("max length = %u\n", IrpSp->Parameters.QueryVolume.Length);
892 
893  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
894 
895  Status = RtlUTF8ToUnicodeN(NULL, 0, &label_len, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
896  if (!NT_SUCCESS(Status)) {
897  ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
898  ExReleaseResourceLite(&Vcb->tree_lock);
899  break;
900  }
901 
902  orig_label_len = label_len;
903 
904  if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len) {
905  if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR))
906  label_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_VOLUME_INFORMATION) + sizeof(WCHAR);
907  else
908  label_len = 0;
909 
910  overflow = TRUE;
911  }
912 
913  TRACE("label_len = %u\n", label_len);
914 
915  ffvi.VolumeCreationTime.QuadPart = 0; // FIXME
916  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];
917  ffvi.VolumeLabelLength = orig_label_len;
918  ffvi.SupportsObjects = FALSE;
919 
920  RtlCopyMemory(data, &ffvi, min(sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR), IrpSp->Parameters.QueryVolume.Length));
921 
922  if (label_len > 0) {
923  ULONG bytecount;
924 
925  Status = RtlUTF8ToUnicodeN(&data->VolumeLabel[0], label_len, &bytecount, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
927  ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
928  ExReleaseResourceLite(&Vcb->tree_lock);
929  break;
930  }
931 
932  TRACE("label = %.*S\n", label_len / sizeof(WCHAR), data->VolumeLabel);
933  }
934 
935  ExReleaseResourceLite(&Vcb->tree_lock);
936 
937  BytesCopied = sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len;
939  break;
940  }
941 
942 #ifndef __REACTOS__
943 #ifdef _MSC_VER // not in mingw yet
944  case FileFsSectorSizeInformation:
945  {
946  FILE_FS_SECTOR_SIZE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
947 
948  data->LogicalBytesPerSector = Vcb->superblock.sector_size;
949  data->PhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size;
950  data->PhysicalBytesPerSectorForPerformance = Vcb->superblock.sector_size;
951  data->FileSystemEffectivePhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size;
952  data->ByteOffsetForSectorAlignment = 0;
953  data->ByteOffsetForPartitionAlignment = 0;
954 
955  data->Flags = SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE;
956 
957  if (Vcb->trim && !Vcb->options.no_trim)
958  data->Flags |= SSINFO_FLAGS_TRIM_ENABLED;
959 
960  BytesCopied = sizeof(FILE_FS_SECTOR_SIZE_INFORMATION);
961 
962  break;
963  }
964 #endif
965 #endif /* __REACTOS__ */
966 
967  default:
969  WARN("unknown FsInformationClass %u\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
970  break;
971  }
972 
974  Irp->IoStatus.Information = 0;
975  else
976  Irp->IoStatus.Information = BytesCopied;
977 
978 end:
979  Irp->IoStatus.Status = Status;
980 
982 
983  if (top_level)
985 
986  TRACE("query volume information returning %08x\n", Status);
987 
989 
990  return Status;
991 }
992 
993 _Function_class_(IO_COMPLETION_ROUTINE)
994 #ifdef __REACTOS__
995 static NTSTATUS NTAPI read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) {
996 #else
997 static NTSTATUS read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) {
998 #endif
999  read_context* context = conptr;
1000 
1002 
1003  context->iosb = Irp->IoStatus;
1004  KeSetEvent(&context->Event, 0, FALSE);
1005 
1007 }
1008 
1010  _Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset, _In_opt_ PIRP Irp) {
1011  NTSTATUS Status;
1012  root* r;
1013  tree* t = NULL;
1014  ROOT_ITEM* ri;
1015  traverse_ptr tp;
1016 
1018  if (!r) {
1019  ERR("out of memory\n");
1021  }
1022 
1024  if (!r->nonpaged) {
1025  ERR("out of memory\n");
1026  ExFreePool(r);
1028  }
1029 
1030  if (!no_tree) {
1032  if (!t) {
1033  ERR("out of memory\n");
1034  ExFreePool(r->nonpaged);
1035  ExFreePool(r);
1037  }
1038 
1039  t->nonpaged = NULL;
1040 
1041  t->is_unique = TRUE;
1042  t->uniqueness_determined = TRUE;
1043  t->buf = NULL;
1044  }
1045 
1047  if (!ri) {
1048  ERR("out of memory\n");
1049 
1050  if (t)
1051  ExFreePool(t);
1052 
1053  ExFreePool(r->nonpaged);
1054  ExFreePool(r);
1056  }
1057 
1058  r->id = id;
1059  r->treeholder.address = 0;
1060  r->treeholder.generation = Vcb->superblock.generation;
1061  r->treeholder.tree = t;
1062  r->lastinode = 0;
1063  r->dirty = FALSE;
1064  r->received = FALSE;
1065  r->reserved = NULL;
1066  r->parent = 0;
1067  r->send_ops = 0;
1068  RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
1069  r->root_item.num_references = 1;
1070  r->fcbs_version = 0;
1071  InitializeListHead(&r->fcbs);
1072  RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
1073 
1074  RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM));
1075 
1076  // We ask here for a traverse_ptr to the item we're inserting, so we can
1077  // copy some of the tree's variables
1078 
1079  Status = insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp);
1080  if (!NT_SUCCESS(Status)) {
1081  ERR("insert_tree_item returned %08x\n", Status);
1082  ExFreePool(ri);
1083 
1084  if (t)
1085  ExFreePool(t);
1086 
1087  ExFreePool(r->nonpaged);
1088  ExFreePool(r);
1089  return Status;
1090  }
1091 
1092  ExInitializeResourceLite(&r->nonpaged->load_tree_lock);
1093 
1094  InsertTailList(&Vcb->roots, &r->list_entry);
1095 
1096  if (!no_tree) {
1097  RtlZeroMemory(&t->header, sizeof(tree_header));
1098  t->header.fs_uuid = tp.tree->header.fs_uuid;
1099  t->header.address = 0;
1100  t->header.flags = HEADER_FLAG_MIXED_BACKREF | 1; // 1 == "written"? Why does the Linux driver record this?
1101  t->header.chunk_tree_uuid = tp.tree->header.chunk_tree_uuid;
1102  t->header.generation = Vcb->superblock.generation;
1103  t->header.tree_id = id;
1104  t->header.num_items = 0;
1105  t->header.level = 0;
1106 
1107  t->has_address = FALSE;
1108  t->size = 0;
1109  t->Vcb = Vcb;
1110  t->parent = NULL;
1111  t->paritem = NULL;
1112  t->root = r;
1113 
1114  InitializeListHead(&t->itemlist);
1115 
1116  t->new_address = 0;
1117  t->has_new_address = FALSE;
1118  t->updated_extents = FALSE;
1119 
1120  InsertTailList(&Vcb->trees, &t->list_entry);
1121  t->list_entry_hash.Flink = NULL;
1122 
1123  t->write = TRUE;
1124  Vcb->need_write = TRUE;
1125  }
1126 
1127  *rootptr = r;
1128 
1129  return STATUS_SUCCESS;
1130 }
1131 
1133  ULONG utf8len;
1134  NTSTATUS Status;
1135  ULONG vollen, i;
1136 
1137  TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel);
1138 
1139  vollen = ffli->VolumeLabelLength;
1140 
1141  for (i = 0; i < ffli->VolumeLabelLength / sizeof(WCHAR); i++) {
1142  if (ffli->VolumeLabel[i] == 0) {
1143  vollen = i * sizeof(WCHAR);
1144  break;
1145  } else if (ffli->VolumeLabel[i] == '/' || ffli->VolumeLabel[i] == '\\') {
1147  goto end;
1148  }
1149  }
1150 
1151  if (vollen == 0) {
1152  utf8len = 0;
1153  } else {
1154  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, vollen);
1155  if (!NT_SUCCESS(Status))
1156  goto end;
1157 
1158  if (utf8len > MAX_LABEL_SIZE) {
1160  goto end;
1161  }
1162  }
1163 
1164  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1165 
1166  if (utf8len > 0) {
1167  Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE, &utf8len, ffli->VolumeLabel, vollen);
1168  if (!NT_SUCCESS(Status))
1169  goto release;
1170  } else
1172 
1173  if (utf8len < MAX_LABEL_SIZE)
1174  RtlZeroMemory(Vcb->superblock.label + utf8len, MAX_LABEL_SIZE - utf8len);
1175 
1176  Vcb->need_write = TRUE;
1177 
1178 release:
1179  ExReleaseResourceLite(&Vcb->tree_lock);
1180 
1181 end:
1182  TRACE("returning %08x\n", Status);
1183 
1184  return Status;
1185 }
1186 
1189 #ifdef __REACTOS__
1190 static NTSTATUS NTAPI drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
1191 #else
1192 static NTSTATUS drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
1193 #endif
1196  NTSTATUS Status;
1197  BOOL top_level;
1198 
1200 
1201  TRACE("set volume information\n");
1202 
1203  top_level = is_top_level(Irp);
1204 
1205  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
1207  goto end;
1208  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
1210  goto end;
1211  }
1212 
1214 
1215  if (Vcb->readonly) {
1217  goto end;
1218  }
1219 
1220  if (Vcb->removing || Vcb->locked) {
1222  goto end;
1223  }
1224 
1225  switch (IrpSp->Parameters.SetVolume.FsInformationClass) {
1227  FIXME("STUB: FileFsControlInformation\n");
1228  break;
1229 
1231  TRACE("FileFsLabelInformation\n");
1232 
1233  Status = set_label(Vcb, Irp->AssociatedIrp.SystemBuffer);
1234  break;
1235 
1237  FIXME("STUB: FileFsObjectIdInformation\n");
1238  break;
1239 
1240  default:
1241  WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp->Parameters.SetVolume.FsInformationClass);
1242  break;
1243  }
1244 
1245 end:
1246  Irp->IoStatus.Status = Status;
1247  Irp->IoStatus.Information = 0;
1248 
1249  TRACE("returning %08x\n", Status);
1250 
1252 
1253  if (top_level)
1255 
1257 
1258  return Status;
1259 }
1260 
1262  char s[60];
1263  NTSTATUS Status;
1265  ANSI_STRING as;
1266 
1267  if (fcb->debug_desc)
1268  return fcb->debug_desc;
1269 
1270  if (fcb == fcb->Vcb->volume_fcb)
1271  return L"volume FCB";
1272 
1274  if (!fcb->debug_desc)
1275  return L"(memory error)";
1276 
1277  // I know this is pretty hackish...
1278  // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
1279  // without the CRT, which breaks drivers.
1280 
1281  sprintf(s, "subvol %x, inode %x", (UINT32)fcb->subvol->id, (UINT32)fcb->inode);
1282 
1283  as.Buffer = s;
1284  as.Length = as.MaximumLength = (USHORT)strlen(s);
1285 
1286  us.Buffer = fcb->debug_desc;
1287  us.MaximumLength = 60 * sizeof(WCHAR);
1288  us.Length = 0;
1289 
1291  if (!NT_SUCCESS(Status))
1292  return L"(RtlAnsiStringToUnicodeString error)";
1293 
1294  us.Buffer[us.Length / sizeof(WCHAR)] = 0;
1295 
1296  return fcb->debug_desc;
1297 }
1298 
1300  NTSTATUS Status;
1302  ULONG reqlen;
1303 
1304  if (fileref->debug_desc)
1305  return fileref->debug_desc;
1306 
1307  fn.Length = fn.MaximumLength = 0;
1308  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1310  return L"ERROR";
1311 
1312  if (reqlen > 0xffff - sizeof(WCHAR))
1313  return L"(too long)";
1314 
1315  fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG);
1316  if (!fileref->debug_desc)
1317  return L"(memory error)";
1318 
1319  fn.Buffer = fileref->debug_desc;
1320  fn.Length = 0;
1321  fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR));
1322 
1323  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1324  if (!NT_SUCCESS(Status)) {
1325  ExFreePool(fileref->debug_desc);
1326  fileref->debug_desc = NULL;
1327  return L"ERROR";
1328  }
1329 
1330  fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0;
1331 
1332  return fileref->debug_desc;
1333 }
1334 
1335 _Ret_z_
1337  fcb* fcb = FileObject->FsContext;
1338  ccb* ccb = FileObject->FsContext2;
1339  file_ref* fileref = ccb ? ccb->fileref : NULL;
1340 
1341  if (fileref)
1342  return file_desc_fileref(fileref);
1343  else
1344  return file_desc_fcb(fcb);
1345 }
1346 
1349  NTSTATUS Status;
1350  ULONG reqlen;
1351  USHORT name_offset;
1352  fcb* fcb = fileref->fcb;
1353 
1354  fn.Length = fn.MaximumLength = 0;
1355  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1356  if (Status != STATUS_BUFFER_OVERFLOW) {
1357  ERR("fileref_get_filename returned %08x\n", Status);
1358  return;
1359  }
1360 
1361  if (reqlen > 0xffff) {
1362  WARN("reqlen was too long for FsRtlNotifyFilterReportChange\n");
1363  return;
1364  }
1365 
1366  fn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
1367  if (!fn.Buffer) {
1368  ERR("out of memory\n");
1369  return;
1370  }
1371 
1372  fn.MaximumLength = (USHORT)reqlen;
1373  fn.Length = 0;
1374 
1375  Status = fileref_get_filename(fileref, &fn, &name_offset, &reqlen);
1376  if (!NT_SUCCESS(Status)) {
1377  ERR("fileref_get_filename returned %08x\n", Status);
1378  ExFreePool(fn.Buffer);
1379  return;
1380  }
1381 
1382  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, name_offset,
1383  (PSTRING)stream, NULL, filter_match, action, NULL, NULL);
1384  ExFreePool(fn.Buffer);
1385 }
1386 
1388  fcb* fcb = fileref->fcb;
1389  LIST_ENTRY* le;
1390  NTSTATUS Status;
1391 
1392  // no point looking for hardlinks if st_nlink == 1
1393  if (fileref->fcb->inode_item.st_nlink == 1) {
1394  send_notification_fileref(fileref, filter_match, action, stream);
1395  return;
1396  }
1397 
1398  ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
1399 
1400  le = fcb->hardlinks.Flink;
1401  while (le != &fcb->hardlinks) {
1403  file_ref* parfr;
1404 
1405  Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL);
1406 
1407  if (!NT_SUCCESS(Status))
1408  ERR("open_fileref_by_inode returned %08x\n", Status);
1409  else if (!parfr->deleted) {
1411  ULONG pathlen;
1412 
1413  fn.Length = fn.MaximumLength = 0;
1414  Status = fileref_get_filename(parfr, &fn, NULL, &pathlen);
1415  if (Status != STATUS_BUFFER_OVERFLOW) {
1416  ERR("fileref_get_filename returned %08x\n", Status);
1417  free_fileref(parfr);
1418  break;
1419  }
1420 
1421  if (parfr != fcb->Vcb->root_fileref)
1422  pathlen += sizeof(WCHAR);
1423 
1424  if (pathlen + hl->name.Length > 0xffff) {
1425  WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n");
1426  free_fileref(parfr);
1427  break;
1428  }
1429 
1430  fn.MaximumLength = (USHORT)(pathlen + hl->name.Length);
1431  fn.Buffer = ExAllocatePoolWithTag(PagedPool, fn.MaximumLength, ALLOC_TAG);
1432  if (!fn.Buffer) {
1433  ERR("out of memory\n");
1434  free_fileref(parfr);
1435  break;
1436  }
1437 
1438  Status = fileref_get_filename(parfr, &fn, NULL, NULL);
1439  if (!NT_SUCCESS(Status)) {
1440  ERR("fileref_get_filename returned %08x\n", Status);
1441  free_fileref(parfr);
1442  ExFreePool(fn.Buffer);
1443  break;
1444  }
1445 
1446  if (parfr != fcb->Vcb->root_fileref) {
1447  fn.Buffer[(pathlen / sizeof(WCHAR)) - 1] = '\\';
1448  fn.Length += sizeof(WCHAR);
1449  }
1450 
1451  RtlCopyMemory(&fn.Buffer[pathlen / sizeof(WCHAR)], hl->name.Buffer, hl->name.Length);
1452  fn.Length += hl->name.Length;
1453 
1454  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, (USHORT)pathlen,
1455  (PSTRING)stream, NULL, filter_match, action, NULL, NULL);
1456 
1457  ExFreePool(fn.Buffer);
1458 
1459  free_fileref(parfr);
1460  }
1461 
1462  le = le->Flink;
1463  }
1464 
1465  ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
1466 }
1467 
1469  if (!fcb->dirty) {
1470 #ifdef DEBUG_FCB_REFCOUNTS
1471  LONG rc;
1472 #endif
1473  fcb->dirty = TRUE;
1474 
1475 #ifdef DEBUG_FCB_REFCOUNTS
1477  WARN("fcb %p: refcount now %i\n", fcb, rc);
1478 #else
1480 #endif
1481 
1482  ExAcquireResourceExclusiveLite(&fcb->Vcb->dirty_fcbs_lock, TRUE);
1483  InsertTailList(&fcb->Vcb->dirty_fcbs, &fcb->list_entry_dirty);
1484  ExReleaseResourceLite(&fcb->Vcb->dirty_fcbs_lock);
1485  }
1486 
1487  fcb->Vcb->need_write = TRUE;
1488 }
1489 
1491  if (!fileref->dirty) {
1492  fileref->dirty = TRUE;
1493  increase_fileref_refcount(fileref);
1494 
1495  ExAcquireResourceExclusiveLite(&fileref->fcb->Vcb->dirty_filerefs_lock, TRUE);
1496  InsertTailList(&fileref->fcb->Vcb->dirty_filerefs, &fileref->list_entry_dirty);
1497  ExReleaseResourceLite(&fileref->fcb->Vcb->dirty_filerefs_lock);
1498  }
1499 
1500  fileref->fcb->Vcb->need_write = TRUE;
1501 }
1502 
1503 #ifdef DEBUG_FCB_REFCOUNTS
1504 void _free_fcb(_Inout_ fcb* fcb, _In_ const char* func) {
1506 #else
1509 #endif
1510 
1511 #ifdef DEBUG_FCB_REFCOUNTS
1512 #ifdef DEBUG_LONG_MESSAGES
1513  ERR("fcb %p (%s): refcount now %i (subvol %llx, inode %llx)\n", fcb, func, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
1514 #else
1515  ERR("fcb %p (%s): refcount now %i (subvol %llx, inode %llx)\n", fcb, func, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
1516 #endif
1517 #endif
1518 }
1519 
1520 void reap_fcb(fcb* fcb) {
1521  UINT8 c = fcb->hash >> 24;
1522 
1523  if (fcb->subvol && fcb->subvol->fcbs_ptrs[c] == &fcb->list_entry) {
1524  if (fcb->list_entry.Flink != &fcb->subvol->fcbs && (CONTAINING_RECORD(fcb->list_entry.Flink, struct _fcb, list_entry)->hash >> 24) == c)
1525  fcb->subvol->fcbs_ptrs[c] = fcb->list_entry.Flink;
1526  else
1527  fcb->subvol->fcbs_ptrs[c] = NULL;
1528  }
1529 
1530  if (fcb->list_entry.Flink)
1532 
1533  if (fcb->list_entry_all.Flink)
1535 
1536  ExDeleteResourceLite(&fcb->nonpaged->resource);
1537  ExDeleteResourceLite(&fcb->nonpaged->paging_resource);
1538  ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock);
1539 
1540  ExFreeToNPagedLookasideList(&fcb->Vcb->fcb_np_lookaside, fcb->nonpaged);
1541 
1542  if (fcb->sd)
1543  ExFreePool(fcb->sd);
1544 
1545  if (fcb->adsxattr.Buffer)
1547 
1548  if (fcb->reparse_xattr.Buffer)
1550 
1551  if (fcb->ea_xattr.Buffer)
1553 
1554  if (fcb->adsdata.Buffer)
1556 
1557  if (fcb->debug_desc)
1559 
1560  while (!IsListEmpty(&fcb->extents)) {
1563 
1564  if (ext->csum)
1565  ExFreePool(ext->csum);
1566 
1567  ExFreePool(ext);
1568  }
1569 
1570  while (!IsListEmpty(&fcb->hardlinks)) {
1573 
1574  if (hl->name.Buffer)
1575  ExFreePool(hl->name.Buffer);
1576 
1577  if (hl->utf8.Buffer)
1578  ExFreePool(hl->utf8.Buffer);
1579 
1580  ExFreePool(hl);
1581  }
1582 
1583  while (!IsListEmpty(&fcb->xattrs)) {
1585 
1586  ExFreePool(xa);
1587  }
1588 
1589  while (!IsListEmpty(&fcb->dir_children_index)) {
1591  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
1592 
1593  ExFreePool(dc->utf8.Buffer);
1594  ExFreePool(dc->name.Buffer);
1595  ExFreePool(dc->name_uc.Buffer);
1596  ExFreePool(dc);
1597  }
1598 
1599  if (fcb->hash_ptrs)
1601 
1602  if (fcb->hash_ptrs_uc)
1604 
1606 
1607  if (fcb->pool_type == NonPagedPool)
1608  ExFreePool(fcb);
1609  else
1610  ExFreeToPagedLookasideList(&fcb->Vcb->fcb_lookaside, fcb);
1611 }
1612 
1614  LIST_ENTRY* le;
1615 
1616  le = Vcb->all_fcbs.Flink;
1617  while (le != &Vcb->all_fcbs) {
1618  fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all);
1619  LIST_ENTRY* le2 = le->Flink;
1620 
1621  if (fcb->refcount == 0)
1622  reap_fcb(fcb);
1623 
1624  le = le2;
1625  }
1626 }
1627 
1629  LONG rc;
1630 
1631  rc = InterlockedDecrement(&fr->refcount);
1632 #ifdef __REACTOS__
1633  (void)rc;
1634 #endif
1635 
1636 #ifdef DEBUG_FCB_REFCOUNTS
1637  ERR("fileref %p: refcount now %i\n", fr, rc);
1638 #endif
1639 
1640 #ifdef _DEBUG
1641  if (rc < 0) {
1642  ERR("fileref %p: refcount now %i\n", fr, rc);
1643  int3;
1644  }
1645 #endif
1646 }
1647 
1649  // FIXME - do we need a file_ref lock?
1650 
1651  // FIXME - do delete if needed
1652 
1653  if (fr->debug_desc)
1654  ExFreePool(fr->debug_desc);
1655 
1657 
1658  ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
1659 
1660  // FIXME - throw error if children not empty
1661 
1662  if (fr->fcb->fileref == fr)
1663  fr->fcb->fileref = NULL;
1664 
1665  if (fr->dc) {
1666  if (fr->fcb->ads)
1667  fr->dc->size = fr->fcb->adsdata.Length;
1668 
1669  fr->dc->fileref = NULL;
1670  }
1671 
1672  if (fr->list_entry.Flink)
1674 
1675  if (fr->parent)
1676  free_fileref(fr->parent);
1677 
1678  free_fcb(fr->fcb);
1679 
1680  ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
1681 }
1682 
1684  LIST_ENTRY* le;
1685 
1686  // FIXME - recursion is a bad idea in kernel mode
1687 
1688  le = fr->children.Flink;
1689  while (le != &fr->children) {
1691  LIST_ENTRY* le2 = le->Flink;
1692 
1693  reap_filerefs(Vcb, c);
1694 
1695  le = le2;
1696  }
1697 
1698  if (fr->refcount == 0)
1699  reap_fileref(Vcb, fr);
1700 }
1701 
1703  fcb* fcb;
1704  ccb* ccb;
1705  file_ref* fileref = NULL;
1706  LONG open_files;
1707 
1708  UNUSED(Irp);
1709 
1710  TRACE("FileObject = %p\n", FileObject);
1711 
1712  fcb = FileObject->FsContext;
1713  if (!fcb) {
1714  TRACE("FCB was NULL, returning success\n");
1715  return STATUS_SUCCESS;
1716  }
1717 
1718  open_files = InterlockedDecrement(&fcb->Vcb->open_files);
1719 
1720  ccb = FileObject->FsContext2;
1721 
1722  TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb);
1723 
1724  // FIXME - make sure notification gets sent if file is being deleted
1725 
1726  if (ccb) {
1727  if (ccb->query_string.Buffer)
1729 
1730  if (ccb->filename.Buffer)
1732 
1733  // FIXME - use refcounts for fileref
1734  fileref = ccb->fileref;
1735 
1736  if (fcb->Vcb->running_sends > 0) {
1737  BOOL send_cancelled = FALSE;
1738 
1739  ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE);
1740 
1741  if (ccb->send) {
1742  ccb->send->cancelling = TRUE;
1743  send_cancelled = TRUE;
1745  }
1746 
1747  ExReleaseResourceLite(&fcb->Vcb->send_load_lock);
1748 
1749  if (send_cancelled) {
1750  while (ccb->send) {
1751  ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE);
1752  ExReleaseResourceLite(&fcb->Vcb->send_load_lock);
1753  }
1754  }
1755  }
1756 
1757  ExFreePool(ccb);
1758  }
1759 
1761 
1762  if (open_files == 0 && fcb->Vcb->removing) {
1763  uninit(fcb->Vcb);
1764  return STATUS_SUCCESS;
1765  }
1766 
1767  if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED))
1768  return STATUS_SUCCESS;
1769 
1770  if (fileref)
1771  free_fileref(fileref);
1772  else
1773  free_fcb(fcb);
1774 
1775  return STATUS_SUCCESS;
1776 }
1777 
1779  UINT64 i;
1780  KIRQL irql;
1781  NTSTATUS Status;
1782  LIST_ENTRY* le;
1784 
1785  if (!Vcb->removing) {
1786  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1787  Vcb->removing = TRUE;
1788  ExReleaseResourceLite(&Vcb->tree_lock);
1789  }
1790 
1792  Vcb->Vpb->Flags &= ~VPB_MOUNTED;
1793  Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
1795 
1796  RemoveEntryList(&Vcb->list_entry);
1797 
1798  if (Vcb->balance.thread) {
1799  Vcb->balance.paused = FALSE;
1800  Vcb->balance.stopping = TRUE;
1801  KeSetEvent(&Vcb->balance.event, 0, FALSE);
1802  KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL);
1803  }
1804 
1805  if (Vcb->scrub.thread) {
1806  Vcb->scrub.paused = FALSE;
1807  Vcb->scrub.stopping = TRUE;
1808  KeSetEvent(&Vcb->scrub.event, 0, FALSE);
1809  KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL);
1810  }
1811 
1812  if (Vcb->running_sends != 0) {
1813  BOOL send_cancelled = FALSE;
1814 
1815  ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
1816 
1817  le = Vcb->send_ops.Flink;
1818  while (le != &Vcb->send_ops) {
1820 
1821  if (!send->cancelling) {
1822  send->cancelling = TRUE;
1823  send_cancelled = TRUE;
1824  send->ccb = NULL;
1825  KeSetEvent(&send->cleared_event, 0, FALSE);
1826  }
1827 
1828  le = le->Flink;
1829  }
1830 
1831  ExReleaseResourceLite(&Vcb->send_load_lock);
1832 
1833  if (send_cancelled) {
1834  while (Vcb->running_sends != 0) {
1835  ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
1836  ExReleaseResourceLite(&Vcb->send_load_lock);
1837  }
1838  }
1839  }
1840 
1841  Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid);
1843  WARN("registry_mark_volume_unmounted returned %08x\n", Status);
1844 
1845  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
1846  Vcb->calcthreads.threads[i].quit = TRUE;
1847  }
1848 
1849  KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
1850 
1851  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
1852  KeWaitForSingleObject(&Vcb->calcthreads.threads[i].finished, Executive, KernelMode, FALSE, NULL);
1853 
1854  ZwClose(Vcb->calcthreads.threads[i].handle);
1855  }
1856 
1857  ExDeleteResourceLite(&Vcb->calcthreads.lock);
1858  ExFreePool(Vcb->calcthreads.threads);
1859 
1860  time.QuadPart = 0;
1861  KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early
1862  KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
1863 
1864  reap_fcb(Vcb->volume_fcb);
1865  reap_fcb(Vcb->dummy_fcb);
1866 
1867  if (Vcb->root_file)
1868  ObDereferenceObject(Vcb->root_file);
1869 
1870  le = Vcb->chunks.Flink;
1871  while (le != &Vcb->chunks) {
1873 
1874  if (c->cache) {
1875  reap_fcb(c->cache);
1876  c->cache = NULL;
1877  }
1878 
1879  le = le->Flink;
1880  }
1881 
1882  while (!IsListEmpty(&Vcb->roots)) {
1884 
1885  ExDeleteResourceLite(&r->nonpaged->load_tree_lock);
1886  ExFreePool(r->nonpaged);
1887  ExFreePool(r);
1888  }
1889 
1890  while (!IsListEmpty(&Vcb->chunks)) {
1892 
1893  while (!IsListEmpty(&c->space)) {
1894  LIST_ENTRY* le2 = RemoveHeadList(&c->space);
1896 
1897  ExFreePool(s);
1898  }
1899 
1900  while (!IsListEmpty(&c->deleting)) {
1901  LIST_ENTRY* le2 = RemoveHeadList(&c->deleting);
1903 
1904  ExFreePool(s);
1905  }
1906 
1907  if (c->devices)
1908  ExFreePool(c->devices);
1909 
1910  if (c->cache)
1911  reap_fcb(c->cache);
1912 
1913  ExDeleteResourceLite(&c->range_locks_lock);
1914  ExDeleteResourceLite(&c->partial_stripes_lock);
1915  ExDeleteResourceLite(&c->lock);
1916  ExDeleteResourceLite(&c->changed_extents_lock);
1917 
1918  ExFreePool(c->chunk_item);
1919  ExFreePool(c);
1920  }
1921 
1922  // FIXME - free any open fcbs?
1923 
1924  while (!IsListEmpty(&Vcb->devices)) {
1926 
1927  while (!IsListEmpty(&dev->space)) {
1928  LIST_ENTRY* le2 = RemoveHeadList(&dev->space);
1930 
1931  ExFreePool(s);
1932  }
1933 
1934  ExFreePool(dev);
1935  }
1936 
1937  ExAcquireResourceExclusiveLite(&Vcb->scrub.stats_lock, TRUE);
1938  while (!IsListEmpty(&Vcb->scrub.errors)) {
1940 
1941  ExFreePool(err);
1942  }
1943  ExReleaseResourceLite(&Vcb->scrub.stats_lock);
1944 
1945  ExDeleteResourceLite(&Vcb->fcb_lock);
1946  ExDeleteResourceLite(&Vcb->fileref_lock);
1947  ExDeleteResourceLite(&Vcb->load_lock);
1948  ExDeleteResourceLite(&Vcb->tree_lock);
1949  ExDeleteResourceLite(&Vcb->chunk_lock);
1950  ExDeleteResourceLite(&Vcb->dirty_fcbs_lock);
1951  ExDeleteResourceLite(&Vcb->dirty_filerefs_lock);
1952  ExDeleteResourceLite(&Vcb->dirty_subvols_lock);
1953  ExDeleteResourceLite(&Vcb->scrub.stats_lock);
1954  ExDeleteResourceLite(&Vcb->send_load_lock);
1955 
1956  ExDeletePagedLookasideList(&Vcb->tree_data_lookaside);
1957  ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside);
1958  ExDeletePagedLookasideList(&Vcb->batch_item_lookaside);
1959  ExDeletePagedLookasideList(&Vcb->fileref_lookaside);
1960  ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
1961  ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
1962  ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
1963  ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
1964  ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
1965 
1966  ZwClose(Vcb->flush_thread_handle);
1967 }
1968 
1970  LARGE_INTEGER newlength, time;
1971  BTRFS_TIME now;
1972  NTSTATUS Status;
1973  ULONG utf8len = 0;
1974 
1977 
1978  ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE);
1979 
1980  if (fileref->deleted) {
1981  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1982  return STATUS_SUCCESS;
1983  }
1984 
1985  if (fileref->fcb->subvol->send_ops > 0) {
1986  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1987  return STATUS_ACCESS_DENIED;
1988  }
1989 
1990  fileref->deleted = TRUE;
1991  mark_fileref_dirty(fileref);
1992 
1993  // delete INODE_ITEM (0x1)
1994 
1995  TRACE("nlink = %u\n", fileref->fcb->inode_item.st_nlink);
1996 
1997  if (!fileref->fcb->ads) {
1998  if (fileref->parent->fcb->subvol == fileref->fcb->subvol) {
1999  LIST_ENTRY* le;
2000 
2001  mark_fcb_dirty(fileref->fcb);
2002 
2003  fileref->fcb->inode_item_changed = TRUE;
2004 
2005  if (fileref->fcb->inode_item.st_nlink > 1) {
2006  fileref->fcb->inode_item.st_nlink--;
2007  fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
2008  fileref->fcb->inode_item.sequence++;
2009  fileref->fcb->inode_item.st_ctime = now;
2010  } else {
2011  // excise extents
2012 
2013  if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) {
2014  Status = excise_extents(fileref->fcb->Vcb, fileref->fcb, 0, sector_align(fileref->fcb->inode_item.st_size, fileref->fcb->Vcb->superblock.sector_size), Irp, rollback);
2015  if (!NT_SUCCESS(Status)) {
2016  ERR("excise_extents returned %08x\n", Status);
2017  ExReleaseResourceLite(fileref->fcb->Header.Resource);
2018  return Status;
2019  }
2020  }
2021 
2022  fileref->fcb->Header.AllocationSize.QuadPart = 0;
2023  fileref->fcb->Header.FileSize.QuadPart = 0;
2024  fileref->fcb->Header.ValidDataLength.QuadPart = 0;
2025 
2026  if (FileObject) {
2027  CC_FILE_SIZES ccfs;
2028 
2029  ccfs.AllocationSize = fileref->fcb->Header.AllocationSize;
2030  ccfs.FileSize = fileref->fcb->Header.FileSize;
2031  ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength;
2032 
2034 
2035  _SEH2_TRY {
2036  CcSetFileSizes(FileObject, &ccfs);
2039  } _SEH2_END;
2040 
2041  if (!NT_SUCCESS(Status)) {
2042  ERR("CcSetFileSizes threw exception %08x\n", Status);
2043  ExReleaseResourceLite(fileref->fcb->Header.Resource);
2044  return Status;
2045  }
2046  }
2047 
2048  fileref->fcb->deleted = TRUE;
2049 
2050  le = fileref->children.Flink;
2051  while (le != &fileref->children) {
2053 
2054  if (fr2->fcb->ads) {
2055  fr2->fcb->deleted = TRUE;
2056  mark_fcb_dirty(fr2->fcb);
2057  }
2058 
2059  le = le->Flink;
2060  }
2061  }
2062 
2063  if (fileref->dc) {
2064  le = fileref->fcb->hardlinks.Flink;
2065  while (le != &fileref->fcb->hardlinks) {
2067 
2068  if (hl->parent == fileref->parent->fcb->inode && hl->index == fileref->dc->index) {
2070 
2071  if (hl->name.Buffer)
2072  ExFreePool(hl->name.Buffer);
2073 
2074  if (hl->utf8.Buffer)
2075  ExFreePool(hl->utf8.Buffer);
2076 
2077  ExFreePool(hl);
2078  break;
2079  }
2080 
2081  le = le->Flink;
2082  }
2083  }
2084  } else if (fileref->fcb->subvol->parent == fileref->parent->fcb->subvol->id) { // valid subvolume
2085  if (fileref->fcb->subvol->root_item.num_references > 1) {
2086  fileref->fcb->subvol->root_item.num_references--;
2087 
2088  mark_fcb_dirty(fileref->fcb); // so ROOT_ITEM gets updated
2089  } else {
2090  LIST_ENTRY* le;
2091 
2092  // FIXME - we need a lock here
2093 
2094  RemoveEntryList(&fileref->fcb->subvol->list_entry);
2095 
2096  InsertTailList(&fileref->fcb->Vcb->drop_roots, &fileref->fcb->subvol->list_entry);
2097 
2098  le = fileref->children.Flink;
2099  while (le != &fileref->children) {
2101 
2102  if (fr2->fcb->ads) {
2103  fr2->fcb->deleted = TRUE;
2104  mark_fcb_dirty(fr2->fcb);
2105  }
2106 
2107  le = le->Flink;
2108  }
2109  }
2110  }
2111  } else {
2112  fileref->fcb->deleted = TRUE;
2113  mark_fcb_dirty(fileref->fcb);
2114  }
2115 
2116  // remove dir_child from parent
2117 
2118  if (fileref->dc) {
2119  TRACE("delete file %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer);
2120 
2121  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
2122  RemoveEntryList(&fileref->dc->list_entry_index);
2123 
2124  if (!fileref->fcb->ads)
2125  remove_dir_child_from_hash_lists(fileref->parent->fcb, fileref->dc);
2126 
2127  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2128 
2129  if (!fileref->oldutf8.Buffer)
2130  fileref->oldutf8 = fileref->dc->utf8;
2131  else
2132  ExFreePool(fileref->dc->utf8.Buffer);
2133 
2134  utf8len = fileref->dc->utf8.Length;
2135 
2136  fileref->oldindex = fileref->dc->index;
2137 
2138  ExFreePool(fileref->dc->name.Buffer);
2139  ExFreePool(fileref->dc->name_uc.Buffer);
2140  ExFreePool(fileref->dc);
2141 
2142  fileref->dc = NULL;
2143  }
2144 
2145  // update INODE_ITEM of parent
2146 
2147  ExAcquireResourceExclusiveLite(fileref->parent->fcb->Header.Resource, TRUE);
2148 
2149  fileref->parent->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
2150  fileref->parent->fcb->inode_item.sequence++;
2151  fileref->parent->fcb->inode_item.st_ctime = now;
2152 
2153  if (!fileref->fcb->ads) {
2154  TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size);
2155  fileref->parent->fcb->inode_item.st_size -= utf8len * 2;
2156  TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size);
2157  fileref->parent->fcb->inode_item.st_mtime = now;
2158  }
2159 
2160  fileref->parent->fcb->inode_item_changed = TRUE;
2161  ExReleaseResourceLite(fileref->parent->fcb->Header.Resource);
2162 
2163  if (!fileref->fcb->ads && fileref->parent->dc)
2165 
2166  mark_fcb_dirty(fileref->parent->fcb);
2167 
2168  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
2169  fileref->fcb->subvol->root_item.ctime = now;
2170 
2171  newlength.QuadPart = 0;
2172 
2173  if (FileObject && !CcUninitializeCacheMap(FileObject, &newlength, NULL))
2174  TRACE("CcUninitializeCacheMap failed\n");
2175 
2176  ExReleaseResourceLite(fileref->fcb->Header.Resource);
2177 
2178  return STATUS_SUCCESS;
2179 }
2180 
2183 #ifdef __REACTOS__
2184 static NTSTATUS NTAPI drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
2185 #else
2186 static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
2187 #endif
2188  NTSTATUS Status;
2192  fcb* fcb = FileObject->FsContext;
2193  BOOL top_level;
2194 
2196 
2197  TRACE("cleanup\n");
2198 
2199  top_level = is_top_level(Irp);
2200 
2201  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
2203  goto exit;
2204  } else if (DeviceObject == master_devobj) {
2205  TRACE("closing file system\n");
2207  goto exit;
2208  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
2210  goto exit;
2211  }
2212 
2213  if (FileObject->Flags & FO_CLEANUP_COMPLETE) {
2214  TRACE("FileObject %p already cleaned up\n", FileObject);
2216  goto exit;
2217  }
2218 
2219  if (!fcb) {
2220  ERR("fcb was NULL\n");
2222  goto exit;
2223  }
2224 
2225  // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
2226  // messages belonging to other devices.
2227 
2228  if (FileObject && FileObject->FsContext) {
2229  LONG oc;
2230  ccb* ccb;
2231  file_ref* fileref;
2232  BOOL locked = TRUE;
2233 
2234  ccb = FileObject->FsContext2;
2235  fileref = ccb ? ccb->fileref : NULL;
2236 
2237  TRACE("cleanup called for FileObject %p\n", FileObject);
2238  TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0);
2239 
2240  ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
2241 
2243 
2245 
2246  if (ccb)
2247  FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb);
2248 
2249  if (fileref) {
2250  oc = InterlockedDecrement(&fileref->open_count);
2251 #ifdef DEBUG_FCB_REFCOUNTS
2252  ERR("fileref %p: open_count now %i\n", fileref, oc);
2253 #endif
2254  }
2255 
2256  if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref)
2257  fileref->delete_on_close = TRUE;
2258 
2259  if (fileref && fileref->delete_on_close && fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && fcb != fcb->Vcb->dummy_fcb)
2260  fileref->delete_on_close = FALSE;
2261 
2262  if (fcb->Vcb->locked && fcb->Vcb->locked_fileobj == FileObject) {
2263  TRACE("unlocking volume\n");
2266  }
2267 
2268  if (ccb && ccb->reserving) {
2269  fcb->subvol->reserved = NULL;
2270  ccb->reserving = FALSE;
2271  // FIXME - flush all of subvol's fcbs
2272  }
2273 
2274  if (fileref && oc == 0) {
2275  if (!fcb->Vcb->removing) {
2276  if (fileref && fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) {
2278 
2280 
2281  if (!fileref->fcb->ads || fileref->dc) {
2282  if (fileref->fcb->ads) {
2284  FILE_ACTION_REMOVED, &fileref->dc->name);
2285  } else
2287  }
2288 
2289  ExReleaseResourceLite(fcb->Header.Resource);
2290  locked = FALSE;
2291 
2292  // fileref_lock needs to be acquired before fcb->Header.Resource
2293  ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
2294 
2295  Status = delete_fileref(fileref, FileObject, Irp, &rollback);
2296  if (!NT_SUCCESS(Status)) {
2297  ERR("delete_fileref returned %08x\n", Status);
2299  ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
2300  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2301  goto exit;
2302  }
2303 
2304  ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
2305 
2307  } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) {
2309  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2310 
2311  if (!NT_SUCCESS(iosb.Status)) {
2312  ERR("CcFlushCache returned %08x\n", iosb.Status);
2313  }
2314 
2315  if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) {
2316  ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
2317  ExReleaseResourceLite(fcb->Header.PagingIoResource);
2318  }
2319 
2320  CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE);
2321 
2322  TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n",
2323  FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
2324  }
2325  }
2326 
2327  if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb)
2329  }
2330 
2331  if (locked)
2332  ExReleaseResourceLite(fcb->Header.Resource);
2333 
2334  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2335 
2336  FileObject->Flags |= FO_CLEANUP_COMPLETE;
2337  }
2338 
2340 
2341 exit:
2342  TRACE("returning %08x\n", Status);
2343 
2344  Irp->IoStatus.Status = Status;
2345  Irp->IoStatus.Information = 0;
2346 
2348 
2349  if (top_level)
2351 
2353 
2354  return Status;
2355 }
2356 
2357 _Success_(return)
2358 BOOL get_file_attributes_from_xattr(_In_reads_bytes_(len) char* val, _In_ UINT16 len, _Out_ ULONG* atts) {
2359  if (len > 2 && val[0] == '0' && val[1] == 'x') {
2360  int i;
2361  ULONG dosnum = 0;
2362 
2363  for (i = 2; i < len; i++) {
2364  dosnum *= 0x10;
2365 
2366  if (val[i] >= '0' && val[i] <= '9')
2367  dosnum |= val[i] - '0';
2368  else if (val[i] >= 'a' && val[i] <= 'f')
2369  dosnum |= val[i] + 10 - 'a';
2370  else if (val[i] >= 'A' && val[i] <= 'F')
2371  dosnum |= val[i] + 10 - 'a';
2372  }
2373 
2374  TRACE("DOSATTRIB: %08x\n", dosnum);
2375 
2376  *atts = dosnum;
2377 
2378  return TRUE;
2379  }
2380 
2381  return FALSE;
2382 }
2383 
2385  _In_ UINT8 type, _In_ BOOL dotfile, _In_ BOOL ignore_xa, _In_opt_ PIRP Irp) {
2386  ULONG att;
2387  char* eaval;
2388  UINT16 ealen;
2389 
2390  if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen, Irp)) {
2391  ULONG dosnum = 0;
2392 
2393  if (get_file_attributes_from_xattr(eaval, ealen, &dosnum)) {
2394  ExFreePool(eaval);
2395 
2396  if (type == BTRFS_TYPE_DIRECTORY)
2397  dosnum |= FILE_ATTRIBUTE_DIRECTORY;
2398  else if (type == BTRFS_TYPE_SYMLINK)
2399  dosnum |= FILE_ATTRIBUTE_REPARSE_POINT;
2400 
2401  if (type != BTRFS_TYPE_DIRECTORY)
2402  dosnum &= ~FILE_ATTRIBUTE_DIRECTORY;
2403 
2404  if (inode == SUBVOL_ROOT_INODE) {
2405  if (r->root_item.flags & BTRFS_SUBVOL_READONLY)
2406  dosnum |= FILE_ATTRIBUTE_READONLY;
2407  else
2408  dosnum &= ~FILE_ATTRIBUTE_READONLY;
2409  }
2410 
2411  return dosnum;
2412  }
2413 
2414  ExFreePool(eaval);
2415  }
2416 
2417  switch (type) {
2418  case BTRFS_TYPE_DIRECTORY:
2420  break;
2421 
2422  case BTRFS_TYPE_SYMLINK:
2424  break;
2425 
2426  default:
2427  att = 0;
2428  break;
2429  }
2430 
2431  if (dotfile) {
2432  att |= FILE_ATTRIBUTE_HIDDEN;
2433  }
2434 
2435  att |= FILE_ATTRIBUTE_ARCHIVE;
2436 
2437  if (inode == SUBVOL_ROOT_INODE) {
2438  if (r->root_item.flags & BTRFS_SUBVOL_READONLY)
2439  att |= FILE_ATTRIBUTE_READONLY;
2440  else
2441  att &= ~FILE_ATTRIBUTE_READONLY;
2442  }
2443 
2444  // FIXME - get READONLY from ii->st_mode
2445  // FIXME - return SYSTEM for block/char devices?
2446 
2447  if (att == 0)
2448  att = FILE_ATTRIBUTE_NORMAL;
2449 
2450  return att;
2451 }
2452 
2457  PIRP Irp;
2459  NTSTATUS Status;
2461 
2462  num_reads++;
2463 
2464  RtlZeroMemory(&context, sizeof(read_context));
2466 
2467  Offset.QuadPart = (LONGLONG)StartingOffset;
2468 
2470 
2471  if (!Irp) {
2472  ERR("IoAllocateIrp failed\n");
2474  }
2475 
2476  Irp->Flags |= IRP_NOCACHE;
2479 
2480  if (override)
2482 
2484  Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, ALLOC_TAG);
2485  if (!Irp->AssociatedIrp.SystemBuffer) {
2486  ERR("out of memory\n");
2488  goto exit;
2489  }
2490 
2492 
2493  Irp->UserBuffer = Buffer;
2494  } else if (DeviceObject->Flags & DO_DIRECT_IO) {
2495  Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);
2496  if (!Irp->MdlAddress) {
2497  ERR("IoAllocateMdl failed\n");
2499  goto exit;
2500  }
2501 
2503 
2504  _SEH2_TRY {
2508  } _SEH2_END;
2509 
2510  if (!NT_SUCCESS(Status)) {
2511  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
2512  IoFreeMdl(Irp->MdlAddress);
2513  goto exit;
2514  }
2515  } else
2516  Irp->UserBuffer = Buffer;
2517 
2518  IrpSp->Parameters.Read.Length = Length;
2519  IrpSp->Parameters.Read.ByteOffset = Offset;
2520 
2521  Irp->UserIosb = &IoStatus;
2522 
2523  Irp->UserEvent = &context.Event;
2524 
2525  IoSetCompletionRoutine(Irp, read_completion, &context, TRUE, TRUE, TRUE);
2526 
2528 
2529  if (Status == STATUS_PENDING) {
2531  Status = context.iosb.Status;
2532  }
2533 
2534  if (DeviceObject->Flags & DO_DIRECT_IO) {
2535  MmUnlockPages(Irp->MdlAddress);
2536  IoFreeMdl(Irp->MdlAddress);
2537  }
2538 
2539 exit:
2540  IoFreeIrp(Irp);
2541 
2542  return Status;
2543 }
2544 
2546  NTSTATUS Status;
2547  superblock* sb;
2548  ULONG i, to_read;
2549  UINT8 valid_superblocks;
2550 
2551  to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize);
2552 
2554  if (!sb) {
2555  ERR("out of memory\n");
2557  }
2558 
2559  if (superblock_addrs[0] + to_read > length) {
2560  WARN("device was too short to have any superblock\n");
2561  ExFreePool(sb);
2563  }
2564 
2565  i = 0;
2566  valid_superblocks = 0;
2567 
2568  while (superblock_addrs[i] > 0) {
2569  UINT32 crc32;
2570 
2571  if (i > 0 && superblock_addrs[i] + to_read > length)
2572  break;
2573 
2575  if (!NT_SUCCESS(Status)) {
2576  ERR("Failed to read superblock %u: %08x\n", i, Status);
2577  ExFreePool(sb);
2578  return Status;
2579  }
2580 
2581  if (sb->magic != BTRFS_MAGIC) {
2582  if (i == 0) {
2583  TRACE("not a BTRFS volume\n");
2584  ExFreePool(sb);
2586  }
2587  } else {
2588  TRACE("got superblock %u!\n", i);
2589 
2590  crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
2591 
2592  if (crc32 != *((UINT32*)sb->checksum))
2593  WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum));
2594  else if (sb->sector_size == 0)
2595  WARN("superblock sector size was 0\n");
2596  else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000)
2597  WARN("invalid node size %x\n", sb->node_size);
2598  else if ((sb->node_size % sb->sector_size) != 0)
2599  WARN("node size %x was not a multiple of sector_size %x\n", sb->node_size, sb->sector_size);
2600  else if (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation) {
2601  RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock));
2602  valid_superblocks++;
2603  }
2604  }
2605 
2606  i++;
2607  }
2608 
2609  ExFreePool(sb);
2610 
2611  if (valid_superblocks == 0) {
2612  ERR("could not find any valid superblocks\n");
2613  return STATUS_INTERNAL_ERROR;
2614  }
2615 
2616  TRACE("label is %s\n", Vcb->superblock.label);
2617 
2618  return STATUS_SUCCESS;
2619 }
2620 
2622  _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb) {
2623  PIRP Irp;
2624  KEVENT Event;
2625  NTSTATUS Status;
2628 
2630 
2632  DeviceObject,
2633  InputBuffer,
2634  InputBufferSize,
2635  OutputBuffer,
2636  OutputBufferSize,
2637  FALSE,
2638  &Event,
2639  &IoStatus);
2640 
2641  if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
2642 
2643  if (Override) {
2646  }
2647 
2649 
2650  if (Status == STATUS_PENDING) {
2652  Status = IoStatus.Status;
2653  }
2654 
2655  if (iosb)
2656  *iosb = IoStatus;
2657 
2658  return Status;
2659 }
2660 
2665  if (!r) {
2666  ERR("out of memory\n");
2668  }
2669 
2670  r->id = id;
2671  r->dirty = FALSE;
2672  r->received = FALSE;
2673  r->reserved = NULL;
2674  r->treeholder.address = addr;
2675  r->treeholder.tree = NULL;
2676  r->treeholder.generation = generation;
2677  r->parent = 0;
2678  r->send_ops = 0;
2679  r->fcbs_version = 0;
2681  RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256);
2682 
2684  if (!r->nonpaged) {
2685  ERR("out of memory\n");
2686  ExFreePool(r);
2688  }
2689 
2690  ExInitializeResourceLite(&r->nonpaged->load_tree_lock);
2691 
2692  r->lastinode = 0;
2693 
2694  if (tp) {
2695  RtlCopyMemory(&r->root_item, tp->item->data, min(sizeof(ROOT_ITEM), tp->item->size));
2696  if (tp->item->size < sizeof(ROOT_ITEM))
2697  RtlZeroMemory(((UINT8*)&r->root_item) + tp->item->size, sizeof(ROOT_ITEM) - tp->item->size);
2698  } else
2699  RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
2700 
2701  if (!Vcb->readonly && (r->id == BTRFS_ROOT_ROOT || r->id == BTRFS_ROOT_FSTREE || (r->id >= 0x100 && !(r->id & 0xf000000000000000)))) { // FS tree root
2702  // FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag)
2703  get_last_inode(Vcb, r, NULL);
2704 
2705  if (r->id == BTRFS_ROOT_ROOT && r->lastinode < 0x100)
2706  r->lastinode = 0x100;
2707  }
2708 
2709  InsertTailList(&Vcb->roots, &r->list_entry);
2710 
2711  switch (r->id) {
2712  case BTRFS_ROOT_ROOT:
2713  Vcb->root_root = r;
2714  break;
2715 
2716  case BTRFS_ROOT_EXTENT:
2717  Vcb->extent_root = r;
2718  break;
2719 
2720  case BTRFS_ROOT_CHUNK:
2721  Vcb->chunk_root = r;
2722  break;
2723 
2724  case BTRFS_ROOT_DEVTREE:
2725  Vcb->dev_root = r;
2726  break;
2727 
2728  case BTRFS_ROOT_CHECKSUM:
2729  Vcb->checksum_root = r;
2730  break;
2731 
2732  case BTRFS_ROOT_UUID:
2733  Vcb->uuid_root = r;
2734  break;
2735 
2736  case BTRFS_ROOT_FREE_SPACE:
2737  Vcb->space_root = r;
2738  break;
2739 
2740  case BTRFS_ROOT_DATA_RELOC:
2741  Vcb->data_reloc_root = r;
2742  break;
2743  }
2744 
2746 }
2747 
2749  traverse_ptr tp, next_tp;
2750  KEY searchkey;
2751  BOOL b;
2752  NTSTATUS Status;
2753 
2754  searchkey.obj_id = 0;
2755  searchkey.obj_type = 0;
2756  searchkey.offset = 0;
2757 
2758  Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
2759  if (!NT_SUCCESS(Status)) {
2760  ERR("error - find_item returned %08x\n", Status);
2761  return Status;
2762  }
2763 
2764  do {
2765  TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
2766 
2767  if (tp.item->key.obj_type == TYPE_ROOT_ITEM) {
2768  ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data;
2769 
2770  if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) {
2771  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));
2772  } else {
2773  TRACE("root %llx - address %llx\n", tp.item->key.obj_id, ri->block_number);
2774 
2776  if (!NT_SUCCESS(Status)) {
2777  ERR("add_root returned %08x\n", Status);
2778  return Status;
2779  }
2780  }
2781  } else if (tp.item->key.obj_type == TYPE_ROOT_BACKREF && !IsListEmpty(&Vcb->roots)) {
2782  root* lastroot = CONTAINING_RECORD(Vcb->roots.Blink, root, list_entry);
2783 
2784  if (lastroot->id == tp.item->key.obj_id)
2785  lastroot->parent = tp.item->key.offset;
2786  }
2787 
2788  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
2789 
2790  if (b)
2791  tp = next_tp;
2792  } while (b);
2793 
2794  if (!Vcb->readonly && !Vcb->data_reloc_root) {
2795  root* reloc_root;
2796  INODE_ITEM* ii;
2797  UINT16 irlen;
2798  INODE_REF* ir;
2800  BTRFS_TIME now;
2801 
2802  WARN("data reloc root doesn't exist, creating it\n");
2803 
2805 
2806  if (!NT_SUCCESS(Status)) {
2807  ERR("create_root returned %08x\n", Status);
2808  return Status;
2809  }
2810 
2811  reloc_root->root_item.inode.generation = 1;
2812  reloc_root->root_item.inode.st_size = 3;
2813  reloc_root->root_item.inode.st_blocks = Vcb->superblock.node_size;
2814  reloc_root->root_item.inode.st_nlink = 1;
2815  reloc_root->root_item.inode.st_mode = 040755;
2816  reloc_root->root_item.inode.flags = 0xffffffff80000000;
2817  reloc_root->root_item.objid = SUBVOL_ROOT_INODE;
2818  reloc_root->root_item.bytes_used = Vcb->superblock.node_size;
2819 
2821  if (!ii) {
2822  ERR("out of memory\n");
2824  }
2825 
2828 
2829  RtlZeroMemory(ii, sizeof(INODE_ITEM));
2830  ii->generation = Vcb->superblock.generation;
2831  ii->st_blocks = Vcb->superblock.node_size;
2832  ii->st_nlink = 1;
2833  ii->st_mode = 040755;
2834  ii->st_atime = now;
2835  ii->st_ctime = now;
2836  ii->st_mtime = now;
2837 
2839  if (!NT_SUCCESS(Status)) {
2840  ERR("insert_tree_item returned %08x\n", Status);
2841  ExFreePool(ii);
2842  return Status;
2843  }
2844 
2845  irlen = (UINT16)offsetof(INODE_REF, name[0]) + 2;
2847  if (!ir) {
2848  ERR("out of memory\n");
2850  }
2851 
2852  ir->index = 0;
2853  ir->n = 2;
2854  ir->name[0] = '.';
2855  ir->name[1] = '.';
2856 
2858  if (!NT_SUCCESS(Status)) {
2859  ERR("insert_tree_item returned %08x\n", Status);
2860  ExFreePool(ir);
2861  return Status;
2862  }
2863 
2864  Vcb->data_reloc_root = reloc_root;
2865  Vcb->need_write = TRUE;
2866  }
2867 
2868  return STATUS_SUCCESS;
2869 }
2870 
2872  KEY searchkey;
2873  traverse_ptr tp, next_tp;
2874  BOOL b;
2875  UINT64 lastaddr;
2876  NTSTATUS Status;
2877 
2878  InitializeListHead(&dev->space);
2879 
2880  searchkey.obj_id = 0;
2881  searchkey.obj_type = TYPE_DEV_STATS;
2882  searchkey.offset = dev->devitem.dev_id;
2883 
2884  Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
2885  if (NT_SUCCESS(Status) && !keycmp(tp.item->key, searchkey))
2886  RtlCopyMemory(dev->stats, tp.item->data, min(sizeof(UINT64) * 5, tp.item->size));
2887 
2888  searchkey.obj_id = dev->devitem.dev_id;
2889  searchkey.obj_type = TYPE_DEV_EXTENT;
2890  searchkey.offset = 0;
2891 
2892  Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
2893  if (!NT_SUCCESS(Status)) {
2894  ERR("error - find_item returned %08x\n", Status);
2895  return Status;
2896  }
2897 
2898  lastaddr = 0;
2899 
2900  do {
2901  if (tp.item->key.obj_id == dev->devitem.dev_id && tp.item->key.obj_type == TYPE_DEV_EXTENT) {
2902  if (tp.item->size >= sizeof(DEV_EXTENT)) {
2903  DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data;
2904 
2905  if (tp.item->key.offset > lastaddr) {
2906  Status = add_space_entry(&dev->space, NULL, lastaddr, tp.item->key.offset - lastaddr);
2907  if (!NT_SUCCESS(Status)) {
2908  ERR("add_space_entry returned %08x\n", Status);
2909  return Status;
2910  }
2911  }
2912 
2913  lastaddr = tp.item->key.offset + de->length;
2914  } else {
2915  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));
2916  }
2917  }
2918 
2919  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
2920 
2921  if (b) {
2922  tp = next_tp;
2923  if (tp.item->key.obj_id > searchkey.obj_id || tp.item->key.obj_type > searchkey.obj_type)
2924  break;
2925  }
2926  } while (b);
2927 
2928  if (lastaddr < dev->devitem.num_bytes) {
2929  Status = add_space_entry(&dev->space, NULL, lastaddr, dev->devitem.num_bytes - lastaddr);
2930  if (!NT_SUCCESS(Status)) {
2931  ERR("add_space_entry returned %08x\n", Status);
2932  return Status;
2933  }
2934  }
2935 
2936  // The Linux driver doesn't like to allocate chunks within the first megabyte of a device.
2937 
2938  space_list_subtract2(&dev->space, NULL, 0, 0x100000, NULL, NULL);
2939 
2940  return STATUS_SUCCESS;
2941 }
2942 
2944  LIST_ENTRY* le;
2945 
2946  le = Vcb->devices.Flink;
2947 
2948  while (le != &Vcb->devices) {
2949  device* dev2 = CONTAINING_RECORD(le, device, list_entry);
2950 
2951  if (dev2->devitem.dev_id > dev->devitem.dev_id) {
2952  InsertHeadList(le->Blink, &dev->list_entry);
2953  return;
2954  }
2955 
2956  le = le->Flink;
2957  }
2958 
2959  InsertTailList(&Vcb->devices, &dev->list_entry);
2960 }
2961 
2965  pdo_device_extension* pdode;
2966  LIST_ENTRY* le;
2967 
2968  le = Vcb->devices.Flink;
2969  while (le != &Vcb->devices) {
2971 
2972  TRACE("device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", dev->devitem.dev_id,
2973  dev->devitem.device_uuid.uuid[0], dev->devitem.device_uuid.uuid[1], dev->devitem.device_uuid.uuid[2], dev->devitem.device_uuid.uuid[3], dev->devitem.device_uuid.uuid[4], dev->devitem.device_uuid.uuid[5], dev->devitem.device_uuid.uuid[6], dev->devitem.device_uuid.uuid[7],
2974  dev->devitem.device_uuid.uuid[8], dev->devitem.device_uuid.uuid[9], dev->devitem.device_uuid.uuid[10], dev->devitem.device_uuid.uuid[11], dev->devitem.device_uuid.uuid[12], dev->devitem.device_uuid.uuid[13], dev->devitem.device_uuid.uuid[14], dev->devitem.device_uuid.uuid[15]);
2975 
2976  if (RtlCompareMemory(&dev->devitem.device_uuid, uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2977  TRACE("returning device %llx\n", dev->devitem.dev_id);
2978  return dev;
2979  }
2980 
2981  le = le->Flink;
2982  }
2983 
2984  vde = Vcb->vde;
2985 
2986  if (!vde)
2987  goto end;
2988 
2989  pdode = vde->pdode;
2990 
2992 
2993  if (Vcb->devices_loaded < Vcb->superblock.num_devices) {
2994  le = pdode->children.Flink;
2995 
2996  while (le != &pdode->children) {
2998 
2999  if (RtlCompareMemory(uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3000  device* dev;
3001 
3003  if (!dev) {
3005  ERR("out of memory\n");
3006  return NULL;
3007  }
3008 
3009  RtlZeroMemory(dev, sizeof(device));
3010  dev->devobj = vc->devobj;
3011  dev->devitem.device_uuid = *uuid;
3012  dev->devitem.dev_id = vc->devid;
3013  dev->devitem.num_bytes = vc->size;
3014  dev->seeding = vc->seeding;
3015  dev->readonly = dev->seeding;
3016  dev->reloc = FALSE;
3017  dev->removable = FALSE;
3018  dev->disk_num = vc->disk_num;
3019  dev->part_num = vc->part_num;
3020  dev->num_trim_entries = 0;
3021  InitializeListHead(&dev->trim_list);
3022 
3024  Vcb->devices_loaded++;
3025 
3027 
3028  return dev;
3029  }
3030 
3031  le = le->Flink;
3032  }
3033  }
3034 
3036 
3037 end:
3038  WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
3039  uuid->uuid[0], uuid->uuid[1], uuid->uuid[2], uuid->uuid[3], uuid->uuid[4], uuid->uuid[5], uuid->uuid[6], uuid->uuid[7],
3040  uuid->uuid[8], uuid->uuid[9], uuid->uuid[10], uuid->uuid[11], uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]);
3041 
3042  return NULL;
3043 }
3044 
3046  NTSTATUS Status;
3048 
3050 
3051  if (!NT_SUCCESS(Status)) {
3052  ERR("dev_ioctl returned %08x\n", Status);
3053  return FALSE;
3054  }
3055 
3056  return shi.MediaRemovable != 0 ? TRUE : FALSE;
3057 }
3058 
3060  NTSTATUS Status;
3061  ULONG cc;
3063 
3064  Status = dev_ioctl(devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb);
3065 
3066  if (!NT_SUCCESS(Status)) {
3067  ERR("dev_ioctl returned %08x\n", Status);
3068  return 0;
3069  }
3070 
3071  if (iosb.Information < sizeof(ULONG)) {
3072  ERR("iosb.Information was too short\n");
3073  return 0;
3074  }
3075 
3076  return cc;
3077 }
3078 
3080  NTSTATUS Status;
3081  ULONG aptelen;
3082  ATA_PASS_THROUGH_EX* apte;
3085 
3086  dev->removable = is_device_removable(dev->devobj);
3087  dev->change_count = dev->removable ? get_device_change_count(dev->devobj) : 0;
3088 
3089  if (get_nums) {
3091 
3093  &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL);
3094 
3095  if (!NT_SUCCESS(Status)) {
3096  WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
3097  dev->disk_num = 0xffffffff;
3098  dev->part_num = 0xffffffff;
3099  } else {
3100  dev->disk_num = sdn.DeviceNumber;
3101  dev->part_num = sdn.PartitionNumber;
3102  }
3103  }
3104 
3105  dev->trim = FALSE;
3106  dev->readonly = dev->seeding;
3107  dev->reloc = FALSE;
3108  dev->num_trim_entries = 0;
3109  dev->stats_changed = FALSE;
3110  InitializeListHead(&dev->trim_list);
3111 
3112  if (!dev->readonly) {
3114  NULL, 0, TRUE, NULL);
3116  dev->readonly = TRUE;
3117  }
3118 
3119  aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512;
3120  apte = ExAllocatePoolWithTag(NonPagedPool, aptelen, ALLOC_TAG);
3121  if (!apte) {
3122  ERR("out of memory\n");
3123  return;
3124  }
3125 
3126  RtlZeroMemory(apte, aptelen);
3127 
3128  apte->Length = sizeof(ATA_PASS_THROUGH_EX);
3129  apte->AtaFlags = ATA_FLAGS_DATA_IN;
3130  apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX);
3131  apte->TimeOutValue = 3;
3132  apte->DataBufferOffset = apte->Length;
3134 
3135  Status = dev_ioctl(dev->devobj, IOCTL_ATA_PASS_THROUGH, apte, aptelen,
3136  apte, aptelen, TRUE, NULL);
3137 
3138  if (!NT_SUCCESS(Status))
3139  TRACE("IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE\n", Status);
3140  else {
3142 
3143  if (idd->CommandSetSupport.FlushCache) {
3144  dev->can_flush = TRUE;
3145  TRACE("FLUSH CACHE supported\n");
3146  } else
3147  TRACE("FLUSH CACHE not supported\n");
3148  }
3149 
3150  ExFreePool(apte);
3151 
3154  spq.AdditionalParameters[0] = 0;
3155 
3157  &dtd, sizeof(DEVICE_TRIM_DESCRIPTOR), TRUE, NULL);
3158 
3159  if (NT_SUCCESS(Status)) {
3160  if (dtd.TrimEnabled) {
3161  dev->trim = TRUE;
3162  Vcb->trim = TRUE;
3163  TRACE("TRIM supported\n");
3164  } else
3165  TRACE("TRIM not supported\n");
3166  }
3167 
3168  RtlZeroMemory(dev->stats, sizeof(UINT64) * 5);
3169 }
3170 
3172  traverse_ptr tp, next_tp;
3173  KEY searchkey;
3174  BOOL b;
3175  chunk* c;
3176  NTSTATUS Status;
3177 
3178  searchkey.obj_id = 0;
3179  searchkey.obj_type = 0;
3180  searchkey.offset = 0;
3181 
3182  Vcb->data_flags = 0;
3183  Vcb->metadata_flags = 0;
3184  Vcb->system_flags = 0;
3185 
3186  Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE, Irp);
3187  if (!NT_SUCCESS(Status)) {
3188  ERR("error - find_item returned %08x\n", Status);
3189  return Status;
3190  }
3191 
3192  do {
3193  TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
3194 
3195  if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM) {
3196  if (tp.item->size < sizeof(DEV_ITEM)) {
3197  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_ITEM));
3198  } else {
3199  DEV_ITEM* di = (DEV_ITEM*)tp.item->data;
3200  LIST_ENTRY* le;
3201  BOOL done = FALSE;
3202 
3203  le = Vcb->devices.Flink;
3204  while (le != &Vcb->devices) {
3206 
3207  if (dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &di->device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3208  RtlCopyMemory(&dev->devitem, tp.item->data, min(tp.item->size, sizeof(DEV_ITEM)));
3209 
3210  if (le != Vcb->devices.Flink)
3211  init_device(Vcb, dev, TRUE);
3212 
3213  done = TRUE;
3214  break;
3215  }
3216 
3217  le = le->Flink;
3218  }
3219 
3220  if (!done && Vcb->vde) {
3221  volume_device_extension* vde = Vcb->vde;
3222  pdo_device_extension* pdode = vde->pdode;
3223 
3225 
3226  if (Vcb->devices_loaded < Vcb->superblock.num_devices) {
3227  le = pdode->children.Flink;
3228 
3229  while (le != &pdode->children) {
3231 
3232  if (RtlCompareMemory(&di->device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3233  device* dev;
3234 
3236  if (!dev) {
3238  ERR("out of memory\n");
3240  }
3241 
3242  RtlZeroMemory(dev, sizeof(device));
3243 
3244  dev->devobj = vc->devobj;
3245  RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM)));
3246  dev->seeding = vc->seeding;
3247  init_device(Vcb, dev, FALSE);
3248 
3249  if (dev->devitem.num_bytes > vc->size) {
3250  WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", tp.item->key.offset,
3251  dev->devitem.num_bytes, vc->size);
3252 
3253  dev->devitem.num_bytes = vc->size;
3254  }
3255 
3256  dev->disk_num = vc->disk_num;
3257  dev->part_num = vc->part_num;
3259  Vcb->devices_loaded++;
3260 
3261  done = TRUE;
3262  break;
3263  }
3264 
3265  le = le->Flink;
3266  }
3267 
3268  if (!done) {
3269  if (!Vcb->options.allow_degraded) {
3270  ERR("volume not found: device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", tp.item->key.offset,
3271  di->device_uuid.uuid[0], di->device_uuid.uuid[1], di->device_uuid.uuid[2], di->device_uuid.uuid[3], di->device_uuid.uuid[4], di->device_uuid.uuid[5], di->device_uuid.uuid[6], di->device_uuid.uuid[7],
3272  di->device_uuid.uuid[8], di->device_uuid.uuid[9], di->device_uuid.uuid[10], di->device_uuid.uuid[11], di->device_uuid.uuid[12], di->device_uuid.uuid[13], di->device_uuid.uuid[14], di->device_uuid.uuid[15]);
3273  } else {
3274  device* dev;
3275 
3277  if (!dev) {
3279  ERR("out of memory\n");
3281  }
3282 
3283  RtlZeroMemory(dev, sizeof(device));
3284 
3285  // Missing device, so we keep dev->devobj as NULL
3286  RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM)));
3287  InitializeListHead(&dev->trim_list);
3288 
3290  Vcb->devices_loaded++;
3291  }
3292  }
3293  } else
3294  ERR("unexpected device %llx found\n", tp.item->key.offset);
3295 
3297  }
3298  }
3299  } else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) {
3300  if (tp.item->size < sizeof(CHUNK_ITEM)) {
3301  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));
3302  } else {
3304 
3305  if (!c) {
3306  ERR("out of memory\n");
3308  }
3309 
3310  c->size = tp.item->size;
3311  c->offset = tp.item->key.offset;
3312  c->used = c->oldused = 0;
3313  c->cache = c->old_cache = NULL;
3314  c->created = FALSE;
3315  c->readonly = FALSE;
3316  c->reloc = FALSE;
3317  c->cache_loaded = FALSE;
3318  c->changed = FALSE;
3319  c->space_changed = FALSE;
3320  c->balance_num = 0;
3321 
3323 
3324  if (!c->chunk_item) {
3325  ERR("out of memory\n");
3326  ExFreePool(c);
3328  }
3329 
3330  RtlCopyMemory(c->chunk_item, tp.item->data, tp.item->size);
3331 
3332  if (c->chunk_item->type & BLOCK_FLAG_DATA && c->chunk_item->type > Vcb->data_flags)
3333  Vcb->data_flags = c->chunk_item->type;
3334 
3335  if (c->chunk_item->type & BLOCK_FLAG_METADATA && c->chunk_item->type > Vcb->metadata_flags)
3336  Vcb->metadata_flags = c->chunk_item->type;
3337 
3338  if (c->chunk_item->type & BLOCK_FLAG_SYSTEM && c->chunk_item->type > Vcb->system_flags)
3339  Vcb->system_flags = c->chunk_item->type;
3340 
3341  if (c->chunk_item->type & BLOCK_FLAG_RAID10) {
3342  if (c->chunk_item->sub_stripes == 0 || c->chunk_item->sub_stripes > c->chunk_item->num_stripes) {
3343  ERR("chunk %llx: invalid stripes (num_stripes %u, sub_stripes %u)\n", c->offset, c->chunk_item->num_stripes, c->chunk_item->sub_stripes);
3344  ExFreePool(c->chunk_item);
3345  ExFreePool(c);
3346  return STATUS_INTERNAL_ERROR;
3347  }
3348  }
3349 
3350  if (c->chunk_item->num_stripes > 0) {
3351  CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
3352  UINT16 i;
3353 
3354  c->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG);
3355 
3356  if (!c->devices) {
3357  ERR("out of memory\n");
3358  ExFreePool(c->chunk_item);
3359  ExFreePool(c);
3361  }
3362 
3363  for (i = 0; i < c->chunk_item->num_stripes; i++) {
3364  c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid);
3365  TRACE("device %llu = %p\n", i, c->devices[i]);
3366 
3367  if (!c->devices[i]) {
3368  ERR("missing device\n");
3369  ExFreePool(c->chunk_item);
3370  ExFreePool(c);
3371  return STATUS_INTERNAL_ERROR;
3372  }
3373 
3374  if (c->devices[i]->readonly)
3375  c->readonly = TRUE;
3376  }
3377  } else {
3378  ERR("chunk %llx: number of stripes is 0\n", c->offset);
3379  ExFreePool(c->chunk_item);
3380  ExFreePool(c);
3381  return STATUS_INTERNAL_ERROR;
3382  }
3383 
3384  ExInitializeResourceLite(&c->lock);
3385  ExInitializeResourceLite(&c->changed_extents_lock);
3386 
3387  InitializeListHead(&c->space);
3388  InitializeListHead(&c->space_size);
3389  InitializeListHead(&c->deleting);
3390  InitializeListHead(&c->changed_extents);
3391 
3392  InitializeListHead(&c->range_locks);
3393  ExInitializeResourceLite(&c->range_locks_lock);
3394  KeInitializeEvent(&c->range_locks_event, NotificationEvent, FALSE);
3395 
3396  InitializeListHead(&c->partial_stripes);
3397  ExInitializeResourceLite(&c->partial_stripes_lock);
3398 
3399  c->last_alloc_set = FALSE;
3400 
3401  c->last_stripe = 0;
3402 
3403  InsertTailList(&Vcb->chunks, &c->list_entry);
3404 
3405  c->list_entry_balance.Flink = NULL;
3406  }
3407  }
3408 
3409  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
3410 
3411  if (b)
3412  tp = next_tp;
3413  } while (b);
3414 
3415  Vcb->log_to_phys_loaded = TRUE;
3416 
3417  if (Vcb->data_flags == 0)
3418  Vcb->data_flags = BLOCK_FLAG_DATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID0 : 0);
3419 
3420  if (Vcb->metadata_flags == 0)
3421  Vcb->metadata_flags = BLOCK_FLAG_METADATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE);
3422 
3423  if (Vcb->system_flags == 0)
3424  Vcb->system_flags = BLOCK_FLAG_SYSTEM | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE);
3425 
3426  if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) {
3427  Vcb->metadata_flags |= BLOCK_FLAG_DATA;
3428  Vcb->data_flags = Vcb->metadata_flags;
3429  }
3430 
3431  return STATUS_SUCCESS;
3432 }
3433 
3435  UINT16 i = 0, j;
3436  UINT64 off_start, off_end;
3437 
3438  // The Linux driver also protects all the space before the first superblock.
3439  // I realize this confuses physical and logical addresses, but this is what btrfs-progs does -
3440  // evidently Linux assumes the chunk at 0 is always SINGLE.
3441  if (c->offset < superblock_addrs[0])
3442  space_list_subtract(c, FALSE, c->offset, superblock_addrs[0] - c->offset, NULL);
3443 
3444  while (superblock_addrs[i] != 0) {
3445  CHUNK_ITEM* ci = c->chunk_item;
3446  CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
3447 
3448  if (ci->type & BLOCK_FLAG_RAID0 || ci->type & BLOCK_FLAG_RAID10) {
3449  for (j = 0; j < ci->num_stripes; j++) {
3450  UINT16 sub_stripes = max(ci->sub_stripes, 1);
3451 
3452  if (cis[j].offset + (ci->size * ci->num_stripes / sub_stripes) > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3453 #ifdef _DEBUG
3454  UINT64 startoff;
3455  UINT16 startoffstripe;
3456 #endif
3457 
3458  TRACE("cut out superblock in chunk %llx\n", c->offset);
3459 
3460  off_start = superblock_addrs[i] - cis[j].offset;
3461  off_start -= off_start % ci->stripe_length;
3462  off_start *= ci->num_stripes / sub_stripes;
3463  off_start += (j / sub_stripes) * ci->stripe_length;
3464 
3465  off_end = off_start + ci->stripe_length;
3466 
3467 #ifdef _DEBUG
3468  get_raid0_offset(off_start, ci->stripe_length, ci->num_stripes / sub_stripes, &startoff, &startoffstripe);
3469  TRACE("j = %u, startoffstripe = %u\n", j, startoffstripe);
3470  TRACE("startoff = %llx, superblock = %llx\n", startoff + cis[j].offset, superblock_addrs[i]);
3471 #endif
3472 
3473  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3474  }
3475  }
3476  } else if (ci->type & BLOCK_FLAG_RAID5) {
3477  UINT64 stripe_size = ci->size / (ci->num_stripes - 1);
3478 
3479  for (j = 0; j < ci->num_stripes; j++) {
3480  if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3481  TRACE("cut out superblock in chunk %llx\n", c->offset);
3482 
3483  off_start = superblock_addrs[i] - cis[j].offset;
3484  off_start -= off_start % ci->stripe_length;
3485  off_start *= ci->num_stripes - 1;
3486 
3487  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length);
3488  off_end *= ci->num_stripes - 1;
3489 
3490  TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start);
3491 
3492  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3493  }
3494  }
3495  } else if (ci->type & BLOCK_FLAG_RAID6) {
3496  UINT64 stripe_size = ci->size / (ci->num_stripes - 2);
3497 
3498  for (j = 0; j < ci->num_stripes; j++) {
3499  if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3500  TRACE("cut out superblock in chunk %llx\n", c->offset);
3501 
3502  off_start = superblock_addrs[i] - cis[j].offset;
3503  off_start -= off_start % ci->stripe_length;
3504  off_start *= ci->num_stripes - 2;
3505 
3506  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length);
3507  off_end *= ci->num_stripes - 2;
3508 
3509  TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start);
3510 
3511  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3512  }
3513  }
3514  } else { // SINGLE, DUPLICATE, RAID1
3515  for (j = 0; j < ci->num_stripes; j++) {
3516  if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3517  TRACE("cut out superblock in chunk %llx\n", c->offset);
3518 
3519  // The Linux driver protects the whole stripe in which the superblock lives
3520 
3521  off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length;
3522  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length);
3523 
3524  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3525  }
3526  }
3527  }
3528 
3529  i++;
3530  }
3531 }
3532 
3534  LIST_ENTRY* le = Vcb->chunks.Flink;
3535  chunk* c;
3536  KEY searchkey;
3537  traverse_ptr tp;
3538  BLOCK_GROUP_ITEM* bgi;
3539  NTSTATUS Status;
3540 
3541  searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM;
3542 
3543  while (le != &Vcb->chunks) {
3545 
3546  searchkey.obj_id = c->offset;
3547  searchkey.offset = c->chunk_item->size;
3548 
3549  Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
3550  if (!NT_SUCCESS(Status)) {
3551  ERR("error - find_item returned %08x\n", Status);
3552  return Status;
3553  }
3554 
3555  if (!keycmp(searchkey, tp.item->key)) {
3556  if (tp.item->size >= sizeof(BLOCK_GROUP_ITEM)) {
3557  bgi = (BLOCK_GROUP_ITEM*)tp.item->data;
3558 
3559  c->used = c->oldused = bgi->used;
3560 
3561  TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used);
3562  } else {
3563  ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n",
3564  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));
3565  }
3566  }
3567 
3568  le = le->Flink;
3569  }
3570 
3571  Vcb->chunk_usage_found = TRUE;
3572 
3573  return STATUS_SUCCESS;
3574 }
3575 
3577  KEY key;
3578  ULONG n = Vcb->superblock.n;
3579 
3580  while (n > 0) {
3581  if (n > sizeof(KEY)) {
3582  RtlCopyMemory(&key, &Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n], sizeof(KEY));
3583  n -= sizeof(KEY);
3584  } else
3585  return STATUS_SUCCESS;
3586 
3587  TRACE("bootstrap: %llx,%x,%llx\n", key.obj_id, key.obj_type, key.offset);
3588 
3589  if (key.obj_type == TYPE_CHUNK_ITEM) {
3590  CHUNK_ITEM* ci;
3591  USHORT cisize;
3592  sys_chunk* sc;
3593 
3594  if (n < sizeof(CHUNK_ITEM))
3595  return STATUS_SUCCESS;
3596 
3597  ci = (CHUNK_ITEM*)&Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n];
3598  cisize = sizeof(CHUNK_ITEM) + (ci->num_stripes * sizeof(CHUNK_ITEM_STRIPE));
3599 
3600  if (n < cisize)
3601  return STATUS_SUCCESS;
3602 
3604 
3605  if (!sc) {
3606  ERR("out of memory\n");
3608  }
3609 
3610  sc->key = key;
3611  sc->size = cisize;
3613 
3614  if (!sc->data) {
3615  ERR("out of memory\n");
3616  ExFreePool(sc);
3618  }
3619 
3620  RtlCopyMemory(sc->data, ci, sc->size);
3621  InsertTailList(&Vcb->sys_chunks, &sc->list_entry);
3622 
3623  n -= cisize;
3624  } else {
3625  ERR("unexpected item %llx,%x,%llx in bootstrap\n", key.obj_id, key.obj_type, key.offset);
3626  return STATUS_INTERNAL_ERROR;
3627  }
3628  }
3629 
3630  return STATUS_SUCCESS;
3631 }
3632 
3635  LIST_ENTRY* le;
3636 
3637  static const char fn[] = "default";
3638  static UINT32 crc32 = 0x8dbfc2d2;
3639 
3640  if (Vcb->options.subvol_id != 0) {
3641  le = Vcb->roots.Flink;
3642  while (le != &Vcb->roots) {
3644 
3645  if (r->id == Vcb->options.subvol_id)
3646  return r;
3647 
3648  le = le->Flink;
3649  }
3650  }
3651 
3652  if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL) {
3653  NTSTATUS Status;
3654  KEY searchkey;
3655  traverse_ptr tp;
3656  DIR_ITEM* di;
3657 
3658  searchkey.obj_id = Vcb->superblock.root_dir_objectid;
3659  searchkey.obj_type = TYPE_DIR_ITEM;
3660  searchkey.offset = crc32;
3661 
3662  Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
3663  if (!NT_SUCCESS(Status)) {
3664  ERR("error - find_item returned %08x\n", Status);
3665  goto end;
3666  }
3667 
3668  if (keycmp(tp.item->key, searchkey)) {
3669  ERR("could not find (%llx,%x,%llx) in root tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
3670  goto end;
3671  }
3672 
3673  if (tp.item->size < sizeof(DIR_ITEM)) {
3674  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));
3675  goto end;
3676  }
3677 
3678  di = (DIR_ITEM*)tp.item->data;
3679 
3680  if (tp.item->size < sizeof(DIR_ITEM) - 1 + di->n) {
3681  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(DIR_ITEM) - 1 + di->n);
3682  goto end;
3683  }
3684 
3685  if (di->n != strlen(fn) || RtlCompareMemory(di->name, fn, di->n) != di->n) {
3686  ERR("root DIR_ITEM had same CRC32, but was not \"default\"\n");
3687  goto end;
3688  }
3689 
3690  if (di->key.obj_type != TYPE_ROOT_ITEM) {
3691  ERR("default root has key (%llx,%x,%llx), expected subvolume\n", di->key.obj_id, di->key.obj_type, di->key.offset);
3692  goto end;
3693  }
3694 
3695  le = Vcb->roots.Flink;
3696  while (le != &Vcb->roots) {
3698 
3699  if (r->id == di->key.obj_id)
3700  return r;
3701 
3702  le = le->Flink;
3703  }
3704 
3705  ERR("could not find root %llx, using default instead\n", di->key.obj_id);
3706  }
3707 
3708 end:
3709  le = Vcb->roots.Flink;
3710  while (le != &Vcb->roots) {
3712 
3713  if (r->id == BTRFS_ROOT_FSTREE)
3714  return r;
3715 
3716  le = le->Flink;
3717  }
3718 
3719  return NULL;
3720 }
3721 
3723  TRACE("(%p, %p)\n", FileObject, ccfs);
3724 
3726 
3727  if (diskacc)
3729 
3731 }
3732 
3735  ULONG i;
3736 
3737  Vcb->calcthreads.num_threads = KeQueryActiveProcessorCount(NULL);
3738 
3739  Vcb->calcthreads.threads = ExAllocatePoolWithTag(NonPagedPool, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads, ALLOC_TAG);
3740  if (!Vcb->calcthreads.threads) {
3741  ERR("out of memory\n");
3743  }
3744 
3745  InitializeListHead(&Vcb->calcthreads.job_list);
3746  ExInitializeResourceLite(&Vcb->calcthreads.lock);
3747  KeInitializeEvent(&Vcb->calcthreads.event, NotificationEvent, FALSE);
3748 
3749  RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads);
3750 
3751  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
3752  NTSTATUS Status;
3753 
3754  Vcb->calcthreads.threads[i].DeviceObject = DeviceObject;
3755  KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, FALSE);
3756 
3757  Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
3758  if (!NT_SUCCESS(Status)) {
3759  ULONG j;
3760 
3761  ERR("PsCreateSystemThread returned %08x\n", Status);
3762 
3763  for (j = 0; j < i; j++) {
3764  Vcb->calcthreads.threads[i].quit = TRUE;
3765  }
3766 
3767  KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
3768 
3769  return Status;
3770  }
3771  }
3772 
3773  return STATUS_SUCCESS;
3774 }
3775 
3776 static BOOL</