ReactOS  0.4.12-dev-409-g9f418243
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->is_unique = TRUE;
1040  t->uniqueness_determined = TRUE;
1041  t->buf = NULL;
1042  }
1043 
1045  if (!ri) {
1046  ERR("out of memory\n");
1047 
1048  if (t)
1049  ExFreePool(t);
1050 
1051  ExFreePool(r->nonpaged);
1052  ExFreePool(r);
1054  }
1055 
1056  r->id = id;
1057  r->treeholder.address = 0;
1058  r->treeholder.generation = Vcb->superblock.generation;
1059  r->treeholder.tree = t;
1060  r->lastinode = 0;
1061  r->dirty = FALSE;
1062  r->received = FALSE;
1063  r->reserved = NULL;
1064  r->parent = 0;
1065  r->send_ops = 0;
1066  RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
1067  r->root_item.num_references = 1;
1068  InitializeListHead(&r->fcbs);
1069 
1070  RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM));
1071 
1072  // We ask here for a traverse_ptr to the item we're inserting, so we can
1073  // copy some of the tree's variables
1074 
1075  Status = insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp);
1076  if (!NT_SUCCESS(Status)) {
1077  ERR("insert_tree_item returned %08x\n", Status);
1078  ExFreePool(ri);
1079 
1080  if (t)
1081  ExFreePool(t);
1082 
1083  ExFreePool(r->nonpaged);
1084  ExFreePool(r);
1085  return Status;
1086  }
1087 
1088  ExInitializeResourceLite(&r->nonpaged->load_tree_lock);
1089 
1090  InsertTailList(&Vcb->roots, &r->list_entry);
1091 
1092  if (!no_tree) {
1093  RtlZeroMemory(&t->header, sizeof(tree_header));
1094  t->header.fs_uuid = tp.tree->header.fs_uuid;
1095  t->header.address = 0;
1096  t->header.flags = HEADER_FLAG_MIXED_BACKREF | 1; // 1 == "written"? Why does the Linux driver record this?
1097  t->header.chunk_tree_uuid = tp.tree->header.chunk_tree_uuid;
1098  t->header.generation = Vcb->superblock.generation;
1099  t->header.tree_id = id;
1100  t->header.num_items = 0;
1101  t->header.level = 0;
1102 
1103  t->has_address = FALSE;
1104  t->size = 0;
1105  t->Vcb = Vcb;
1106  t->parent = NULL;
1107  t->paritem = NULL;
1108  t->root = r;
1109 
1110  InitializeListHead(&t->itemlist);
1111 
1112  t->new_address = 0;
1113  t->has_new_address = FALSE;
1114  t->updated_extents = FALSE;
1115 
1116  InsertTailList(&Vcb->trees, &t->list_entry);
1117  t->list_entry_hash.Flink = NULL;
1118 
1119  t->write = TRUE;
1120  Vcb->need_write = TRUE;
1121  }
1122 
1123  *rootptr = r;
1124 
1125  return STATUS_SUCCESS;
1126 }
1127 
1129  ULONG utf8len;
1130  NTSTATUS Status;
1131  ULONG vollen, i;
1132 
1133  TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel);
1134 
1135  vollen = ffli->VolumeLabelLength;
1136 
1137  for (i = 0; i < ffli->VolumeLabelLength / sizeof(WCHAR); i++) {
1138  if (ffli->VolumeLabel[i] == 0) {
1139  vollen = i * sizeof(WCHAR);
1140  break;
1141  } else if (ffli->VolumeLabel[i] == '/' || ffli->VolumeLabel[i] == '\\') {
1143  goto end;
1144  }
1145  }
1146 
1147  if (vollen == 0) {
1148  utf8len = 0;
1149  } else {
1150  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, vollen);
1151  if (!NT_SUCCESS(Status))
1152  goto end;
1153 
1154  if (utf8len > MAX_LABEL_SIZE) {
1156  goto end;
1157  }
1158  }
1159 
1160  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1161 
1162  if (utf8len > 0) {
1163  Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE, &utf8len, ffli->VolumeLabel, vollen);
1164  if (!NT_SUCCESS(Status))
1165  goto release;
1166  } else
1168 
1169  if (utf8len < MAX_LABEL_SIZE)
1170  RtlZeroMemory(Vcb->superblock.label + utf8len, MAX_LABEL_SIZE - utf8len);
1171 
1172  Vcb->need_write = TRUE;
1173 
1174 release:
1175  ExReleaseResourceLite(&Vcb->tree_lock);
1176 
1177 end:
1178  TRACE("returning %08x\n", Status);
1179 
1180  return Status;
1181 }
1182 
1185 #ifdef __REACTOS__
1186 static NTSTATUS NTAPI drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
1187 #else
1188 static NTSTATUS drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
1189 #endif
1192  NTSTATUS Status;
1193  BOOL top_level;
1194 
1196 
1197  TRACE("set volume information\n");
1198 
1199  top_level = is_top_level(Irp);
1200 
1201  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
1203  goto end;
1204  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
1206  goto end;
1207  }
1208 
1210 
1211  if (Vcb->readonly) {
1213  goto end;
1214  }
1215 
1216  if (Vcb->removing || Vcb->locked) {
1218  goto end;
1219  }
1220 
1221  switch (IrpSp->Parameters.SetVolume.FsInformationClass) {
1223  FIXME("STUB: FileFsControlInformation\n");
1224  break;
1225 
1227  TRACE("FileFsLabelInformation\n");
1228 
1229  Status = set_label(Vcb, Irp->AssociatedIrp.SystemBuffer);
1230  break;
1231 
1233  FIXME("STUB: FileFsObjectIdInformation\n");
1234  break;
1235 
1236  default:
1237  WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp->Parameters.SetVolume.FsInformationClass);
1238  break;
1239  }
1240 
1241 end:
1242  Irp->IoStatus.Status = Status;
1243  Irp->IoStatus.Information = 0;
1244 
1245  TRACE("returning %08x\n", Status);
1246 
1248 
1249  if (top_level)
1251 
1253 
1254  return Status;
1255 }
1256 
1258  char s[60];
1259  NTSTATUS Status;
1261  ANSI_STRING as;
1262 
1263  if (fcb->debug_desc)
1264  return fcb->debug_desc;
1265 
1266  if (fcb == fcb->Vcb->volume_fcb)
1267  return L"volume FCB";
1268 
1270  if (!fcb->debug_desc)
1271  return L"(memory error)";
1272 
1273  // I know this is pretty hackish...
1274  // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
1275  // without the CRT, which breaks drivers.
1276 
1277  sprintf(s, "subvol %x, inode %x", (UINT32)fcb->subvol->id, (UINT32)fcb->inode);
1278 
1279  as.Buffer = s;
1280  as.Length = as.MaximumLength = (USHORT)strlen(s);
1281 
1282  us.Buffer = fcb->debug_desc;
1283  us.MaximumLength = 60 * sizeof(WCHAR);
1284  us.Length = 0;
1285 
1287  if (!NT_SUCCESS(Status))
1288  return L"(RtlAnsiStringToUnicodeString error)";
1289 
1290  us.Buffer[us.Length / sizeof(WCHAR)] = 0;
1291 
1292  return fcb->debug_desc;
1293 }
1294 
1296  NTSTATUS Status;
1298  ULONG reqlen;
1299 
1300  if (fileref->debug_desc)
1301  return fileref->debug_desc;
1302 
1303  fn.Length = fn.MaximumLength = 0;
1304  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1306  return L"ERROR";
1307 
1308  if (reqlen > 0xffff - sizeof(WCHAR))
1309  return L"(too long)";
1310 
1311  fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG);
1312  if (!fileref->debug_desc)
1313  return L"(memory error)";
1314 
1315  fn.Buffer = fileref->debug_desc;
1316  fn.Length = 0;
1317  fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR));
1318 
1319  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1320  if (!NT_SUCCESS(Status)) {
1321  ExFreePool(fileref->debug_desc);
1322  fileref->debug_desc = NULL;
1323  return L"ERROR";
1324  }
1325 
1326  fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0;
1327 
1328  return fileref->debug_desc;
1329 }
1330 
1331 _Ret_z_
1333  fcb* fcb = FileObject->FsContext;
1334  ccb* ccb = FileObject->FsContext2;
1335  file_ref* fileref = ccb ? ccb->fileref : NULL;
1336 
1337  if (fileref)
1338  return file_desc_fileref(fileref);
1339  else
1340  return file_desc_fcb(fcb);
1341 }
1342 
1345  NTSTATUS Status;
1346  ULONG reqlen;
1347  USHORT name_offset;
1348  fcb* fcb = fileref->fcb;
1349 
1350  fn.Length = fn.MaximumLength = 0;
1351  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1352  if (Status != STATUS_BUFFER_OVERFLOW) {
1353  ERR("fileref_get_filename returned %08x\n", Status);
1354  return;
1355  }
1356 
1357  if (reqlen > 0xffff) {
1358  WARN("reqlen was too long for FsRtlNotifyFilterReportChange\n");
1359  return;
1360  }
1361 
1362  fn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
1363  if (!fn.Buffer) {
1364  ERR("out of memory\n");
1365  return;
1366  }
1367 
1368  fn.MaximumLength = (USHORT)reqlen;
1369  fn.Length = 0;
1370 
1371  Status = fileref_get_filename(fileref, &fn, &name_offset, &reqlen);
1372  if (!NT_SUCCESS(Status)) {
1373  ERR("fileref_get_filename returned %08x\n", Status);
1374  ExFreePool(fn.Buffer);
1375  return;
1376  }
1377 
1378  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, name_offset,
1379  (PSTRING)stream, NULL, filter_match, action, NULL, NULL);
1380  ExFreePool(fn.Buffer);
1381 }
1382 
1384  fcb* fcb = fileref->fcb;
1385  LIST_ENTRY* le;
1386  NTSTATUS Status;
1387 
1388  // no point looking for hardlinks if st_nlink == 1
1389  if (fileref->fcb->inode_item.st_nlink == 1) {
1390  send_notification_fileref(fileref, filter_match, action, stream);
1391  return;
1392  }
1393 
1394  acquire_fcb_lock_exclusive(fcb->Vcb);
1395 
1396  le = fcb->hardlinks.Flink;
1397  while (le != &fcb->hardlinks) {
1399  file_ref* parfr;
1400 
1401  Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL);
1402 
1403  if (!NT_SUCCESS(Status))
1404  ERR("open_fileref_by_inode returned %08x\n", Status);
1405  else if (!parfr->deleted) {
1407  ULONG pathlen;
1408 
1409  fn.Length = fn.MaximumLength = 0;
1410  Status = fileref_get_filename(parfr, &fn, NULL, &pathlen);
1411  if (Status != STATUS_BUFFER_OVERFLOW) {
1412  ERR("fileref_get_filename returned %08x\n", Status);
1413  free_fileref(fcb->Vcb, parfr);
1414  break;
1415  }
1416 
1417  if (parfr != fcb->Vcb->root_fileref)
1418  pathlen += sizeof(WCHAR);
1419 
1420  if (pathlen + hl->name.Length > 0xffff) {
1421  WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n");
1422  free_fileref(fcb->Vcb, parfr);
1423  break;
1424  }
1425 
1426  fn.MaximumLength = (USHORT)(pathlen + hl->name.Length);
1427  fn.Buffer = ExAllocatePoolWithTag(PagedPool, fn.MaximumLength, ALLOC_TAG);
1428  if (!fn.Buffer) {
1429  ERR("out of memory\n");
1430  free_fileref(fcb->Vcb, parfr);
1431  break;
1432  }
1433 
1434  Status = fileref_get_filename(parfr, &fn, NULL, NULL);
1435  if (!NT_SUCCESS(Status)) {
1436  ERR("fileref_get_filename returned %08x\n", Status);
1437  free_fileref(fcb->Vcb, parfr);
1438  ExFreePool(fn.Buffer);
1439  break;
1440  }
1441 
1442  if (parfr != fcb->Vcb->root_fileref) {
1443  fn.Buffer[(pathlen / sizeof(WCHAR)) - 1] = '\\';
1444  fn.Length += sizeof(WCHAR);
1445  }
1446 
1447  RtlCopyMemory(&fn.Buffer[pathlen / sizeof(WCHAR)], hl->name.Buffer, hl->name.Length);
1448  fn.Length += hl->name.Length;
1449 
1450  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, (USHORT)pathlen,
1451  (PSTRING)stream, NULL, filter_match, action, NULL, NULL);
1452 
1453  ExFreePool(fn.Buffer);
1454 
1455  free_fileref(fcb->Vcb, parfr);
1456  }
1457 
1458  le = le->Flink;
1459  }
1460 
1461  release_fcb_lock(fcb->Vcb);
1462 }
1463 
1465  if (!fcb->dirty) {
1466 #ifdef DEBUG_FCB_REFCOUNTS
1467  LONG rc;
1468 #endif
1469  fcb->dirty = TRUE;
1470 
1471 #ifdef DEBUG_FCB_REFCOUNTS
1473  WARN("fcb %p: refcount now %i\n", fcb, rc);
1474 #else
1476 #endif
1477 
1478  ExAcquireResourceExclusiveLite(&fcb->Vcb->dirty_fcbs_lock, TRUE);
1479  InsertTailList(&fcb->Vcb->dirty_fcbs, &fcb->list_entry_dirty);
1480  ExReleaseResourceLite(&fcb->Vcb->dirty_fcbs_lock);
1481  }
1482 
1483  fcb->Vcb->need_write = TRUE;
1484 }
1485 
1487  if (!fileref->dirty) {
1488  fileref->dirty = TRUE;
1489  increase_fileref_refcount(fileref);
1490 
1491  ExAcquireResourceExclusiveLite(&fileref->fcb->Vcb->dirty_filerefs_lock, TRUE);
1492  InsertTailList(&fileref->fcb->Vcb->dirty_filerefs, &fileref->list_entry_dirty);
1493  ExReleaseResourceLite(&fileref->fcb->Vcb->dirty_filerefs_lock);
1494  }
1495 
1496  fileref->fcb->Vcb->need_write = TRUE;
1497 }
1498 
1499 #ifdef DEBUG_FCB_REFCOUNTS
1500 void _free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb, _In_ const char* func) {
1501 #else
1503 #endif
1504  LONG rc;
1505 
1507 
1508 #ifdef DEBUG_FCB_REFCOUNTS
1509 #ifdef DEBUG_LONG_MESSAGES
1510  ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
1511 #else
1512  ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
1513 #endif
1514 #endif
1515 
1516  if (rc > 0)
1517  return;
1518 
1519  if (fcb->list_entry.Flink)
1521 
1522  if (fcb->list_entry_all.Flink)
1524 
1525  ExDeleteResourceLite(&fcb->nonpaged->resource);
1526  ExDeleteResourceLite(&fcb->nonpaged->paging_resource);
1527  ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock);
1528 
1529  ExFreeToNPagedLookasideList(&Vcb->fcb_np_lookaside, fcb->nonpaged);
1530 
1531  if (fcb->sd)
1532  ExFreePool(fcb->sd);
1533 
1534  if (fcb->adsxattr.Buffer)
1536 
1537  if (fcb->reparse_xattr.Buffer)
1539 
1540  if (fcb->ea_xattr.Buffer)
1542 
1543  if (fcb->adsdata.Buffer)
1545 
1546  if (fcb->debug_desc)
1548 
1549  while (!IsListEmpty(&fcb->extents)) {
1552 
1553  if (ext->csum)
1554  ExFreePool(ext->csum);
1555 
1556  ExFreePool(ext);
1557  }
1558 
1559  while (!IsListEmpty(&fcb->hardlinks)) {
1562 
1563  if (hl->name.Buffer)
1564  ExFreePool(hl->name.Buffer);
1565 
1566  if (hl->utf8.Buffer)
1567  ExFreePool(hl->utf8.Buffer);
1568 
1569  ExFreePool(hl);
1570  }
1571 
1572  while (!IsListEmpty(&fcb->xattrs)) {
1574 
1575  ExFreePool(xa);
1576  }
1577 
1578  while (!IsListEmpty(&fcb->dir_children_index)) {
1580  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
1581 
1582  ExFreePool(dc->utf8.Buffer);
1583  ExFreePool(dc->name.Buffer);
1584  ExFreePool(dc->name_uc.Buffer);
1585  ExFreePool(dc);
1586  }
1587 
1588  if (fcb->hash_ptrs)
1590 
1591  if (fcb->hash_ptrs_uc)
1593 
1595 
1596  if (fcb->pool_type == NonPagedPool)
1597  ExFreePool(fcb);
1598  else
1599  ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb);
1600 
1601 #ifdef DEBUG_FCB_REFCOUNTS
1602 #ifdef DEBUG_LONG_MESSAGES
1603  _debug_message(func, file, line, "freeing fcb %p\n", fcb);
1604 #else
1605  _debug_message(func, "freeing fcb %p\n", fcb);
1606 #endif
1607 #endif
1608 }
1609 
1611  LONG rc;
1612 
1613  rc = InterlockedDecrement(&fr->refcount);
1614 
1615 #ifdef DEBUG_FCB_REFCOUNTS
1616  ERR("fileref %p: refcount now %i\n", fr, rc);
1617 #endif
1618 
1619 #ifdef _DEBUG
1620  if (rc < 0) {
1621  ERR("fileref %p: refcount now %i\n", fr, rc);
1622  int3;
1623  }
1624 #endif
1625 
1626  if (rc > 0)
1627  return;
1628 
1629  if (fr->parent)
1630  ExAcquireResourceExclusiveLite(&fr->parent->nonpaged->children_lock, TRUE);
1631 
1632  // FIXME - do we need a file_ref lock?
1633 
1634  // FIXME - do delete if needed
1635 
1636  if (fr->debug_desc)
1637  ExFreePool(fr->debug_desc);
1638 
1639  ExDeleteResourceLite(&fr->nonpaged->children_lock);
1640  ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
1641 
1642  ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
1643 
1644  // FIXME - throw error if children not empty
1645 
1646  if (fr->fcb->fileref == fr)
1647  fr->fcb->fileref = NULL;
1648 
1649  if (fr->dc) {
1650  if (fr->fcb->ads)
1651  fr->dc->size = fr->fcb->adsdata.Length;
1652 
1653  fr->dc->fileref = NULL;
1654  }
1655 
1656  if (fr->list_entry.Flink)
1657  RemoveEntryList(&fr->list_entry);
1658 
1659  if (fr->parent) {
1660  ExReleaseResourceLite(&fr->parent->nonpaged->children_lock);
1661  free_fileref(Vcb, fr->parent);
1662  }
1663 
1664  free_fcb(Vcb, fr->fcb);
1665 
1666  ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
1667 }
1668 
1670  fcb* fcb;
1671  ccb* ccb;
1672  file_ref* fileref = NULL;
1673  LONG open_files;
1675 
1676  UNUSED(Irp);
1677 
1678  TRACE("FileObject = %p\n", FileObject);
1679 
1680  fcb = FileObject->FsContext;
1681  if (!fcb) {
1682  TRACE("FCB was NULL, returning success\n");
1683  return STATUS_SUCCESS;
1684  }
1685 
1686  open_files = InterlockedDecrement(&fcb->Vcb->open_files);
1687 
1688  ccb = FileObject->FsContext2;
1689 
1690  TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb);
1691 
1692  // FIXME - make sure notification gets sent if file is being deleted
1693 
1694  if (ccb) {
1695  if (ccb->query_string.Buffer)
1697 
1698  if (ccb->filename.Buffer)
1700 
1701  // FIXME - use refcounts for fileref
1702  fileref = ccb->fileref;
1703 
1704  if (fcb->Vcb->running_sends > 0) {
1705  BOOL send_cancelled = FALSE;
1706 
1707  ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE);
1708 
1709  if (ccb->send) {
1710  ccb->send->cancelling = TRUE;
1711  send_cancelled = TRUE;
1713  }
1714 
1715  ExReleaseResourceLite(&fcb->Vcb->send_load_lock);
1716 
1717  if (send_cancelled) {
1718  while (ccb->send) {
1719  ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE);
1720  ExReleaseResourceLite(&fcb->Vcb->send_load_lock);
1721  }
1722  }
1723  }
1724 
1725  ExFreePool(ccb);
1726  }
1727 
1729 
1730  if (open_files == 0 && fcb->Vcb->removing) {
1731  uninit(fcb->Vcb);
1732  return STATUS_SUCCESS;
1733  }
1734 
1735  if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED))
1736  return STATUS_SUCCESS;
1737 
1738  Vcb = fcb->Vcb;
1739 
1740  acquire_fcb_lock_exclusive(Vcb);
1741 
1742  if (fileref)
1743  free_fileref(fcb->Vcb, fileref);
1744  else
1745  free_fcb(Vcb, fcb);
1746 
1747  release_fcb_lock(Vcb);
1748 
1749  return STATUS_SUCCESS;
1750 }
1751 
1753  UINT64 i;
1754  KIRQL irql;
1755  NTSTATUS Status;
1756  LIST_ENTRY* le;
1758 
1759  if (!Vcb->removing) {
1760  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1761  Vcb->removing = TRUE;
1762  ExReleaseResourceLite(&Vcb->tree_lock);
1763  }
1764 
1766  Vcb->Vpb->Flags &= ~VPB_MOUNTED;
1767  Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
1769 
1770  RemoveEntryList(&Vcb->list_entry);
1771 
1772  if (Vcb->balance.thread) {
1773  Vcb->balance.paused = FALSE;
1774  Vcb->balance.stopping = TRUE;
1775  KeSetEvent(&Vcb->balance.event, 0, FALSE);
1776  KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL);
1777  }
1778 
1779  if (Vcb->scrub.thread) {
1780  Vcb->scrub.paused = FALSE;
1781  Vcb->scrub.stopping = TRUE;
1782  KeSetEvent(&Vcb->scrub.event, 0, FALSE);
1783  KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL);
1784  }
1785 
1786  if (Vcb->running_sends != 0) {
1787  BOOL send_cancelled = FALSE;
1788 
1789  ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
1790 
1791  le = Vcb->send_ops.Flink;
1792  while (le != &Vcb->send_ops) {
1794 
1795  if (!send->cancelling) {
1796  send->cancelling = TRUE;
1797  send_cancelled = TRUE;
1798  send->ccb = NULL;
1799  KeSetEvent(&send->cleared_event, 0, FALSE);
1800  }
1801 
1802  le = le->Flink;
1803  }
1804 
1805  ExReleaseResourceLite(&Vcb->send_load_lock);
1806 
1807  if (send_cancelled) {
1808  while (Vcb->running_sends != 0) {
1809  ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
1810  ExReleaseResourceLite(&Vcb->send_load_lock);
1811  }
1812  }
1813  }
1814 
1815  Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid);
1817  WARN("registry_mark_volume_unmounted returned %08x\n", Status);
1818 
1819  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
1820  Vcb->calcthreads.threads[i].quit = TRUE;
1821  }
1822 
1823  KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
1824 
1825  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
1826  KeWaitForSingleObject(&Vcb->calcthreads.threads[i].finished, Executive, KernelMode, FALSE, NULL);
1827 
1828  ZwClose(Vcb->calcthreads.threads[i].handle);
1829  }
1830 
1831  ExDeleteResourceLite(&Vcb->calcthreads.lock);
1832  ExFreePool(Vcb->calcthreads.threads);
1833 
1834  time.QuadPart = 0;
1835  KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early
1836  KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
1837 
1838  acquire_fcb_lock_exclusive(Vcb);
1839  free_fcb(Vcb, Vcb->volume_fcb);
1840  free_fcb(Vcb, Vcb->dummy_fcb);
1841  release_fcb_lock(Vcb);
1842 
1843  if (Vcb->root_file)
1844  ObDereferenceObject(Vcb->root_file);
1845 
1846  le = Vcb->chunks.Flink;
1847  while (le != &Vcb->chunks) {
1849 
1850  if (c->cache) {
1851  acquire_fcb_lock_exclusive(Vcb);
1852  free_fcb(Vcb, c->cache);
1853  release_fcb_lock(Vcb);
1854  c->cache = NULL;
1855  }
1856 
1857  le = le->Flink;
1858  }
1859 
1860  while (!IsListEmpty(&Vcb->roots)) {
1862 
1863  ExDeleteResourceLite(&r->nonpaged->load_tree_lock);
1864  ExFreePool(r->nonpaged);
1865  ExFreePool(r);
1866  }
1867 
1868  while (!IsListEmpty(&Vcb->chunks)) {
1870 
1871  while (!IsListEmpty(&c->space)) {
1872  LIST_ENTRY* le2 = RemoveHeadList(&c->space);
1874 
1875  ExFreePool(s);
1876  }
1877 
1878  while (!IsListEmpty(&c->deleting)) {
1879  LIST_ENTRY* le2 = RemoveHeadList(&c->deleting);
1881 
1882  ExFreePool(s);
1883  }
1884 
1885  if (c->devices)
1886  ExFreePool(c->devices);
1887 
1888  if (c->cache) {
1889  acquire_fcb_lock_exclusive(Vcb);
1890  free_fcb(Vcb, c->cache);
1891  release_fcb_lock(Vcb);
1892  }
1893 
1894  ExDeleteResourceLite(&c->range_locks_lock);
1895  ExDeleteResourceLite(&c->partial_stripes_lock);
1896  ExDeleteResourceLite(&c->lock);
1897  ExDeleteResourceLite(&c->changed_extents_lock);
1898 
1899  ExFreePool(c->chunk_item);
1900  ExFreePool(c);
1901  }
1902 
1903  // FIXME - free any open fcbs?
1904 
1905  while (!IsListEmpty(&Vcb->devices)) {
1907 
1908  while (!IsListEmpty(&dev->space)) {
1909  LIST_ENTRY* le2 = RemoveHeadList(&dev->space);
1911 
1912  ExFreePool(s);
1913  }
1914 
1915  ExFreePool(dev);
1916  }
1917 
1918  ExAcquireResourceExclusiveLite(&Vcb->scrub.stats_lock, TRUE);
1919  while (!IsListEmpty(&Vcb->scrub.errors)) {
1921 
1922  ExFreePool(err);
1923  }
1924  ExReleaseResourceLite(&Vcb->scrub.stats_lock);
1925 
1926  ExDeleteResourceLite(&Vcb->fcb_lock);
1927  ExDeleteResourceLite(&Vcb->load_lock);
1928  ExDeleteResourceLite(&Vcb->tree_lock);
1929  ExDeleteResourceLite(&Vcb->chunk_lock);
1930  ExDeleteResourceLite(&Vcb->dirty_fcbs_lock);
1931  ExDeleteResourceLite(&Vcb->dirty_filerefs_lock);
1932  ExDeleteResourceLite(&Vcb->dirty_subvols_lock);
1933  ExDeleteResourceLite(&Vcb->scrub.stats_lock);
1934  ExDeleteResourceLite(&Vcb->send_load_lock);
1935 
1936  ExDeletePagedLookasideList(&Vcb->tree_data_lookaside);
1937  ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside);
1938  ExDeletePagedLookasideList(&Vcb->batch_item_lookaside);
1939  ExDeletePagedLookasideList(&Vcb->fileref_lookaside);
1940  ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
1941  ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
1942  ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
1943  ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
1944  ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
1945 
1946  ZwClose(Vcb->flush_thread_handle);
1947 }
1948 
1950  LARGE_INTEGER newlength, time;
1951  BTRFS_TIME now;
1952  NTSTATUS Status;
1953  ULONG utf8len = 0;
1954 
1957 
1958  ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE);
1959 
1960  if (fileref->deleted) {
1961  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1962  return STATUS_SUCCESS;
1963  }
1964 
1965  if (fileref->fcb->subvol->send_ops > 0) {
1966  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1967  return STATUS_ACCESS_DENIED;
1968  }
1969 
1970  fileref->deleted = TRUE;
1971  mark_fileref_dirty(fileref);
1972 
1973  // delete INODE_ITEM (0x1)
1974 
1975  TRACE("nlink = %u\n", fileref->fcb->inode_item.st_nlink);
1976 
1977  if (!fileref->fcb->ads) {
1978  if (fileref->parent->fcb->subvol == fileref->fcb->subvol) {
1979  LIST_ENTRY* le;
1980 
1981  mark_fcb_dirty(fileref->fcb);
1982 
1983  fileref->fcb->inode_item_changed = TRUE;
1984 
1985  if (fileref->fcb->inode_item.st_nlink > 1) {
1986  fileref->fcb->inode_item.st_nlink--;
1987  fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
1988  fileref->fcb->inode_item.sequence++;
1989  fileref->fcb->inode_item.st_ctime = now;
1990  } else {
1991  // excise extents
1992 
1993  if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) {
1994  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);
1995  if (!NT_SUCCESS(Status)) {
1996  ERR("excise_extents returned %08x\n", Status);
1997  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1998  return Status;
1999  }
2000  }
2001 
2002  fileref->fcb->Header.AllocationSize.QuadPart = 0;
2003  fileref->fcb->Header.FileSize.QuadPart = 0;
2004  fileref->fcb->Header.ValidDataLength.QuadPart = 0;
2005 
2006  if (FileObject) {
2007  CC_FILE_SIZES ccfs;
2008 
2009  ccfs.AllocationSize = fileref->fcb->Header.AllocationSize;
2010  ccfs.FileSize = fileref->fcb->Header.FileSize;
2011  ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength;
2012 
2014 
2015  _SEH2_TRY {
2016  CcSetFileSizes(FileObject, &ccfs);
2019  } _SEH2_END;
2020 
2021  if (!NT_SUCCESS(Status)) {
2022  ERR("CcSetFileSizes threw exception %08x\n", Status);
2023  ExReleaseResourceLite(fileref->fcb->Header.Resource);
2024  return Status;
2025  }
2026  }
2027 
2028  fileref->fcb->deleted = TRUE;
2029 
2030  le = fileref->children.Flink;
2031  while (le != &fileref->children) {
2033 
2034  if (fr2->fcb->ads) {
2035  fr2->fcb->deleted = TRUE;
2036  mark_fcb_dirty(fr2->fcb);
2037  }
2038 
2039  le = le->Flink;
2040  }
2041  }
2042 
2043  if (fileref->dc) {
2044  le = fileref->fcb->hardlinks.Flink;
2045  while (le != &fileref->fcb->hardlinks) {
2047 
2048  if (hl->parent == fileref->parent->fcb->inode && hl->index == fileref->dc->index) {
2050 
2051  if (hl->name.Buffer)
2052  ExFreePool(hl->name.Buffer);
2053 
2054  if (hl->utf8.Buffer)
2055  ExFreePool(hl->utf8.Buffer);
2056 
2057  ExFreePool(hl);
2058  break;
2059  }
2060 
2061  le = le->Flink;
2062  }
2063  }
2064  } else if (fileref->fcb->subvol->parent == fileref->parent->fcb->subvol->id) { // valid subvolume
2065  if (fileref->fcb->subvol->root_item.num_references > 1) {
2066  fileref->fcb->subvol->root_item.num_references--;
2067 
2068  mark_fcb_dirty(fileref->fcb); // so ROOT_ITEM gets updated
2069  } else {
2070  LIST_ENTRY* le;
2071 
2072  // FIXME - we need a lock here
2073 
2074  RemoveEntryList(&fileref->fcb->subvol->list_entry);
2075 
2076  InsertTailList(&fileref->fcb->Vcb->drop_roots, &fileref->fcb->subvol->list_entry);
2077 
2078  le = fileref->children.Flink;
2079  while (le != &fileref->children) {
2081 
2082  if (fr2->fcb->ads) {
2083  fr2->fcb->deleted = TRUE;
2084  mark_fcb_dirty(fr2->fcb);
2085  }
2086 
2087  le = le->Flink;
2088  }
2089  }
2090  }
2091  } else {
2092  fileref->fcb->deleted = TRUE;
2093  mark_fcb_dirty(fileref->fcb);
2094  }
2095 
2096  // remove dir_child from parent
2097 
2098  if (fileref->dc) {
2099  TRACE("delete file %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer);
2100 
2101  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
2102  RemoveEntryList(&fileref->dc->list_entry_index);
2103 
2104  if (!fileref->fcb->ads)
2105  remove_dir_child_from_hash_lists(fileref->parent->fcb, fileref->dc);
2106 
2107  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2108 
2109  if (!fileref->oldutf8.Buffer)
2110  fileref->oldutf8 = fileref->dc->utf8;
2111  else
2112  ExFreePool(fileref->dc->utf8.Buffer);
2113 
2114  utf8len = fileref->dc->utf8.Length;
2115 
2116  fileref->oldindex = fileref->dc->index;
2117 
2118  ExFreePool(fileref->dc->name.Buffer);
2119  ExFreePool(fileref->dc->name_uc.Buffer);
2120  ExFreePool(fileref->dc);
2121 
2122  fileref->dc = NULL;
2123  }
2124 
2125  // update INODE_ITEM of parent
2126 
2127  ExAcquireResourceExclusiveLite(fileref->parent->fcb->Header.Resource, TRUE);
2128 
2129  fileref->parent->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
2130  fileref->parent->fcb->inode_item.sequence++;
2131  fileref->parent->fcb->inode_item.st_ctime = now;
2132 
2133  if (!fileref->fcb->ads) {
2134  TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size);
2135  fileref->parent->fcb->inode_item.st_size -= utf8len * 2;
2136  TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size);
2137  fileref->parent->fcb->inode_item.st_mtime = now;
2138  }
2139 
2140  fileref->parent->fcb->inode_item_changed = TRUE;
2141  ExReleaseResourceLite(fileref->parent->fcb->Header.Resource);
2142 
2143  if (!fileref->fcb->ads && fileref->parent->dc)
2145 
2146  mark_fcb_dirty(fileref->parent->fcb);
2147 
2148  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
2149  fileref->fcb->subvol->root_item.ctime = now;
2150 
2151  newlength.QuadPart = 0;
2152 
2153  if (FileObject && !CcUninitializeCacheMap(FileObject, &newlength, NULL))
2154  TRACE("CcUninitializeCacheMap failed\n");
2155 
2156  ExReleaseResourceLite(fileref->fcb->Header.Resource);
2157 
2158  return STATUS_SUCCESS;
2159 }
2160 
2163 #ifdef __REACTOS__
2164 static NTSTATUS NTAPI drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
2165 #else
2166 static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
2167 #endif
2168  NTSTATUS Status;
2172  fcb* fcb = FileObject->FsContext;
2173  BOOL top_level;
2174 
2176 
2177  TRACE("cleanup\n");
2178 
2179  top_level = is_top_level(Irp);
2180 
2181  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
2183  goto exit;
2184  } else if (DeviceObject == master_devobj) {
2185  TRACE("closing file system\n");
2187  goto exit;
2188  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
2190  goto exit;
2191  }
2192 
2193  if (FileObject->Flags & FO_CLEANUP_COMPLETE) {
2194  TRACE("FileObject %p already cleaned up\n", FileObject);
2196  goto exit;
2197  }
2198 
2199  if (!fcb) {
2200  ERR("fcb was NULL\n");
2202  goto exit;
2203  }
2204 
2205  // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
2206  // messages belonging to other devices.
2207 
2208  if (FileObject && FileObject->FsContext) {
2209  LONG oc;
2210  ccb* ccb;
2211  file_ref* fileref;
2212  BOOL locked = TRUE;
2213 
2214  ccb = FileObject->FsContext2;
2215  fileref = ccb ? ccb->fileref : NULL;
2216 
2217  TRACE("cleanup called for FileObject %p\n", FileObject);
2218  TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0);
2219 
2220  ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
2221 
2223 
2225 
2226  if (ccb)
2227  FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb);
2228 
2229  if (fileref) {
2230  oc = InterlockedDecrement(&fileref->open_count);
2231 #ifdef DEBUG_FCB_REFCOUNTS
2232  ERR("fileref %p: open_count now %i\n", fileref, oc);
2233 #endif
2234  }
2235 
2236  if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref)
2237  fileref->delete_on_close = TRUE;
2238 
2239  if (fileref && fileref->delete_on_close && fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && fcb != fcb->Vcb->dummy_fcb)
2240  fileref->delete_on_close = FALSE;
2241 
2242  if (fcb->Vcb->locked && fcb->Vcb->locked_fileobj == FileObject) {
2243  TRACE("unlocking volume\n");
2246  }
2247 
2248  if (ccb && ccb->reserving) {
2249  fcb->subvol->reserved = NULL;
2250  ccb->reserving = FALSE;
2251  // FIXME - flush all of subvol's fcbs
2252  }
2253 
2254  if (fileref && oc == 0) {
2255  if (!fcb->Vcb->removing) {
2256  if (fileref && fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) {
2258 
2260 
2261  if (!fileref->fcb->ads || fileref->dc) {
2262  if (fileref->fcb->ads) {
2264  FILE_ACTION_REMOVED, &fileref->dc->name);
2265  } else
2267  }
2268 
2269  ExReleaseResourceLite(fcb->Header.Resource);
2270  locked = FALSE;
2271 
2272  // fcb_lock needs to be acquired before fcb->Header.Resource
2273  acquire_fcb_lock_exclusive(fcb->Vcb);
2274 
2275  Status = delete_fileref(fileref, FileObject, Irp, &rollback);
2276  if (!NT_SUCCESS(Status)) {
2277  ERR("delete_fileref returned %08x\n", Status);
2279  release_fcb_lock(fcb->Vcb);
2280  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2281  goto exit;
2282  }
2283 
2284  release_fcb_lock(fcb->Vcb);
2285 
2286  locked = FALSE;
2287 
2289  } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) {
2291  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2292 
2293  if (!NT_SUCCESS(iosb.Status)) {
2294  ERR("CcFlushCache returned %08x\n", iosb.Status);
2295  }
2296 
2297  if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) {
2298  ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
2299  ExReleaseResourceLite(fcb->Header.PagingIoResource);
2300  }
2301 
2302  CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE);
2303 
2304  TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n",
2305  FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
2306  }
2307  }
2308 
2309  if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb)
2311  }
2312 
2313  if (locked)
2314  ExReleaseResourceLite(fcb->Header.Resource);
2315 
2316  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2317 
2318  FileObject->Flags |= FO_CLEANUP_COMPLETE;
2319  }
2320 
2322 
2323 exit:
2324  TRACE("returning %08x\n", Status);
2325 
2326  Irp->IoStatus.Status = Status;
2327  Irp->IoStatus.Information = 0;
2328 
2330 
2331  if (top_level)
2333 
2335 
2336  return Status;
2337 }
2338 
2339 _Success_(return)
2340 BOOL get_file_attributes_from_xattr(_In_reads_bytes_(len) char* val, _In_ UINT16 len, _Out_ ULONG* atts) {
2341  if (len > 2 && val[0] == '0' && val[1] == 'x') {
2342  int i;
2343  ULONG dosnum = 0;
2344 
2345  for (i = 2; i < len; i++) {
2346  dosnum *= 0x10;
2347 
2348  if (val[i] >= '0' && val[i] <= '9')
2349  dosnum |= val[i] - '0';
2350  else if (val[i] >= 'a' && val[i] <= 'f')
2351  dosnum |= val[i] + 10 - 'a';
2352  else if (val[i] >= 'A' && val[i] <= 'F')
2353  dosnum |= val[i] + 10 - 'a';
2354  }
2355 
2356  TRACE("DOSATTRIB: %08x\n", dosnum);
2357 
2358  *atts = dosnum;
2359 
2360  return TRUE;
2361  }
2362 
2363  return FALSE;
2364 }
2365 
2367  _In_ UINT8 type, _In_ BOOL dotfile, _In_ BOOL ignore_xa, _In_opt_ PIRP Irp) {
2368  ULONG att;
2369  char* eaval;
2370  UINT16 ealen;
2371 
2372  if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen, Irp)) {
2373  ULONG dosnum = 0;
2374 
2375  if (get_file_attributes_from_xattr(eaval, ealen, &dosnum)) {
2376  ExFreePool(eaval);
2377 
2378  if (type == BTRFS_TYPE_DIRECTORY)
2379  dosnum |= FILE_ATTRIBUTE_DIRECTORY;
2380  else if (type == BTRFS_TYPE_SYMLINK)
2381  dosnum |= FILE_ATTRIBUTE_REPARSE_POINT;
2382 
2383  if (type != BTRFS_TYPE_DIRECTORY)
2384  dosnum &= ~FILE_ATTRIBUTE_DIRECTORY;
2385 
2386  if (inode == SUBVOL_ROOT_INODE) {
2387  if (r->root_item.flags & BTRFS_SUBVOL_READONLY)
2388  dosnum |= FILE_ATTRIBUTE_READONLY;
2389  else
2390  dosnum &= ~FILE_ATTRIBUTE_READONLY;
2391  }
2392 
2393  return dosnum;
2394  }
2395 
2396  ExFreePool(eaval);
2397  }
2398 
2399  switch (type) {
2400  case BTRFS_TYPE_DIRECTORY:
2402  break;
2403 
2404  case BTRFS_TYPE_SYMLINK:
2406  break;
2407 
2408  default:
2409  att = 0;
2410  break;
2411  }
2412 
2413  if (dotfile) {
2414  att |= FILE_ATTRIBUTE_HIDDEN;
2415  }
2416 
2417  att |= FILE_ATTRIBUTE_ARCHIVE;
2418 
2419  if (inode == SUBVOL_ROOT_INODE) {
2420  if (r->root_item.flags & BTRFS_SUBVOL_READONLY)
2421  att |= FILE_ATTRIBUTE_READONLY;
2422  else
2423  att &= ~FILE_ATTRIBUTE_READONLY;
2424  }
2425 
2426  // FIXME - get READONLY from ii->st_mode
2427  // FIXME - return SYSTEM for block/char devices?
2428 
2429  if (att == 0)
2430  att = FILE_ATTRIBUTE_NORMAL;
2431 
2432  return att;
2433 }
2434 
2439  PIRP Irp;
2441  NTSTATUS Status;
2443 
2444  num_reads++;
2445 
2446  RtlZeroMemory(&context, sizeof(read_context));
2448 
2449  Offset.QuadPart = (LONGLONG)StartingOffset;
2450 
2452 
2453  if (!Irp) {
2454  ERR("IoAllocateIrp failed\n");
2456  }
2457 
2458  Irp->Flags |= IRP_NOCACHE;
2461 
2462  if (override)
2464 
2466  Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, ALLOC_TAG);
2467  if (!Irp->AssociatedIrp.SystemBuffer) {
2468  ERR("out of memory\n");
2470  goto exit;
2471  }
2472 
2474 
2475  Irp->UserBuffer = Buffer;
2476  } else if (DeviceObject->Flags & DO_DIRECT_IO) {
2477  Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);
2478  if (!Irp->MdlAddress) {
2479  ERR("IoAllocateMdl failed\n");
2481  goto exit;
2482  }
2483 
2485 
2486  _SEH2_TRY {
2490  } _SEH2_END;
2491 
2492  if (!NT_SUCCESS(Status)) {
2493  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
2494  IoFreeMdl(Irp->MdlAddress);
2495  goto exit;
2496  }
2497  } else
2498  Irp->UserBuffer = Buffer;
2499 
2500  IrpSp->Parameters.Read.Length = Length;
2501  IrpSp->Parameters.Read.ByteOffset = Offset;
2502 
2503  Irp->UserIosb = &IoStatus;
2504 
2505  Irp->UserEvent = &context.Event;
2506 
2507  IoSetCompletionRoutine(Irp, read_completion, &context, TRUE, TRUE, TRUE);
2508 
2510 
2511  if (Status == STATUS_PENDING) {
2513  Status = context.iosb.Status;
2514  }
2515 
2516  if (DeviceObject->Flags & DO_DIRECT_IO) {
2517  MmUnlockPages(Irp->MdlAddress);
2518  IoFreeMdl(Irp->MdlAddress);
2519  }
2520 
2521 exit:
2522  IoFreeIrp(Irp);
2523 
2524  return Status;
2525 }
2526 
2528  NTSTATUS Status;
2529  superblock* sb;
2530  ULONG i, to_read;
2531  UINT8 valid_superblocks;
2532 
2533  to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize);
2534 
2536  if (!sb) {
2537  ERR("out of memory\n");
2539  }
2540 
2541  if (superblock_addrs[0] + to_read > length) {
2542  WARN("device was too short to have any superblock\n");
2543  ExFreePool(sb);
2545  }
2546 
2547  i = 0;
2548  valid_superblocks = 0;
2549 
2550  while (superblock_addrs[i] > 0) {
2551  UINT32 crc32;
2552 
2553  if (i > 0 && superblock_addrs[i] + to_read > length)
2554  break;
2555 
2557  if (!NT_SUCCESS(Status)) {
2558  ERR("Failed to read superblock %u: %08x\n", i, Status);
2559  ExFreePool(sb);
2560  return Status;
2561  }
2562 
2563  if (sb->magic != BTRFS_MAGIC) {
2564  if (i == 0) {
2565  TRACE("not a BTRFS volume\n");
2566  ExFreePool(sb);
2568  }
2569  } else {
2570  TRACE("got superblock %u!\n", i);
2571 
2572  crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
2573 
2574  if (crc32 != *((UINT32*)sb->checksum))
2575  WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum));
2576  else if (sb->sector_size == 0)
2577  WARN("superblock sector size was 0\n");
2578  else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000)
2579  WARN("invalid node size %x\n", sb->node_size);
2580  else if ((sb->node_size % sb->sector_size) != 0)
2581  WARN("node size %x was not a multiple of sector_size %x\n", sb->node_size, sb->sector_size);
2582  else if (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation) {
2583  RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock));
2584  valid_superblocks++;
2585  }
2586  }
2587 
2588  i++;
2589  }
2590 
2591  ExFreePool(sb);
2592 
2593  if (valid_superblocks == 0) {
2594  ERR("could not find any valid superblocks\n");
2595  return STATUS_INTERNAL_ERROR;
2596  }
2597 
2598  TRACE("label is %s\n", Vcb->superblock.label);
2599 
2600  return STATUS_SUCCESS;
2601 }
2602 
2604  _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb) {
2605  PIRP Irp;
2606  KEVENT Event;
2607  NTSTATUS Status;
2610 
2612 
2614  DeviceObject,
2615  InputBuffer,
2616  InputBufferSize,
2617  OutputBuffer,
2618  OutputBufferSize,
2619  FALSE,
2620  &Event,
2621  &IoStatus);
2622 
2623  if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
2624 
2625  if (Override) {
2628  }
2629 
2631 
2632  if (Status == STATUS_PENDING) {
2634  Status = IoStatus.Status;
2635  }
2636 
2637  if (iosb)
2638  *iosb = IoStatus;
2639 
2640  return Status;
2641 }
2642 
2647  if (!r) {
2648  ERR("out of memory\n");
2650  }
2651 
2652  r->id = id;
2653  r->dirty = FALSE;
2654  r->received = FALSE;
2655  r->reserved = NULL;
2656  r->treeholder.address = addr;
2657  r->treeholder.tree = NULL;
2658  r->treeholder.generation = generation;
2659  r->parent = 0;
2660  r->send_ops = 0;
2662 
2664  if (!r->nonpaged) {
2665  ERR("out of memory\n");
2666  ExFreePool(r);
2668  }
2669 
2670  ExInitializeResourceLite(&r->nonpaged->load_tree_lock);
2671 
2672  r->lastinode = 0;
2673 
2674  if (tp) {
2675  RtlCopyMemory(&r->root_item, tp->item->data, min(sizeof(ROOT_ITEM), tp->item->size));
2676  if (tp->item->size < sizeof(ROOT_ITEM))
2677  RtlZeroMemory(((UINT8*)&r->root_item) + tp->item->size, sizeof(ROOT_ITEM) - tp->item->size);
2678  } else
2679  RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
2680 
2681  if (!Vcb->readonly && (r->id == BTRFS_ROOT_ROOT || r->id == BTRFS_ROOT_FSTREE || (r->id >= 0x100 && !(r->id & 0xf000000000000000)))) { // FS tree root
2682  // FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag)
2683  get_last_inode(Vcb, r, NULL);
2684 
2685  if (r->id == BTRFS_ROOT_ROOT && r->lastinode < 0x100)
2686  r->lastinode = 0x100;
2687  }
2688 
2689  InsertTailList(&Vcb->roots, &r->list_entry);
2690 
2691  switch (r->id) {
2692  case BTRFS_ROOT_ROOT:
2693  Vcb->root_root = r;
2694  break;
2695 
2696  case BTRFS_ROOT_EXTENT:
2697  Vcb->extent_root = r;
2698  break;
2699 
2700  case BTRFS_ROOT_CHUNK:
2701  Vcb->chunk_root = r;
2702  break;
2703 
2704  case BTRFS_ROOT_DEVTREE:
2705  Vcb->dev_root = r;
2706  break;
2707 
2708  case BTRFS_ROOT_CHECKSUM:
2709  Vcb->checksum_root = r;
2710  break;
2711 
2712  case BTRFS_ROOT_UUID:
2713  Vcb->uuid_root = r;
2714  break;
2715 
2716  case BTRFS_ROOT_FREE_SPACE:
2717  Vcb->space_root = r;
2718  break;
2719 
2720  case BTRFS_ROOT_DATA_RELOC:
2721  Vcb->data_reloc_root = r;
2722  break;
2723  }
2724 
2726 }
2727 
2729  traverse_ptr tp, next_tp;
2730  KEY searchkey;
2731  BOOL b;
2732  NTSTATUS Status;
2733 
2734  searchkey.obj_id = 0;
2735  searchkey.obj_type = 0;
2736  searchkey.offset = 0;
2737 
2738  Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
2739  if (!NT_SUCCESS(Status)) {
2740  ERR("error - find_item returned %08x\n", Status);
2741  return Status;
2742  }
2743 
2744  do {
2745  TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
2746 
2747  if (tp.item->key.obj_type == TYPE_ROOT_ITEM) {
2748  ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data;
2749 
2750  if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) {
2751  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));
2752  } else {
2753  TRACE("root %llx - address %llx\n", tp.item->key.obj_id, ri->block_number);
2754 
2756  if (!NT_SUCCESS(Status)) {
2757  ERR("add_root returned %08x\n", Status);
2758  return Status;
2759  }
2760  }
2761  } else if (tp.item->key.obj_type == TYPE_ROOT_BACKREF && !IsListEmpty(&Vcb->roots)) {
2762  root* lastroot = CONTAINING_RECORD(Vcb->roots.Blink, root, list_entry);
2763 
2764  if (lastroot->id == tp.item->key.obj_id)
2765  lastroot->parent = tp.item->key.offset;
2766  }
2767 
2768  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
2769 
2770  if (b)
2771  tp = next_tp;
2772  } while (b);
2773 
2774  if (!Vcb->readonly && !Vcb->data_reloc_root) {
2775  root* reloc_root;
2776  INODE_ITEM* ii;
2777  UINT16 irlen;
2778  INODE_REF* ir;
2780  BTRFS_TIME now;
2781 
2782  WARN("data reloc root doesn't exist, creating it\n");
2783 
2785 
2786  if (!NT_SUCCESS(Status)) {
2787  ERR("create_root returned %08x\n", Status);
2788  return Status;
2789  }
2790 
2791  reloc_root->root_item.inode.generation = 1;
2792  reloc_root->root_item.inode.st_size = 3;
2793  reloc_root->root_item.inode.st_blocks = Vcb->superblock.node_size;
2794  reloc_root->root_item.inode.st_nlink = 1;
2795  reloc_root->root_item.inode.st_mode = 040755;
2796  reloc_root->root_item.inode.flags = 0xffffffff80000000;
2797  reloc_root->root_item.objid = SUBVOL_ROOT_INODE;
2798  reloc_root->root_item.bytes_used = Vcb->superblock.node_size;
2799 
2801  if (!ii) {
2802  ERR("out of memory\n");
2804  }
2805 
2808 
2809  RtlZeroMemory(ii, sizeof(INODE_ITEM));
2810  ii->generation = Vcb->superblock.generation;
2811  ii->st_blocks = Vcb->superblock.node_size;
2812  ii->st_nlink = 1;
2813  ii->st_mode = 040755;
2814  ii->st_atime = now;
2815  ii->st_ctime = now;
2816  ii->st_mtime = now;
2817 
2819  if (!NT_SUCCESS(Status)) {
2820  ERR("insert_tree_item returned %08x\n", Status);
2821  ExFreePool(ii);
2822  return Status;
2823  }
2824 
2825  irlen = (UINT16)offsetof(INODE_REF, name[0]) + 2;
2827  if (!ir) {
2828  ERR("out of memory\n");
2830  }
2831 
2832  ir->index = 0;
2833  ir->n = 2;
2834  ir->name[0] = '.';
2835  ir->name[1] = '.';
2836 
2838  if (!NT_SUCCESS(Status)) {
2839  ERR("insert_tree_item returned %08x\n", Status);
2840  ExFreePool(ir);
2841  return Status;
2842  }
2843 
2844  Vcb->data_reloc_root = reloc_root;
2845  Vcb->need_write = TRUE;
2846  }
2847 
2848  return STATUS_SUCCESS;
2849 }
2850 
2852  KEY searchkey;
2853  traverse_ptr tp, next_tp;
2854  BOOL b;
2855  UINT64 lastaddr;
2856  NTSTATUS Status;
2857 
2858  InitializeListHead(&dev->space);
2859 
2860  searchkey.obj_id = 0;
2861  searchkey.obj_type = TYPE_DEV_STATS;
2862  searchkey.offset = dev->devitem.dev_id;
2863 
2864  Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
2865  if (NT_SUCCESS(Status) && !keycmp(tp.item->key, searchkey))
2866  RtlCopyMemory(dev->stats, tp.item->data, min(sizeof(UINT64) * 5, tp.item->size));
2867 
2868  searchkey.obj_id = dev->devitem.dev_id;
2869  searchkey.obj_type = TYPE_DEV_EXTENT;
2870  searchkey.offset = 0;
2871 
2872  Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
2873  if (!NT_SUCCESS(Status)) {
2874  ERR("error - find_item returned %08x\n", Status);
2875  return Status;
2876  }
2877 
2878  lastaddr = 0;
2879 
2880  do {
2881  if (tp.item->key.obj_id == dev->devitem.dev_id && tp.item->key.obj_type == TYPE_DEV_EXTENT) {
2882  if (tp.item->size >= sizeof(DEV_EXTENT)) {
2883  DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data;
2884 
2885  if (tp.item->key.offset > lastaddr) {
2886  Status = add_space_entry(&dev->space, NULL, lastaddr, tp.item->key.offset - lastaddr);
2887  if (!NT_SUCCESS(Status)) {
2888  ERR("add_space_entry returned %08x\n", Status);
2889  return Status;
2890  }
2891  }
2892 
2893  lastaddr = tp.item->key.offset + de->length;
2894  } else {
2895  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));
2896  }
2897  }
2898 
2899  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
2900 
2901  if (b) {
2902  tp = next_tp;
2903  if (tp.item->key.obj_id > searchkey.obj_id || tp.item->key.obj_type > searchkey.obj_type)
2904  break;
2905  }
2906  } while (b);
2907 
2908  if (lastaddr < dev->devitem.num_bytes) {
2909  Status = add_space_entry(&dev->space, NULL, lastaddr, dev->devitem.num_bytes - lastaddr);
2910  if (!NT_SUCCESS(Status)) {
2911  ERR("add_space_entry returned %08x\n", Status);
2912  return Status;
2913  }
2914  }
2915 
2916  // The Linux driver doesn't like to allocate chunks within the first megabyte of a device.
2917 
2918  space_list_subtract2(&dev->space, NULL, 0, 0x100000, NULL, NULL);
2919 
2920  return STATUS_SUCCESS;
2921 }
2922 
2924  LIST_ENTRY* le;
2925 
2926  le = Vcb->devices.Flink;
2927 
2928  while (le != &Vcb->devices) {
2929  device* dev2 = CONTAINING_RECORD(le, device, list_entry);
2930 
2931  if (dev2->devitem.dev_id > dev->devitem.dev_id) {
2932  InsertHeadList(le->Blink, &dev->list_entry);
2933  return;
2934  }
2935 
2936  le = le->Flink;
2937  }
2938 
2939  InsertTailList(&Vcb->devices, &dev->list_entry);
2940 }
2941 
2945  pdo_device_extension* pdode;
2946  LIST_ENTRY* le;
2947 
2948  le = Vcb->devices.Flink;
2949  while (le != &Vcb->devices) {
2951 
2952  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,
2953  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],
2954  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]);
2955 
2956  if (RtlCompareMemory(&dev->devitem.device_uuid, uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2957  TRACE("returning device %llx\n", dev->devitem.dev_id);
2958  return dev;
2959  }
2960 
2961  le = le->Flink;
2962  }
2963 
2964  vde = Vcb->vde;
2965 
2966  if (!vde)
2967  goto end;
2968 
2969  pdode = vde->pdode;
2970 
2972 
2973  if (Vcb->devices_loaded < Vcb->superblock.num_devices) {
2974  le = pdode->children.Flink;
2975 
2976  while (le != &pdode->children) {
2978 
2979  if (RtlCompareMemory(uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2980  device* dev;
2981 
2983  if (!dev) {
2985  ERR("out of memory\n");
2986  return NULL;
2987  }
2988 
2989  RtlZeroMemory(dev, sizeof(device));
2990  dev->devobj = vc->devobj;
2991  dev->devitem.device_uuid = *uuid;
2992  dev->devitem.dev_id = vc->devid;
2993  dev->devitem.num_bytes = vc->size;
2994  dev->seeding = vc->seeding;
2995  dev->readonly = dev->seeding;
2996  dev->reloc = FALSE;
2997  dev->removable = FALSE;
2998  dev->disk_num = vc->disk_num;
2999  dev->part_num = vc->part_num;
3000  dev->num_trim_entries = 0;
3001  InitializeListHead(&dev->trim_list);
3002 
3004  Vcb->devices_loaded++;
3005 
3007 
3008  return dev;
3009  }
3010 
3011  le = le->Flink;
3012  }
3013  }
3014 
3016 
3017 end:
3018  WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
3019  uuid->uuid[0], uuid->uuid[1], uuid->uuid[2], uuid->uuid[3], uuid->uuid[4], uuid->uuid[5], uuid->uuid[6], uuid->uuid[7],
3020  uuid->uuid[8], uuid->uuid[9], uuid->uuid[10], uuid->uuid[11], uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]);
3021 
3022  return NULL;
3023 }
3024 
3026  NTSTATUS Status;
3028 
3030 
3031  if (!NT_SUCCESS(Status)) {
3032  ERR("dev_ioctl returned %08x\n", Status);
3033  return FALSE;
3034  }
3035 
3036  return shi.MediaRemovable != 0 ? TRUE : FALSE;
3037 }
3038 
3040  NTSTATUS Status;
3041  ULONG cc;
3043 
3044  Status = dev_ioctl(devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb);
3045 
3046  if (!NT_SUCCESS(Status)) {
3047  ERR("dev_ioctl returned %08x\n", Status);
3048  return 0;
3049  }
3050 
3051  if (iosb.Information < sizeof(ULONG)) {
3052  ERR("iosb.Information was too short\n");
3053  return 0;
3054  }
3055 
3056  return cc;
3057 }
3058 
3060  NTSTATUS Status;
3061  ULONG aptelen;
3062  ATA_PASS_THROUGH_EX* apte;
3065 
3066  dev->removable = is_device_removable(dev->devobj);
3067  dev->change_count = dev->removable ? get_device_change_count(dev->devobj) : 0;
3068 
3069  if (get_nums) {
3071 
3073  &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL);
3074 
3075  if (!NT_SUCCESS(Status)) {
3076  WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
3077  dev->disk_num = 0xffffffff;
3078  dev->part_num = 0xffffffff;
3079  } else {
3080  dev->disk_num = sdn.DeviceNumber;
3081  dev->part_num = sdn.PartitionNumber;
3082  }
3083  }
3084 
3085  dev->trim = FALSE;
3086  dev->readonly = dev->seeding;
3087  dev->reloc = FALSE;
3088  dev->num_trim_entries = 0;
3089  dev->stats_changed = FALSE;
3090  InitializeListHead(&dev->trim_list);
3091 
3092  if (!dev->readonly) {
3094  NULL, 0, TRUE, NULL);
3096  dev->readonly = TRUE;
3097  }
3098 
3099  aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512;
3100  apte = ExAllocatePoolWithTag(NonPagedPool, aptelen, ALLOC_TAG);
3101  if (!apte) {
3102  ERR("out of memory\n");
3103  return;
3104  }
3105 
3106  RtlZeroMemory(apte, aptelen);
3107 
3108  apte->Length = sizeof(ATA_PASS_THROUGH_EX);
3109  apte->AtaFlags = ATA_FLAGS_DATA_IN;
3110  apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX);
3111  apte->TimeOutValue = 3;
3112  apte->DataBufferOffset = apte->Length;
3114 
3115  Status = dev_ioctl(dev->devobj, IOCTL_ATA_PASS_THROUGH, apte, aptelen,
3116  apte, aptelen, TRUE, NULL);
3117 
3118  if (!NT_SUCCESS(Status))
3119  TRACE("IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE\n", Status);
3120  else {
3122 
3123  if (idd->CommandSetSupport.FlushCache) {
3124  dev->can_flush = TRUE;
3125  TRACE("FLUSH CACHE supported\n");
3126  } else
3127  TRACE("FLUSH CACHE not supported\n");
3128  }
3129 
3130  ExFreePool(apte);
3131 
3134  spq.AdditionalParameters[0] = 0;
3135 
3137  &dtd, sizeof(DEVICE_TRIM_DESCRIPTOR), TRUE, NULL);
3138 
3139  if (NT_SUCCESS(Status)) {
3140  if (dtd.TrimEnabled) {
3141  dev->trim = TRUE;
3142  Vcb->trim = TRUE;
3143  TRACE("TRIM supported\n");
3144  } else
3145  TRACE("TRIM not supported\n");
3146  }
3147 
3148  RtlZeroMemory(dev->stats, sizeof(UINT64) * 5);
3149 }
3150 
3152  traverse_ptr tp, next_tp;
3153  KEY searchkey;
3154  BOOL b;
3155  chunk* c;
3156  NTSTATUS Status;
3157 
3158  searchkey.obj_id = 0;
3159  searchkey.obj_type = 0;
3160  searchkey.offset = 0;
3161 
3162  Vcb->data_flags = 0;
3163  Vcb->metadata_flags = 0;
3164  Vcb->system_flags = 0;
3165 
3166  Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE, Irp);
3167  if (!NT_SUCCESS(Status)) {
3168  ERR("error - find_item returned %08x\n", Status);
3169  return Status;
3170  }
3171 
3172  do {
3173  TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
3174 
3175  if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM) {
3176  if (tp.item->size < sizeof(DEV_ITEM)) {
3177  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));
3178  } else {
3179  DEV_ITEM* di = (DEV_ITEM*)tp.item->data;
3180  LIST_ENTRY* le;
3181  BOOL done = FALSE;
3182 
3183  le = Vcb->devices.Flink;
3184  while (le != &Vcb->devices) {
3186 
3187  if (dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &di->device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3188  RtlCopyMemory(&dev->devitem, tp.item->data, min(tp.item->size, sizeof(DEV_ITEM)));
3189 
3190  if (le != Vcb->devices.Flink)
3191  init_device(Vcb, dev, TRUE);
3192 
3193  done = TRUE;
3194  break;
3195  }
3196 
3197  le = le->Flink;
3198  }
3199 
3200  if (!done && Vcb->vde) {
3201  volume_device_extension* vde = Vcb->vde;
3202  pdo_device_extension* pdode = vde->pdode;
3203 
3205 
3206  if (Vcb->devices_loaded < Vcb->superblock.num_devices) {
3207  le = pdode->children.Flink;
3208 
3209  while (le != &pdode->children) {
3211 
3212  if (RtlCompareMemory(&di->device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3213  device* dev;
3214 
3216  if (!dev) {
3218  ERR("out of memory\n");
3220  }
3221 
3222  RtlZeroMemory(dev, sizeof(device));
3223 
3224  dev->devobj = vc->devobj;
3225  RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM)));
3226  dev->seeding = vc->seeding;
3227  init_device(Vcb, dev, FALSE);
3228 
3229  if (dev->devitem.num_bytes > vc->size) {
3230  WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", tp.item->key.offset,
3231  dev->devitem.num_bytes, vc->size);
3232 
3233  dev->devitem.num_bytes = vc->size;
3234  }
3235 
3236  dev->disk_num = vc->disk_num;
3237  dev->part_num = vc->part_num;
3239  Vcb->devices_loaded++;
3240 
3241  done = TRUE;
3242  break;
3243  }
3244 
3245  le = le->Flink;
3246  }
3247 
3248  if (!done) {
3249  if (!Vcb->options.allow_degraded) {
3250  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,
3251  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],
3252  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]);
3253  } else {
3254  device* dev;
3255 
3257  if (!dev) {
3259  ERR("out of memory\n");
3261  }
3262 
3263  RtlZeroMemory(dev, sizeof(device));
3264 
3265  // Missing device, so we keep dev->devobj as NULL
3266  RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM)));
3267  InitializeListHead(&dev->trim_list);
3268 
3270  Vcb->devices_loaded++;
3271  }
3272  }
3273  } else
3274  ERR("unexpected device %llx found\n", tp.item->key.offset);
3275 
3277  }
3278  }
3279  } else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) {
3280  if (tp.item->size < sizeof(CHUNK_ITEM)) {
3281  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));
3282  } else {
3284 
3285  if (!c) {
3286  ERR("out of memory\n");
3288  }
3289 
3290  c->size = tp.item->size;
3291  c->offset = tp.item->key.offset;
3292  c->used = c->oldused = 0;
3293  c->cache = c->old_cache = NULL;
3294  c->created = FALSE;
3295  c->readonly = FALSE;
3296  c->reloc = FALSE;
3297  c->cache_loaded = FALSE;
3298  c->changed = FALSE;
3299  c->space_changed = FALSE;
3300  c->balance_num = 0;
3301 
3303 
3304  if (!c->chunk_item) {
3305  ERR("out of memory\n");
3306  ExFreePool(c);
3308  }
3309 
3310  RtlCopyMemory(c->chunk_item, tp.item->data, tp.item->size);
3311 
3312  if (c->chunk_item->type & BLOCK_FLAG_DATA && c->chunk_item->type > Vcb->data_flags)
3313  Vcb->data_flags = c->chunk_item->type;
3314 
3315  if (c->chunk_item->type & BLOCK_FLAG_METADATA && c->chunk_item->type > Vcb->metadata_flags)
3316  Vcb->metadata_flags = c->chunk_item->type;
3317 
3318  if (c->chunk_item->type & BLOCK_FLAG_SYSTEM && c->chunk_item->type > Vcb->system_flags)
3319  Vcb->system_flags = c->chunk_item->type;
3320 
3321  if (c->chunk_item->type & BLOCK_FLAG_RAID10) {
3322  if (c->chunk_item->sub_stripes == 0 || c->chunk_item->sub_stripes > c->chunk_item->num_stripes) {
3323  ERR("chunk %llx: invalid stripes (num_stripes %u, sub_stripes %u)\n", c->offset, c->chunk_item->num_stripes, c->chunk_item->sub_stripes);
3324  ExFreePool(c->chunk_item);
3325  ExFreePool(c);
3326  return STATUS_INTERNAL_ERROR;
3327  }
3328  }
3329 
3330  if (c->chunk_item->num_stripes > 0) {
3331  CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
3332  UINT16 i;
3333 
3334  c->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG);
3335 
3336  if (!c->devices) {
3337  ERR("out of memory\n");
3338  ExFreePool(c->chunk_item);
3339  ExFreePool(c);
3341  }
3342 
3343  for (i = 0; i < c->chunk_item->num_stripes; i++) {
3344  c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid);
3345  TRACE("device %llu = %p\n", i, c->devices[i]);
3346 
3347  if (!c->devices[i]) {
3348  ERR("missing device\n");
3349  ExFreePool(c->chunk_item);
3350  ExFreePool(c);
3351  return STATUS_INTERNAL_ERROR;
3352  }
3353 
3354  if (c->devices[i]->readonly)
3355  c->readonly = TRUE;
3356  }
3357  } else {
3358  ERR("chunk %llx: number of stripes is 0\n", c->offset);
3359  ExFreePool(c->chunk_item);
3360  ExFreePool(c);
3361  return STATUS_INTERNAL_ERROR;
3362  }
3363 
3364  ExInitializeResourceLite(&c->lock);
3365  ExInitializeResourceLite(&c->changed_extents_lock);
3366 
3367  InitializeListHead(&c->space);
3368  InitializeListHead(&c->space_size);
3369  InitializeListHead(&c->deleting);
3370  InitializeListHead(&c->changed_extents);
3371 
3372  InitializeListHead(&c->range_locks);
3373  ExInitializeResourceLite(&c->range_locks_lock);
3374  KeInitializeEvent(&c->range_locks_event, NotificationEvent, FALSE);
3375 
3376  InitializeListHead(&c->partial_stripes);
3377  ExInitializeResourceLite(&c->partial_stripes_lock);
3378 
3379  c->last_alloc_set = FALSE;
3380 
3381  c->last_stripe = 0;
3382 
3383  InsertTailList(&Vcb->chunks, &c->list_entry);
3384 
3385  c->list_entry_balance.Flink = NULL;
3386  }
3387  }
3388 
3389  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
3390 
3391  if (b)
3392  tp = next_tp;
3393  } while (b);
3394 
3395  Vcb->log_to_phys_loaded = TRUE;
3396 
3397  if (Vcb->data_flags == 0)
3398  Vcb->data_flags = BLOCK_FLAG_DATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID0 : 0);
3399 
3400  if (Vcb->metadata_flags == 0)
3401  Vcb->metadata_flags = BLOCK_FLAG_METADATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE);
3402 
3403  if (Vcb->system_flags == 0)
3404  Vcb->system_flags = BLOCK_FLAG_SYSTEM | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE);
3405 
3406  if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) {
3407  Vcb->metadata_flags |= BLOCK_FLAG_DATA;
3408  Vcb->data_flags = Vcb->metadata_flags;
3409  }
3410 
3411  return STATUS_SUCCESS;
3412 }
3413 
3415  UINT16 i = 0, j;
3416  UINT64 off_start, off_end;
3417 
3418  // The Linux driver also protects all the space before the first superblock.
3419  // I realize this confuses physical and logical addresses, but this is what btrfs-progs does -
3420  // evidently Linux assumes the chunk at 0 is always SINGLE.
3421  if (c->offset < superblock_addrs[0])
3422  space_list_subtract(c, FALSE, c->offset, superblock_addrs[0] - c->offset, NULL);
3423 
3424  while (superblock_addrs[i] != 0) {
3425  CHUNK_ITEM* ci = c->chunk_item;
3426  CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
3427 
3428  if (ci->type & BLOCK_FLAG_RAID0 || ci->type & BLOCK_FLAG_RAID10) {
3429  for (j = 0; j < ci->num_stripes; j++) {
3430  UINT16 sub_stripes = max(ci->sub_stripes, 1);
3431 
3432  if (cis[j].offset + (ci->size * ci->num_stripes / sub_stripes) > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3433 #ifdef _DEBUG
3434  UINT64 startoff;
3435  UINT16 startoffstripe;
3436 #endif
3437 
3438  TRACE("cut out superblock in chunk %llx\n", c->offset);
3439 
3440  off_start = superblock_addrs[i] - cis[j].offset;
3441  off_start -= off_start % ci->stripe_length;
3442  off_start *= ci->num_stripes / sub_stripes;
3443  off_start += (j / sub_stripes) * ci->stripe_length;
3444 
3445  off_end = off_start + ci->stripe_length;
3446 
3447 #ifdef _DEBUG
3448  get_raid0_offset(off_start, ci->stripe_length, ci->num_stripes / sub_stripes, &startoff, &startoffstripe);
3449  TRACE("j = %u, startoffstripe = %u\n", j, startoffstripe);
3450  TRACE("startoff = %llx, superblock = %llx\n", startoff + cis[j].offset, superblock_addrs[i]);
3451 #endif
3452 
3453  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3454  }
3455  }
3456  } else if (ci->type & BLOCK_FLAG_RAID5) {
3457  UINT64 stripe_size = ci->size / (ci->num_stripes - 1);
3458 
3459  for (j = 0; j < ci->num_stripes; j++) {
3460  if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3461  TRACE("cut out superblock in chunk %llx\n", c->offset);
3462 
3463  off_start = superblock_addrs[i] - cis[j].offset;
3464  off_start -= off_start % ci->stripe_length;
3465  off_start *= ci->num_stripes - 1;
3466 
3467  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length);
3468  off_end *= ci->num_stripes - 1;
3469 
3470  TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start);
3471 
3472  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3473  }
3474  }
3475  } else if (ci->type & BLOCK_FLAG_RAID6) {
3476  UINT64 stripe_size = ci->size / (ci->num_stripes - 2);
3477 
3478  for (j = 0; j < ci->num_stripes; j++) {
3479  if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3480  TRACE("cut out superblock in chunk %llx\n", c->offset);
3481 
3482  off_start = superblock_addrs[i] - cis[j].offset;
3483  off_start -= off_start % ci->stripe_length;
3484  off_start *= ci->num_stripes - 2;
3485 
3486  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length);
3487  off_end *= ci->num_stripes - 2;
3488 
3489  TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start);
3490 
3491  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3492  }
3493  }
3494  } else { // SINGLE, DUPLICATE, RAID1
3495  for (j = 0; j < ci->num_stripes; j++) {
3496  if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3497  TRACE("cut out superblock in chunk %llx\n", c->offset);
3498 
3499  // The Linux driver protects the whole stripe in which the superblock lives
3500 
3501  off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length;
3502  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length);
3503 
3504  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3505  }
3506  }
3507  }
3508 
3509  i++;
3510  }
3511 }
3512 
3514  LIST_ENTRY* le = Vcb->chunks.Flink;
3515  chunk* c;
3516  KEY searchkey;
3517  traverse_ptr tp;
3518  BLOCK_GROUP_ITEM* bgi;
3519  NTSTATUS Status;
3520 
3521  searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM;
3522 
3523  while (le != &Vcb->chunks) {
3525 
3526  searchkey.obj_id = c->offset;
3527  searchkey.offset = c->chunk_item->size;
3528 
3529  Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
3530  if (!NT_SUCCESS(Status)) {
3531  ERR("error - find_item returned %08x\n", Status);
3532  return Status;
3533  }
3534 
3535  if (!keycmp(searchkey, tp.item->key)) {
3536  if (tp.item->size >= sizeof(BLOCK_GROUP_ITEM)) {
3537  bgi = (BLOCK_GROUP_ITEM*)tp.item->data;
3538 
3539  c->used = c->oldused = bgi->used;
3540 
3541  TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used);
3542  } else {
3543  ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n",
3544  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));
3545  }
3546  }
3547 
3548  le = le->Flink;
3549  }
3550 
3551  Vcb->chunk_usage_found = TRUE;
3552 
3553  return STATUS_SUCCESS;
3554 }
3555 
3557  KEY key;
3558  ULONG n = Vcb->superblock.n;
3559 
3560  while (n > 0) {
3561  if (n > sizeof(KEY)) {
3562  RtlCopyMemory(&key, &Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n], sizeof(KEY));
3563  n -= sizeof(KEY);
3564  } else
3565  return STATUS_SUCCESS;
3566 
3567  TRACE("bootstrap: %llx,%x,%llx\n", key.obj_id, key.obj_type, key.offset);
3568 
3569  if (key.obj_type == TYPE_CHUNK_ITEM) {
3570  CHUNK_ITEM* ci;
3571  USHORT cisize;
3572  sys_chunk* sc;
3573 
3574  if (n < sizeof(CHUNK_ITEM))
3575  return STATUS_SUCCESS;
3576 
3577  ci = (CHUNK_ITEM*)&Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n];
3578  cisize = sizeof(CHUNK_ITEM) + (ci->num_stripes * sizeof(CHUNK_ITEM_STRIPE));
3579 
3580  if (n < cisize)
3581  return STATUS_SUCCESS;
3582 
3584 
3585  if (!sc) {
3586  ERR("out of memory\n");
3588  }
3589 
3590  sc->key = key;
3591  sc->size = cisize;
3593 
3594  if (!sc->data) {
3595  ERR("out of memory\n");
3596  ExFreePool(sc);
3598  }
3599 
3600  RtlCopyMemory(sc->data, ci, sc->size);
3601  InsertTailList(&Vcb->sys_chunks, &sc->list_entry);
3602 
3603  n -= cisize;
3604  } else {
3605  ERR("unexpected item %llx,%x,%llx in bootstrap\n", key.obj_id, key.obj_type, key.offset);
3606  return STATUS_INTERNAL_ERROR;
3607  }
3608  }
3609 
3610  return STATUS_SUCCESS;
3611 }
3612 
3615  LIST_ENTRY* le;
3616 
3617  static const char fn[] = "default";
3618  static UINT32 crc32 = 0x8dbfc2d2;
3619 
3620  if (Vcb->options.subvol_id != 0) {
3621  le = Vcb->roots.Flink;
3622  while (le != &Vcb->roots) {
3624 
3625  if (r->id == Vcb->options.subvol_id)
3626  return r;
3627 
3628  le = le->Flink;
3629  }
3630  }
3631 
3632  if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL) {
3633  NTSTATUS Status;
3634  KEY searchkey;
3635  traverse_ptr tp;
3636  DIR_ITEM* di;
3637 
3638  searchkey.obj_id = Vcb->superblock.root_dir_objectid;
3639  searchkey.obj_type = TYPE_DIR_ITEM;
3640  searchkey.offset = crc32;
3641 
3642  Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
3643  if (!NT_SUCCESS(Status)) {
3644  ERR("error - find_item returned %08x\n", Status);
3645  goto end;
3646  }
3647 
3648  if (keycmp(tp.item->key, searchkey)) {
3649  ERR("could not find (%llx,%x,%llx) in root tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
3650  goto end;
3651  }
3652 
3653  if (tp.item->size < sizeof(DIR_ITEM)) {
3654  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));
3655  goto end;
3656  }
3657 
3658  di = (DIR_ITEM*)tp.item->data;
3659 
3660  if (tp.item->size < sizeof(DIR_ITEM) - 1 + di->n) {
3661  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);
3662  goto end;
3663  }
3664 
3665  if (di->n != strlen(fn) || RtlCompareMemory(di->name, fn, di->n) != di->n) {
3666  ERR("root DIR_ITEM had same CRC32, but was not \"default\"\n");
3667  goto end;
3668  }
3669 
3670  if (di->key.obj_type != TYPE_ROOT_ITEM) {
3671  ERR("default root has key (%llx,%x,%llx), expected subvolume\n", di->key.obj_id, di->key.obj_type, di->key.offset);
3672  goto end;
3673  }
3674 
3675  le = Vcb->roots.Flink;
3676  while (le != &Vcb->roots) {
3678 
3679  if (r->id == di->key.obj_id)
3680  return r;
3681 
3682  le = le->Flink;
3683  }
3684 
3685  ERR("could not find root %llx, using default instead\n", di->key.obj_id);
3686  }
3687 
3688 end:
3689  le = Vcb->roots.Flink;
3690  while (le != &Vcb->roots) {
3692 
3693  if (r->id == BTRFS_ROOT_FSTREE)
3694  return r;
3695 
3696  le = le->Flink;
3697  }
3698 
3699  return NULL;
3700 }
3701 
3703  TRACE("(%p, %p)\n", FileObject, ccfs);
3704 
3706 
3707  if (diskacc)
3709 
3711 }
3712 
3715  ULONG i;
3716 
3717  Vcb->calcthreads.num_threads = KeQueryActiveProcessorCount(NULL);
3718 
3719  Vcb->calcthreads.threads = ExAllocatePoolWithTag(NonPagedPool, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads, ALLOC_TAG);
3720  if (!Vcb->calcthreads.threads) {
3721  ERR("out of memory\n");
3723  }
3724 
3725  InitializeListHead(&Vcb->calcthreads.job_list);
3726  ExInitializeResourceLite(&Vcb->calcthreads.lock);
3727  KeInitializeEvent(&Vcb->calcthreads.event, NotificationEvent, FALSE);
3728 
3729  RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads);
3730 
3731  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
3732  NTSTATUS Status;
3733 
3734  Vcb->calcthreads.threads[i].DeviceObject = DeviceObject;
3735  KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, FALSE);
3736 
3737  Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
3738  if (!NT_SUCCESS(Status)) {
3739  ULONG j;
3740 
3741  ERR("PsCreateSystemThread returned %08x\n", Status);
3742 
3743  for (j = 0; j < i; j++) {
3744  Vcb->calcthreads.threads[i].quit = TRUE;
3745  }
3746 
3747  KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
3748 
3749  return Status;
3750  }
3751  }
3752 
3753  return STATUS_SUCCESS;
3754 }
3755 
3757  NTSTATUS Status;
3758  MOUNTDEV_NAME mdn, *mdn2;
3759  ULONG mdnsize;
3760 
3763  ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
3764  return FALSE;
3765  }
3766 
3767  mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
3768 
3769  mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG);
3770  if (!mdn2) {
3771  ERR("out of memory\n");
3772  return FALSE;
3773  }
3774 
3776  if (!NT_SUCCESS(Status)) {
3777  ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
3778  ExFreePool(mdn2);
3779  return FALSE;
3780  }
3781 
3782  if (mdn2->NameLength > (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) &&
3783  RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) == sizeof(<