ReactOS  0.4.10-dev-348-gbcec1fd
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 #define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)
53 
54 static WCHAR device_name[] = {'\\','B','t','r','f','s',0};
55 static WCHAR dosdevice_name[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0};
56 
57 DEFINE_GUID(BtrfsBusInterface, 0x4d414874, 0x6865, 0x6761, 0x6d, 0x65, 0x83, 0x69, 0x17, 0x9a, 0x7d, 0x1d);
58 
61 #ifndef __REACTOS__
63 #endif
98 
99 #ifdef _DEBUG
100 PFILE_OBJECT comfo = NULL;
101 PDEVICE_OBJECT comdo = NULL;
102 HANDLE log_handle = NULL;
103 ERESOURCE log_lock;
104 HANDLE serial_thread_handle = NULL;
105 
106 static void init_serial(BOOL first_time);
107 #endif
108 
110 
111 typedef struct {
114 } read_context;
115 
116 #ifdef _DEBUG
117 _Function_class_(IO_COMPLETION_ROUTINE)
118 static NTSTATUS dbg_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) {
119  read_context* context = conptr;
120 
121  UNUSED(DeviceObject);
122 
123  context->iosb = Irp->IoStatus;
124  KeSetEvent(&context->Event, 0, FALSE);
125 
127 }
128 
129 #ifdef DEBUG_LONG_MESSAGES
130 void _debug_message(_In_ const char* func, _In_ const char* file, _In_ unsigned int line, _In_ char* s, ...) {
131 #else
132 void _debug_message(_In_ const char* func, _In_ char* s, ...) {
133 #endif
137  PIRP Irp;
138  va_list ap;
139  char *buf2, *buf;
141  UINT32 length;
142 
144 
145  if (!buf2) {
146  DbgPrint("Couldn't allocate buffer in debug_message\n");
147  return;
148  }
149 
150 #ifdef DEBUG_LONG_MESSAGES
151  sprintf(buf2, "%p:%s:%s:%u:", PsGetCurrentThread(), func, file, line);
152 #else
153  sprintf(buf2, "%p:%s:", PsGetCurrentThread(), func);
154 #endif
155  buf = &buf2[strlen(buf2)];
156 
157  va_start(ap, s);
158  vsprintf(buf, s, ap);
159 
160  ExAcquireResourceSharedLite(&log_lock, TRUE);
161 
162  if (!log_started || (log_device.Length == 0 && log_file.Length == 0)) {
163  DbgPrint(buf2);
164  } else if (log_device.Length > 0) {
165  if (!comdo) {
166  DbgPrint("comdo is NULL :-(\n");
167  DbgPrint(buf2);
168  goto exit2;
169  }
170 
171  length = (UINT32)strlen(buf2);
172 
173  offset.u.LowPart = 0;
174  offset.u.HighPart = 0;
175 
176  RtlZeroMemory(&context, sizeof(read_context));
177 
179 
180  Irp = IoAllocateIrp(comdo->StackSize, FALSE);
181 
182  if (!Irp) {
183  DbgPrint("IoAllocateIrp failed\n");
184  goto exit2;
185  }
186 
187  IrpSp = IoGetNextIrpStackLocation(Irp);
188  IrpSp->MajorFunction = IRP_MJ_WRITE;
189 
190  if (comdo->Flags & DO_BUFFERED_IO) {
191  Irp->AssociatedIrp.SystemBuffer = buf2;
192 
193  Irp->Flags = IRP_BUFFERED_IO;
194  } else if (comdo->Flags & DO_DIRECT_IO) {
195  Irp->MdlAddress = IoAllocateMdl(buf2, length, FALSE, FALSE, NULL);
196  if (!Irp->MdlAddress) {
197  DbgPrint("IoAllocateMdl failed\n");
198  goto exit;
199  }
200 
201  MmBuildMdlForNonPagedPool(Irp->MdlAddress);
202  } else {
203  Irp->UserBuffer = buf2;
204  }
205 
206  IrpSp->Parameters.Write.Length = length;
207  IrpSp->Parameters.Write.ByteOffset = offset;
208 
209  Irp->UserIosb = &context.iosb;
210 
211  Irp->UserEvent = &context.Event;
212 
213  IoSetCompletionRoutine(Irp, dbg_completion, &context, TRUE, TRUE, TRUE);
214 
215  Status = IoCallDriver(comdo, Irp);
216 
217  if (Status == STATUS_PENDING) {
219  Status = context.iosb.Status;
220  }
221 
222  if (comdo->Flags & DO_DIRECT_IO)
223  IoFreeMdl(Irp->MdlAddress);
224 
225  if (!NT_SUCCESS(Status)) {
226  DbgPrint("failed to write to COM1 - error %08x\n", Status);
227  goto exit;
228  }
229 
230 exit:
231  IoFreeIrp(Irp);
232  } else if (log_handle != NULL) {
234 
235  length = (UINT32)strlen(buf2);
236 
237  Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, buf2, length, NULL, NULL);
238 
239  if (!NT_SUCCESS(Status)) {
240  DbgPrint("failed to write to file - error %08x\n", Status);
241  }
242  }
243 
244 exit2:
245  ExReleaseResourceLite(&log_lock);
246 
247  va_end(ap);
248 
249  if (buf2)
250  ExFreePool(buf2);
251 }
252 #endif
253 
255  if (!IoGetTopLevelIrp()) {
256  IoSetTopLevelIrp(Irp);
257  return TRUE;
258  }
259 
260  return FALSE;
261 }
262 
263 _Function_class_(DRIVER_UNLOAD)
264 #ifdef __REACTOS__
266 #else
267 static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
268 #endif
269  UNICODE_STRING dosdevice_nameW;
270 
271  ERR("DriverUnload\n");
272 
273  free_cache();
274 
275  IoUnregisterFileSystem(DriverObject->DeviceObject);
276 
278 #ifdef __REACTOS__
280 #else
281  IoUnregisterPlugPlayNotificationEx(notification_entry2);
282 #endif
283 
285 #ifdef __REACTOS__
287 #else
288  IoUnregisterPlugPlayNotificationEx(notification_entry3);
289 #endif
290 
291  if (notification_entry)
292 #ifdef __REACTOS__
293  IoUnregisterPlugPlayNotification(notification_entry);
294 #else
295  IoUnregisterPlugPlayNotificationEx(notification_entry);
296 #endif
297 
298  dosdevice_nameW.Buffer = dosdevice_name;
299  dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = (USHORT)wcslen(dosdevice_name) * sizeof(WCHAR);
300 
301  IoDeleteSymbolicLink(&dosdevice_nameW);
302  IoDeleteDevice(DriverObject->DeviceObject);
303 
304  while (!IsListEmpty(&uid_map_list)) {
305  LIST_ENTRY* le = RemoveHeadList(&uid_map_list);
306  uid_map* um = CONTAINING_RECORD(le, uid_map, listentry);
307 
308  ExFreePool(um->sid);
309 
310  ExFreePool(um);
311  }
312 
313  while (!IsListEmpty(&gid_map_list)) {
314  gid_map* gm = CONTAINING_RECORD(RemoveHeadList(&gid_map_list), gid_map, listentry);
315 
316  ExFreePool(gm->sid);
317  ExFreePool(gm);
318  }
319 
320  // FIXME - free volumes and their devpaths
321 
322 #ifdef _DEBUG
323  if (comfo)
324  ObDereferenceObject(comfo);
325 
326  if (log_handle)
327  ZwClose(log_handle);
328 #endif
329 
332 
333  if (log_device.Buffer)
334  ExFreePool(log_device.Buffer);
335 
336  if (log_file.Buffer)
337  ExFreePool(log_file.Buffer);
338 
339  if (registry_path.Buffer)
340  ExFreePool(registry_path.Buffer);
341 
342 #ifdef _DEBUG
343  ExDeleteResourceLite(&log_lock);
344 #endif
346 }
347 
349  KEY searchkey;
350  traverse_ptr tp, prev_tp;
352 
353  // get last entry
354  searchkey.obj_id = 0xffffffffffffffff;
355  searchkey.obj_type = 0xff;
356  searchkey.offset = 0xffffffffffffffff;
357 
358  Status = find_item(Vcb, r, &tp, &searchkey, FALSE, Irp);
359  if (!NT_SUCCESS(Status)) {
360  ERR("error - find_item returned %08x\n", Status);
361  return FALSE;
362  }
363 
364  if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) {
365  r->lastinode = tp.item->key.obj_id;
366  TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode);
367  return TRUE;
368  }
369 
370  while (find_prev_item(Vcb, &tp, &prev_tp, Irp)) {
371  tp = prev_tp;
372 
373  TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
374 
375  if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) {
376  r->lastinode = tp.item->key.obj_id;
377  TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode);
378  return TRUE;
379  }
380  }
381 
382  r->lastinode = SUBVOL_ROOT_INODE;
383 
384  WARN("no INODE_ITEMs in tree %llx\n", r->id);
385 
386  return TRUE;
387 }
388 
389 _Success_(return)
390 static BOOL extract_xattr(_In_reads_bytes_(size) void* item, _In_ USHORT size, _In_z_ char* name, _Out_ UINT8** data, _Out_ UINT16* datalen) {
391  DIR_ITEM* xa = (DIR_ITEM*)item;
392  USHORT xasize;
393 
394  while (TRUE) {
395  if (size < sizeof(DIR_ITEM) || size < (sizeof(DIR_ITEM) - 1 + xa->m + xa->n)) {
396  WARN("DIR_ITEM is truncated\n");
397  return FALSE;
398  }
399 
400  if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) {
401  TRACE("found xattr %s\n", name);
402 
403  *datalen = xa->m;
404 
405  if (xa->m > 0) {
407  if (!*data) {
408  ERR("out of memory\n");
409  return FALSE;
410  }
411 
412  RtlCopyMemory(*data, &xa->name[xa->n], xa->m);
413  } else
414  *data = NULL;
415 
416  return TRUE;
417  }
418 
419  xasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n;
420 
421  if (size > xasize) {
422  size -= xasize;
423  xa = (DIR_ITEM*)&xa->name[xa->m + xa->n];
424  } else
425  break;
426  }
427 
428  TRACE("xattr %s not found\n", name);
429 
430  return FALSE;
431 }
432 
433 _Success_(return)
434 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,
436  KEY searchkey;
439 
440  TRACE("(%p, %llx, %llx, %s, %08x, %p, %p)\n", Vcb, subvol->id, inode, name, crc32, data, datalen);
441 
442  searchkey.obj_id = inode;
443  searchkey.obj_type = TYPE_XATTR_ITEM;
444  searchkey.offset = crc32;
445 
446  Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
447  if (!NT_SUCCESS(Status)) {
448  ERR("error - find_item returned %08x\n", Status);
449  return FALSE;
450  }
451 
452  if (keycmp(tp.item->key, searchkey)) {
453  TRACE("could not find item (%llx,%x,%llx)\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
454  return FALSE;
455  }
456 
457  if (tp.item->size < sizeof(DIR_ITEM)) {
458  ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
459  return FALSE;
460  }
461 
462  return extract_xattr(tp.item->data, tp.item->size, name, data, datalen);
463 }
464 
467 static NTSTATUS drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
470  device_extension* Vcb = DeviceObject->DeviceExtension;
471  BOOL top_level;
472 
474 
475  TRACE("close\n");
476 
477  top_level = is_top_level(Irp);
478 
479  if (DeviceObject == master_devobj) {
480  TRACE("Closing file system\n");
481  Status = STATUS_SUCCESS;
482  goto end;
483  } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
484  Status = vol_close(DeviceObject, Irp);
485  goto end;
486  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
487  Status = STATUS_INVALID_PARAMETER;
488  goto end;
489  }
490 
491  IrpSp = IoGetCurrentIrpStackLocation(Irp);
492 
493  // FIXME - unmount if called for volume
494  // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
495 
496  Status = close_file(IrpSp->FileObject, Irp);
497 
498 end:
499  Irp->IoStatus.Status = Status;
500  Irp->IoStatus.Information = 0;
501 
503 
504  if (top_level)
506 
507  TRACE("returning %08x\n", Status);
508 
510 
511  return Status;
512 }
513 
516 static NTSTATUS drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
520  fcb* fcb = FileObject->FsContext;
521  device_extension* Vcb = DeviceObject->DeviceExtension;
522  BOOL top_level;
523 
525 
526  TRACE("flush buffers\n");
527 
528  top_level = is_top_level(Irp);
529 
530  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
531  Status = vol_flush_buffers(DeviceObject, Irp);
532  goto end;
533  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
534  Status = STATUS_INVALID_PARAMETER;
535  goto end;
536  }
537 
538  if (!fcb) {
539  ERR("fcb was NULL\n");
540  Status = STATUS_INVALID_PARAMETER;
541  goto end;
542  }
543 
544  if (fcb == Vcb->volume_fcb) {
545  Status = STATUS_INVALID_PARAMETER;
546  goto end;
547  }
548 
549  Irp->IoStatus.Information = 0;
550 
551  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
552 
553  Status = STATUS_SUCCESS;
554  Irp->IoStatus.Status = Status;
555 
556  if (fcb->type != BTRFS_TYPE_DIRECTORY) {
557  CcFlushCache(&fcb->nonpaged->segment_object, NULL, 0, &Irp->IoStatus);
558 
559  if (fcb->Header.PagingIoResource) {
560  ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
561  ExReleaseResourceLite(fcb->Header.PagingIoResource);
562  }
563 
564  Status = Irp->IoStatus.Status;
565  }
566 
567 end:
569 
570  TRACE("returning %08x\n", Status);
571 
572  if (top_level)
574 
576 
577  return Status;
578 }
579 
581  UINT64 nfactor, dfactor, sectors_used;
582 
583  if (Vcb->data_flags & BLOCK_FLAG_DUPLICATE || Vcb->data_flags & BLOCK_FLAG_RAID1 || Vcb->data_flags & BLOCK_FLAG_RAID10) {
584  nfactor = 1;
585  dfactor = 2;
586  } else if (Vcb->data_flags & BLOCK_FLAG_RAID5) {
587  nfactor = Vcb->superblock.num_devices - 1;
588  dfactor = Vcb->superblock.num_devices;
589  } else if (Vcb->data_flags & BLOCK_FLAG_RAID6) {
590  nfactor = Vcb->superblock.num_devices - 2;
591  dfactor = Vcb->superblock.num_devices;
592  } else {
593  nfactor = 1;
594  dfactor = 1;
595  }
596 
597  sectors_used = Vcb->superblock.bytes_used / Vcb->superblock.sector_size;
598 
599  *totalsize = (Vcb->superblock.total_bytes / Vcb->superblock.sector_size) * nfactor / dfactor;
600  *freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used);
601 }
602 
603 #ifndef __REACTOS__
604 // This function exists because we have to lie about our FS type in certain situations.
605 // MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match,
606 // it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
607 // The command mklink refuses to create hard links on anything other than NTFS, so we have to
608 // blacklist cmd.exe too.
609 
613  PPEB peb;
614  LIST_ENTRY* le;
615  ULONG retlen;
616 
617  static WCHAR mpr[] = L"MPR.DLL";
618  static WCHAR cmd[] = L"CMD.EXE";
619  static WCHAR fsutil[] = L"FSUTIL.EXE";
620  UNICODE_STRING mprus, cmdus, fsutilus;
621 
622  mprus.Buffer = mpr;
623  mprus.Length = mprus.MaximumLength = (USHORT)(wcslen(mpr) * sizeof(WCHAR));
624  cmdus.Buffer = cmd;
625  cmdus.Length = cmdus.MaximumLength = (USHORT)(wcslen(cmd) * sizeof(WCHAR));
626  fsutilus.Buffer = fsutil;
627  fsutilus.Length = fsutilus.MaximumLength = (USHORT)(wcslen(fsutil) * sizeof(WCHAR));
628 
629  if (!PsGetCurrentProcess())
630  return FALSE;
631 
632  Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen);
633 
634  if (!NT_SUCCESS(Status)) {
635  ERR("ZwQueryInformationProcess returned %08x\n", Status);
636  return FALSE;
637  }
638 
639  if (!pbi.PebBaseAddress)
640  return FALSE;
641 
642  peb = pbi.PebBaseAddress;
643 
644  if (!peb->Ldr)
645  return FALSE;
646 
647  le = peb->Ldr->InMemoryOrderModuleList.Flink;
648  while (le != &peb->Ldr->InMemoryOrderModuleList) {
650  BOOL blacklist = FALSE;
651 
652  if (entry->FullDllName.Length >= mprus.Length) {
654 
655  name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - mprus.Length) / sizeof(WCHAR)];
656  name.Length = name.MaximumLength = mprus.Length;
657 
658  blacklist = FsRtlAreNamesEqual(&name, &mprus, TRUE, NULL);
659  }
660 
661  if (!blacklist && entry->FullDllName.Length >= cmdus.Length) {
663 
664  name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - cmdus.Length) / sizeof(WCHAR)];
665  name.Length = name.MaximumLength = cmdus.Length;
666 
667  blacklist = FsRtlAreNamesEqual(&name, &cmdus, TRUE, NULL);
668  }
669 
670  if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) {
672 
673  name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - fsutilus.Length) / sizeof(WCHAR)];
674  name.Length = name.MaximumLength = fsutilus.Length;
675 
676  blacklist = FsRtlAreNamesEqual(&name, &fsutilus, TRUE, NULL);
677  }
678 
679  if (blacklist) {
680  void** frames;
681  ULONG i, num_frames;
682 
683  frames = ExAllocatePoolWithTag(PagedPool, 256 * sizeof(void*), ALLOC_TAG);
684  if (!frames) {
685  ERR("out of memory\n");
686  return FALSE;
687  }
688 
689  num_frames = RtlWalkFrameChain(frames, 256, 1);
690 
691  for (i = 0; i < num_frames; i++) {
692  // entry->Reserved3[1] appears to be the image size
693  if (frames[i] >= entry->DllBase && (ULONG_PTR)frames[i] <= (ULONG_PTR)entry->DllBase + (ULONG_PTR)entry->Reserved3[1]) {
694  ExFreePool(frames);
695  return TRUE;
696  }
697  }
698 
699  ExFreePool(frames);
700  }
701 
702  le = le->Flink;
703  }
704 
705  return FALSE;
706 }
707 #endif
708 
711 static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
714  ULONG BytesCopied = 0;
715  device_extension* Vcb = DeviceObject->DeviceExtension;
716  BOOL top_level;
717 
719 
720  TRACE("query volume information\n");
721  top_level = is_top_level(Irp);
722 
723  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
724  Status = vol_query_volume_information(DeviceObject, Irp);
725  goto end;
726  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
727  Status = STATUS_INVALID_PARAMETER;
728  goto end;
729  }
730 
731  IrpSp = IoGetCurrentIrpStackLocation(Irp);
732 
733  Status = STATUS_NOT_IMPLEMENTED;
734 
735  switch (IrpSp->Parameters.QueryVolume.FsInformationClass) {
737  {
738  FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
739  BOOL overflow = FALSE;
740 #ifndef __REACTOS__
741  WCHAR* fs_name = (Irp->RequestorMode == UserMode && lie_about_fs_type()) ? L"NTFS" : L"Btrfs";
742  ULONG fs_name_len = (ULONG)wcslen(fs_name) * sizeof(WCHAR);
743 #else
744  WCHAR* fs_name = L"Btrfs";
745  ULONG fs_name_len = 5 * sizeof(WCHAR);
746 #endif
747  ULONG orig_fs_name_len = fs_name_len;
748 
749  TRACE("FileFsAttributeInformation\n");
750 
751  if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len) {
752  if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR))
753  fs_name_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + sizeof(WCHAR);
754  else
755  fs_name_len = 0;
756 
757  overflow = TRUE;
758  }
759 
764  if (Vcb->readonly)
766 
767  // should also be FILE_FILE_COMPRESSION when supported
768  data->MaximumComponentNameLength = 255; // FIXME - check
769  data->FileSystemNameLength = orig_fs_name_len;
770  RtlCopyMemory(data->FileSystemName, fs_name, fs_name_len);
771 
772  BytesCopied = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len;
773  Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
774  break;
775  }
776 
778  {
779  FILE_FS_DEVICE_INFORMATION* ffdi = Irp->AssociatedIrp.SystemBuffer;
780 
781  TRACE("FileFsDeviceInformation\n");
782 
784 
785  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
786  ffdi->Characteristics = Vcb->Vpb->RealDevice->Characteristics;
787  ExReleaseResourceLite(&Vcb->tree_lock);
788 
789  if (Vcb->readonly)
791  else
793 
794  BytesCopied = sizeof(FILE_FS_DEVICE_INFORMATION);
795  Status = STATUS_SUCCESS;
796 
797  break;
798  }
799 
801  {
802  FILE_FS_FULL_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer;
803 
804  TRACE("FileFsFullSizeInformation\n");
805 
808  ffsi->SectorsPerAllocationUnit = 1;
810 
811  BytesCopied = sizeof(FILE_FS_FULL_SIZE_INFORMATION);
812  Status = STATUS_SUCCESS;
813 
814  break;
815  }
816 
818  {
819  FILE_FS_OBJECTID_INFORMATION* ffoi = Irp->AssociatedIrp.SystemBuffer;
820 
821  TRACE("FileFsObjectIdInformation\n");
822 
823  RtlCopyMemory(ffoi->ObjectId, &Vcb->superblock.uuid.uuid[0], sizeof(UCHAR) * 16);
824  RtlZeroMemory(ffoi->ExtendedInfo, sizeof(ffoi->ExtendedInfo));
825 
826  BytesCopied = sizeof(FILE_FS_OBJECTID_INFORMATION);
827  Status = STATUS_SUCCESS;
828 
829  break;
830  }
831 
833  {
834  FILE_FS_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer;
835 
836  TRACE("FileFsSizeInformation\n");
837 
839  ffsi->SectorsPerAllocationUnit = 1;
841 
842  BytesCopied = sizeof(FILE_FS_SIZE_INFORMATION);
843  Status = STATUS_SUCCESS;
844 
845  break;
846  }
847 
849  {
850  FILE_FS_VOLUME_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
852  BOOL overflow = FALSE;
853  ULONG label_len, orig_label_len;
854 
855  TRACE("FileFsVolumeInformation\n");
856  TRACE("max length = %u\n", IrpSp->Parameters.QueryVolume.Length);
857 
858  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
859 
860  Status = RtlUTF8ToUnicodeN(NULL, 0, &label_len, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
861  if (!NT_SUCCESS(Status)) {
862  ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
863  ExReleaseResourceLite(&Vcb->tree_lock);
864  break;
865  }
866 
867  orig_label_len = label_len;
868 
869  if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len) {
870  if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR))
871  label_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_VOLUME_INFORMATION) + sizeof(WCHAR);
872  else
873  label_len = 0;
874 
875  overflow = TRUE;
876  }
877 
878  TRACE("label_len = %u\n", label_len);
879 
880  ffvi.VolumeCreationTime.QuadPart = 0; // FIXME
881  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];
882  ffvi.VolumeLabelLength = orig_label_len;
883  ffvi.SupportsObjects = FALSE;
884 
885  RtlCopyMemory(data, &ffvi, min(sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR), IrpSp->Parameters.QueryVolume.Length));
886 
887  if (label_len > 0) {
888  ULONG bytecount;
889 
890  Status = RtlUTF8ToUnicodeN(&data->VolumeLabel[0], label_len, &bytecount, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label));
891  if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) {
892  ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
893  ExReleaseResourceLite(&Vcb->tree_lock);
894  break;
895  }
896 
897  TRACE("label = %.*S\n", label_len / sizeof(WCHAR), data->VolumeLabel);
898  }
899 
900  ExReleaseResourceLite(&Vcb->tree_lock);
901 
902  BytesCopied = sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len;
903  Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
904  break;
905  }
906 
907 #ifndef __REACTOS__
908 #ifdef _MSC_VER // not in mingw yet
909  case FileFsSectorSizeInformation:
910  {
911  FILE_FS_SECTOR_SIZE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
912 
913  data->LogicalBytesPerSector = Vcb->superblock.sector_size;
914  data->PhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size;
915  data->PhysicalBytesPerSectorForPerformance = Vcb->superblock.sector_size;
916  data->FileSystemEffectivePhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size;
917  data->ByteOffsetForSectorAlignment = 0;
918  data->ByteOffsetForPartitionAlignment = 0;
919 
920  data->Flags = SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE;
921 
922  if (Vcb->trim && !Vcb->options.no_trim)
923  data->Flags |= SSINFO_FLAGS_TRIM_ENABLED;
924 
925  BytesCopied = sizeof(FILE_FS_SECTOR_SIZE_INFORMATION);
926 
927  break;
928  }
929 #endif
930 #endif /* __REACTOS__ */
931 
932  default:
933  Status = STATUS_INVALID_PARAMETER;
934  WARN("unknown FsInformationClass %u\n", IrpSp->Parameters.QueryVolume.FsInformationClass);
935  break;
936  }
937 
938  if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
939  Irp->IoStatus.Information = 0;
940  else
941  Irp->IoStatus.Information = BytesCopied;
942 
943 end:
944  Irp->IoStatus.Status = Status;
945 
947 
948  if (top_level)
950 
951  TRACE("query volume information returning %08x\n", Status);
952 
954 
955  return Status;
956 }
957 
958 _Function_class_(IO_COMPLETION_ROUTINE)
959 #ifdef __REACTOS__
960 static NTSTATUS NTAPI read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) {
961 #else
962 static NTSTATUS read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) {
963 #endif
964  read_context* context = conptr;
965 
966  UNUSED(DeviceObject);
967 
968  context->iosb = Irp->IoStatus;
969  KeSetEvent(&context->Event, 0, FALSE);
970 
972 }
973 
975  _Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset, _In_opt_ PIRP Irp) {
977  root* r;
978  tree* t = NULL;
979  ROOT_ITEM* ri;
981 
983  if (!r) {
984  ERR("out of memory\n");
986  }
987 
989  if (!r->nonpaged) {
990  ERR("out of memory\n");
991  ExFreePool(r);
993  }
994 
995  if (!no_tree) {
997  if (!t) {
998  ERR("out of memory\n");
999  ExFreePool(r->nonpaged);
1000  ExFreePool(r);
1002  }
1003 
1004  t->is_unique = TRUE;
1006  t->buf = NULL;
1007  }
1008 
1010  if (!ri) {
1011  ERR("out of memory\n");
1012 
1013  if (t)
1014  ExFreePool(t);
1015 
1016  ExFreePool(r->nonpaged);
1017  ExFreePool(r);
1019  }
1020 
1021  r->id = id;
1022  r->treeholder.address = 0;
1024  r->treeholder.tree = t;
1025  r->lastinode = 0;
1026  r->dirty = FALSE;
1027  r->received = FALSE;
1028  r->reserved = NULL;
1029  r->parent = 0;
1030  r->send_ops = 0;
1031  RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
1032  r->root_item.num_references = 1;
1033  InitializeListHead(&r->fcbs);
1034 
1035  RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM));
1036 
1037  // We ask here for a traverse_ptr to the item we're inserting, so we can
1038  // copy some of the tree's variables
1039 
1040  Status = insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp);
1041  if (!NT_SUCCESS(Status)) {
1042  ERR("insert_tree_item returned %08x\n", Status);
1043  ExFreePool(ri);
1044 
1045  if (t)
1046  ExFreePool(t);
1047 
1048  ExFreePool(r->nonpaged);
1049  ExFreePool(r);
1050  return Status;
1051  }
1052 
1054 
1055  InsertTailList(&Vcb->roots, &r->list_entry);
1056 
1057  if (!no_tree) {
1058  RtlZeroMemory(&t->header, sizeof(tree_header));
1059  t->header.fs_uuid = tp.tree->header.fs_uuid;
1060  t->header.address = 0;
1061  t->header.flags = HEADER_FLAG_MIXED_BACKREF | 1; // 1 == "written"? Why does the Linux driver record this?
1064  t->header.tree_id = id;
1065  t->header.num_items = 0;
1066  t->header.level = 0;
1067 
1068  t->has_address = FALSE;
1069  t->size = 0;
1070  t->Vcb = Vcb;
1071  t->parent = NULL;
1072  t->paritem = NULL;
1073  t->root = r;
1074 
1076 
1077  t->new_address = 0;
1078  t->has_new_address = FALSE;
1079  t->updated_extents = FALSE;
1080 
1081  InsertTailList(&Vcb->trees, &t->list_entry);
1082  t->list_entry_hash.Flink = NULL;
1083 
1084  t->write = TRUE;
1085  Vcb->need_write = TRUE;
1086  }
1087 
1088  *rootptr = r;
1089 
1090  return STATUS_SUCCESS;
1091 }
1092 
1094  ULONG utf8len;
1095  NTSTATUS Status;
1096  ULONG vollen, i;
1097 
1098  TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel);
1099 
1100  vollen = ffli->VolumeLabelLength;
1101 
1102  for (i = 0; i < ffli->VolumeLabelLength / sizeof(WCHAR); i++) {
1103  if (ffli->VolumeLabel[i] == 0) {
1104  vollen = i * sizeof(WCHAR);
1105  break;
1106  } else if (ffli->VolumeLabel[i] == '/' || ffli->VolumeLabel[i] == '\\') {
1107  Status = STATUS_INVALID_VOLUME_LABEL;
1108  goto end;
1109  }
1110  }
1111 
1112  if (vollen == 0) {
1113  utf8len = 0;
1114  } else {
1115  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, vollen);
1116  if (!NT_SUCCESS(Status))
1117  goto end;
1118 
1119  if (utf8len > MAX_LABEL_SIZE) {
1120  Status = STATUS_INVALID_VOLUME_LABEL;
1121  goto end;
1122  }
1123  }
1124 
1125  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1126 
1127  if (utf8len > 0) {
1128  Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE, &utf8len, ffli->VolumeLabel, vollen);
1129  if (!NT_SUCCESS(Status))
1130  goto release;
1131  } else
1132  Status = STATUS_SUCCESS;
1133 
1134  if (utf8len < MAX_LABEL_SIZE)
1135  RtlZeroMemory(Vcb->superblock.label + utf8len, MAX_LABEL_SIZE - utf8len);
1136 
1137  Vcb->need_write = TRUE;
1138 
1139 release:
1140  ExReleaseResourceLite(&Vcb->tree_lock);
1141 
1142 end:
1143  TRACE("returning %08x\n", Status);
1144 
1145  return Status;
1146 }
1147 
1150 static NTSTATUS drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
1152  device_extension* Vcb = DeviceObject->DeviceExtension;
1153  NTSTATUS Status;
1154  BOOL top_level;
1155 
1157 
1158  TRACE("set volume information\n");
1159 
1160  top_level = is_top_level(Irp);
1161 
1162  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
1163  Status = vol_set_volume_information(DeviceObject, Irp);
1164  goto end;
1165  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
1166  Status = STATUS_INVALID_PARAMETER;
1167  goto end;
1168  }
1169 
1170  Status = STATUS_NOT_IMPLEMENTED;
1171 
1172  if (Vcb->readonly) {
1174  goto end;
1175  }
1176 
1177  if (Vcb->removing || Vcb->locked) {
1178  Status = STATUS_ACCESS_DENIED;
1179  goto end;
1180  }
1181 
1182  switch (IrpSp->Parameters.SetVolume.FsInformationClass) {
1184  FIXME("STUB: FileFsControlInformation\n");
1185  break;
1186 
1188  TRACE("FileFsLabelInformation\n");
1189 
1190  Status = set_label(Vcb, Irp->AssociatedIrp.SystemBuffer);
1191  break;
1192 
1194  FIXME("STUB: FileFsObjectIdInformation\n");
1195  break;
1196 
1197  default:
1198  WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp->Parameters.SetVolume.FsInformationClass);
1199  break;
1200  }
1201 
1202 end:
1203  Irp->IoStatus.Status = Status;
1204  Irp->IoStatus.Information = 0;
1205 
1206  TRACE("returning %08x\n", Status);
1207 
1209 
1210  if (top_level)
1212 
1214 
1215  return Status;
1216 }
1217 
1219  char s[60];
1220  NTSTATUS Status;
1222  ANSI_STRING as;
1223 
1224  if (fcb->debug_desc)
1225  return fcb->debug_desc;
1226 
1227  if (fcb == fcb->Vcb->volume_fcb)
1228  return L"volume FCB";
1229 
1230  fcb->debug_desc = ExAllocatePoolWithTag(PagedPool, 60 * sizeof(WCHAR), ALLOC_TAG);
1231  if (!fcb->debug_desc)
1232  return L"(memory error)";
1233 
1234  // I know this is pretty hackish...
1235  // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
1236  // without the CRT, which breaks drivers.
1237 
1238  sprintf(s, "subvol %x, inode %x", (UINT32)fcb->subvol->id, (UINT32)fcb->inode);
1239 
1240  as.Buffer = s;
1241  as.Length = as.MaximumLength = (USHORT)strlen(s);
1242 
1243  us.Buffer = fcb->debug_desc;
1244  us.MaximumLength = 60 * sizeof(WCHAR);
1245  us.Length = 0;
1246 
1247  Status = RtlAnsiStringToUnicodeString(&us, &as, FALSE);
1248  if (!NT_SUCCESS(Status))
1249  return L"(RtlAnsiStringToUnicodeString error)";
1250 
1251  us.Buffer[us.Length / sizeof(WCHAR)] = 0;
1252 
1253  return fcb->debug_desc;
1254 }
1255 
1257  NTSTATUS Status;
1259  ULONG reqlen;
1260 
1261  if (fileref->debug_desc)
1262  return fileref->debug_desc;
1263 
1264  fn.Length = fn.MaximumLength = 0;
1265  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1266  if (Status != STATUS_BUFFER_OVERFLOW)
1267  return L"ERROR";
1268 
1269  if (reqlen > 0xffff - sizeof(WCHAR))
1270  return L"(too long)";
1271 
1272  fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG);
1273  if (!fileref->debug_desc)
1274  return L"(memory error)";
1275 
1276  fn.Buffer = fileref->debug_desc;
1277  fn.Length = 0;
1278  fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR));
1279 
1280  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1281  if (!NT_SUCCESS(Status)) {
1282  ExFreePool(fileref->debug_desc);
1283  fileref->debug_desc = NULL;
1284  return L"ERROR";
1285  }
1286 
1287  fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0;
1288 
1289  return fileref->debug_desc;
1290 }
1291 
1292 _Ret_z_
1294  fcb* fcb = FileObject->FsContext;
1295  ccb* ccb = FileObject->FsContext2;
1296  file_ref* fileref = ccb ? ccb->fileref : NULL;
1297 
1298  if (fileref)
1299  return file_desc_fileref(fileref);
1300  else
1301  return file_desc_fcb(fcb);
1302 }
1303 
1306  NTSTATUS Status;
1307  ULONG reqlen;
1308  USHORT name_offset;
1309  fcb* fcb = fileref->fcb;
1310 
1311  fn.Length = fn.MaximumLength = 0;
1312  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
1313  if (Status != STATUS_BUFFER_OVERFLOW) {
1314  ERR("fileref_get_filename returned %08x\n", Status);
1315  return;
1316  }
1317 
1318  if (reqlen > 0xffff) {
1319  WARN("reqlen was too long for FsRtlNotifyFilterReportChange\n");
1320  return;
1321  }
1322 
1324  if (!fn.Buffer) {
1325  ERR("out of memory\n");
1326  return;
1327  }
1328 
1329  fn.MaximumLength = (USHORT)reqlen;
1330  fn.Length = 0;
1331 
1332  Status = fileref_get_filename(fileref, &fn, &name_offset, &reqlen);
1333  if (!NT_SUCCESS(Status)) {
1334  ERR("fileref_get_filename returned %08x\n", Status);
1335  ExFreePool(fn.Buffer);
1336  return;
1337  }
1338 
1339  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, name_offset,
1340  (PSTRING)stream, NULL, filter_match, action, NULL, NULL);
1341  ExFreePool(fn.Buffer);
1342 }
1343 
1345  fcb* fcb = fileref->fcb;
1346  LIST_ENTRY* le;
1347  NTSTATUS Status;
1348 
1349  // no point looking for hardlinks if st_nlink == 1
1350  if (fileref->fcb->inode_item.st_nlink == 1) {
1351  send_notification_fileref(fileref, filter_match, action, stream);
1352  return;
1353  }
1354 
1355  acquire_fcb_lock_exclusive(fcb->Vcb);
1356 
1357  le = fcb->hardlinks.Flink;
1358  while (le != &fcb->hardlinks) {
1360  file_ref* parfr;
1361 
1362  Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL);
1363 
1364  if (!NT_SUCCESS(Status))
1365  ERR("open_fileref_by_inode returned %08x\n", Status);
1366  else if (!parfr->deleted) {
1368  ULONG pathlen;
1369 
1370  fn.Length = fn.MaximumLength = 0;
1371  Status = fileref_get_filename(parfr, &fn, NULL, &pathlen);
1372  if (Status != STATUS_BUFFER_OVERFLOW) {
1373  ERR("fileref_get_filename returned %08x\n", Status);
1374  free_fileref(fcb->Vcb, parfr);
1375  break;
1376  }
1377 
1378  if (parfr != fcb->Vcb->root_fileref)
1379  pathlen += sizeof(WCHAR);
1380 
1381  if (pathlen + hl->name.Length > 0xffff) {
1382  WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n");
1383  free_fileref(fcb->Vcb, parfr);
1384  break;
1385  }
1386 
1387  fn.MaximumLength = (USHORT)(pathlen + hl->name.Length);
1389  if (!fn.Buffer) {
1390  ERR("out of memory\n");
1391  free_fileref(fcb->Vcb, parfr);
1392  break;
1393  }
1394 
1395  Status = fileref_get_filename(parfr, &fn, NULL, NULL);
1396  if (!NT_SUCCESS(Status)) {
1397  ERR("fileref_get_filename returned %08x\n", Status);
1398  free_fileref(fcb->Vcb, parfr);
1399  ExFreePool(fn.Buffer);
1400  break;
1401  }
1402 
1403  if (parfr != fcb->Vcb->root_fileref) {
1404  fn.Buffer[(pathlen / sizeof(WCHAR)) - 1] = '\\';
1405  fn.Length += sizeof(WCHAR);
1406  }
1407 
1408  RtlCopyMemory(&fn.Buffer[pathlen / sizeof(WCHAR)], hl->name.Buffer, hl->name.Length);
1409  fn.Length += hl->name.Length;
1410 
1411  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, (USHORT)pathlen,
1412  (PSTRING)stream, NULL, filter_match, action, NULL, NULL);
1413 
1414  ExFreePool(fn.Buffer);
1415 
1416  free_fileref(fcb->Vcb, parfr);
1417  }
1418 
1419  le = le->Flink;
1420  }
1421 
1422  release_fcb_lock(fcb->Vcb);
1423 }
1424 
1426  if (!fcb->dirty) {
1427 #ifdef DEBUG_FCB_REFCOUNTS
1428  LONG rc;
1429 #endif
1430  fcb->dirty = TRUE;
1431 
1432 #ifdef DEBUG_FCB_REFCOUNTS
1433  rc = InterlockedIncrement(&fcb->refcount);
1434  WARN("fcb %p: refcount now %i\n", fcb, rc);
1435 #else
1436  InterlockedIncrement(&fcb->refcount);
1437 #endif
1438 
1439  ExAcquireResourceExclusiveLite(&fcb->Vcb->dirty_fcbs_lock, TRUE);
1440  InsertTailList(&fcb->Vcb->dirty_fcbs, &fcb->list_entry_dirty);
1441  ExReleaseResourceLite(&fcb->Vcb->dirty_fcbs_lock);
1442  }
1443 
1444  fcb->Vcb->need_write = TRUE;
1445 }
1446 
1448  if (!fileref->dirty) {
1449  fileref->dirty = TRUE;
1450  increase_fileref_refcount(fileref);
1451 
1452  ExAcquireResourceExclusiveLite(&fileref->fcb->Vcb->dirty_filerefs_lock, TRUE);
1453  InsertTailList(&fileref->fcb->Vcb->dirty_filerefs, &fileref->list_entry_dirty);
1454  ExReleaseResourceLite(&fileref->fcb->Vcb->dirty_filerefs_lock);
1455  }
1456 
1457  fileref->fcb->Vcb->need_write = TRUE;
1458 }
1459 
1460 #ifdef DEBUG_FCB_REFCOUNTS
1461 void _free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb, _In_ const char* func) {
1462 #else
1463 void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb) {
1464 #endif
1465  LONG rc;
1466 
1467  rc = InterlockedDecrement(&fcb->refcount);
1468 
1469 #ifdef DEBUG_FCB_REFCOUNTS
1470 #ifdef DEBUG_LONG_MESSAGES
1471  ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
1472 #else
1473  ERR("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode);
1474 #endif
1475 #endif
1476 
1477  if (rc > 0)
1478  return;
1479 
1480  if (fcb->list_entry.Flink)
1481  RemoveEntryList(&fcb->list_entry);
1482 
1483  if (fcb->list_entry_all.Flink)
1484  RemoveEntryList(&fcb->list_entry_all);
1485 
1486  ExDeleteResourceLite(&fcb->nonpaged->resource);
1487  ExDeleteResourceLite(&fcb->nonpaged->paging_resource);
1488  ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock);
1489 
1490  ExFreeToNPagedLookasideList(&Vcb->fcb_np_lookaside, fcb->nonpaged);
1491 
1492  if (fcb->sd)
1493  ExFreePool(fcb->sd);
1494 
1495  if (fcb->adsxattr.Buffer)
1496  ExFreePool(fcb->adsxattr.Buffer);
1497 
1498  if (fcb->reparse_xattr.Buffer)
1499  ExFreePool(fcb->reparse_xattr.Buffer);
1500 
1501  if (fcb->ea_xattr.Buffer)
1502  ExFreePool(fcb->ea_xattr.Buffer);
1503 
1504  if (fcb->adsdata.Buffer)
1505  ExFreePool(fcb->adsdata.Buffer);
1506 
1507  if (fcb->debug_desc)
1508  ExFreePool(fcb->debug_desc);
1509 
1510  while (!IsListEmpty(&fcb->extents)) {
1511  LIST_ENTRY* le = RemoveHeadList(&fcb->extents);
1513 
1514  if (ext->csum)
1515  ExFreePool(ext->csum);
1516 
1517  ExFreePool(ext);
1518  }
1519 
1520  while (!IsListEmpty(&fcb->hardlinks)) {
1521  LIST_ENTRY* le = RemoveHeadList(&fcb->hardlinks);
1523 
1524  if (hl->name.Buffer)
1525  ExFreePool(hl->name.Buffer);
1526 
1527  if (hl->utf8.Buffer)
1528  ExFreePool(hl->utf8.Buffer);
1529 
1530  ExFreePool(hl);
1531  }
1532 
1533  while (!IsListEmpty(&fcb->xattrs)) {
1534  xattr* xa = CONTAINING_RECORD(RemoveHeadList(&fcb->xattrs), xattr, list_entry);
1535 
1536  ExFreePool(xa);
1537  }
1538 
1539  while (!IsListEmpty(&fcb->dir_children_index)) {
1540  LIST_ENTRY* le = RemoveHeadList(&fcb->dir_children_index);
1541  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
1542 
1543  ExFreePool(dc->utf8.Buffer);
1544  ExFreePool(dc->name.Buffer);
1545  ExFreePool(dc->name_uc.Buffer);
1546  ExFreePool(dc);
1547  }
1548 
1549  if (fcb->hash_ptrs)
1550  ExFreePool(fcb->hash_ptrs);
1551 
1552  if (fcb->hash_ptrs_uc)
1553  ExFreePool(fcb->hash_ptrs_uc);
1554 
1555  FsRtlUninitializeFileLock(&fcb->lock);
1556 
1557  if (fcb->pool_type == NonPagedPool)
1558  ExFreePool(fcb);
1559  else
1560  ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb);
1561 
1562 #ifdef DEBUG_FCB_REFCOUNTS
1563 #ifdef DEBUG_LONG_MESSAGES
1564  _debug_message(func, file, line, "freeing fcb %p\n", fcb);
1565 #else
1566  _debug_message(func, "freeing fcb %p\n", fcb);
1567 #endif
1568 #endif
1569 }
1570 
1572  LONG rc;
1573 
1574  rc = InterlockedDecrement(&fr->refcount);
1575 
1576 #ifdef DEBUG_FCB_REFCOUNTS
1577  ERR("fileref %p: refcount now %i\n", fr, rc);
1578 #endif
1579 
1580 #ifdef _DEBUG
1581  if (rc < 0) {
1582  ERR("fileref %p: refcount now %i\n", fr, rc);
1583  int3;
1584  }
1585 #endif
1586 
1587  if (rc > 0)
1588  return;
1589 
1590  if (fr->parent)
1591  ExAcquireResourceExclusiveLite(&fr->parent->nonpaged->children_lock, TRUE);
1592 
1593  // FIXME - do we need a file_ref lock?
1594 
1595  // FIXME - do delete if needed
1596 
1597  if (fr->debug_desc)
1598  ExFreePool(fr->debug_desc);
1599 
1600  ExDeleteResourceLite(&fr->nonpaged->children_lock);
1601  ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
1602 
1603  ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
1604 
1605  // FIXME - throw error if children not empty
1606 
1607  if (fr->fcb->fileref == fr)
1608  fr->fcb->fileref = NULL;
1609 
1610  if (fr->dc) {
1611  if (fr->fcb->ads)
1612  fr->dc->size = fr->fcb->adsdata.Length;
1613 
1614  fr->dc->fileref = NULL;
1615  }
1616 
1617  if (fr->list_entry.Flink)
1618  RemoveEntryList(&fr->list_entry);
1619 
1620  if (fr->parent) {
1621  ExReleaseResourceLite(&fr->parent->nonpaged->children_lock);
1622  free_fileref(Vcb, fr->parent);
1623  }
1624 
1625  free_fcb(Vcb, fr->fcb);
1626 
1627  ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
1628 }
1629 
1631  fcb* fcb;
1632  ccb* ccb;
1633  file_ref* fileref = NULL;
1634  LONG open_files;
1636 
1637  UNUSED(Irp);
1638 
1639  TRACE("FileObject = %p\n", FileObject);
1640 
1641  fcb = FileObject->FsContext;
1642  if (!fcb) {
1643  TRACE("FCB was NULL, returning success\n");
1644  return STATUS_SUCCESS;
1645  }
1646 
1647  open_files = InterlockedDecrement(&fcb->Vcb->open_files);
1648 
1649  ccb = FileObject->FsContext2;
1650 
1651  TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb);
1652 
1653  // FIXME - make sure notification gets sent if file is being deleted
1654 
1655  if (ccb) {
1656  if (ccb->query_string.Buffer)
1658 
1659  if (ccb->filename.Buffer)
1660  ExFreePool(ccb->filename.Buffer);
1661 
1662  // FIXME - use refcounts for fileref
1663  fileref = ccb->fileref;
1664 
1665  if (fcb->Vcb->running_sends > 0) {
1666  BOOL send_cancelled = FALSE;
1667 
1668  ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE);
1669 
1670  if (ccb->send) {
1671  ccb->send->cancelling = TRUE;
1672  send_cancelled = TRUE;
1673  KeSetEvent(&ccb->send->cleared_event, 0, FALSE);
1674  }
1675 
1676  ExReleaseResourceLite(&fcb->Vcb->send_load_lock);
1677 
1678  if (send_cancelled) {
1679  while (ccb->send) {
1680  ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE);
1681  ExReleaseResourceLite(&fcb->Vcb->send_load_lock);
1682  }
1683  }
1684  }
1685 
1686  ExFreePool(ccb);
1687  }
1688 
1689  CcUninitializeCacheMap(FileObject, NULL, NULL);
1690 
1691  if (open_files == 0 && fcb->Vcb->removing) {
1692  uninit(fcb->Vcb, FALSE);
1693  return STATUS_SUCCESS;
1694  }
1695 
1696  if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED))
1697  return STATUS_SUCCESS;
1698 
1699  Vcb = fcb->Vcb;
1700 
1701  acquire_fcb_lock_exclusive(Vcb);
1702 
1703  if (fileref)
1704  free_fileref(fcb->Vcb, fileref);
1705  else
1706  free_fcb(Vcb, fcb);
1707 
1708  release_fcb_lock(Vcb);
1709 
1710  return STATUS_SUCCESS;
1711 }
1712 
1714  UINT64 i;
1715  NTSTATUS Status;
1716  LIST_ENTRY* le;
1718 
1719  if (!Vcb->removing) {
1720  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1721  Vcb->removing = TRUE;
1722  ExReleaseResourceLite(&Vcb->tree_lock);
1723  }
1724 
1725  RemoveEntryList(&Vcb->list_entry);
1726 
1727  if (Vcb->balance.thread) {
1728  Vcb->balance.paused = FALSE;
1729  Vcb->balance.stopping = TRUE;
1730  KeSetEvent(&Vcb->balance.event, 0, FALSE);
1731  KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL);
1732  }
1733 
1734  if (Vcb->scrub.thread) {
1735  Vcb->scrub.paused = FALSE;
1736  Vcb->scrub.stopping = TRUE;
1737  KeSetEvent(&Vcb->scrub.event, 0, FALSE);
1738  KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL);
1739  }
1740 
1741  if (Vcb->running_sends != 0) {
1742  BOOL send_cancelled = FALSE;
1743 
1744  ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
1745 
1746  le = Vcb->send_ops.Flink;
1747  while (le != &Vcb->send_ops) {
1749 
1750  if (!send->cancelling) {
1751  send->cancelling = TRUE;
1752  send_cancelled = TRUE;
1753  send->ccb = NULL;
1754  KeSetEvent(&send->cleared_event, 0, FALSE);
1755  }
1756 
1757  le = le->Flink;
1758  }
1759 
1760  ExReleaseResourceLite(&Vcb->send_load_lock);
1761 
1762  if (send_cancelled) {
1763  while (Vcb->running_sends != 0) {
1764  ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
1765  ExReleaseResourceLite(&Vcb->send_load_lock);
1766  }
1767  }
1768  }
1769 
1770  Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid);
1771  if (!NT_SUCCESS(Status) && Status != STATUS_TOO_LATE)
1772  WARN("registry_mark_volume_unmounted returned %08x\n", Status);
1773 
1774  if (flush) {
1775  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1776 
1777  if (Vcb->need_write && !Vcb->readonly) {
1778  Status = do_write(Vcb, NULL);
1779  if (!NT_SUCCESS(Status))
1780  ERR("do_write returned %08x\n", Status);
1781  }
1782 
1783  free_trees(Vcb);
1784 
1785  ExReleaseResourceLite(&Vcb->tree_lock);
1786  }
1787 
1788  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
1789  Vcb->calcthreads.threads[i].quit = TRUE;
1790  }
1791 
1792  KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
1793 
1794  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
1795  KeWaitForSingleObject(&Vcb->calcthreads.threads[i].finished, Executive, KernelMode, FALSE, NULL);
1796 
1797  ZwClose(Vcb->calcthreads.threads[i].handle);
1798  }
1799 
1800  ExDeleteResourceLite(&Vcb->calcthreads.lock);
1801  ExFreePool(Vcb->calcthreads.threads);
1802 
1803  time.QuadPart = 0;
1804  KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early
1805  KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
1806 
1807  acquire_fcb_lock_exclusive(Vcb);
1808  free_fcb(Vcb, Vcb->volume_fcb);
1809  free_fcb(Vcb, Vcb->dummy_fcb);
1810  release_fcb_lock(Vcb);
1811 
1812  if (Vcb->root_file)
1813  ObDereferenceObject(Vcb->root_file);
1814 
1815  le = Vcb->chunks.Flink;
1816  while (le != &Vcb->chunks) {
1818 
1819  if (c->cache) {
1820  acquire_fcb_lock_exclusive(Vcb);
1821  free_fcb(Vcb, c->cache);
1822  release_fcb_lock(Vcb);
1823  c->cache = NULL;
1824  }
1825 
1826  le = le->Flink;
1827  }
1828 
1829  while (!IsListEmpty(&Vcb->roots)) {
1831 
1833  ExFreePool(r->nonpaged);
1834  ExFreePool(r);
1835  }
1836 
1837  while (!IsListEmpty(&Vcb->chunks)) {
1839 
1840  while (!IsListEmpty(&c->space)) {
1841  LIST_ENTRY* le2 = RemoveHeadList(&c->space);
1843 
1844  ExFreePool(s);
1845  }
1846 
1847  while (!IsListEmpty(&c->deleting)) {
1848  LIST_ENTRY* le2 = RemoveHeadList(&c->deleting);
1850 
1851  ExFreePool(s);
1852  }
1853 
1854  if (c->devices)
1855  ExFreePool(c->devices);
1856 
1857  if (c->cache) {
1858  acquire_fcb_lock_exclusive(Vcb);
1859  free_fcb(Vcb, c->cache);
1860  release_fcb_lock(Vcb);
1861  }
1862 
1867 
1868  ExFreePool(c->chunk_item);
1869  ExFreePool(c);
1870  }
1871 
1872  // FIXME - free any open fcbs?
1873 
1874  while (!IsListEmpty(&Vcb->devices)) {
1876 
1877  while (!IsListEmpty(&dev->space)) {
1878  LIST_ENTRY* le2 = RemoveHeadList(&dev->space);
1880 
1881  ExFreePool(s);
1882  }
1883 
1884  ExFreePool(dev);
1885  }
1886 
1887  ExAcquireResourceExclusiveLite(&Vcb->scrub.stats_lock, TRUE);
1888  while (!IsListEmpty(&Vcb->scrub.errors)) {
1890 
1891  ExFreePool(err);
1892  }
1893  ExReleaseResourceLite(&Vcb->scrub.stats_lock);
1894 
1895  ExDeleteResourceLite(&Vcb->fcb_lock);
1896  ExDeleteResourceLite(&Vcb->load_lock);
1897  ExDeleteResourceLite(&Vcb->tree_lock);
1898  ExDeleteResourceLite(&Vcb->chunk_lock);
1899  ExDeleteResourceLite(&Vcb->dirty_fcbs_lock);
1900  ExDeleteResourceLite(&Vcb->dirty_filerefs_lock);
1901  ExDeleteResourceLite(&Vcb->dirty_subvols_lock);
1902  ExDeleteResourceLite(&Vcb->scrub.stats_lock);
1903  ExDeleteResourceLite(&Vcb->send_load_lock);
1904 
1905  ExDeletePagedLookasideList(&Vcb->tree_data_lookaside);
1906  ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside);
1907  ExDeletePagedLookasideList(&Vcb->batch_item_lookaside);
1908  ExDeletePagedLookasideList(&Vcb->fileref_lookaside);
1909  ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
1910  ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
1911  ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
1912  ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
1913  ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
1914 
1915  ZwClose(Vcb->flush_thread_handle);
1916 }
1917 
1919  LARGE_INTEGER newlength, time;
1920  BTRFS_TIME now;
1921  NTSTATUS Status;
1922  ULONG utf8len = 0;
1923 
1924  KeQuerySystemTime(&time);
1925  win_time_to_unix(time, &now);
1926 
1927  ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE);
1928 
1929  if (fileref->deleted) {
1930  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1931  return STATUS_SUCCESS;
1932  }
1933 
1934  if (fileref->fcb->subvol->send_ops > 0) {
1935  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1936  return STATUS_ACCESS_DENIED;
1937  }
1938 
1939  fileref->deleted = TRUE;
1940  mark_fileref_dirty(fileref);
1941 
1942  // delete INODE_ITEM (0x1)
1943 
1944  TRACE("nlink = %u\n", fileref->fcb->inode_item.st_nlink);
1945 
1946  if (!fileref->fcb->ads) {
1947  if (fileref->parent->fcb->subvol == fileref->fcb->subvol) {
1948  LIST_ENTRY* le;
1949 
1950  mark_fcb_dirty(fileref->fcb);
1951 
1952  fileref->fcb->inode_item_changed = TRUE;
1953 
1954  if (fileref->fcb->inode_item.st_nlink > 1) {
1955  fileref->fcb->inode_item.st_nlink--;
1956  fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
1957  fileref->fcb->inode_item.sequence++;
1958  fileref->fcb->inode_item.st_ctime = now;
1959  } else {
1960  // excise extents
1961 
1962  if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) {
1963  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);
1964  if (!NT_SUCCESS(Status)) {
1965  ERR("excise_extents returned %08x\n", Status);
1966  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1967  return Status;
1968  }
1969  }
1970 
1971  fileref->fcb->Header.AllocationSize.QuadPart = 0;
1972  fileref->fcb->Header.FileSize.QuadPart = 0;
1973  fileref->fcb->Header.ValidDataLength.QuadPart = 0;
1974 
1975  if (FileObject) {
1976  CC_FILE_SIZES ccfs;
1977 
1978  ccfs.AllocationSize = fileref->fcb->Header.AllocationSize;
1979  ccfs.FileSize = fileref->fcb->Header.FileSize;
1980  ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength;
1981 
1982  Status = STATUS_SUCCESS;
1983 
1984  _SEH2_TRY {
1985  CcSetFileSizes(FileObject, &ccfs);
1987  Status = _SEH2_GetExceptionCode();
1988  } _SEH2_END;
1989 
1990  if (!NT_SUCCESS(Status)) {
1991  ERR("CcSetFileSizes threw exception %08x\n", Status);
1992  ExReleaseResourceLite(fileref->fcb->Header.Resource);
1993  return Status;
1994  }
1995  }
1996 
1997  fileref->fcb->deleted = TRUE;
1998 
1999  le = fileref->children.Flink;
2000  while (le != &fileref->children) {
2002 
2003  if (fr2->fcb->ads) {
2004  fr2->fcb->deleted = TRUE;
2005  mark_fcb_dirty(fr2->fcb);
2006  }
2007 
2008  le = le->Flink;
2009  }
2010  }
2011 
2012  if (fileref->dc) {
2013  le = fileref->fcb->hardlinks.Flink;
2014  while (le != &fileref->fcb->hardlinks) {
2016 
2017  if (hl->parent == fileref->parent->fcb->inode && hl->index == fileref->dc->index) {
2019 
2020  if (hl->name.Buffer)
2021  ExFreePool(hl->name.Buffer);
2022 
2023  if (hl->utf8.Buffer)
2024  ExFreePool(hl->utf8.Buffer);
2025 
2026  ExFreePool(hl);
2027  break;
2028  }
2029 
2030  le = le->Flink;
2031  }
2032  }
2033  } else if (fileref->fcb->subvol->parent == fileref->parent->fcb->subvol->id) { // valid subvolume
2034  if (fileref->fcb->subvol->root_item.num_references > 1) {
2035  fileref->fcb->subvol->root_item.num_references--;
2036 
2037  mark_fcb_dirty(fileref->fcb); // so ROOT_ITEM gets updated
2038  } else {
2039  LIST_ENTRY* le;
2040 
2041  // FIXME - we need a lock here
2042 
2043  RemoveEntryList(&fileref->fcb->subvol->list_entry);
2044 
2045  InsertTailList(&fileref->fcb->Vcb->drop_roots, &fileref->fcb->subvol->list_entry);
2046 
2047  le = fileref->children.Flink;
2048  while (le != &fileref->children) {
2050 
2051  if (fr2->fcb->ads) {
2052  fr2->fcb->deleted = TRUE;
2053  mark_fcb_dirty(fr2->fcb);
2054  }
2055 
2056  le = le->Flink;
2057  }
2058  }
2059  }
2060  } else {
2061  fileref->fcb->deleted = TRUE;
2062  mark_fcb_dirty(fileref->fcb);
2063  }
2064 
2065  // remove dir_child from parent
2066 
2067  if (fileref->dc) {
2068  TRACE("delete file %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer);
2069 
2070  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
2071  RemoveEntryList(&fileref->dc->list_entry_index);
2072 
2073  if (!fileref->fcb->ads)
2074  remove_dir_child_from_hash_lists(fileref->parent->fcb, fileref->dc);
2075 
2076  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2077 
2078  if (!fileref->oldutf8.Buffer)
2079  fileref->oldutf8 = fileref->dc->utf8;
2080  else
2081  ExFreePool(fileref->dc->utf8.Buffer);
2082 
2083  utf8len = fileref->dc->utf8.Length;
2084 
2085  fileref->oldindex = fileref->dc->index;
2086 
2087  ExFreePool(fileref->dc->name.Buffer);
2088  ExFreePool(fileref->dc->name_uc.Buffer);
2089  ExFreePool(fileref->dc);
2090 
2091  fileref->dc = NULL;
2092  }
2093 
2094  // update INODE_ITEM of parent
2095 
2096  ExAcquireResourceExclusiveLite(fileref->parent->fcb->Header.Resource, TRUE);
2097 
2098  fileref->parent->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
2099  fileref->parent->fcb->inode_item.sequence++;
2100  fileref->parent->fcb->inode_item.st_ctime = now;
2101 
2102  if (!fileref->fcb->ads) {
2103  TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size);
2104  fileref->parent->fcb->inode_item.st_size -= utf8len * 2;
2105  TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size);
2106  fileref->parent->fcb->inode_item.st_mtime = now;
2107  }
2108 
2109  fileref->parent->fcb->inode_item_changed = TRUE;
2110  ExReleaseResourceLite(fileref->parent->fcb->Header.Resource);
2111 
2112  if (!fileref->fcb->ads && fileref->parent->dc)
2114 
2115  mark_fcb_dirty(fileref->parent->fcb);
2116 
2117  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
2118  fileref->fcb->subvol->root_item.ctime = now;
2119 
2120  newlength.QuadPart = 0;
2121 
2122  if (FileObject && !CcUninitializeCacheMap(FileObject, &newlength, NULL))
2123  TRACE("CcUninitializeCacheMap failed\n");
2124 
2125  ExReleaseResourceLite(fileref->fcb->Header.Resource);
2126 
2127  return STATUS_SUCCESS;
2128 }
2129 
2132 static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
2133  NTSTATUS Status;
2136  device_extension* Vcb = DeviceObject->DeviceExtension;
2137  fcb* fcb = FileObject->FsContext;
2138  BOOL top_level;
2139 
2141 
2142  TRACE("cleanup\n");
2143 
2144  top_level = is_top_level(Irp);
2145 
2146  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
2147  Status = vol_cleanup(DeviceObject, Irp);
2148  goto exit;
2149  } else if (DeviceObject == master_devobj) {
2150  TRACE("closing file system\n");
2151  Status = STATUS_SUCCESS;
2152  goto exit;
2153  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
2154  Status = STATUS_INVALID_PARAMETER;
2155  goto exit;
2156  }
2157 
2158  if (FileObject->Flags & FO_CLEANUP_COMPLETE) {
2159  TRACE("FileObject %p already cleaned up\n", FileObject);
2160  Status = STATUS_SUCCESS;
2161  goto exit;
2162  }
2163 
2164  if (!fcb) {
2165  ERR("fcb was NULL\n");
2166  Status = STATUS_INVALID_PARAMETER;
2167  goto exit;
2168  }
2169 
2170  // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
2171  // messages belonging to other devices.
2172 
2173  if (FileObject && FileObject->FsContext) {
2174  LONG oc;
2175  ccb* ccb;
2176  file_ref* fileref;
2177  BOOL locked = TRUE;
2178 
2179  ccb = FileObject->FsContext2;
2180  fileref = ccb ? ccb->fileref : NULL;
2181 
2182  TRACE("cleanup called for FileObject %p\n", FileObject);
2183  TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0);
2184 
2185  ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
2186 
2187  ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
2188 
2189  IoRemoveShareAccess(FileObject, &fcb->share_access);
2190 
2191  if (ccb)
2192  FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb);
2193 
2194  if (fileref) {
2195  oc = InterlockedDecrement(&fileref->open_count);
2196 #ifdef DEBUG_FCB_REFCOUNTS
2197  ERR("fileref %p: open_count now %i\n", fileref, oc);
2198 #endif
2199  }
2200 
2201  if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref)
2202  fileref->delete_on_close = TRUE;
2203 
2204  if (fileref && fileref->delete_on_close && fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && fcb != fcb->Vcb->dummy_fcb)
2205  fileref->delete_on_close = FALSE;
2206 
2207  if (fcb->Vcb->locked && fcb->Vcb->locked_fileobj == FileObject) {
2208  TRACE("unlocking volume\n");
2209  do_unlock_volume(fcb->Vcb);
2211  }
2212 
2213  if (ccb && ccb->reserving) {
2214  fcb->subvol->reserved = NULL;
2215  ccb->reserving = FALSE;
2216  // FIXME - flush all of subvol's fcbs
2217  }
2218 
2219  if (fileref && oc == 0) {
2220  if (!fcb->Vcb->removing) {
2221  if (fileref && fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) {
2223 
2224  InitializeListHead(&rollback);
2225 
2226  if (!fileref->fcb->ads || fileref->dc) {
2227  if (fileref->fcb->ads) {
2229  FILE_ACTION_REMOVED, &fileref->dc->name);
2230  } else
2232  }
2233 
2234  ExReleaseResourceLite(fcb->Header.Resource);
2235  locked = FALSE;
2236 
2237  // fcb_lock needs to be acquired before fcb->Header.Resource
2238  acquire_fcb_lock_exclusive(fcb->Vcb);
2239 
2240  Status = delete_fileref(fileref, FileObject, Irp, &rollback);
2241  if (!NT_SUCCESS(Status)) {
2242  ERR("delete_fileref returned %08x\n", Status);
2243  do_rollback(fcb->Vcb, &rollback);
2244  release_fcb_lock(fcb->Vcb);
2245  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2246  goto exit;
2247  }
2248 
2249  release_fcb_lock(fcb->Vcb);
2250 
2251  locked = FALSE;
2252 
2253  clear_rollback(&rollback);
2254  } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) {
2256  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2257 
2258  if (!NT_SUCCESS(iosb.Status)) {
2259  ERR("CcFlushCache returned %08x\n", iosb.Status);
2260  }
2261 
2262  if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) {
2263  ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE);
2264  ExReleaseResourceLite(fcb->Header.PagingIoResource);
2265  }
2266 
2267  CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE);
2268 
2269  TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n",
2270  FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
2271  }
2272  }
2273 
2274  if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb)
2275  CcUninitializeCacheMap(FileObject, NULL, NULL);
2276  }
2277 
2278  if (locked)
2279  ExReleaseResourceLite(fcb->Header.Resource);
2280 
2281  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2282 
2283  FileObject->Flags |= FO_CLEANUP_COMPLETE;
2284  }
2285 
2286  Status = STATUS_SUCCESS;
2287 
2288 exit:
2289  TRACE("returning %08x\n", Status);
2290 
2291  Irp->IoStatus.Status = Status;
2292  Irp->IoStatus.Information = 0;
2293 
2295 
2296  if (top_level)
2298 
2300 
2301  return Status;
2302 }
2303 
2304 _Success_(return)
2305 BOOL get_file_attributes_from_xattr(_In_reads_bytes_(len) char* val, _In_ UINT16 len, _Out_ ULONG* atts) {
2306  if (len > 2 && val[0] == '0' && val[1] == 'x') {
2307  int i;
2308  ULONG dosnum = 0;
2309 
2310  for (i = 2; i < len; i++) {
2311  dosnum *= 0x10;
2312 
2313  if (val[i] >= '0' && val[i] <= '9')
2314  dosnum |= val[i] - '0';
2315  else if (val[i] >= 'a' && val[i] <= 'f')
2316  dosnum |= val[i] + 10 - 'a';
2317  else if (val[i] >= 'A' && val[i] <= 'F')
2318  dosnum |= val[i] + 10 - 'a';
2319  }
2320 
2321  TRACE("DOSATTRIB: %08x\n", dosnum);
2322 
2323  *atts = dosnum;
2324 
2325  return TRUE;
2326  }
2327 
2328  return FALSE;
2329 }
2330 
2332  _In_ UINT8 type, _In_ BOOL dotfile, _In_ BOOL ignore_xa, _In_opt_ PIRP Irp) {
2333  ULONG att;
2334  char* eaval;
2335  UINT16 ealen;
2336 
2337  if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen, Irp)) {
2338  ULONG dosnum = 0;
2339 
2340  if (get_file_attributes_from_xattr(eaval, ealen, &dosnum)) {
2341  ExFreePool(eaval);
2342 
2343  if (type == BTRFS_TYPE_DIRECTORY)
2344  dosnum |= FILE_ATTRIBUTE_DIRECTORY;
2345  else if (type == BTRFS_TYPE_SYMLINK)
2346  dosnum |= FILE_ATTRIBUTE_REPARSE_POINT;
2347 
2348  if (type != BTRFS_TYPE_DIRECTORY)
2349  dosnum &= ~FILE_ATTRIBUTE_DIRECTORY;
2350 
2351  if (inode == SUBVOL_ROOT_INODE) {
2352  if (r->root_item.flags & BTRFS_SUBVOL_READONLY)
2353  dosnum |= FILE_ATTRIBUTE_READONLY;
2354  else
2355  dosnum &= ~FILE_ATTRIBUTE_READONLY;
2356  }
2357 
2358  return dosnum;
2359  }
2360 
2361  ExFreePool(eaval);
2362  }
2363 
2364  switch (type) {
2365  case BTRFS_TYPE_DIRECTORY:
2367  break;
2368 
2369  case BTRFS_TYPE_SYMLINK:
2371  break;
2372 
2373  default:
2374  att = 0;
2375  break;
2376  }
2377 
2378  if (dotfile) {
2379  att |= FILE_ATTRIBUTE_HIDDEN;
2380  }
2381 
2382  att |= FILE_ATTRIBUTE_ARCHIVE;
2383 
2384  if (inode == SUBVOL_ROOT_INODE) {
2385  if (r->root_item.flags & BTRFS_SUBVOL_READONLY)
2386  att |= FILE_ATTRIBUTE_READONLY;
2387  else
2388  att &= ~FILE_ATTRIBUTE_READONLY;
2389  }
2390 
2391  // FIXME - get READONLY from ii->st_mode
2392  // FIXME - return SYSTEM for block/char devices?
2393 
2394  if (att == 0)
2395  att = FILE_ATTRIBUTE_NORMAL;
2396 
2397  return att;
2398 }
2399 
2401  _Out_writes_bytes_(Length) PUCHAR Buffer, _In_ BOOL override) {
2404  PIRP Irp;
2406  NTSTATUS Status;
2408 
2409  num_reads++;
2410 
2411  RtlZeroMemory(&context, sizeof(read_context));
2413 
2414  Offset.QuadPart = (LONGLONG)StartingOffset;
2415 
2416  Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
2417 
2418  if (!Irp) {
2419  ERR("IoAllocateIrp failed\n");
2421  }
2422 
2423  Irp->Flags |= IRP_NOCACHE;
2424  IrpSp = IoGetNextIrpStackLocation(Irp);
2425  IrpSp->MajorFunction = IRP_MJ_READ;
2426 
2427  if (override)
2428  IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2429 
2430  if (DeviceObject->Flags & DO_BUFFERED_IO) {
2431  Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, ALLOC_TAG);
2432  if (!Irp->AssociatedIrp.SystemBuffer) {
2433  ERR("out of memory\n");
2435  goto exit;
2436  }
2437 
2439 
2440  Irp->UserBuffer = Buffer;
2441  } else if (DeviceObject->Flags & DO_DIRECT_IO) {
2442  Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);
2443  if (!Irp->MdlAddress) {
2444  ERR("IoAllocateMdl failed\n");
2446  goto exit;
2447  }
2448 
2449  Status = STATUS_SUCCESS;
2450 
2451  _SEH2_TRY {
2452  MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoWriteAccess);
2454  Status = _SEH2_GetExceptionCode();
2455  } _SEH2_END;
2456 
2457  if (!NT_SUCCESS(Status)) {
2458  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
2459  IoFreeMdl(Irp->MdlAddress);
2460  goto exit;
2461  }
2462  } else
2463  Irp->UserBuffer = Buffer;
2464 
2465  IrpSp->Parameters.Read.Length = Length;
2466  IrpSp->Parameters.Read.ByteOffset = Offset;
2467 
2468  Irp->UserIosb = &IoStatus;
2469 
2470  Irp->UserEvent = &context.Event;
2471 
2472  IoSetCompletionRoutine(Irp, read_completion, &context, TRUE, TRUE, TRUE);
2473 
2474  Status = IoCallDriver(DeviceObject, Irp);
2475 
2476  if (Status == STATUS_PENDING) {
2478  Status = context.iosb.Status;
2479  }
2480 
2481  if (DeviceObject->Flags & DO_DIRECT_IO) {
2482  MmUnlockPages(Irp->MdlAddress);
2483  IoFreeMdl(Irp->MdlAddress);
2484  }
2485 
2486 exit:
2487  IoFreeIrp(Irp);
2488 
2489  return Status;
2490 }
2491 
2493  NTSTATUS Status;
2494  superblock* sb;
2495  ULONG i, to_read;
2496  UINT8 valid_superblocks;
2497 
2498  to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize);
2499 
2501  if (!sb) {
2502  ERR("out of memory\n");
2504  }
2505 
2506  if (superblock_addrs[0] + to_read > length) {
2507  WARN("device was too short to have any superblock\n");
2508  ExFreePool(sb);
2510  }
2511 
2512  i = 0;
2513  valid_superblocks = 0;
2514 
2515  while (superblock_addrs[i] > 0) {
2516  UINT32 crc32;
2517 
2518  if (i > 0 && superblock_addrs[i] + to_read > length)
2519  break;
2520 
2521  Status = sync_read_phys(device, superblock_addrs[i], to_read, (PUCHAR)sb, FALSE);
2522  if (!NT_SUCCESS(Status)) {
2523  ERR("Failed to read superblock %u: %08x\n", i, Status);
2524  ExFreePool(sb);
2525  return Status;
2526  }
2527 
2528  if (sb->magic != BTRFS_MAGIC) {
2529  if (i == 0) {
2530  TRACE("not a BTRFS volume\n");
2531  ExFreePool(sb);
2533  }
2534  } else {
2535  TRACE("got superblock %u!\n", i);
2536 
2537  crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
2538 
2539  if (crc32 != *((UINT32*)sb->checksum))
2540  WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum));
2541  else if (sb->sector_size == 0)
2542  WARN("superblock sector size was 0\n");
2543  else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000)
2544  WARN("invalid node size %x\n", sb->node_size);
2545  else if ((sb->node_size % sb->sector_size) != 0)
2546  WARN("node size %x was not a multiple of sector_size %x\n", sb->node_size, sb->sector_size);
2547  else if (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation) {
2548  RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock));
2549  valid_superblocks++;
2550  }
2551  }
2552 
2553  i++;
2554  }
2555 
2556  ExFreePool(sb);
2557 
2558  if (valid_superblocks == 0) {
2559  ERR("could not find any valid superblocks\n");
2560  return STATUS_INTERNAL_ERROR;
2561  }
2562 
2563  TRACE("label is %s\n", Vcb->superblock.label);
2564 
2565  return STATUS_SUCCESS;
2566 }
2567 
2569  _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb) {
2570  PIRP Irp;
2571  KEVENT Event;
2572  NTSTATUS Status;
2575 
2577 
2578  Irp = IoBuildDeviceIoControlRequest(ControlCode,
2579  DeviceObject,
2580  InputBuffer,
2581  InputBufferSize,
2582  OutputBuffer,
2583  OutputBufferSize,
2584  FALSE,
2585  &Event,
2586  &IoStatus);
2587 
2588  if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
2589 
2590  if (Override) {
2591  IrpSp = IoGetNextIrpStackLocation(Irp);
2592  IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2593  }
2594 
2595  Status = IoCallDriver(DeviceObject, Irp);
2596 
2597  if (Status == STATUS_PENDING) {
2599  Status = IoStatus.Status;
2600  }
2601 
2602  if (iosb)
2603  *iosb = IoStatus;
2604 
2605  return Status;
2606 }
2607 
2608 _Requires_exclusive_lock_held_(Vcb->tree_lock)
2612  if (!r) {
2613  ERR("out of memory\n");
2615  }
2616 
2617  r->id = id;
2618  r->dirty = FALSE;
2624  r->parent = 0;
2625  r->send_ops = 0;
2627 
2629  if (!r->nonpaged) {
2630  ERR("out of memory\n");
2631  ExFreePool(r);
2633  }
2634 
2636 
2637  r->lastinode = 0;
2638 
2639  if (tp) {
2640  RtlCopyMemory(&r->root_item, tp->item->data, min(sizeof(ROOT_ITEM), tp->item->size));
2641  if (tp->item->size < sizeof(ROOT_ITEM))
2642  RtlZeroMemory(((UINT8*)&r->root_item) + tp->item->size, sizeof(ROOT_ITEM) - tp->item->size);
2643  } else
2644  RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM));
2645 
2646  if (!Vcb->readonly && (r->id == BTRFS_ROOT_ROOT || r->id == BTRFS_ROOT_FSTREE || (r->id >= 0x100 && !(r->id & 0xf000000000000000)))) { // FS tree root
2647  // FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag)
2648  get_last_inode(Vcb, r, NULL);
2649 
2650  if (r->id == BTRFS_ROOT_ROOT && r->lastinode < 0x100)
2651  r->lastinode = 0x100;
2652  }
2653 
2654  InsertTailList(&Vcb->roots, &r->list_entry);
2655 
2656  switch (r->id) {
2657  case BTRFS_ROOT_ROOT:
2658  Vcb->root_root = r;
2659  break;
2660 
2661  case BTRFS_ROOT_EXTENT:
2662  Vcb->extent_root = r;
2663  break;
2664 
2665  case BTRFS_ROOT_CHUNK:
2666  Vcb->chunk_root = r;
2667  break;
2668 
2669  case BTRFS_ROOT_DEVTREE:
2670  Vcb->dev_root = r;
2671  break;
2672 
2673  case BTRFS_ROOT_CHECKSUM:
2674  Vcb->checksum_root = r;
2675  break;
2676 
2677  case BTRFS_ROOT_UUID:
2678  Vcb->uuid_root = r;
2679  break;
2680 
2681  case BTRFS_ROOT_FREE_SPACE:
2682  Vcb->space_root = r;
2683  break;
2684 
2685  case BTRFS_ROOT_DATA_RELOC:
2686  Vcb->data_reloc_root = r;
2687  break;
2688  }
2689 
2691 }
2692 
2694  traverse_ptr tp, next_tp;
2695  KEY searchkey;
2696  BOOL b;
2697  NTSTATUS Status;
2698 
2699  searchkey.obj_id = 0;
2700  searchkey.obj_type = 0;
2701  searchkey.offset = 0;
2702 
2703  Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
2704  if (!NT_SUCCESS(Status)) {
2705  ERR("error - find_item returned %08x\n", Status);
2706  return Status;
2707  }
2708 
2709  do {
2710  TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
2711 
2712  if (tp.item->key.obj_type == TYPE_ROOT_ITEM) {
2713  ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data;
2714 
2715  if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) {
2716  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));
2717  } else {
2718  TRACE("root %llx - address %llx\n", tp.item->key.obj_id, ri->block_number);
2719 
2720  Status = add_root(Vcb, tp.item->key.obj_id, ri->block_number, ri->generation, &tp);
2721  if (!NT_SUCCESS(Status)) {
2722  ERR("add_root returned %08x\n", Status);
2723  return Status;
2724  }
2725  }
2726  } else if (tp.item->key.obj_type == TYPE_ROOT_BACKREF && !IsListEmpty(&Vcb->roots)) {
2727  root* lastroot = CONTAINING_RECORD(Vcb->roots.Blink, root, list_entry);
2728 
2729  if (lastroot->id == tp.item->key.obj_id)
2730  lastroot->parent = tp.item->key.offset;
2731  }
2732 
2733  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
2734 
2735  if (b)
2736  tp = next_tp;
2737  } while (b);
2738 
2739  if (!Vcb->readonly && !Vcb->data_reloc_root) {
2740  root* reloc_root;
2741  INODE_ITEM* ii;
2742  UINT16 irlen;
2743  INODE_REF* ir;
2745  BTRFS_TIME now;
2746 
2747  WARN("data reloc root doesn't exist, creating it\n");
2748 
2749  Status = create_root(Vcb, BTRFS_ROOT_DATA_RELOC, &reloc_root, FALSE, 0, Irp);
2750 
2751  if (!NT_SUCCESS(Status)) {
2752  ERR("create_root returned %08x\n", Status);
2753  return Status;
2754  }
2755 
2756  reloc_root->root_item.inode.generation = 1;
2757  reloc_root->root_item.inode.st_size = 3;
2758  reloc_root->root_item.inode.st_blocks = Vcb->superblock.node_size;
2759  reloc_root->root_item.inode.st_nlink = 1;
2760  reloc_root->root_item.inode.st_mode = 040755;
2761  reloc_root->root_item.inode.flags = 0xffffffff80000000;
2762  reloc_root->root_item.objid = SUBVOL_ROOT_INODE;
2763  reloc_root->root_item.bytes_used = Vcb->superblock.node_size;
2764 
2766  if (!ii) {
2767  ERR("out of memory\n");
2769  }
2770 
2771  KeQuerySystemTime(&time);
2772  win_time_to_unix(time, &now);
2773 
2774  RtlZeroMemory(ii, sizeof(INODE_ITEM));
2775  ii->generation = Vcb->superblock.generation;
2776  ii->st_blocks = Vcb->superblock.node_size;
2777  ii->st_nlink = 1;
2778  ii->st_mode = 040755;
2779  ii->st_atime = now;
2780  ii->st_ctime = now;
2781  ii->st_mtime = now;
2782 
2783  Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, Irp);
2784  if (!NT_SUCCESS(Status)) {
2785  ERR("insert_tree_item returned %08x\n", Status);
2786  ExFreePool(ii);
2787  return Status;
2788  }
2789 
2790  irlen = (UINT16)offsetof(INODE_REF, name[0]) + 2;
2792  if (!ir) {
2793  ERR("out of memory\n");
2795  }
2796 
2797  ir->index = 0;
2798  ir->n = 2;
2799  ir->name[0] = '.';
2800  ir->name[1] = '.';
2801 
2802  Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, irlen, NULL, Irp);
2803  if (!NT_SUCCESS(Status)) {
2804  ERR("insert_tree_item returned %08x\n", Status);
2805  ExFreePool(ir);
2806  return Status;
2807  }
2808 
2809  Vcb->data_reloc_root = reloc_root;
2810  Vcb->need_write = TRUE;
2811  }
2812 
2813  return STATUS_SUCCESS;
2814 }
2815 
2817  KEY searchkey;
2818  traverse_ptr tp, next_tp;
2819  BOOL b;
2820  UINT64 lastaddr;
2821  NTSTATUS Status;
2822 
2823  InitializeListHead(&dev->space);
2824 
2825  searchkey.obj_id = 0;
2826  searchkey.obj_type = TYPE_DEV_STATS;
2827  searchkey.offset = dev->devitem.dev_id;
2828 
2829  Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
2830  if (NT_SUCCESS(Status) && !keycmp(tp.item->key, searchkey))
2831  RtlCopyMemory(dev->stats, tp.item->data, min(sizeof(UINT64) * 5, tp.item->size));
2832 
2833  searchkey.obj_id = dev->devitem.dev_id;
2834  searchkey.obj_type = TYPE_DEV_EXTENT;
2835  searchkey.offset = 0;
2836 
2837  Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
2838  if (!NT_SUCCESS(Status)) {
2839  ERR("error - find_item returned %08x\n", Status);
2840  return Status;
2841  }
2842 
2843  lastaddr = 0;
2844 
2845  do {
2846  if (tp.item->key.obj_id == dev->devitem.dev_id && tp.item->key.obj_type == TYPE_DEV_EXTENT) {
2847  if (tp.item->size >= sizeof(DEV_EXTENT)) {
2848  DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data;
2849 
2850  if (tp.item->key.offset > lastaddr) {
2851  Status = add_space_entry(&dev->space, NULL, lastaddr, tp.item->key.offset - lastaddr);
2852  if (!NT_SUCCESS(Status)) {
2853  ERR("add_space_entry returned %08x\n", Status);
2854  return Status;
2855  }
2856  }
2857 
2858  lastaddr = tp.item->key.offset + de->length;
2859  } else {
2860  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));
2861  }
2862  }
2863 
2864  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
2865 
2866  if (b) {
2867  tp = next_tp;
2868  if (tp.item->key.obj_id > searchkey.obj_id || tp.item->key.obj_type > searchkey.obj_type)
2869  break;
2870  }
2871  } while (b);
2872 
2873  if (lastaddr < dev->devitem.num_bytes) {
2874  Status = add_space_entry(&dev->space, NULL, lastaddr, dev->devitem.num_bytes - lastaddr);
2875  if (!NT_SUCCESS(Status)) {
2876  ERR("add_space_entry returned %08x\n", Status);
2877  return Status;
2878  }
2879  }
2880 
2881  // The Linux driver doesn't like to allocate chunks within the first megabyte of a device.
2882 
2883  space_list_subtract2(&dev->space, NULL, 0, 0x100000, NULL, NULL);
2884 
2885  return STATUS_SUCCESS;
2886 }
2887 
2889  LIST_ENTRY* le;
2890 
2891  le = Vcb->devices.Flink;
2892 
2893  while (le != &Vcb->devices) {
2894  device* dev2 = CONTAINING_RECORD(le, device, list_entry);
2895 
2896  if (dev2->devitem.dev_id > dev->devitem.dev_id) {
2897  InsertHeadList(le->Blink, &dev->list_entry);
2898  return;
2899  }
2900 
2901  le = le->Flink;
2902  }
2903 
2904  InsertTailList(&Vcb->devices, &dev->list_entry);
2905 }
2906 
2910  pdo_device_extension* pdode;
2911  LIST_ENTRY* le;
2912 
2913  le = Vcb->devices.Flink;
2914  while (le != &Vcb->devices) {
2916 
2917  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,
2920 
2921  if (RtlCompareMemory(&dev->devitem.device_uuid, uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2922  TRACE("returning device %llx\n", dev->devitem.dev_id);
2923  return dev;
2924  }
2925 
2926  le = le->Flink;
2927  }
2928 
2929  vde = Vcb->vde;
2930 
2931  if (!vde)
2932  goto end;
2933 
2934  pdode = vde->pdode;
2935 
2937 
2938  if (Vcb->devices_loaded < Vcb->superblock.num_devices) {
2939  le = pdode->children.Flink;
2940 
2941  while (le != &pdode->children) {
2943 
2944  if (RtlCompareMemory(uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
2945  device* dev;
2946 
2948  if (!dev) {
2950  ERR("out of memory\n");
2951  return NULL;
2952  }
2953 
2954  RtlZeroMemory(dev, sizeof(device));
2955  dev->devobj = vc->devobj;
2956  dev->devitem.device_uuid = *uuid;
2957  dev->devitem.dev_id = vc->devid;
2958  dev->devitem.num_bytes = vc->size;
2959  dev->seeding = vc->seeding;
2960  dev->readonly = dev->seeding;
2961  dev->reloc = FALSE;
2962  dev->removable = FALSE;
2963  dev->disk_num = vc->disk_num;
2964  dev->part_num = vc->part_num;
2965  dev->num_trim_entries = 0;
2967 
2968  add_device_to_list(Vcb, dev);
2969  Vcb->devices_loaded++;
2970 
2972 
2973  return dev;
2974  }
2975 
2976  le = le->Flink;
2977  }
2978  }
2979 
2981 
2982 end:
2983  WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
2984  uuid->uuid[0], uuid->uuid[1], uuid->uuid[2], uuid->uuid[3], uuid->uuid[4], uuid->uuid[5], uuid->uuid[6], uuid->uuid[7],
2985  uuid->uuid[8], uuid->uuid[9], uuid->uuid[10], uuid->uuid[11], uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]);
2986 
2987  return NULL;
2988 }
2989 
2991  NTSTATUS Status;
2993 
2994  Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_HOTPLUG_INFO, NULL, 0, &shi, sizeof(STORAGE_HOTPLUG_INFO), TRUE, NULL);
2995 
2996  if (!NT_SUCCESS(Status)) {
2997  ERR("dev_ioctl returned %08x\n", Status);
2998  return FALSE;
2999  }
3000 
3001  return shi.MediaRemovable != 0 ? TRUE : FALSE;
3002 }
3003 
3005  NTSTATUS Status;
3006  ULONG cc;
3008 
3009  Status = dev_ioctl(devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb);
3010 
3011  if (!NT_SUCCESS(Status)) {
3012  ERR("dev_ioctl returned %08x\n", Status);
3013  return 0;
3014  }
3015 
3016  if (iosb.Information < sizeof(ULONG)) {
3017  ERR("iosb.Information was too short\n");
3018  return 0;
3019  }
3020 
3021  return cc;
3022 }
3023 
3025  NTSTATUS Status;
3026  ULONG aptelen;
3027  ATA_PASS_THROUGH_EX* apte;
3030 
3031  dev->removable = is_device_removable(dev->devobj);
3032  dev->change_count = dev->removable ? get_device_change_count(dev->devobj) : 0;
3033 
3034  if (get_nums) {
3036 
3037  Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
3038  &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL);
3039 
3040  if (!NT_SUCCESS(Status)) {
3041  WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
3042  dev->disk_num = 0xffffffff;
3043  dev->part_num = 0xffffffff;
3044  } else {
3045  dev->disk_num = sdn.DeviceNumber;
3046  dev->part_num = sdn.PartitionNumber;
3047  }
3048  }
3049 
3050  dev->trim = FALSE;
3051  dev->readonly = dev->seeding;
3052  dev->reloc = FALSE;
3053  dev->num_trim_entries = 0;
3054  dev->stats_changed = FALSE;
3055  InitializeListHead(&dev->trim_list);
3056 
3057  if (!dev->readonly) {
3058  Status = dev_ioctl(dev->devobj, IOCTL_DISK_IS_WRITABLE, NULL, 0,
3059  NULL, 0, TRUE, NULL);
3060  if (Status == STATUS_MEDIA_WRITE_PROTECTED)
3061  dev->readonly = TRUE;
3062  }
3063 
3064  aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512;
3065  apte = ExAllocatePoolWithTag(NonPagedPool, aptelen, ALLOC_TAG);
3066  if (!apte) {
3067  ERR("out of memory\n");
3068  return;
3069  }
3070 
3071  RtlZeroMemory(apte, aptelen);
3072 
3073  apte->Length = sizeof(ATA_PASS_THROUGH_EX);
3074  apte->AtaFlags = ATA_FLAGS_DATA_IN;
3075  apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX);
3076  apte->TimeOutValue = 3;
3077  apte->DataBufferOffset = apte->Length;
3079 
3080  Status = dev_ioctl(dev->devobj, IOCTL_ATA_PASS_THROUGH, apte, aptelen,
3081  apte, aptelen, TRUE, NULL);
3082 
3083  if (!NT_SUCCESS(Status))
3084  TRACE("IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE\n", Status);
3085  else {
3087 
3088  if (idd->CommandSetSupport.FlushCache) {
3089  dev->can_flush = TRUE;
3090  TRACE("FLUSH CACHE supported\n");
3091  } else
3092  TRACE("FLUSH CACHE not supported\n");
3093  }
3094 
3095  ExFreePool(apte);
3096 
3099  spq.AdditionalParameters[0] = 0;
3100 
3101  Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(STORAGE_PROPERTY_QUERY),
3102  &dtd, sizeof(DEVICE_TRIM_DESCRIPTOR), TRUE, NULL);
3103 
3104  if (NT_SUCCESS(Status)) {
3105  if (dtd.TrimEnabled) {
3106  dev->trim = TRUE;
3107  Vcb->trim = TRUE;
3108  TRACE("TRIM supported\n");
3109  } else
3110  TRACE("TRIM not supported\n");
3111  }
3112 
3113  RtlZeroMemory(dev->stats, sizeof(UINT64) * 5);
3114 }
3115 
3117  traverse_ptr tp, next_tp;
3118  KEY searchkey;
3119  BOOL b;
3120  chunk* c;
3121  NTSTATUS Status;
3122 
3123  searchkey.obj_id = 0;
3124  searchkey.obj_type = 0;
3125  searchkey.offset = 0;
3126 
3127  Vcb->data_flags = 0;
3128  Vcb->metadata_flags = 0;
3129  Vcb->system_flags = 0;
3130 
3131  Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE, Irp);
3132  if (!NT_SUCCESS(Status)) {
3133  ERR("error - find_item returned %08x\n", Status);
3134  return Status;
3135  }
3136 
3137  do {
3138  TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
3139 
3140  if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM) {
3141  if (tp.item->size < sizeof(DEV_ITEM)) {
3142  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));
3143  } else {
3144  DEV_ITEM* di = (DEV_ITEM*)tp.item->data;
3145  LIST_ENTRY* le;
3146  BOOL done = FALSE;
3147 
3148  le = Vcb->devices.Flink;
3149  while (le != &Vcb->devices) {
3151 
3152  if (dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &di->device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3153  RtlCopyMemory(&dev->devitem, tp.item->data, min(tp.item->size, sizeof(DEV_ITEM)));
3154 
3155  if (le != Vcb->devices.Flink)
3156  init_device(Vcb, dev, TRUE);
3157 
3158  done = TRUE;
3159  break;
3160  }
3161 
3162  le = le->Flink;
3163  }
3164 
3165  if (!done && Vcb->vde) {
3166  volume_device_extension* vde = Vcb->vde;
3167  pdo_device_extension* pdode = vde->pdode;
3168 
3170 
3171  if (Vcb->devices_loaded < Vcb->superblock.num_devices) {
3172  le = pdode->children.Flink;
3173 
3174  while (le != &pdode->children) {
3176 
3177  if (RtlCompareMemory(&di->device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
3178  device* dev;
3179 
3181  if (!dev) {
3183  ERR("out of memory\n");
3185  }
3186 
3187  RtlZeroMemory(dev, sizeof(device));
3188 
3189  dev->devobj = vc->devobj;
3190  RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM)));
3191  dev->seeding = vc->seeding;
3192  init_device(Vcb, dev, FALSE);
3193 
3194  if (dev->devitem.num_bytes > vc->size) {
3195  WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", tp.item->key.offset,
3196  dev->devitem.num_bytes, vc->size);
3197 
3198  dev->devitem.num_bytes = vc->size;
3199  }
3200 
3201  dev->disk_num = vc->disk_num;
3202  dev->part_num = vc->part_num;
3203  add_device_to_list(Vcb, dev);
3204  Vcb->devices_loaded++;
3205 
3206  done = TRUE;
3207  break;
3208  }
3209 
3210  le = le->Flink;
3211  }
3212 
3213  if (!done) {
3214  if (!Vcb->options.allow_degraded) {
3215  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,
3216  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],
3217  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]);
3218  } else {
3219  device* dev;
3220 
3222  if (!dev) {
3224  ERR("out of memory\n");
3226  }
3227 
3228  RtlZeroMemory(dev, sizeof(device));
3229 
3230  // Missing device, so we keep dev->devobj as NULL
3231  RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM)));
3233 
3234  add_device_to_list(Vcb, dev);
3235  Vcb->devices_loaded++;
3236  }
3237  }
3238  } else
3239  ERR("unexpected device %llx found\n", tp.item->key.offset);
3240 
3242  }
3243  }
3244  } else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) {
3245  if (tp.item->size < sizeof(CHUNK_ITEM)) {
3246  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));
3247  } else {
3249 
3250  if (!c) {
3251  ERR("out of memory\n");
3253  }
3254 
3255  c->size = tp.item->size;
3256  c->offset = tp.item->key.offset;
3257  c->used = c->oldused = 0;
3258  c->cache = c->old_cache = NULL;
3259  c->created = FALSE;
3260  c->readonly = FALSE;
3261  c->reloc = FALSE;
3262  c->cache_loaded = FALSE;
3263  c->changed = FALSE;
3264  c->space_changed = FALSE;
3265  c->balance_num = 0;
3266 
3268 
3269  if (!c->chunk_item) {
3270  ERR("out of memory\n");
3271  ExFreePool(c);
3273  }
3274 
3275  RtlCopyMemory(c->chunk_item, tp.item->data, tp.item->size);
3276 
3277  if (c->chunk_item->type & BLOCK_FLAG_DATA && c->chunk_item->type > Vcb->data_flags)
3278  Vcb->data_flags = c->chunk_item->type;
3279 
3281  Vcb->metadata_flags = c->chunk_item->type;
3282 
3283  if (c->chunk_item->type & BLOCK_FLAG_SYSTEM && c->chunk_item->type > Vcb->system_flags)
3284  Vcb->system_flags = c->chunk_item->type;
3285 
3286  if (c->chunk_item->type & BLOCK_FLAG_RAID10) {
3287  if (c->chunk_item->sub_stripes == 0 || c->chunk_item->sub_stripes > c->chunk_item->num_stripes) {
3288  ERR("chunk %llx: invalid stripes (num_stripes %u, sub_stripes %u)\n", c->offset, c->chunk_item->num_stripes, c->chunk_item->sub_stripes);
3289  ExFreePool(c->chunk_item);
3290  ExFreePool(c);
3291  return STATUS_INTERNAL_ERROR;
3292  }
3293  }
3294 
3295  if (c->chunk_item->num_stripes > 0) {
3297  UINT16 i;
3298 
3300 
3301  if (!c->devices) {
3302  ERR("out of memory\n");
3303  ExFreePool(c->chunk_item);
3304  ExFreePool(c);
3306  }
3307 
3308  for (i = 0; i < c->chunk_item->num_stripes; i++) {
3309  c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid);
3310  TRACE("device %llu = %p\n", i, c->devices[i]);
3311 
3312  if (!c->devices[i]) {
3313  ERR("missing device\n");
3314  ExFreePool(c->chunk_item);
3315  ExFreePool(c);
3316  return STATUS_INTERNAL_ERROR;
3317  }
3318 
3319  if (c->devices[i]->readonly)
3320  c->readonly = TRUE;
3321  }
3322  } else {
3323  ERR("chunk %llx: number of stripes is 0\n", c->offset);
3324  ExFreePool(c->chunk_item);
3325  ExFreePool(c);
3326  return STATUS_INTERNAL_ERROR;
3327  }
3328 
3331 
3336 
3340 
3343 
3344  c->last_alloc_set = FALSE;
3345 
3346  c->last_stripe = 0;
3347 
3348  InsertTailList(&Vcb->chunks, &c->list_entry);
3349 
3351  }
3352  }
3353 
3354  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
3355 
3356  if (b)
3357  tp = next_tp;
3358  } while (b);
3359 
3360  Vcb->log_to_phys_loaded = TRUE;
3361 
3362  if (Vcb->data_flags == 0)
3364 
3365  if (Vcb->metadata_flags == 0)
3367 
3368  if (Vcb->system_flags == 0)
3370 
3373  Vcb->data_flags = Vcb->metadata_flags;
3374  }
3375 
3376  return STATUS_SUCCESS;
3377 }
3378 
3380  UINT16 i = 0, j;
3381  UINT64 off_start, off_end;
3382 
3383  // The Linux driver also protects all the space before the first superblock.
3384  // I realize this confuses physical and logical addresses, but this is what btrfs-progs does -
3385  // evidently Linux assumes the chunk at 0 is always SINGLE.
3386  if (c->offset < superblock_addrs[0])
3387  space_list_subtract(c, FALSE, c->offset, superblock_addrs[0] - c->offset, NULL);
3388 
3389  while (superblock_addrs[i] != 0) {
3390  CHUNK_ITEM* ci = c->chunk_item;
3391  CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
3392 
3393  if (ci->type & BLOCK_FLAG_RAID0 || ci->type & BLOCK_FLAG_RAID10) {
3394  for (j = 0; j < ci->num_stripes; j++) {
3395  UINT16 sub_stripes = max(ci->sub_stripes, 1);
3396 
3397  if (cis[j].offset + (ci->size * ci->num_stripes / sub_stripes) > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3398 #ifdef _DEBUG
3399  UINT64 startoff;
3400  UINT16 startoffstripe;
3401 #endif
3402 
3403  TRACE("cut out superblock in chunk %llx\n", c->offset);
3404 
3405  off_start = superblock_addrs[i] - cis[j].offset;
3406  off_start -= off_start % ci->stripe_length;
3407  off_start *= ci->num_stripes / sub_stripes;
3408  off_start += (j / sub_stripes) * ci->stripe_length;
3409 
3410  off_end = off_start + ci->stripe_length;
3411 
3412 #ifdef _DEBUG
3413  get_raid0_offset(off_start, ci->stripe_length, ci->num_stripes / sub_stripes, &startoff, &startoffstripe);
3414  TRACE("j = %u, startoffstripe = %u\n", j, startoffstripe);
3415  TRACE("startoff = %llx, superblock = %llx\n", startoff + cis[j].offset, superblock_addrs[i]);
3416 #endif
3417 
3418  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3419  }
3420  }
3421  } else if (ci->type & BLOCK_FLAG_RAID5) {
3422  UINT64 stripe_size = ci->size / (ci->num_stripes - 1);
3423 
3424  for (j = 0; j < ci->num_stripes; j++) {
3425  if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3426  TRACE("cut out superblock in chunk %llx\n", c->offset);
3427 
3428  off_start = superblock_addrs[i] - cis[j].offset;
3429  off_start -= off_start % ci->stripe_length;
3430  off_start *= ci->num_stripes - 1;
3431 
3432  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length);
3433  off_end *= ci->num_stripes - 1;
3434 
3435  TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start);
3436 
3437  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3438  }
3439  }
3440  } else if (ci->type & BLOCK_FLAG_RAID6) {
3441  UINT64 stripe_size = ci->size / (ci->num_stripes - 2);
3442 
3443  for (j = 0; j < ci->num_stripes; j++) {
3444  if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3445  TRACE("cut out superblock in chunk %llx\n", c->offset);
3446 
3447  off_start = superblock_addrs[i] - cis[j].offset;
3448  off_start -= off_start % ci->stripe_length;
3449  off_start *= ci->num_stripes - 2;
3450 
3451  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length);
3452  off_end *= ci->num_stripes - 2;
3453 
3454  TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start);
3455 
3456  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3457  }
3458  }
3459  } else { // SINGLE, DUPLICATE, RAID1
3460  for (j = 0; j < ci->num_stripes; j++) {
3461  if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) {
3462  TRACE("cut out superblock in chunk %llx\n", c->offset);
3463 
3464  // The Linux driver protects the whole stripe in which the superblock lives
3465 
3466  off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length;
3467  off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length);
3468 
3469  space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL);
3470  }
3471  }
3472  }
3473 
3474  i++;
3475  }
3476 }
3477 
3479  LIST_ENTRY* le = Vcb->chunks.Flink;
3480  chunk* c;
3481  KEY searchkey;
3482  traverse_ptr tp;
3483  BLOCK_GROUP_ITEM* bgi;
3484  NTSTATUS Status;
3485 
3486  searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM;
3487 
3488  while (le != &Vcb->chunks) {
3490 
3491  searchkey.obj_id = c->offset;
3492  searchkey.offset = c->chunk_item->size;
3493 
3494  Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
3495  if (!NT_SUCCESS(Status)) {
3496  ERR("error - find_item returned %08x\n", Status);
3497  return Status;
3498  }
3499 
3500  if (!keycmp(searchkey, tp.item->key)) {
3501  if (tp.item->size >= sizeof(BLOCK_GROUP_ITEM)) {
3502  bgi = (BLOCK_GROUP_ITEM*)tp.item->data;
3503 
3504  c->used = c->oldused = bgi->used;
3505 
3506  TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used);
3507  } else {
3508  ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n",
3509  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));
3510  }
3511  }
3512 
3513  le = le->Flink;
3514  }
3515 
3516  Vcb->chunk_usage_found = TRUE;
3517 
3518  return STATUS_SUCCESS;
3519 }
3520 
3522  KEY key;
3523  ULONG n = Vcb->superblock.n;
3524 
3525  while (n > 0) {
3526  if (n > sizeof(KEY)) {
3527  RtlCopyMemory(&key, &Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n], sizeof(KEY));
3528  n -= sizeof(KEY);
3529  } else
3530  return STATUS_SUCCESS;
3531 
3532  TRACE("bootstrap: %llx,%x,%llx\n", key.obj_id, key.obj_type, key.offset);
3533 
3534  if (key.obj_type == TYPE_CHUNK_ITEM) {
3535  CHUNK_ITEM* ci;
3536  USHORT cisize;
3537  sys_chunk* sc;
3538 
3539  if (n < sizeof(CHUNK_ITEM))
3540  return STATUS_SUCCESS;
3541 
3542  ci = (CHUNK_ITEM*)&Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n];
3543  cisize = sizeof(CHUNK_ITEM) + (ci->num_stripes * sizeof(CHUNK_ITEM_STRIPE));
3544 
3545  if (n < cisize)
3546  return STATUS_SUCCESS;
3547 
3549 
3550  if (!sc) {
3551  ERR("out of memory\n");
3553  }
3554 
3555  sc->key = key;
3556  sc->size = cisize;
3558 
3559  if (!sc->data) {
3560  ERR("out of memory\n");
3561  ExFreePool(sc);
3563  }
3564 
3565  RtlCopyMemory(sc->data, ci, sc->size);
3566  InsertTailList(&Vcb->sys_chunks, &sc->list_entry);
3567 
3568  n -= cisize;
3569  } else {
3570  ERR("unexpected item %llx,%x,%llx in bootstrap\n", key.obj_id, key.obj_type, key.offset);
3571  return STATUS_INTERNAL_ERROR;
3572  }
3573  }
3574 
3575  return STATUS_SUCCESS;
3576 }
3577 
3580  LIST_ENTRY* le;
3581 
3582  static char fn[] = "default";
3583  static UINT32 crc32 = 0x8dbfc2d2;
3584 
3585  if (Vcb->options.subvol_id != 0) {
3586  le = Vcb->roots.Flink;
3587  while (le != &Vcb->roots) {
3589 
3590  if (r->id == Vcb->options.subvol_id)
3591  return r;
3592 
3593  le = le->Flink;
3594  }
3595  }
3596 
3598  NTSTATUS Status;
3599  KEY searchkey;
3600  traverse_ptr tp;
3601  DIR_ITEM* di;
3602 
3603  searchkey.obj_id = Vcb->superblock.root_dir_objectid;
3604  searchkey.obj_type = TYPE_DIR_ITEM;
3605  searchkey.offset = crc32;
3606 
3607  Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
3608  if (!NT_SUCCESS(Status)) {
3609  ERR("error - find_item returned %08x\n", Status);
3610  goto end;
3611  }
3612 
3613  if (keycmp(tp.item->key, searchkey)) {
3614  ERR("could not find (%llx,%x,%llx) in root tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
3615  goto end;
3616  }
3617 
3618  if (tp.item->size < sizeof(DIR_ITEM)) {
3619  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));
3620  goto end;
3621  }
3622 
3623  di = (DIR_ITEM*)tp.item->data;
3624 
3625  if (tp.item->size < sizeof(DIR_ITEM) - 1 + di->n) {
3626  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);
3627  goto end;
3628  }
3629 
3630  if (di->n != strlen(fn) || RtlCompareMemory(di->name, fn, di->n) != di->n) {
3631  ERR("root DIR_ITEM had same CRC32, but was not \"default\"\n");
3632  goto end;
3633  }
3634 
3635  if (di->key.obj_type != TYPE_ROOT_ITEM) {
3636  ERR("default root has key (%llx,%x,%llx), expected subvolume\n", di->key.obj_id, di->key.obj_type, di->key.offset);
3637  goto end;
3638  }
3639 
3640  le = Vcb->roots.Flink;
3641  while (le != &Vcb->roots) {
3643 
3644  if (r->id == di->key.obj_id)
3645  return r;
3646 
3647  le = le->Flink;
3648  }
3649 
3650  ERR("could not find root %llx, using default instead\n", di->key.obj_id);
3651  }
3652 
3653 end:
3654  le = Vcb->roots.Flink;
3655  while (le != &Vcb->roots) {
3657 
3658  if (r->id == BTRFS_ROOT_FSTREE)
3659  return r;
3660 
3661  le = le->Flink;
3662  }
3663 
3664  return NULL;
3665 }
3666 
3668  TRACE("(%p, %p)\n", FileObject, ccfs);
3669 
3670  CcInitializeCacheMap(FileObject, ccfs, FALSE, cache_callbacks, FileObject);
3671 
3672  if (diskacc)
3674 
3676 }
3677 
3679  device_extension* Vcb = DeviceObject->DeviceExtension;
3680  ULONG i;
3681 
3683 
3685  if (!Vcb->calcthreads.threads) {
3686  ERR("out of memory\n");
3688  }
3689 
3693 
3695 
3696  for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
3697  NTSTATUS Status;
3698 
3701 
3702  Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
3703  if (!NT_SUCCESS(Status)) {
3704  ULONG j;
3705 
3706  ERR("PsCreateSystemThread returned %08x\n", Status);
3707 
3708  for (j = 0; j < i; j++) {
3709  Vcb->calcthreads.threads[i].quit = TRUE;
3710  }
3711 
3712  KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
3713 
3714  return Status;
3715  }
3716  }
3717 
3718  return STATUS_SUCCESS;
3719 }
3720 
3721 static BOOL is_btrfs_volume(_In_ PDEVICE_OBJECT DeviceObject) {
3722  NTSTATUS Status;
3723  MOUNTDEV_NAME mdn, *mdn2;
3724  ULONG mdnsize;
3725 
3726  Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL);
3727  if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
3728  ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
3729  return FALSE;
3730  }
3731 
3732  mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
3733 
3734  mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG);
3735  if (!mdn2) {
3736  ERR("out of memory\n");
3737  return FALSE;
3738  }
3739 
3740  Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, TRUE, NULL);
3741  if (!NT_SUCCESS(Status)) {
3742  ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
3743  ExFreePool(mdn2);
3744  return FALSE;
3745  }
3746 
3747  if (mdn2->NameLength > wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR) &&
3749  ExFreePool(mdn2);
3750  return TRUE;
3751  }
3752 
3753  ExFreePool(mdn2);
3754 
3755  return FALSE;
3756 }
3757 
3759  NTSTATUS Status;
3760  WCHAR *list = NULL, *s;
3761 
3762  Status = IoGetDeviceInterfaces((PVOID)guid, NULL, 0, &list);
3763  if (!NT_SUCCESS(Status)) {
3764  ERR("IoGetDeviceInterfaces returned %08x\n", Status);
3765  return Status;
3766  }
3767 
3768  s = list;
3769  while (s[0] != 0) {
3771  PDEVICE_OBJECT devobj;
3773 
3774  name.Length = name.MaximumLength = (USHORT)wcslen(s) * sizeof(WCHAR);
3775  name.Buffer = s;
3776 
3777  if (NT_SUCCESS(IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &FileObject, &devobj))) {
3778  if (DeviceObject == devobj || DeviceObject == FileObject->DeviceObject) {
3779  ObDereferenceObject(FileObject);
3780 
3781  pnp_name->Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
3782  if (!pnp_name->Buffer) {
3783  ERR("out of memory\n");
3785  goto end;
3786  }
3787 
3788  RtlCopyMemory(pnp_name->Buffer, name.Buffer, name.Length);
3789  pnp_name->Length = pnp_name->MaximumLength = name.Length;
3790 
3791  Status = STATUS_SUCCESS;
3792  goto end;
3793  }
3794 
3795  ObDereferenceObject(FileObject);
3796  }
3797 
3798  s = &s[wcslen(s) + 1];
3799  }
3800 
3801  pnp_name->Length = pnp_name->MaximumLength = 0;
3802  pnp_name->Buffer = 0;
3803 
3804  Status = STATUS_NOT_FOUND;
3805 
3806 end:
3807  if (list)
3808  ExFreePool(list);
3809 
3810  return Status;
3811 }
3812 
3814  NTSTATUS Status;
3815 
3816  Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_VOLUME);
3817  if (NT_SUCCESS(Status)) {
3818  *guid = &GUID_DEVINTERFACE_VOLUME;
3819  return Status;
3820  }
3821 
3822  Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_HIDDEN_VOLUME);
3823  if (NT_SUCCESS(Status)) {
3824  *guid = &GUID_DEVINTERFACE_HIDDEN_VOLUME;
3825  return Status;
3826  }
3827 
3828  Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_DISK);
3829  if (NT_SUCCESS(Status)) {
3830  *guid = &GUID_DEVINTERFACE_DISK;
3831  return Status;
3832  }
3833 
3834  return STATUS_NOT_FOUND;
3835 }
3836 
3837 _Success_(return>=0)
3838 static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT DeviceObject, _Out_ BOOL* no_pnp) {
3839  NTSTATUS Status;
3844  const GUID* guid;
3845 
3846  to_read = DeviceObject->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), DeviceObject->SectorSize);
3847 
3849  if (!sb) {
3850  ERR("out of memory\n");
3852  }
3853 
3854  Status = sync_read_phys(DeviceObject, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE);
3855  if (!NT_SUCCESS(Status)) {
3856  ERR("sync_read_phys returned %08x\n", Status);
3857  goto end;
3858  }
3859 
3860  if (sb->magic != BTRFS_MAGIC) {
3861  Status = STATUS_SUCCESS;
3862  goto end;
3863  }
3864 
3865  crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
3866 
3867  if (crc32 != *((UINT32*)sb->checksum)) {
3868  WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum));
3869  Status = STATUS_SUCCESS;
3870  goto end;
3871  }
3872 
3873  DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
3874 
3875  pnp_name.Buffer = NULL;
3876 
3877  Status = get_device_pnp_name(DeviceObject, &pnp_name, &guid);
3878  if (!NT_SUCCESS(Status)) {
3879  WARN("get_device_pnp_name returned %08x\n", Status);
3880  pnp_name.Length = 0;
3881  }
3882 
3883  if (pnp_name.Length == 0)
3884  *no_pnp = TRUE;
3885  else {
3886  *no_pnp = FALSE;
3887  volume_arrival(drvobj, &pnp_name);
3888  }
3889 
3890  if (pnp_name.Buffer)
3891  ExFreePool(pnp_name.Buffer);
3892 
3893  Status = STATUS_SUCCESS;
3894 
3895 end:
3897 
3898  return Status;
3899 }
3900 
3902  NTSTATUS Status;
3903  ULONG to_read;
3904  superblock* sb;
3905  PDEVICE_OBJECT device2;
3906 
3907  if (!device)
3908  return FALSE;
3909 
3910  to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize);
3911 
3913  if (!sb) {
3914  ERR("out of memory\n");
3915  return FALSE;
3916  }
3917 
3918  Status = sync_read_phys(device, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE);
3919  if (!NT_SUCCESS(Status)) {
3920  ERR("Failed to read superblock: %08x\n", Status);
3921  ExFreePool(sb);
3922  return FALSE;
3923  }
3924 
3925  if (sb->magic != BTRFS_MAGIC) {
3926  TRACE("not a BTRFS volume\n");
3927  ExFreePool(sb);
3928  return FALSE;
3929  } else {
3930  UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
3931 
3932  if (crc32 != *((UINT32*)sb->checksum)) {
3933  WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum));
3934  ExFreePool(sb);
3935  return FALSE;
3936  }
3937  }
3938 
3939  device2 = device;
3940 
3941  do {
3942  device2->Flags &= ~DO_VERIFY_VOLUME;
3943  device2 = IoGetLowerDeviceObject(device2);
3944  } while (device2);
3945 
3946  ExFreePool(sb);
3947  return TRUE;
3948 }
3949 
3950 static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
3952  PDEVICE_OBJECT NewDeviceObject = NULL;
3953  PDEVICE_OBJECT DeviceToMount, readobj;
3954  NTSTATUS Status;
3955  device_extension* Vcb = NULL;
3956  LIST_ENTRY *le, batchlist;
3957  KEY searchkey;
3958  traverse_ptr tp;
3959  fcb* root_fcb = NULL;
3960  ccb* root_ccb = NULL;
3961  BOOL init_lookaside = FALSE;
3962  device* dev;
3964  pdo_device_extension* pdode = NULL;
3965  volume_child* vc;
3966  BOOL no_pnp = FALSE;
3967  UINT64 readobjsize;
3968 
3969  TRACE("(%p, %p)\n", DeviceObject, Irp);
3970 
3971  if (DeviceObject != master_devobj) {
3973  goto exit;
3974  }
3975 
3976  IrpSp = IoGetCurrentIrpStackLocation(Irp);
3977  DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject;
3978 
3979  if (!is_btrfs_volume(DeviceToMount)) {
3980  Status = check_mount_device(DeviceToMount, &no_pnp);
3981  if (!NT_SUCCESS(Status))
3982  WARN("check_mount_device returned %08x\n", Status);
3983 
3984  if (!no_pnp) {
3985  Status = STATUS_UNRECOGNIZED_VOLUME;
3986  goto exit2;
3987  }
3988  } else {
3989  PDEVICE_OBJECT pdo;
3990 
3991  pdo = DeviceToMount;
3992 
3993  while (IoGetLowerDeviceObject(pdo)) {
3994  pdo = IoGetLowerDeviceObject(pdo);
3995  }
3996 
3998 
3999  le = pdo_list.Flink;
4000  while (le != &pdo_list) {
4002 
4003  if (pdode->pdo == pdo) {
4004  vde = pdode->vde;
4005  break;
4006  }
4007 
4008  le = le->Flink;
4009  }
4010 
4012 
4013  if (!vde || vde->type != VCB_TYPE_VOLUME) {
4014  vde = NULL;
4015  Status = STATUS_UNRECOGNIZED_VOLUME;
4016  goto exit2;
4017  }
4018  }
4019 
4020  if (vde) {
4021  pdode = vde->pdode;
4022 
4024 
4025  le = pdode->children.Flink;
4026  while (le != &pdode->children) {
4027  LIST_ENTRY* le2 = le->Flink;
4028 
4030 
4031  if (!still_has_superblock(vc->devobj)) {
4032  remove_volume_child(vde, vc, FALSE);
4033 
4034  if (pdode->num_children == 0) {
4035  ERR("error - number of devices is zero\n");
4036  Status = STATUS_INTERNAL_ERROR;
4037  goto exit2;
4038  }
4039 
4040  Status = STATUS_DEVICE_NOT_READY;
4041  goto exit2;
4042  }
4043 
4044  le = le2;
4045  }
4046 
4047  if (pdode->num_children == 0 || pdode->children_loaded == 0) {
4048  ERR("error - number of devices is zero\n");
4049  Status = STATUS_INTERNAL_ERROR;
4050  goto exit;
4051  }
4052 
4054 
4056 
4057  readobj = vc->devobj;
4058  readobjsize = vc->size;
4059 
4060  vde->device->Characteristics &= ~FILE_DEVICE_SECURE_OPEN;
4061  } else {
4063 
4064  vc = NULL;
4065  readobj = DeviceToMount;
4066 
4067  Status = dev_ioctl(readobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
4068  &gli, sizeof(gli), TRUE, NULL);
4069 
4070  if (!NT_SUCCESS(Status)) {
4071  ERR("error reading length information: %08x\n", Status);
4072  goto exit;
4073  }
4074 
4075  readobjsize = gli.Length.QuadPart;
4076  }
4077 
4078  Status = IoCreateDevice(drvobj, sizeof(device_extension), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &NewDeviceObject);
4079  if (!NT_SUCCESS(Status)) {
4080  ERR("IoCreateDevice returned %08x\n", Status);
4081  Status = STATUS_UNRECOGNIZED_VOLUME;
4082  goto exit;
4083  }
4084 
4085  NewDeviceObject->Flags |= DO_DIRECT_IO;
4086 
4087  // Some programs seem to expect that the sector size will be 512, for
4088  // FILE_NO_INTERMEDIATE_BUFFERING and the like.
4089  NewDeviceObject->SectorSize = min(DeviceToMount->SectorSize, 512);
4090 
4091  Vcb = (PVOID)NewDeviceObject->DeviceExtension;
4092  RtlZeroMemory(Vcb, sizeof(device_extension));
4093  Vcb->type = VCB_TYPE_FS;
4094  Vcb->vde = vde;
4095 
4096  ExInitializeResourceLite(&Vcb->tree_lock);
4097  Vcb->need_write = FALSE;
4098 
4099  ExInitializeResourceLite(&Vcb->fcb_lock);
4105 
4108 
4109  ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
4110 
4111  DeviceToMount->Flags |= DO_DIRECT_IO;
4112 
4113  Status = read_superblock(Vcb, readobj, readobjsize);
4114  if (!NT_SUCCESS(Status)) {
4115  if (!IoIsErrorUserInduced(Status))
4116  Status = STATUS_UNRECOGNIZED_VOLUME;
4117  else if (Irp->Tail.Overlay.Thread)
4118  IoSetHardErrorOrVerifyDevice(Irp, readobj);
4119 
4120  goto exit;
4121  }
4122 
4123  if (!vde && Vcb->superblock.num_devices > 1) {
4124  ERR("cannot mount multi-device FS with non-PNP device\n");
4125  Status = STATUS_UNRECOGNIZED_VOLUME;
4126  goto exit;
4127  }
4128 
4129  Status = registry_load_volume_options(Vcb);
4130  if (!NT_SUCCESS(Status)) {
4131  ERR("registry_load_volume_options returned %08x\n", Status);
4132  goto exit;
4133  }
4134 
4135  if (pdode && pdode->children_loaded < pdode->num_children && (!Vcb->options.allow_degraded || !finished_probing || degraded_wait)) {
4136  ERR("could not mount as %u device(s) missing\n", pdode->num_children - pdode->children_loaded);
4137  Status = STATUS_DEVICE_NOT_READY;
4138  goto exit;
4139  }
4140 
4141  if (Vcb->options.ignore) {
4142  TRACE("ignoring volume\n");
4143  Status = STATUS_UNRECOGNIZED_VOLUME;
4144  goto exit;
4145  }
4146 
4148  WARN("cannot mount because of unsupported incompat flags (%llx)\n", Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED);
4149  Status = STATUS_UNRECOGNIZED_VOLUME;
4150  goto exit;
4151  }
4152 
4153  Vcb->readonly = FALSE;
4155  WARN("mounting read-only because of unsupported flags (%llx)\n", Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED);
4156  Vcb->readonly = TRUE;
4157  }
4158 
4159  if (Vcb->options.readonly)
4160  Vcb->readonly = TRUE;
4161 
4162  Vcb->superblock.generation++;
4164 
4165  InitializeListHead(&Vcb->devices);
4167  if (!dev) {
4168  ERR("out of memory\n");
4170  goto exit;
4171  }
4172 
4173  dev->devobj = readobj;
4174  RtlCopyMemory(&dev->devitem, &Vcb->superblock.dev_item, sizeof(DEV_ITEM));
4175 
4176  if (dev->devitem.num_bytes > readobjsize) {
4177  WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", dev->devitem.dev_id,
4178  dev->devitem.num_bytes, readobjsize);
4179 
4180  dev->devitem.num_bytes = readobjsize;
4181  }
4182 
4184 
4185  init_device(Vcb, dev, TRUE);
4186 
4187  InsertTailList(&Vcb->devices, &dev->list_entry);
4188  Vcb->devices_loaded = 1;
4189 
4190  if (DeviceToMount->Flags & DO_SYSTEM_BOOT_PARTITION)
4191  Vcb->disallow_dismount = TRUE;
4192 
4193  TRACE("DeviceToMount = %p\n", DeviceToMount);
4194  TRACE("IrpSp->Parameters.MountVolume.Vpb = %p\n", IrpSp->Parameters.MountVolume.Vpb);
4195 
4196  NewDeviceObject->StackSize = DeviceToMount->StackSize + 1;
4197  NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
4198 
4199  InitializeListHead(&Vcb->roots);
4201 
4202  Vcb->log_to_phys_loaded = FALSE;
4203 
4205 
4206  if (!Vcb->chunk_root) {
4207  ERR("Could not load chunk root.\n");
4208  Status = STATUS_INTERNAL_ERROR;
4209  goto exit;
4210  }
4211 
4213  Status = load_sys_chunks(Vcb);
4214  if (!NT_SUCCESS(Status)) {
4215  ERR("load_sys_chunks returned %08x\n", Status);
4216  goto exit;
4217  }
4218 
4219  InitializeListHead(&Vcb->chunks);
4220  InitializeListHead(&Vcb->trees);
4227 
4230 
4232 
4237  ExInitializePagedLookasideList(&Vcb->fcb_lookaside, NULL, NULL, 0, sizeof(fcb), ALLOC_TAG, 0);
4242  init_lookaside = TRUE;
4243 
4244  Vcb->Vpb = IrpSp->Parameters.MountVolume.Vpb;
4245 
4246  Status = load_chunk_root(Vcb, Irp);
4247  if (!NT_SUCCESS(Status)) {
4248  ERR("load_chunk_root returned %08x\n", Status);
4249  goto exit;
4250  }
4251 
4252  if (Vcb->superblock.num_devices > 1) {
4254  ERR("could not mount as %u device(s) missing\n", Vcb->superblock.num_devices - Vcb->devices_loaded);
4255 
4257 
4258  Status = STATUS_INTERNAL_ERROR;
4259  goto exit;
4260  }
4261 
4262  if (dev->readonly && !Vcb->readonly) {
4263  Vcb->readonly = TRUE;
4264 
4265  le = Vcb->devices.Flink;
4266  while (le != &Vcb->devices) {
4267  device* dev2 = CONTAINING_RECORD(le, device, list_entry);
4268 
4269  if (dev2->readonly && !dev2->seeding)
4270  break;
4271 
4272  if (!dev2->readonly) {
4273  Vcb->readonly = FALSE;
4274  break;
4275  }
4276 
<