1 /* Copyright (c) Mark Harmstone 2016
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
18 #include "btrfs_drv.h"
19 #include "btrfsioctl.h"
24 #ifndef FSCTL_CSV_CONTROL
25 #define FSCTL_CSV_CONTROL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 181, METHOD_BUFFERED, FILE_ANY_ACCESS)
30 #define SEF_AVOID_PRIVILEGE_CHECK 0x08 // on MSDN but not in any header files(?)
32 extern LIST_ENTRY VcbList
;
33 extern ERESOURCE global_loading_lock
;
34 extern LIST_ENTRY volumes
;
35 extern ERESOURCE volumes_lock
;
37 static NTSTATUS
get_file_ids(PFILE_OBJECT FileObject
, void* data
, ULONG length
) {
38 btrfs_get_file_ids
* bgfi
;
41 if (length
< sizeof(btrfs_get_file_ids
))
42 return STATUS_BUFFER_OVERFLOW
;
45 return STATUS_INVALID_PARAMETER
;
47 fcb
= FileObject
->FsContext
;
50 return STATUS_INVALID_PARAMETER
;
54 bgfi
->subvol
= fcb
->subvol
->id
;
55 bgfi
->inode
= fcb
->inode
;
56 bgfi
->top
= fcb
->Vcb
->root_fileref
->fcb
== fcb
? TRUE
: FALSE
;
58 return STATUS_SUCCESS
;
61 static void get_uuid(BTRFS_UUID
* uuid
) {
65 seed
= KeQueryPerformanceCounter(NULL
);
67 for (i
= 0; i
< 16; i
+=2) {
68 ULONG rand
= RtlRandomEx(&seed
.LowPart
);
70 uuid
->uuid
[i
] = (rand
& 0xff00) >> 8;
71 uuid
->uuid
[i
+1] = rand
& 0xff;
75 static NTSTATUS
snapshot_tree_copy(device_extension
* Vcb
, UINT64 addr
, root
* subvol
, UINT64
* newaddr
, PIRP Irp
, LIST_ENTRY
* rollback
) {
78 write_data_context
* wtc
;
84 buf
= ExAllocatePoolWithTag(NonPagedPool
, Vcb
->superblock
.node_size
, ALLOC_TAG
);
86 ERR("out of memory\n");
87 return STATUS_INSUFFICIENT_RESOURCES
;
90 wtc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(write_data_context
), ALLOC_TAG
);
92 ERR("out of memory\n");
94 return STATUS_INSUFFICIENT_RESOURCES
;
97 Status
= read_data(Vcb
, addr
, Vcb
->superblock
.node_size
, NULL
, TRUE
, buf
, NULL
, NULL
, Irp
, FALSE
);
98 if (!NT_SUCCESS(Status
)) {
99 ERR("read_data returned %08x\n", Status
);
103 th
= (tree_header
*)buf
;
105 RtlZeroMemory(&t
, sizeof(tree
));
107 t
.header
.level
= th
->level
;
108 t
.header
.tree_id
= t
.root
->id
;
110 Status
= get_tree_new_address(Vcb
, &t
, Irp
, rollback
);
111 if (!NT_SUCCESS(Status
)) {
112 ERR("get_tree_new_address returned %08x\n", Status
);
116 if (!t
.has_new_address
) {
117 ERR("tree new address not set\n");
118 Status
= STATUS_INTERNAL_ERROR
;
122 c
= get_chunk_from_address(Vcb
, t
.new_address
);
125 increase_chunk_usage(c
, Vcb
->superblock
.node_size
);
127 ERR("could not find chunk for address %llx\n", t
.new_address
);
128 Status
= STATUS_INTERNAL_ERROR
;
132 th
->address
= t
.new_address
;
133 th
->tree_id
= subvol
->id
;
134 th
->generation
= Vcb
->superblock
.generation
;
135 th
->fs_uuid
= Vcb
->superblock
.uuid
;
137 if (th
->level
== 0) {
139 leaf_node
* ln
= (leaf_node
*)&th
[1];
141 for (i
= 0; i
< th
->num_items
; i
++) {
142 if (ln
[i
].key
.obj_type
== TYPE_EXTENT_DATA
&& ln
[i
].size
>= sizeof(EXTENT_DATA
) && ln
[i
].offset
+ ln
[i
].size
<= Vcb
->superblock
.node_size
- sizeof(tree_header
)) {
143 EXTENT_DATA
* ed
= (EXTENT_DATA
*)(((UINT8
*)&th
[1]) + ln
[i
].offset
);
145 if ((ed
->type
== EXTENT_TYPE_REGULAR
|| ed
->type
== EXTENT_TYPE_PREALLOC
) && ln
[i
].size
>= sizeof(EXTENT_DATA
) - 1 + sizeof(EXTENT_DATA2
)) {
146 EXTENT_DATA2
* ed2
= (EXTENT_DATA2
*)&ed
->data
[0];
148 if (ed2
->size
!= 0) { // not sparse
149 Status
= increase_extent_refcount_data(Vcb
, ed2
->address
, ed2
->size
, subvol
->id
, ln
[i
].key
.obj_id
, ln
[i
].key
.offset
- ed2
->offset
, 1, Irp
, rollback
);
151 if (!NT_SUCCESS(Status
)) {
152 ERR("increase_extent_refcount_data returned %08x\n", Status
);
161 internal_node
* in
= (internal_node
*)&th
[1];
163 for (i
= 0; i
< th
->num_items
; i
++) {
166 tbr
.offset
= subvol
->id
;
168 Status
= increase_extent_refcount(Vcb
, in
[i
].address
, Vcb
->superblock
.node_size
, TYPE_TREE_BLOCK_REF
, &tbr
, NULL
, th
->level
- 1, Irp
, rollback
);
169 if (!NT_SUCCESS(Status
)) {
170 ERR("increase_extent_refcount returned %08x\n", Status
);
176 *((UINT32
*)buf
) = ~calc_crc32c(0xffffffff, (UINT8
*)&th
->fs_uuid
, Vcb
->superblock
.node_size
- sizeof(th
->csum
));
178 KeInitializeEvent(&wtc
->Event
, NotificationEvent
, FALSE
);
179 InitializeListHead(&wtc
->stripes
);
181 wtc
->stripes_left
= 0;
183 Status
= write_data(Vcb
, t
.new_address
, buf
, FALSE
, Vcb
->superblock
.node_size
, wtc
, NULL
, NULL
);
184 if (!NT_SUCCESS(Status
)) {
185 ERR("write_data returned %08x\n", Status
);
189 if (wtc
->stripes
.Flink
!= &wtc
->stripes
) {
190 // launch writes and wait
191 le
= wtc
->stripes
.Flink
;
192 while (le
!= &wtc
->stripes
) {
193 write_data_stripe
* stripe
= CONTAINING_RECORD(le
, write_data_stripe
, list_entry
);
195 if (stripe
->status
!= WriteDataStatus_Ignore
)
196 IoCallDriver(stripe
->device
->devobj
, stripe
->Irp
);
201 KeWaitForSingleObject(&wtc
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
203 le
= wtc
->stripes
.Flink
;
204 while (le
!= &wtc
->stripes
) {
205 write_data_stripe
* stripe
= CONTAINING_RECORD(le
, write_data_stripe
, list_entry
);
207 if (stripe
->status
!= WriteDataStatus_Ignore
&& !NT_SUCCESS(stripe
->iosb
.Status
)) {
208 Status
= stripe
->iosb
.Status
;
215 free_write_data_stripes(wtc
);
219 if (NT_SUCCESS(Status
))
220 *newaddr
= t
.new_address
;
231 static void flush_subvol_fcbs(root
* subvol
, LIST_ENTRY
* rollback
) {
232 LIST_ENTRY
* le
= subvol
->fcbs
.Flink
;
234 if (IsListEmpty(&subvol
->fcbs
))
237 while (le
!= &subvol
->fcbs
) {
238 struct _fcb
* fcb
= CONTAINING_RECORD(le
, struct _fcb
, list_entry
);
239 IO_STATUS_BLOCK iosb
;
241 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
&& !fcb
->deleted
)
242 CcFlushCache(&fcb
->nonpaged
->segment_object
, NULL
, 0, &iosb
);
248 static NTSTATUS
do_create_snapshot(device_extension
* Vcb
, PFILE_OBJECT parent
, fcb
* subvol_fcb
, PANSI_STRING utf8
, PUNICODE_STRING name
, PIRP Irp
) {
252 root
*r
, *subvol
= subvol_fcb
->subvol
;
255 UINT64 address
, dirpos
, *root_num
;
258 fcb
* fcb
= parent
->FsContext
;
259 ccb
* ccb
= parent
->FsContext2
;
261 file_ref
*fileref
, *fr
;
262 dir_child
* dc
= NULL
;
265 ERR("error - ccb was NULL\n");
266 return STATUS_INTERNAL_ERROR
;
269 if (!(ccb
->access
& FILE_ADD_SUBDIRECTORY
)) {
270 WARN("insufficient privileges\n");
271 return STATUS_ACCESS_DENIED
;
274 fileref
= ccb
->fileref
;
276 InitializeListHead(&rollback
);
278 // flush open files on this subvol
280 flush_subvol_fcbs(subvol
, &rollback
);
285 do_write(Vcb
, Irp
, &rollback
);
289 clear_rollback(Vcb
, &rollback
);
291 InitializeListHead(&rollback
);
295 id
= InterlockedIncrement64(&Vcb
->root_root
->lastinode
);
296 Status
= create_root(Vcb
, id
, &r
, TRUE
, Vcb
->superblock
.generation
, Irp
, &rollback
);
298 if (!NT_SUCCESS(Status
)) {
299 ERR("create_root returned %08x\n", Status
);
303 r
->lastinode
= subvol
->lastinode
;
305 if (!Vcb
->uuid_root
) {
308 TRACE("uuid root doesn't exist, creating it\n");
310 Status
= create_root(Vcb
, BTRFS_ROOT_UUID
, &uuid_root
, FALSE
, 0, Irp
, &rollback
);
312 if (!NT_SUCCESS(Status
)) {
313 ERR("create_root returned %08x\n", Status
);
317 Vcb
->uuid_root
= uuid_root
;
320 root_num
= ExAllocatePoolWithTag(PagedPool
, sizeof(UINT64
), ALLOC_TAG
);
322 ERR("out of memory\n");
323 Status
= STATUS_INSUFFICIENT_RESOURCES
;
330 get_uuid(&r
->root_item
.uuid
);
332 RtlCopyMemory(&searchkey
.obj_id
, &r
->root_item
.uuid
, sizeof(UINT64
));
333 searchkey
.obj_type
= TYPE_SUBVOL_UUID
;
334 RtlCopyMemory(&searchkey
.offset
, &r
->root_item
.uuid
.uuid
[sizeof(UINT64
)], sizeof(UINT64
));
336 Status
= find_item(Vcb
, Vcb
->uuid_root
, &tp
, &searchkey
, FALSE
, Irp
);
337 } while (NT_SUCCESS(Status
) && !keycmp(searchkey
, tp
.item
->key
));
341 if (!insert_tree_item(Vcb
, Vcb
->uuid_root
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, root_num
, sizeof(UINT64
), NULL
, Irp
, &rollback
)) {
342 ERR("insert_tree_item failed\n");
343 ExFreePool(root_num
);
344 Status
= STATUS_INTERNAL_ERROR
;
348 searchkey
.obj_id
= r
->id
;
349 searchkey
.obj_type
= TYPE_ROOT_ITEM
;
350 searchkey
.offset
= 0xffffffffffffffff;
352 Status
= find_item(Vcb
, Vcb
->root_root
, &tp
, &searchkey
, FALSE
, Irp
);
353 if (!NT_SUCCESS(Status
)) {
354 ERR("error - find_item returned %08x\n", Status
);
358 Status
= snapshot_tree_copy(Vcb
, subvol
->root_item
.block_number
, r
, &address
, Irp
, &rollback
);
359 if (!NT_SUCCESS(Status
)) {
360 ERR("snapshot_tree_copy returned %08x\n", Status
);
364 KeQuerySystemTime(&time
);
365 win_time_to_unix(time
, &now
);
367 r
->root_item
.inode
.generation
= 1;
368 r
->root_item
.inode
.st_size
= 3;
369 r
->root_item
.inode
.st_blocks
= subvol
->root_item
.inode
.st_blocks
;
370 r
->root_item
.inode
.st_nlink
= 1;
371 r
->root_item
.inode
.st_mode
= __S_IFDIR
| S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
; // 40755
372 r
->root_item
.inode
.flags
= 0xffffffff80000000; // FIXME - find out what these mean
373 r
->root_item
.generation
= Vcb
->superblock
.generation
;
374 r
->root_item
.objid
= subvol
->root_item
.objid
;
375 r
->root_item
.block_number
= address
;
376 r
->root_item
.bytes_used
= subvol
->root_item
.bytes_used
;
377 r
->root_item
.last_snapshot_generation
= Vcb
->superblock
.generation
;
378 r
->root_item
.root_level
= subvol
->root_item
.root_level
;
379 r
->root_item
.generation2
= Vcb
->superblock
.generation
;
380 r
->root_item
.parent_uuid
= subvol
->root_item
.uuid
;
381 r
->root_item
.ctransid
= subvol
->root_item
.ctransid
;
382 r
->root_item
.otransid
= Vcb
->superblock
.generation
;
383 r
->root_item
.ctime
= subvol
->root_item
.ctime
;
384 r
->root_item
.otime
= now
;
386 r
->treeholder
.address
= address
;
388 // FIXME - do we need to copy over the send and receive fields too?
390 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) {
391 ERR("error - could not find ROOT_ITEM for subvol %llx\n", r
->id
);
392 Status
= STATUS_INTERNAL_ERROR
;
396 RtlCopyMemory(tp
.item
->data
, &r
->root_item
, sizeof(ROOT_ITEM
));
398 // update ROOT_ITEM of original subvol
400 subvol
->root_item
.last_snapshot_generation
= Vcb
->superblock
.generation
;
402 // We also rewrite the top of the old subvolume tree, for some reason
403 searchkey
.obj_id
= 0;
404 searchkey
.obj_type
= 0;
405 searchkey
.offset
= 0;
407 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
, Irp
);
408 if (!NT_SUCCESS(Status
)) {
409 ERR("error - find_item returned %08x\n", Status
);
413 subvol
->treeholder
.tree
->write
= TRUE
;
415 // create fileref for entry in other subvolume
417 fr
= create_fileref();
419 ERR("out of memory\n");
420 Status
= STATUS_INSUFFICIENT_RESOURCES
;
424 fr
->utf8
.Length
= fr
->utf8
.MaximumLength
= utf8
->Length
;
425 fr
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->utf8
.MaximumLength
, ALLOC_TAG
);
426 if (!fr
->utf8
.Buffer
) {
427 ERR("out of memory\n");
429 Status
= STATUS_INSUFFICIENT_RESOURCES
;
433 RtlCopyMemory(fr
->utf8
.Buffer
, utf8
->Buffer
, utf8
->Length
);
435 Status
= open_fcb(Vcb
, r
, r
->root_item
.objid
, BTRFS_TYPE_DIRECTORY
, utf8
, fcb
, &fr
->fcb
, PagedPool
, Irp
);
436 if (!NT_SUCCESS(Status
)) {
437 ERR("open_fcb returned %08x\n", Status
);
442 Status
= fcb_get_last_dir_index(fcb
, &dirpos
, Irp
);
443 if (!NT_SUCCESS(Status
)) {
444 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
451 fr
->filepart
.MaximumLength
= fr
->filepart
.Length
= name
->Length
;
453 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->filepart
.MaximumLength
, ALLOC_TAG
);
454 if (!fr
->filepart
.Buffer
) {
455 ERR("out of memory\n");
457 Status
= STATUS_INSUFFICIENT_RESOURCES
;
461 RtlCopyMemory(fr
->filepart
.Buffer
, name
->Buffer
, name
->Length
);
463 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
464 if (!NT_SUCCESS(Status
)) {
465 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
470 fr
->parent
= fileref
;
472 Status
= add_dir_child(fileref
->fcb
, r
->id
, TRUE
, dirpos
, utf8
, &fr
->filepart
, &fr
->filepart_uc
, BTRFS_TYPE_DIRECTORY
, &dc
);
473 if (!NT_SUCCESS(Status
))
474 WARN("add_dir_child returned %08x\n", Status
);
479 insert_fileref_child(fileref
, fr
, TRUE
);
480 increase_fileref_refcount(fileref
);
483 mark_fileref_dirty(fr
);
485 if (fr
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
486 fr
->fcb
->fileref
= fr
;
490 // change fcb's INODE_ITEM
492 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
493 fcb
->inode_item
.sequence
++;
494 fcb
->inode_item
.st_size
+= utf8
->Length
* 2;
496 if (!ccb
->user_set_change_time
)
497 fcb
->inode_item
.st_ctime
= now
;
499 if (!ccb
->user_set_write_time
)
500 fcb
->inode_item
.st_mtime
= now
;
502 fcb
->inode_item_changed
= TRUE
;
505 fcb
->subvol
->root_item
.ctime
= now
;
506 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
508 send_notification_fileref(fr
, FILE_NOTIFY_CHANGE_DIR_NAME
, FILE_ACTION_ADDED
);
509 send_notification_fileref(fr
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
511 le
= subvol
->fcbs
.Flink
;
512 while (le
!= &subvol
->fcbs
) {
513 struct _fcb
* fcb2
= CONTAINING_RECORD(le
, struct _fcb
, list_entry
);
514 LIST_ENTRY
* le2
= fcb2
->extents
.Flink
;
516 while (le2
!= &fcb2
->extents
) {
517 extent
* ext
= CONTAINING_RECORD(le2
, extent
, list_entry
);
528 do_write(Vcb
, Irp
, &rollback
);
532 Status
= STATUS_SUCCESS
;
535 if (NT_SUCCESS(Status
))
536 clear_rollback(Vcb
, &rollback
);
538 do_rollback(Vcb
, &rollback
);
543 static NTSTATUS
create_snapshot(device_extension
* Vcb
, PFILE_OBJECT FileObject
, void* data
, ULONG length
, PIRP Irp
) {
544 PFILE_OBJECT subvol_obj
;
546 btrfs_create_snapshot
* bcs
= data
;
549 UNICODE_STRING nameus
;
553 file_ref
*fileref
, *fr2
;
555 if (length
< offsetof(btrfs_create_snapshot
, name
))
556 return STATUS_INVALID_PARAMETER
;
558 if (length
< offsetof(btrfs_create_snapshot
, name
) + bcs
->namelen
)
559 return STATUS_INVALID_PARAMETER
;
562 return STATUS_INVALID_PARAMETER
;
564 if (!FileObject
|| !FileObject
->FsContext
)
565 return STATUS_INVALID_PARAMETER
;
567 fcb
= FileObject
->FsContext
;
568 ccb
= FileObject
->FsContext2
;
570 if (!fcb
|| !ccb
|| fcb
->type
!= BTRFS_TYPE_DIRECTORY
)
571 return STATUS_INVALID_PARAMETER
;
573 fileref
= ccb
->fileref
;
576 ERR("fileref was NULL\n");
577 return STATUS_INVALID_PARAMETER
;
580 if (!(ccb
->access
& FILE_ADD_SUBDIRECTORY
)) {
581 WARN("insufficient privileges\n");
582 return STATUS_ACCESS_DENIED
;
585 if (fcb
->subvol
->root_item
.flags
& BTRFS_SUBVOL_READONLY
)
586 return STATUS_ACCESS_DENIED
;
588 nameus
.Buffer
= bcs
->name
;
589 nameus
.Length
= nameus
.MaximumLength
= bcs
->namelen
;
591 if (!is_file_name_valid(&nameus
))
592 return STATUS_OBJECT_NAME_INVALID
;
596 Status
= RtlUnicodeToUTF8N(NULL
, 0, &len
, bcs
->name
, bcs
->namelen
);
597 if (!NT_SUCCESS(Status
)) {
598 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
603 ERR("RtlUnicodeToUTF8N returned a length of 0\n");
604 return STATUS_INTERNAL_ERROR
;
607 utf8
.MaximumLength
= utf8
.Length
= len
;
608 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.Length
, ALLOC_TAG
);
611 ERR("out of memory\n");
612 return STATUS_INSUFFICIENT_RESOURCES
;
615 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, len
, &len
, bcs
->name
, bcs
->namelen
);
616 if (!NT_SUCCESS(Status
)) {
617 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
621 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
623 // no need for fcb_lock as we have tree_lock exclusively
624 Status
= open_fileref(fcb
->Vcb
, &fr2
, &nameus
, fileref
, FALSE
, NULL
, NULL
, PagedPool
, FALSE
, Irp
);
626 if (NT_SUCCESS(Status
)) {
628 WARN("file already exists\n");
630 Status
= STATUS_OBJECT_NAME_COLLISION
;
634 } else if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) {
635 ERR("open_fileref returned %08x\n", Status
);
639 Status
= ObReferenceObjectByHandle(bcs
->subvol
, 0, *IoFileObjectType
, UserMode
, (void**)&subvol_obj
, NULL
);
640 if (!NT_SUCCESS(Status
)) {
641 ERR("ObReferenceObjectByHandle returned %08x\n", Status
);
645 subvol_fcb
= subvol_obj
->FsContext
;
647 Status
= STATUS_INVALID_PARAMETER
;
651 if (subvol_fcb
->inode
!= subvol_fcb
->subvol
->root_item
.objid
) {
652 WARN("handle inode was %llx, expected %llx\n", subvol_fcb
->inode
, subvol_fcb
->subvol
->root_item
.objid
);
653 Status
= STATUS_INVALID_PARAMETER
;
657 ccb
= subvol_obj
->FsContext2
;
660 Status
= STATUS_INVALID_PARAMETER
;
664 if (!(ccb
->access
& FILE_TRAVERSE
)) {
665 WARN("insufficient privileges\n");
666 Status
= STATUS_ACCESS_DENIED
;
670 // clear unique flag on extents of open files in subvol
671 if (!IsListEmpty(&subvol_fcb
->subvol
->fcbs
)) {
672 LIST_ENTRY
* le
= subvol_fcb
->subvol
->fcbs
.Flink
;
674 while (le
!= &subvol_fcb
->subvol
->fcbs
) {
675 struct _fcb
* openfcb
= CONTAINING_RECORD(le
, struct _fcb
, list_entry
);
678 le2
= openfcb
->extents
.Flink
;
680 while (le2
!= &openfcb
->extents
) {
681 extent
* ext
= CONTAINING_RECORD(le2
, extent
, list_entry
);
692 Status
= do_create_snapshot(Vcb
, FileObject
, subvol_fcb
, &utf8
, &nameus
, Irp
);
694 if (NT_SUCCESS(Status
)) {
697 Status
= open_fileref(Vcb
, &fr
, &nameus
, fileref
, FALSE
, NULL
, NULL
, PagedPool
, FALSE
, Irp
);
699 if (!NT_SUCCESS(Status
)) {
700 ERR("open_fileref returned %08x\n", Status
);
701 Status
= STATUS_SUCCESS
;
703 send_notification_fileref(fr
, FILE_NOTIFY_CHANGE_DIR_NAME
, FILE_ACTION_ADDED
);
709 ObDereferenceObject(subvol_obj
);
712 ExReleaseResourceLite(&Vcb
->tree_lock
);
715 ExFreePool(utf8
.Buffer
);
720 static NTSTATUS
create_subvol(device_extension
* Vcb
, PFILE_OBJECT FileObject
, WCHAR
* name
, ULONG length
, PIRP Irp
) {
731 UNICODE_STRING nameus
;
737 SECURITY_SUBJECT_CONTEXT subjcont
;
741 file_ref
*fr
= NULL
, *fr2
;
742 dir_child
* dc
= NULL
;
744 fcb
= FileObject
->FsContext
;
746 ERR("error - fcb was NULL\n");
747 return STATUS_INTERNAL_ERROR
;
750 ccb
= FileObject
->FsContext2
;
752 ERR("error - ccb was NULL\n");
753 return STATUS_INTERNAL_ERROR
;
756 fileref
= ccb
->fileref
;
758 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
) {
759 ERR("parent FCB was not a directory\n");
760 return STATUS_NOT_A_DIRECTORY
;
764 ERR("fileref was NULL\n");
765 return STATUS_INVALID_PARAMETER
;
768 if (fileref
->deleted
|| fcb
->deleted
) {
769 ERR("parent has been deleted\n");
770 return STATUS_FILE_DELETED
;
773 if (!(ccb
->access
& FILE_ADD_SUBDIRECTORY
)) {
774 WARN("insufficient privileges\n");
775 return STATUS_ACCESS_DENIED
;
778 if (fcb
->subvol
->root_item
.flags
& BTRFS_SUBVOL_READONLY
)
779 return STATUS_ACCESS_DENIED
;
781 nameus
.Length
= nameus
.MaximumLength
= length
;
782 nameus
.Buffer
= name
;
784 if (!is_file_name_valid(&nameus
))
785 return STATUS_OBJECT_NAME_INVALID
;
789 Status
= RtlUnicodeToUTF8N(NULL
, 0, &len
, name
, length
);
790 if (!NT_SUCCESS(Status
)) {
791 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
796 ERR("RtlUnicodeToUTF8N returned a length of 0\n");
797 return STATUS_INTERNAL_ERROR
;
800 utf8
.MaximumLength
= utf8
.Length
= len
;
801 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.Length
, ALLOC_TAG
);
804 ERR("out of memory\n");
805 return STATUS_INSUFFICIENT_RESOURCES
;
808 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, len
, &len
, name
, length
);
809 if (!NT_SUCCESS(Status
)) {
810 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
814 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
816 KeQuerySystemTime(&time
);
817 win_time_to_unix(time
, &now
);
819 InitializeListHead(&rollback
);
821 // no need for fcb_lock as we have tree_lock exclusively
822 Status
= open_fileref(fcb
->Vcb
, &fr2
, &nameus
, fileref
, FALSE
, NULL
, NULL
, PagedPool
, FALSE
, Irp
);
824 if (NT_SUCCESS(Status
)) {
826 WARN("file already exists\n");
828 Status
= STATUS_OBJECT_NAME_COLLISION
;
832 } else if (!NT_SUCCESS(Status
) && Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) {
833 ERR("open_fileref returned %08x\n", Status
);
837 // FIXME - make sure rollback removes new roots from internal structures
839 id
= InterlockedIncrement64(&Vcb
->root_root
->lastinode
);
840 Status
= create_root(Vcb
, id
, &r
, FALSE
, 0, Irp
, &rollback
);
842 if (!NT_SUCCESS(Status
)) {
843 ERR("create_root returned %08x\n", Status
);
847 TRACE("created root %llx\n", id
);
849 if (!Vcb
->uuid_root
) {
852 TRACE("uuid root doesn't exist, creating it\n");
854 Status
= create_root(Vcb
, BTRFS_ROOT_UUID
, &uuid_root
, FALSE
, 0, Irp
, &rollback
);
856 if (!NT_SUCCESS(Status
)) {
857 ERR("create_root returned %08x\n", Status
);
861 Vcb
->uuid_root
= uuid_root
;
864 root_num
= ExAllocatePoolWithTag(PagedPool
, sizeof(UINT64
), ALLOC_TAG
);
866 ERR("out of memory\n");
867 Status
= STATUS_INSUFFICIENT_RESOURCES
;
874 get_uuid(&r
->root_item
.uuid
);
876 RtlCopyMemory(&searchkey
.obj_id
, &r
->root_item
.uuid
, sizeof(UINT64
));
877 searchkey
.obj_type
= TYPE_SUBVOL_UUID
;
878 RtlCopyMemory(&searchkey
.offset
, &r
->root_item
.uuid
.uuid
[sizeof(UINT64
)], sizeof(UINT64
));
880 Status
= find_item(Vcb
, Vcb
->uuid_root
, &tp
, &searchkey
, FALSE
, Irp
);
881 } while (NT_SUCCESS(Status
) && !keycmp(searchkey
, tp
.item
->key
));
885 if (!insert_tree_item(Vcb
, Vcb
->uuid_root
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, root_num
, sizeof(UINT64
), NULL
, Irp
, &rollback
)) {
886 ERR("insert_tree_item failed\n");
887 Status
= STATUS_INTERNAL_ERROR
;
891 r
->root_item
.inode
.generation
= 1;
892 r
->root_item
.inode
.st_size
= 3;
893 r
->root_item
.inode
.st_blocks
= Vcb
->superblock
.node_size
;
894 r
->root_item
.inode
.st_nlink
= 1;
895 r
->root_item
.inode
.st_mode
= __S_IFDIR
| S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
; // 40755
896 r
->root_item
.inode
.flags
= 0xffffffff80000000; // FIXME - find out what these mean
898 r
->root_item
.objid
= SUBVOL_ROOT_INODE
;
899 r
->root_item
.bytes_used
= Vcb
->superblock
.node_size
;
900 r
->root_item
.ctransid
= Vcb
->superblock
.generation
;
901 r
->root_item
.otransid
= Vcb
->superblock
.generation
;
902 r
->root_item
.ctime
= now
;
903 r
->root_item
.otime
= now
;
905 // add .. inode to new subvol
907 rootfcb
= create_fcb(PagedPool
);
909 ERR("out of memory\n");
910 Status
= STATUS_INSUFFICIENT_RESOURCES
;
917 rootfcb
->inode
= SUBVOL_ROOT_INODE
;
918 rootfcb
->type
= BTRFS_TYPE_DIRECTORY
;
920 rootfcb
->inode_item
.generation
= Vcb
->superblock
.generation
;
921 rootfcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
922 rootfcb
->inode_item
.st_nlink
= 1;
923 rootfcb
->inode_item
.st_mode
= __S_IFDIR
| S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
; // 40755
924 rootfcb
->inode_item
.st_atime
= rootfcb
->inode_item
.st_ctime
= rootfcb
->inode_item
.st_mtime
= rootfcb
->inode_item
.otime
= now
;
925 rootfcb
->inode_item
.st_gid
= GID_NOBODY
; // FIXME?
927 rootfcb
->atts
= get_file_attributes(Vcb
, &rootfcb
->inode_item
, rootfcb
->subvol
, rootfcb
->inode
, rootfcb
->type
, FALSE
, TRUE
, Irp
);
929 SeCaptureSubjectContext(&subjcont
);
931 Status
= SeAssignSecurity(fcb
->sd
, NULL
, (void**)&rootfcb
->sd
, TRUE
, &subjcont
, IoGetFileObjectGenericMapping(), PagedPool
);
933 if (!NT_SUCCESS(Status
)) {
934 ERR("SeAssignSecurity returned %08x\n", Status
);
939 ERR("SeAssignSecurity returned NULL security descriptor\n");
940 Status
= STATUS_INTERNAL_ERROR
;
944 Status
= RtlGetOwnerSecurityDescriptor(rootfcb
->sd
, &owner
, &defaulted
);
945 if (!NT_SUCCESS(Status
)) {
946 ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status
);
947 rootfcb
->inode_item
.st_uid
= UID_NOBODY
;
949 rootfcb
->inode_item
.st_uid
= sid_to_uid(owner
);
952 rootfcb
->sd_dirty
= TRUE
;
953 rootfcb
->inode_item_changed
= TRUE
;
955 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
956 InsertTailList(&r
->fcbs
, &rootfcb
->list_entry
);
957 InsertTailList(&Vcb
->all_fcbs
, &rootfcb
->list_entry_all
);
958 ExReleaseResourceLite(&Vcb
->fcb_lock
);
960 rootfcb
->Header
.IsFastIoPossible
= fast_io_possible(rootfcb
);
961 rootfcb
->Header
.AllocationSize
.QuadPart
= 0;
962 rootfcb
->Header
.FileSize
.QuadPart
= 0;
963 rootfcb
->Header
.ValidDataLength
.QuadPart
= 0;
965 rootfcb
->created
= TRUE
;
967 r
->lastinode
= rootfcb
->inode
;
971 irsize
= sizeof(INODE_REF
) - 1 + strlen(DOTDOT
);
972 ir
= ExAllocatePoolWithTag(PagedPool
, irsize
, ALLOC_TAG
);
974 ERR("out of memory\n");
975 Status
= STATUS_INSUFFICIENT_RESOURCES
;
980 ir
->n
= strlen(DOTDOT
);
981 RtlCopyMemory(ir
->name
, DOTDOT
, ir
->n
);
983 if (!insert_tree_item(Vcb
, r
, r
->root_item
.objid
, TYPE_INODE_REF
, r
->root_item
.objid
, ir
, irsize
, NULL
, Irp
, &rollback
)) {
984 ERR("insert_tree_item failed\n");
985 Status
= STATUS_INTERNAL_ERROR
;
989 // create fileref for entry in other subvolume
991 fr
= create_fileref();
993 ERR("out of memory\n");
995 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
997 ExReleaseResourceLite(&Vcb
->fcb_lock
);
999 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1005 mark_fcb_dirty(rootfcb
);
1007 Status
= fcb_get_last_dir_index(fcb
, &dirpos
, Irp
);
1008 if (!NT_SUCCESS(Status
)) {
1009 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
1010 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1012 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1019 fr
->filepart
.MaximumLength
= fr
->filepart
.Length
= nameus
.Length
;
1020 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->filepart
.MaximumLength
, ALLOC_TAG
);
1021 if (!fr
->filepart
.Buffer
) {
1022 ERR("out of memory\n");
1023 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1025 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1026 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1030 RtlCopyMemory(fr
->filepart
.Buffer
, nameus
.Buffer
, nameus
.Length
);
1032 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
1033 if (!NT_SUCCESS(Status
)) {
1034 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1035 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1037 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1041 fr
->parent
= fileref
;
1043 Status
= add_dir_child(fileref
->fcb
, r
->id
, TRUE
, dirpos
, &utf8
, &fr
->filepart
, &fr
->filepart_uc
, BTRFS_TYPE_DIRECTORY
, &dc
);
1044 if (!NT_SUCCESS(Status
))
1045 WARN("add_dir_child returned %08x\n", Status
);
1050 fr
->fcb
->hash_ptrs
= ExAllocatePoolWithTag(PagedPool
, sizeof(LIST_ENTRY
*) * 256, ALLOC_TAG
);
1051 if (!fr
->fcb
->hash_ptrs
) {
1052 ERR("out of memory\n");
1053 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1055 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1056 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1060 RtlZeroMemory(fr
->fcb
->hash_ptrs
, sizeof(LIST_ENTRY
*) * 256);
1062 fr
->fcb
->hash_ptrs_uc
= ExAllocatePoolWithTag(PagedPool
, sizeof(LIST_ENTRY
*) * 256, ALLOC_TAG
);
1063 if (!fcb
->hash_ptrs_uc
) {
1064 ERR("out of memory\n");
1065 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1067 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1068 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1072 RtlZeroMemory(fr
->fcb
->hash_ptrs_uc
, sizeof(LIST_ENTRY
*) * 256);
1074 insert_fileref_child(fileref
, fr
, TRUE
);
1075 increase_fileref_refcount(fileref
);
1077 if (fr
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
1078 fr
->fcb
->fileref
= fr
;
1081 mark_fileref_dirty(fr
);
1083 // change fcb->subvol's ROOT_ITEM
1085 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
1086 fcb
->subvol
->root_item
.ctime
= now
;
1088 // change fcb's INODE_ITEM
1090 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1091 fcb
->inode_item
.st_size
+= utf8
.Length
* 2;
1092 fcb
->inode_item
.sequence
++;
1094 if (!ccb
->user_set_change_time
)
1095 fcb
->inode_item
.st_ctime
= now
;
1097 if (!ccb
->user_set_write_time
)
1098 fcb
->inode_item
.st_mtime
= now
;
1100 fcb
->inode_item_changed
= TRUE
;
1101 mark_fcb_dirty(fcb
);
1103 Status
= STATUS_SUCCESS
;
1106 if (!NT_SUCCESS(Status
))
1107 do_rollback(Vcb
, &rollback
);
1109 clear_rollback(Vcb
, &rollback
);
1111 ExReleaseResourceLite(&Vcb
->tree_lock
);
1113 if (NT_SUCCESS(Status
)) {
1114 send_notification_fileref(fr
, FILE_NOTIFY_CHANGE_DIR_NAME
, FILE_ACTION_ADDED
);
1115 send_notification_fileref(fr
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1120 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1122 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1128 static NTSTATUS
get_inode_info(PFILE_OBJECT FileObject
, void* data
, ULONG length
) {
1129 btrfs_inode_info
* bii
= data
;
1133 if (length
< sizeof(btrfs_inode_info
))
1134 return STATUS_BUFFER_OVERFLOW
;
1137 return STATUS_INVALID_PARAMETER
;
1139 fcb
= FileObject
->FsContext
;
1142 return STATUS_INVALID_PARAMETER
;
1144 ccb
= FileObject
->FsContext2
;
1147 return STATUS_INVALID_PARAMETER
;
1149 if (!(ccb
->access
& FILE_READ_ATTRIBUTES
)) {
1150 WARN("insufficient privileges\n");
1151 return STATUS_ACCESS_DENIED
;
1154 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, TRUE
);
1156 bii
->subvol
= fcb
->subvol
->id
;
1157 bii
->inode
= fcb
->inode
;
1158 bii
->top
= fcb
->Vcb
->root_fileref
->fcb
== fcb
? TRUE
: FALSE
;
1159 bii
->type
= fcb
->type
;
1160 bii
->st_uid
= fcb
->inode_item
.st_uid
;
1161 bii
->st_gid
= fcb
->inode_item
.st_gid
;
1162 bii
->st_mode
= fcb
->inode_item
.st_mode
;
1163 bii
->st_rdev
= fcb
->inode_item
.st_rdev
;
1164 bii
->flags
= fcb
->inode_item
.flags
;
1166 bii
->inline_length
= 0;
1167 bii
->disk_size
[0] = 0;
1168 bii
->disk_size
[1] = 0;
1169 bii
->disk_size
[2] = 0;
1171 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
) {
1174 le
= fcb
->extents
.Flink
;
1175 while (le
!= &fcb
->extents
) {
1176 extent
* ext
= CONTAINING_RECORD(le
, extent
, list_entry
);
1179 if (ext
->data
->type
== EXTENT_TYPE_INLINE
) {
1180 bii
->inline_length
+= ext
->data
->decoded_size
;
1182 EXTENT_DATA2
* ed2
= (EXTENT_DATA2
*)ext
->data
->data
;
1184 // FIXME - compressed extents with a hole in them are counted more than once
1185 if (ed2
->size
!= 0) {
1186 if (ext
->data
->compression
== BTRFS_COMPRESSION_NONE
) {
1187 bii
->disk_size
[0] += ed2
->num_bytes
;
1188 } else if (ext
->data
->compression
== BTRFS_COMPRESSION_ZLIB
) {
1189 bii
->disk_size
[1] += ed2
->size
;
1190 } else if (ext
->data
->compression
== BTRFS_COMPRESSION_LZO
) {
1191 bii
->disk_size
[2] += ed2
->size
;
1201 ExReleaseResourceLite(fcb
->Header
.Resource
);
1203 return STATUS_SUCCESS
;
1206 static NTSTATUS
set_inode_info(PFILE_OBJECT FileObject
, void* data
, ULONG length
) {
1207 btrfs_set_inode_info
* bsii
= data
;
1212 if (length
< sizeof(btrfs_set_inode_info
))
1213 return STATUS_BUFFER_OVERFLOW
;
1216 return STATUS_INVALID_PARAMETER
;
1218 fcb
= FileObject
->FsContext
;
1221 return STATUS_INVALID_PARAMETER
;
1223 ccb
= FileObject
->FsContext2
;
1226 return STATUS_INVALID_PARAMETER
;
1228 if (bsii
->flags_changed
&& !(ccb
->access
& FILE_WRITE_ATTRIBUTES
)) {
1229 WARN("insufficient privileges\n");
1230 return STATUS_ACCESS_DENIED
;
1233 if (bsii
->mode_changed
&& !(ccb
->access
& WRITE_DAC
)) {
1234 WARN("insufficient privileges\n");
1235 return STATUS_ACCESS_DENIED
;
1238 if ((bsii
->uid_changed
|| bsii
->gid_changed
) && !(ccb
->access
& WRITE_OWNER
)) {
1239 WARN("insufficient privileges\n");
1240 return STATUS_ACCESS_DENIED
;
1243 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1245 if (bsii
->flags_changed
) {
1246 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
&& fcb
->inode_item
.st_size
> 0 &&
1247 (bsii
->flags
& BTRFS_INODE_NODATACOW
) != (fcb
->inode_item
.flags
& BTRFS_INODE_NODATACOW
)) {
1248 WARN("trying to change nocow flag on non-empty file\n");
1249 Status
= STATUS_INVALID_PARAMETER
;
1253 fcb
->inode_item
.flags
= bsii
->flags
;
1255 if (fcb
->inode_item
.flags
& BTRFS_INODE_NODATACOW
)
1256 fcb
->inode_item
.flags
|= BTRFS_INODE_NODATASUM
;
1258 fcb
->inode_item
.flags
&= ~(UINT64
)BTRFS_INODE_NODATASUM
;
1261 if (bsii
->mode_changed
) {
1262 UINT32 allowed
= S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IWGRP
| S_IXGRP
| S_IROTH
| S_IWOTH
| S_IXOTH
;
1264 fcb
->inode_item
.st_mode
&= ~allowed
;
1265 fcb
->inode_item
.st_mode
|= bsii
->st_mode
& allowed
;
1268 if (bsii
->uid_changed
) {
1270 SECURITY_INFORMATION secinfo
;
1271 SECURITY_DESCRIPTOR sd
;
1274 fcb
->inode_item
.st_uid
= bsii
->st_uid
;
1276 uid_to_sid(bsii
->st_uid
, &sid
);
1278 Status
= RtlCreateSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
);
1279 if (!NT_SUCCESS(Status
)) {
1280 ERR("RtlCreateSecurityDescriptor returned %08x\n", Status
);
1284 Status
= RtlSetOwnerSecurityDescriptor(&sd
, sid
, FALSE
);
1285 if (!NT_SUCCESS(Status
)) {
1286 ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status
);
1292 secinfo
= OWNER_SECURITY_INFORMATION
;
1293 Status
= SeSetSecurityDescriptorInfoEx(NULL
, &secinfo
, &sd
, (void**)&fcb
->sd
, SEF_AVOID_PRIVILEGE_CHECK
, PagedPool
, IoGetFileObjectGenericMapping());
1295 if (!NT_SUCCESS(Status
)) {
1296 ERR("SeSetSecurityDescriptorInfo returned %08x\n", Status
);
1302 fcb
->sd_dirty
= TRUE
;
1304 send_notification_fcb(ccb
->fileref
, FILE_NOTIFY_CHANGE_SECURITY
, FILE_ACTION_MODIFIED
);
1307 if (bsii
->gid_changed
)
1308 fcb
->inode_item
.st_gid
= bsii
->st_gid
;
1310 if (bsii
->flags_changed
|| bsii
->mode_changed
|| bsii
->uid_changed
|| bsii
->gid_changed
) {
1311 fcb
->inode_item_changed
= TRUE
;
1312 mark_fcb_dirty(fcb
);
1315 Status
= STATUS_SUCCESS
;
1318 ExReleaseResourceLite(fcb
->Header
.Resource
);
1323 static NTSTATUS
get_devices(device_extension
* Vcb
, void* data
, ULONG length
) {
1324 btrfs_device
* dev
= NULL
;
1328 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1330 le
= Vcb
->devices
.Flink
;
1331 while (le
!= &Vcb
->devices
) {
1332 device
* dev2
= CONTAINING_RECORD(le
, device
, list_entry
);
1335 if (length
< sizeof(btrfs_device
) - sizeof(WCHAR
)) {
1336 Status
= STATUS_BUFFER_OVERFLOW
;
1343 dev
->next_entry
= sizeof(btrfs_device
) - sizeof(WCHAR
) + dev
->namelen
;
1344 dev
= (btrfs_device
*)((UINT8
*)dev
+ dev
->next_entry
);
1347 structlen
= length
- offsetof(btrfs_device
, namelen
);
1349 Status
= dev_ioctl(dev2
->devobj
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0, &dev
->namelen
, structlen
, TRUE
, NULL
);
1350 if (!NT_SUCCESS(Status
))
1353 dev
->next_entry
= 0;
1354 dev
->dev_id
= dev2
->devitem
.dev_id
;
1355 dev
->size
= dev2
->length
;
1356 dev
->readonly
= (Vcb
->readonly
|| dev2
->readonly
) ? TRUE
: FALSE
;
1357 dev
->device_number
= dev2
->disk_num
;
1358 dev
->partition_number
= dev2
->part_num
;
1360 length
-= sizeof(btrfs_device
) - sizeof(WCHAR
) + dev
->namelen
;
1366 ExReleaseResourceLite(&Vcb
->tree_lock
);
1371 static NTSTATUS
get_usage(device_extension
* Vcb
, void* data
, ULONG length
) {
1372 btrfs_usage
* usage
= (btrfs_usage
*)data
;
1373 btrfs_usage
* lastbue
= NULL
;
1377 if (length
< sizeof(btrfs_usage
))
1378 return STATUS_BUFFER_OVERFLOW
;
1380 length
-= offsetof(btrfs_usage
, devices
);
1382 ExAcquireResourceSharedLite(&Vcb
->chunk_lock
, TRUE
);
1384 le
= Vcb
->chunks
.Flink
;
1385 while (le
!= &Vcb
->chunks
) {
1386 BOOL addnew
= FALSE
;
1388 chunk
* c
= CONTAINING_RECORD(le
, chunk
, list_entry
);
1390 if (!lastbue
) // first entry
1393 btrfs_usage
* bue
= usage
;
1398 if (bue
->type
== c
->chunk_item
->type
) {
1403 if (bue
->next_entry
== 0)
1406 bue
= (btrfs_usage
*)((UINT8
*)bue
+ bue
->next_entry
);
1418 if (length
< offsetof(btrfs_usage
, devices
)) {
1419 Status
= STATUS_BUFFER_OVERFLOW
;
1423 length
-= offsetof(btrfs_usage
, devices
);
1425 lastbue
->next_entry
= offsetof(btrfs_usage
, devices
) + (lastbue
->num_devices
* sizeof(btrfs_usage_device
));
1427 bue
= (btrfs_usage
*)((UINT8
*)lastbue
+ lastbue
->next_entry
);
1430 bue
->next_entry
= 0;
1431 bue
->type
= c
->chunk_item
->type
;
1434 bue
->num_devices
= 0;
1436 if (c
->chunk_item
->type
& BLOCK_FLAG_RAID0
)
1437 factor
= c
->chunk_item
->num_stripes
;
1438 else if (c
->chunk_item
->type
& BLOCK_FLAG_RAID10
)
1439 factor
= c
->chunk_item
->num_stripes
/ c
->chunk_item
->sub_stripes
;
1440 else if (c
->chunk_item
->type
& BLOCK_FLAG_RAID5
)
1441 factor
= c
->chunk_item
->num_stripes
- 1;
1442 else if (c
->chunk_item
->type
& BLOCK_FLAG_RAID6
)
1443 factor
= c
->chunk_item
->num_stripes
- 2;
1448 while (le2
!= &Vcb
->chunks
) {
1449 chunk
* c2
= CONTAINING_RECORD(le2
, chunk
, list_entry
);
1451 if (c2
->chunk_item
->type
== c
->chunk_item
->type
) {
1453 CHUNK_ITEM_STRIPE
* cis
= (CHUNK_ITEM_STRIPE
*)&c2
->chunk_item
[1];
1456 bue
->size
+= c2
->chunk_item
->size
;
1457 bue
->used
+= c2
->used
;
1459 stripesize
= c2
->chunk_item
->size
/ factor
;
1461 for (i
= 0; i
< c2
->chunk_item
->num_stripes
; i
++) {
1465 for (j
= 0; j
< bue
->num_devices
; j
++) {
1466 if (bue
->devices
[j
].dev_id
== cis
[i
].dev_id
) {
1467 bue
->devices
[j
].alloc
+= stripesize
;
1474 if (length
< sizeof(btrfs_usage_device
)) {
1475 Status
= STATUS_BUFFER_OVERFLOW
;
1479 length
-= sizeof(btrfs_usage_device
);
1481 bue
->devices
[bue
->num_devices
].dev_id
= cis
[i
].dev_id
;
1482 bue
->devices
[bue
->num_devices
].alloc
= stripesize
;
1497 Status
= STATUS_SUCCESS
;
1500 ExReleaseResourceLite(&Vcb
->chunk_lock
);
1505 static NTSTATUS
is_volume_mounted(device_extension
* Vcb
, PIRP Irp
) {
1508 IO_STATUS_BLOCK iosb
;
1509 BOOL verify
= FALSE
;
1512 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1514 le
= Vcb
->devices
.Flink
;
1515 while (le
!= &Vcb
->devices
) {
1516 device
* dev
= CONTAINING_RECORD(le
, device
, list_entry
);
1518 if (dev
->devobj
&& dev
->removable
) {
1519 Status
= dev_ioctl(dev
->devobj
, IOCTL_STORAGE_CHECK_VERIFY
, NULL
, 0, &cc
, sizeof(ULONG
), FALSE
, &iosb
);
1521 if (iosb
.Information
!= sizeof(ULONG
))
1524 if (Status
== STATUS_VERIFY_REQUIRED
|| (NT_SUCCESS(Status
) && cc
!= dev
->change_count
)) {
1525 dev
->devobj
->Flags
|= DO_VERIFY_VOLUME
;
1529 if (NT_SUCCESS(Status
) && iosb
.Information
== sizeof(ULONG
))
1530 dev
->change_count
= cc
;
1532 if (!NT_SUCCESS(Status
) || verify
) {
1533 IoSetHardErrorOrVerifyDevice(Irp
, dev
->devobj
);
1534 ExReleaseResourceLite(&Vcb
->tree_lock
);
1536 return verify
? STATUS_VERIFY_REQUIRED
: Status
;
1543 ExReleaseResourceLite(&Vcb
->tree_lock
);
1545 return STATUS_SUCCESS
;
1548 static NTSTATUS
fs_get_statistics(PDEVICE_OBJECT DeviceObject
, PFILE_OBJECT FileObject
, void* buffer
, DWORD buflen
, ULONG_PTR
* retlen
) {
1549 FILESYSTEM_STATISTICS
* fss
;
1551 WARN("STUB: FSCTL_FILESYSTEM_GET_STATISTICS\n");
1553 // This is hideously wrong, but at least it stops SMB from breaking
1555 if (buflen
< sizeof(FILESYSTEM_STATISTICS
))
1556 return STATUS_BUFFER_TOO_SMALL
;
1559 RtlZeroMemory(fss
, sizeof(FILESYSTEM_STATISTICS
));
1562 fss
->FileSystemType
= FILESYSTEM_STATISTICS_TYPE_NTFS
;
1563 fss
->SizeOfCompleteStructure
= sizeof(FILESYSTEM_STATISTICS
);
1565 *retlen
= sizeof(FILESYSTEM_STATISTICS
);
1567 return STATUS_SUCCESS
;
1570 static NTSTATUS
set_sparse(device_extension
* Vcb
, PFILE_OBJECT FileObject
, void* data
, ULONG length
, PIRP Irp
) {
1571 FILE_SET_SPARSE_BUFFER
* fssb
= data
;
1575 ccb
* ccb
= FileObject
->FsContext2
;
1576 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
1578 if (data
&& length
< sizeof(FILE_SET_SPARSE_BUFFER
))
1579 return STATUS_INVALID_PARAMETER
;
1582 ERR("FileObject was NULL\n");
1583 return STATUS_INVALID_PARAMETER
;
1586 fcb
= FileObject
->FsContext
;
1589 ERR("FCB was NULL\n");
1590 return STATUS_INVALID_PARAMETER
;
1594 ERR("CCB was NULL\n");
1595 return STATUS_INVALID_PARAMETER
;
1598 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_ATTRIBUTES
)) {
1599 WARN("insufficient privileges\n");
1600 return STATUS_ACCESS_DENIED
;
1604 ERR("no fileref\n");
1605 return STATUS_INVALID_PARAMETER
;
1608 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1609 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1611 if (fcb
->type
!= BTRFS_TYPE_FILE
) {
1612 WARN("FileObject did not point to a file\n");
1613 Status
= STATUS_INVALID_PARAMETER
;
1618 set
= fssb
->SetSparse
;
1623 fcb
->atts
|= FILE_ATTRIBUTE_SPARSE_FILE
;
1624 fcb
->atts_changed
= TRUE
;
1628 fcb
->atts
&= ~FILE_ATTRIBUTE_SPARSE_FILE
;
1629 fcb
->atts_changed
= TRUE
;
1631 defda
= get_file_attributes(Vcb
, &fcb
->inode_item
, fcb
->subvol
, fcb
->inode
, fcb
->type
,
1632 fileref
&& fileref
->filepart
.Length
> 0 && fileref
->filepart
.Buffer
[0] == '.', TRUE
, Irp
);
1634 fcb
->atts_deleted
= defda
== fcb
->atts
;
1637 mark_fcb_dirty(fcb
);
1638 send_notification_fcb(fileref
, FILE_NOTIFY_CHANGE_ATTRIBUTES
, FILE_ACTION_MODIFIED
);
1640 Status
= STATUS_SUCCESS
;
1643 ExReleaseResourceLite(fcb
->Header
.Resource
);
1644 ExReleaseResourceLite(&Vcb
->tree_lock
);
1649 static NTSTATUS
zero_data(device_extension
* Vcb
, fcb
* fcb
, UINT64 start
, UINT64 length
, PIRP Irp
, LIST_ENTRY
* rollback
) {
1651 BOOL compress
= write_fcb_compressed(fcb
);
1652 UINT64 start_data
, end_data
;
1656 start_data
= start
& ~(UINT64
)(COMPRESSED_EXTENT_SIZE
- 1);
1657 end_data
= min(sector_align(start
+ length
, COMPRESSED_EXTENT_SIZE
),
1658 sector_align(fcb
->inode_item
.st_size
, fcb
->Vcb
->superblock
.sector_size
));
1660 start_data
= start
& ~(UINT64
)(fcb
->Vcb
->superblock
.sector_size
- 1);
1661 end_data
= sector_align(start
+ length
, fcb
->Vcb
->superblock
.sector_size
);
1664 data
= ExAllocatePoolWithTag(PagedPool
, end_data
- start_data
, ALLOC_TAG
);
1666 ERR("out of memory\n");
1667 return STATUS_INSUFFICIENT_RESOURCES
;
1670 RtlZeroMemory(data
, end_data
- start_data
);
1672 if (start
> start_data
|| start
+ length
< end_data
) {
1673 Status
= read_file(fcb
, data
, start_data
, end_data
- start_data
, NULL
, Irp
, TRUE
);
1675 if (!NT_SUCCESS(Status
)) {
1676 ERR("read_file returned %08x\n", Status
);
1682 RtlZeroMemory(data
+ start
- start_data
, length
);
1685 Status
= write_compressed(fcb
, start_data
, end_data
, data
, Irp
, rollback
);
1689 if (!NT_SUCCESS(Status
)) {
1690 ERR("write_compressed returned %08x\n", Status
);
1694 Status
= do_write_file(fcb
, start_data
, end_data
, data
, Irp
, rollback
);
1698 if (!NT_SUCCESS(Status
)) {
1699 ERR("do_write_file returned %08x\n", Status
);
1704 return STATUS_SUCCESS
;
1707 static NTSTATUS
set_zero_data(device_extension
* Vcb
, PFILE_OBJECT FileObject
, void* data
, ULONG length
, PIRP Irp
) {
1708 FILE_ZERO_DATA_INFORMATION
* fzdi
= data
;
1713 LIST_ENTRY rollback
, *le
;
1718 IO_STATUS_BLOCK iosb
;
1720 if (!data
|| length
< sizeof(FILE_ZERO_DATA_INFORMATION
))
1721 return STATUS_INVALID_PARAMETER
;
1724 ERR("FileObject was NULL\n");
1725 return STATUS_INVALID_PARAMETER
;
1728 if (fzdi
->BeyondFinalZero
.QuadPart
<= fzdi
->FileOffset
.QuadPart
) {
1729 WARN("BeyondFinalZero was less than or equal to FileOffset (%llx <= %llx)\n", fzdi
->BeyondFinalZero
.QuadPart
, fzdi
->FileOffset
.QuadPart
);
1730 return STATUS_INVALID_PARAMETER
;
1733 fcb
= FileObject
->FsContext
;
1736 ERR("FCB was NULL\n");
1737 return STATUS_INVALID_PARAMETER
;
1740 ccb
= FileObject
->FsContext2
;
1743 ERR("ccb was NULL\n");
1744 return STATUS_INVALID_PARAMETER
;
1747 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_DATA
)) {
1748 WARN("insufficient privileges\n");
1749 return STATUS_ACCESS_DENIED
;
1752 fileref
= ccb
->fileref
;
1755 ERR("fileref was NULL\n");
1756 return STATUS_INVALID_PARAMETER
;
1759 InitializeListHead(&rollback
);
1761 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1762 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1764 CcFlushCache(&fcb
->nonpaged
->segment_object
, NULL
, 0, &iosb
);
1766 if (fcb
->type
!= BTRFS_TYPE_FILE
) {
1767 WARN("FileObject did not point to a file\n");
1768 Status
= STATUS_INVALID_PARAMETER
;
1773 ERR("FileObject is stream\n");
1774 Status
= STATUS_INVALID_PARAMETER
;
1778 if (fzdi
->FileOffset
.QuadPart
>= fcb
->inode_item
.st_size
) {
1779 Status
= STATUS_SUCCESS
;
1784 le
= fcb
->extents
.Flink
;
1785 while (le
!= &fcb
->extents
) {
1786 extent
* ext2
= CONTAINING_RECORD(le
, extent
, list_entry
);
1788 if (!ext2
->ignore
) {
1797 Status
= STATUS_SUCCESS
;
1801 if (ext
->datalen
>= sizeof(EXTENT_DATA
) && ext
->data
->type
== EXTENT_TYPE_INLINE
) {
1802 Status
= zero_data(Vcb
, fcb
, fzdi
->FileOffset
.QuadPart
, fzdi
->BeyondFinalZero
.QuadPart
- fzdi
->FileOffset
.QuadPart
, Irp
, &rollback
);
1803 if (!NT_SUCCESS(Status
)) {
1804 ERR("zero_data returned %08x\n", Status
);
1808 start
= sector_align(fzdi
->FileOffset
.QuadPart
, Vcb
->superblock
.sector_size
);
1810 if (fzdi
->BeyondFinalZero
.QuadPart
> fcb
->inode_item
.st_size
)
1811 end
= sector_align(fcb
->inode_item
.st_size
, Vcb
->superblock
.sector_size
);
1813 end
= (fzdi
->BeyondFinalZero
.QuadPart
/ Vcb
->superblock
.sector_size
) * Vcb
->superblock
.sector_size
;
1816 Status
= zero_data(Vcb
, fcb
, fzdi
->FileOffset
.QuadPart
, fzdi
->BeyondFinalZero
.QuadPart
- fzdi
->FileOffset
.QuadPart
, Irp
, &rollback
);
1817 if (!NT_SUCCESS(Status
)) {
1818 ERR("zero_data returned %08x\n", Status
);
1822 if (start
> fzdi
->FileOffset
.QuadPart
) {
1823 Status
= zero_data(Vcb
, fcb
, fzdi
->FileOffset
.QuadPart
, start
- fzdi
->FileOffset
.QuadPart
, Irp
, &rollback
);
1824 if (!NT_SUCCESS(Status
)) {
1825 ERR("zero_data returned %08x\n", Status
);
1830 if (end
< fzdi
->BeyondFinalZero
.QuadPart
) {
1831 Status
= zero_data(Vcb
, fcb
, end
, fzdi
->BeyondFinalZero
.QuadPart
- end
, Irp
, &rollback
);
1832 if (!NT_SUCCESS(Status
)) {
1833 ERR("zero_data returned %08x\n", Status
);
1839 Status
= excise_extents(Vcb
, fcb
, start
, end
, Irp
, &rollback
);
1840 if (!NT_SUCCESS(Status
)) {
1841 ERR("excise_extents returned %08x\n", Status
);
1848 CcPurgeCacheSection(&fcb
->nonpaged
->segment_object
, &fzdi
->FileOffset
, fzdi
->BeyondFinalZero
.QuadPart
- fzdi
->FileOffset
.QuadPart
, FALSE
);
1850 KeQuerySystemTime(&time
);
1851 win_time_to_unix(time
, &now
);
1853 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1854 fcb
->inode_item
.sequence
++;
1856 if (!ccb
->user_set_change_time
)
1857 fcb
->inode_item
.st_ctime
= now
;
1859 if (!ccb
->user_set_write_time
)
1860 fcb
->inode_item
.st_mtime
= now
;
1862 fcb
->extents_changed
= TRUE
;
1863 fcb
->inode_item_changed
= TRUE
;
1864 mark_fcb_dirty(fcb
);
1866 send_notification_fcb(fileref
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1868 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
1869 fcb
->subvol
->root_item
.ctime
= now
;
1871 Status
= STATUS_SUCCESS
;
1874 if (!NT_SUCCESS(Status
))
1875 do_rollback(Vcb
, &rollback
);
1877 clear_rollback(Vcb
, &rollback
);
1879 ExReleaseResourceLite(fcb
->Header
.Resource
);
1880 ExReleaseResourceLite(&Vcb
->tree_lock
);
1885 static NTSTATUS
query_ranges(device_extension
* Vcb
, PFILE_OBJECT FileObject
, FILE_ALLOCATED_RANGE_BUFFER
* inbuf
, ULONG inbuflen
, void* outbuf
, ULONG outbuflen
, ULONG_PTR
* retlen
) {
1889 FILE_ALLOCATED_RANGE_BUFFER
* ranges
= outbuf
;
1891 UINT64 last_start
, last_end
;
1893 TRACE("FSCTL_QUERY_ALLOCATED_RANGES\n");
1896 ERR("FileObject was NULL\n");
1897 return STATUS_INVALID_PARAMETER
;
1900 if (!inbuf
|| inbuflen
< sizeof(FILE_ALLOCATED_RANGE_BUFFER
) || !outbuf
)
1901 return STATUS_INVALID_PARAMETER
;
1903 fcb
= FileObject
->FsContext
;
1906 ERR("FCB was NULL\n");
1907 return STATUS_INVALID_PARAMETER
;
1910 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, TRUE
);
1912 // If file is not marked as sparse, claim the whole thing as an allocated range
1914 if (!(fcb
->atts
& FILE_ATTRIBUTE_SPARSE_FILE
)) {
1915 if (fcb
->inode_item
.st_size
== 0)
1916 Status
= STATUS_SUCCESS
;
1917 else if (outbuflen
< sizeof(FILE_ALLOCATED_RANGE_BUFFER
))
1918 Status
= STATUS_BUFFER_TOO_SMALL
;
1920 ranges
[i
].FileOffset
.QuadPart
= 0;
1921 ranges
[i
].Length
.QuadPart
= fcb
->inode_item
.st_size
;
1923 Status
= STATUS_SUCCESS
;
1930 le
= fcb
->extents
.Flink
;
1935 while (le
!= &fcb
->extents
) {
1936 extent
* ext
= CONTAINING_RECORD(le
, extent
, list_entry
);
1939 EXTENT_DATA2
* ed2
= (ext
->data
->type
== EXTENT_TYPE_REGULAR
|| ext
->data
->type
== EXTENT_TYPE_PREALLOC
) ? (EXTENT_DATA2
*)ext
->data
->data
: NULL
;
1940 UINT64 len
= ed2
? ed2
->num_bytes
: ext
->data
->decoded_size
;
1942 if (ext
->offset
> last_end
) { // first extent after a hole
1943 if (last_end
> last_start
) {
1944 if ((i
+ 1) * sizeof(FILE_ALLOCATED_RANGE_BUFFER
) <= outbuflen
) {
1945 ranges
[i
].FileOffset
.QuadPart
= last_start
;
1946 ranges
[i
].Length
.QuadPart
= min(fcb
->inode_item
.st_size
, last_end
) - last_start
;
1949 Status
= STATUS_BUFFER_TOO_SMALL
;
1954 last_start
= ext
->offset
;
1957 last_end
= ext
->offset
+ len
;
1963 if (last_end
> last_start
) {
1964 if ((i
+ 1) * sizeof(FILE_ALLOCATED_RANGE_BUFFER
) <= outbuflen
) {
1965 ranges
[i
].FileOffset
.QuadPart
= last_start
;
1966 ranges
[i
].Length
.QuadPart
= min(fcb
->inode_item
.st_size
, last_end
) - last_start
;
1969 Status
= STATUS_BUFFER_TOO_SMALL
;
1974 Status
= STATUS_SUCCESS
;
1977 *retlen
= i
* sizeof(FILE_ALLOCATED_RANGE_BUFFER
);
1979 ExReleaseResourceLite(fcb
->Header
.Resource
);
1984 static NTSTATUS
get_object_id(device_extension
* Vcb
, PFILE_OBJECT FileObject
, FILE_OBJECTID_BUFFER
* buf
, ULONG buflen
, ULONG_PTR
* retlen
) {
1987 TRACE("(%p, %p, %p, %x, %p)\n", Vcb
, FileObject
, buf
, buflen
, retlen
);
1990 ERR("FileObject was NULL\n");
1991 return STATUS_INVALID_PARAMETER
;
1994 if (!buf
|| buflen
< sizeof(FILE_OBJECTID_BUFFER
))
1995 return STATUS_INVALID_PARAMETER
;
1997 fcb
= FileObject
->FsContext
;
2000 ERR("FCB was NULL\n");
2001 return STATUS_INVALID_PARAMETER
;
2004 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, TRUE
);
2006 RtlCopyMemory(&buf
->ObjectId
[0], &fcb
->inode
, sizeof(UINT64
));
2007 RtlCopyMemory(&buf
->ObjectId
[sizeof(UINT64
)], &fcb
->subvol
->id
, sizeof(UINT64
));
2009 ExReleaseResourceLite(fcb
->Header
.Resource
);
2011 RtlZeroMemory(&buf
->ExtendedInfo
, sizeof(buf
->ExtendedInfo
));
2013 *retlen
= sizeof(FILE_OBJECTID_BUFFER
);
2015 return STATUS_SUCCESS
;
2018 static void flush_fcb_caches(device_extension
* Vcb
) {
2021 le
= Vcb
->all_fcbs
.Flink
;
2022 while (le
!= &Vcb
->all_fcbs
) {
2023 struct _fcb
* fcb
= CONTAINING_RECORD(le
, struct _fcb
, list_entry_all
);
2024 IO_STATUS_BLOCK iosb
;
2026 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
&& !fcb
->deleted
)
2027 CcFlushCache(&fcb
->nonpaged
->segment_object
, NULL
, 0, &iosb
);
2033 static NTSTATUS
lock_volume(device_extension
* Vcb
, PIRP Irp
) {
2034 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2036 LIST_ENTRY rollback
;
2038 BOOL lock_paused_balance
= FALSE
;
2040 TRACE("FSCTL_LOCK_VOLUME\n");
2042 TRACE("locking volume\n");
2044 FsRtlNotifyVolumeEvent(IrpSp
->FileObject
, FSRTL_VOLUME_LOCK
);
2047 return STATUS_SUCCESS
;
2049 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2051 if (Vcb
->root_fileref
&& Vcb
->root_fileref
->fcb
&& (Vcb
->root_fileref
->open_count
> 0 || has_open_children(Vcb
->root_fileref
))) {
2052 Status
= STATUS_ACCESS_DENIED
;
2053 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2057 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2059 InitializeListHead(&rollback
);
2061 if (Vcb
->balance
.thread
&& KeReadStateEvent(&Vcb
->balance
.event
)) {
2062 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
2063 KeClearEvent(&Vcb
->balance
.event
);
2064 ExReleaseResourceLite(&Vcb
->tree_lock
);
2066 lock_paused_balance
= TRUE
;
2069 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
2071 flush_fcb_caches(Vcb
);
2073 if (Vcb
->need_write
&& !Vcb
->readonly
)
2074 do_write(Vcb
, Irp
, &rollback
);
2078 clear_rollback(Vcb
, &rollback
);
2080 ExReleaseResourceLite(&Vcb
->tree_lock
);
2082 IoAcquireVpbSpinLock(&irql
);
2084 if (!(Vcb
->Vpb
->Flags
& VPB_LOCKED
)) {
2085 Vcb
->Vpb
->Flags
|= VPB_LOCKED
;
2087 Vcb
->locked_fileobj
= IrpSp
->FileObject
;
2088 Vcb
->lock_paused_balance
= lock_paused_balance
;
2090 Status
= STATUS_ACCESS_DENIED
;
2091 IoReleaseVpbSpinLock(irql
);
2093 if (lock_paused_balance
)
2094 KeSetEvent(&Vcb
->balance
.event
, 0, FALSE
);
2099 IoReleaseVpbSpinLock(irql
);
2101 Status
= STATUS_SUCCESS
;
2104 if (!NT_SUCCESS(Status
))
2105 FsRtlNotifyVolumeEvent(IrpSp
->FileObject
, FSRTL_VOLUME_LOCK_FAILED
);
2110 void do_unlock_volume(device_extension
* Vcb
) {
2113 IoAcquireVpbSpinLock(&irql
);
2115 Vcb
->locked
= FALSE
;
2116 Vcb
->Vpb
->Flags
&= ~VPB_LOCKED
;
2117 Vcb
->locked_fileobj
= NULL
;
2119 IoReleaseVpbSpinLock(irql
);
2121 if (Vcb
->lock_paused_balance
)
2122 KeSetEvent(&Vcb
->balance
.event
, 0, FALSE
);
2125 static NTSTATUS
unlock_volume(device_extension
* Vcb
, PIRP Irp
) {
2126 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2128 TRACE("FSCTL_UNLOCK_VOLUME\n");
2130 if (!Vcb
->locked
|| IrpSp
->FileObject
!= Vcb
->locked_fileobj
)
2131 return STATUS_NOT_LOCKED
;
2133 TRACE("unlocking volume\n");
2135 do_unlock_volume(Vcb
);
2137 FsRtlNotifyVolumeEvent(IrpSp
->FileObject
, FSRTL_VOLUME_UNLOCK
);
2139 return STATUS_SUCCESS
;
2142 static NTSTATUS
invalidate_volumes(PIRP Irp
) {
2143 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2144 LUID TcbPrivilege
= {SE_TCB_PRIVILEGE
, 0};
2147 PFILE_OBJECT fileobj
;
2148 PDEVICE_OBJECT devobj
;
2151 TRACE("FSCTL_INVALIDATE_VOLUMES\n");
2153 if (!SeSinglePrivilegeCheck(TcbPrivilege
, Irp
->RequestorMode
))
2154 return STATUS_PRIVILEGE_NOT_HELD
;
2157 if (IoIs32bitProcess(Irp
)) {
2158 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof(UINT32
))
2159 return STATUS_INVALID_PARAMETER
;
2161 h
= (HANDLE
)LongToHandle((*(PUINT32
)Irp
->AssociatedIrp
.SystemBuffer
));
2164 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof(HANDLE
))
2165 return STATUS_INVALID_PARAMETER
;
2167 h
= *(PHANDLE
)Irp
->AssociatedIrp
.SystemBuffer
;
2172 Status
= ObReferenceObjectByHandle(h
, 0, *IoFileObjectType
, KernelMode
, (void**)&fileobj
, NULL
);
2174 if (!NT_SUCCESS(Status
)) {
2175 ERR("ObReferenceObjectByHandle returned %08x\n", Status
);
2179 devobj
= fileobj
->DeviceObject
;
2180 ObDereferenceObject(fileobj
);
2182 ExAcquireResourceSharedLite(&global_loading_lock
, TRUE
);
2186 while (le
!= &VcbList
) {
2187 device_extension
* Vcb
= CONTAINING_RECORD(le
, device_extension
, list_entry
);
2189 if (Vcb
->Vpb
&& Vcb
->Vpb
->RealDevice
== devobj
) {
2190 if (Vcb
->Vpb
== devobj
->Vpb
) {
2193 BOOL free_newvpb
= FALSE
;
2194 LIST_ENTRY rollback
;
2196 newvpb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(VPB
), ALLOC_TAG
);
2198 ERR("out of memory\n");
2199 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2203 RtlZeroMemory(newvpb
, sizeof(VPB
));
2205 IoAcquireVpbSpinLock(&irql
);
2206 devobj
->Vpb
->Flags
&= ~VPB_MOUNTED
;
2207 IoReleaseVpbSpinLock(irql
);
2209 InitializeListHead(&rollback
);
2211 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
2213 Vcb
->removing
= TRUE
;
2215 ExReleaseResourceLite(&Vcb
->tree_lock
);
2217 CcWaitForCurrentLazyWriterActivity();
2219 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
2221 flush_fcb_caches(Vcb
);
2223 if (Vcb
->need_write
&& !Vcb
->readonly
)
2224 do_write(Vcb
, Irp
, &rollback
);
2228 clear_rollback(Vcb
, &rollback
);
2230 flush_fcb_caches(Vcb
);
2232 ExReleaseResourceLite(&Vcb
->tree_lock
);
2234 IoAcquireVpbSpinLock(&irql
);
2236 if (devobj
->Vpb
->Flags
& VPB_MOUNTED
) {
2237 newvpb
->Type
= IO_TYPE_VPB
;
2238 newvpb
->Size
= sizeof(VPB
);
2239 newvpb
->RealDevice
= devobj
;
2240 newvpb
->Flags
= devobj
->Vpb
->Flags
& VPB_REMOVE_PENDING
;
2242 devobj
->Vpb
= newvpb
;
2246 IoReleaseVpbSpinLock(irql
);
2260 Status
= STATUS_SUCCESS
;
2263 ExReleaseResourceLite(&global_loading_lock
);
2268 static NTSTATUS
is_volume_dirty(device_extension
* Vcb
, PIRP Irp
) {
2269 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2272 if (Irp
->AssociatedIrp
.SystemBuffer
) {
2273 volstate
= Irp
->AssociatedIrp
.SystemBuffer
;
2274 } else if (Irp
->MdlAddress
!= NULL
) {
2275 volstate
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, LowPagePriority
);
2278 return STATUS_INSUFFICIENT_RESOURCES
;
2280 return STATUS_INVALID_USER_BUFFER
;
2282 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(ULONG
))
2283 return STATUS_INVALID_PARAMETER
;
2287 if (IrpSp
->FileObject
->FsContext
!= Vcb
->volume_fcb
)
2288 return STATUS_INVALID_PARAMETER
;
2290 Irp
->IoStatus
.Information
= sizeof(ULONG
);
2292 return STATUS_SUCCESS
;
2295 static NTSTATUS
get_compression(device_extension
* Vcb
, PIRP Irp
) {
2296 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2297 USHORT
* compression
;
2299 TRACE("FSCTL_GET_COMPRESSION\n");
2301 if (Irp
->AssociatedIrp
.SystemBuffer
) {
2302 compression
= Irp
->AssociatedIrp
.SystemBuffer
;
2303 } else if (Irp
->MdlAddress
!= NULL
) {
2304 compression
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, LowPagePriority
);
2307 return STATUS_INSUFFICIENT_RESOURCES
;
2309 return STATUS_INVALID_USER_BUFFER
;
2311 if (IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(USHORT
))
2312 return STATUS_INVALID_PARAMETER
;
2314 *compression
= COMPRESSION_FORMAT_NONE
;
2316 Irp
->IoStatus
.Information
= sizeof(USHORT
);
2318 return STATUS_SUCCESS
;
2321 static void update_volumes(device_extension
* Vcb
) {
2324 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
2325 ExAcquireResourceExclusiveLite(&volumes_lock
, TRUE
);
2329 while (le
!= &volumes
) {
2330 volume
* v
= CONTAINING_RECORD(le
, volume
, list_entry
);
2332 if (RtlCompareMemory(&Vcb
->superblock
.uuid
, &v
->fsuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
2335 le
= Vcb
->devices
.Flink
;
2336 while (le
!= &Vcb
->devices
) {
2337 device
* dev
= CONTAINING_RECORD(le
, device
, list_entry
);
2339 if (RtlCompareMemory(&dev
->devitem
.device_uuid
, &v
->devuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
2340 v
->gen1
= v
->gen2
= Vcb
->superblock
.generation
- 1;
2351 ExReleaseResourceLite(&volumes_lock
);
2352 ExReleaseResourceLite(&Vcb
->tree_lock
);
2355 static NTSTATUS
dismount_volume(device_extension
* Vcb
, PIRP Irp
) {
2358 LIST_ENTRY rollback
;
2360 TRACE("FSCTL_DISMOUNT_VOLUME\n");
2362 if (!(Vcb
->Vpb
->Flags
& VPB_MOUNTED
))
2363 return STATUS_SUCCESS
;
2365 if (Vcb
->disallow_dismount
) {
2366 WARN("attempting to dismount boot volume or one containing a pagefile\n");
2367 return STATUS_ACCESS_DENIED
;
2370 InitializeListHead(&rollback
);
2372 Status
= FsRtlNotifyVolumeEvent(Vcb
->root_file
, FSRTL_VOLUME_DISMOUNT
);
2373 if (!NT_SUCCESS(Status
)) {
2374 WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status
);
2377 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
2379 flush_fcb_caches(Vcb
);
2381 if (Vcb
->need_write
&& !Vcb
->readonly
)
2382 do_write(Vcb
, Irp
, &rollback
);
2386 clear_rollback(Vcb
, &rollback
);
2388 Vcb
->removing
= TRUE
;
2389 update_volumes(Vcb
);
2391 ExReleaseResourceLite(&Vcb
->tree_lock
);
2393 IoAcquireVpbSpinLock(&irql
);
2394 Vcb
->Vpb
->Flags
&= ~VPB_MOUNTED
;
2395 Vcb
->Vpb
->Flags
|= VPB_DIRECT_WRITES_ALLOWED
;
2396 IoReleaseVpbSpinLock(irql
);
2398 return STATUS_SUCCESS
;
2401 static NTSTATUS
is_device_part_of_mounted_btrfs_raid(PDEVICE_OBJECT devobj
) {
2406 BTRFS_UUID fsuuid
, devuuid
;
2409 to_read
= devobj
->SectorSize
== 0 ? sizeof(superblock
) : sector_align(sizeof(superblock
), devobj
->SectorSize
);
2411 sb
= ExAllocatePoolWithTag(PagedPool
, to_read
, ALLOC_TAG
);
2413 ERR("out of memory\n");
2414 return STATUS_INSUFFICIENT_RESOURCES
;
2417 Status
= sync_read_phys(devobj
, superblock_addrs
[0], to_read
, (UINT8
*)sb
, TRUE
);
2418 if (!NT_SUCCESS(Status
)) {
2419 ERR("sync_read_phys returned %08x\n", Status
);
2424 if (sb
->magic
!= BTRFS_MAGIC
) {
2425 TRACE("device is not Btrfs\n");
2427 return STATUS_SUCCESS
;
2430 crc32
= ~calc_crc32c(0xffffffff, (UINT8
*)&sb
->uuid
, (ULONG
)sizeof(superblock
) - sizeof(sb
->checksum
));
2432 if (crc32
!= *((UINT32
*)sb
->checksum
)) {
2433 TRACE("device has Btrfs magic, but invalid superblock checksum\n");
2435 return STATUS_SUCCESS
;
2439 devuuid
= sb
->dev_item
.device_uuid
;
2443 ExAcquireResourceSharedLite(&global_loading_lock
, TRUE
);
2447 while (le
!= &VcbList
) {
2448 device_extension
* Vcb
= CONTAINING_RECORD(le
, device_extension
, list_entry
);
2450 if (RtlCompareMemory(&Vcb
->superblock
.uuid
, &fsuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
2453 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
2455 if (Vcb
->superblock
.num_devices
> 1) {
2456 le2
= Vcb
->devices
.Flink
;
2457 while (le2
!= &Vcb
->devices
) {
2458 device
* dev
= CONTAINING_RECORD(le2
, device
, list_entry
);
2460 if (RtlCompareMemory(&dev
->devitem
.device_uuid
, &devuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
2461 ExReleaseResourceLite(&Vcb
->tree_lock
);
2462 ExReleaseResourceLite(&global_loading_lock
);
2463 return STATUS_DEVICE_NOT_READY
;
2470 ExReleaseResourceLite(&Vcb
->tree_lock
);
2471 ExReleaseResourceLite(&global_loading_lock
);
2472 return STATUS_SUCCESS
;
2478 ExReleaseResourceLite(&global_loading_lock
);
2480 return STATUS_SUCCESS
;
2483 static NTSTATUS
add_device(device_extension
* Vcb
, PIRP Irp
, void* data
, ULONG length
, KPROCESSOR_MODE processor_mode
) {
2484 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2486 PFILE_OBJECT fileobj
, mountmgrfo
;
2488 LIST_ENTRY rollback
, *le
;
2489 GET_LENGTH_INFORMATION gli
;
2495 MOUNTDEV_NAME mdn1
, *mdn2
;
2496 UNICODE_STRING volname
, mmdevpath
;
2498 PDEVICE_OBJECT mountmgr
;
2501 STORAGE_DEVICE_NUMBER sdn
;
2503 volname
.Buffer
= NULL
;
2505 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE
), processor_mode
))
2506 return STATUS_PRIVILEGE_NOT_HELD
;
2508 if (Vcb
->readonly
) // FIXME - handle adding R/W device to seeding device
2509 return STATUS_MEDIA_WRITE_PROTECTED
;
2512 if (IoIs32bitProcess(Irp
)) {
2513 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof(UINT32
))
2514 return STATUS_INVALID_PARAMETER
;
2516 h
= (HANDLE
)LongToHandle((*(PUINT32
)Irp
->AssociatedIrp
.SystemBuffer
));
2519 if (IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
!= sizeof(HANDLE
))
2520 return STATUS_INVALID_PARAMETER
;
2522 h
= *(PHANDLE
)Irp
->AssociatedIrp
.SystemBuffer
;
2527 Status
= ObReferenceObjectByHandle(h
, 0, *IoFileObjectType
, Irp
->RequestorMode
, (void**)&fileobj
, NULL
);
2529 if (!NT_SUCCESS(Status
)) {
2530 ERR("ObReferenceObjectByHandle returned %08x\n", Status
);
2534 Status
= is_device_part_of_mounted_btrfs_raid(fileobj
->DeviceObject
);
2535 if (!NT_SUCCESS(Status
)) {
2536 ERR("is_device_part_of_mounted_btrfs_raid returned %08x\n", Status
);
2537 ObDereferenceObject(fileobj
);
2541 Status
= dev_ioctl(fileobj
->DeviceObject
, IOCTL_DISK_IS_WRITABLE
, NULL
, 0, NULL
, 0, TRUE
, NULL
);
2542 if (!NT_SUCCESS(Status
)) {
2543 ERR("IOCTL_DISK_IS_WRITABLE returned %08x\n", Status
);
2544 ObDereferenceObject(fileobj
);
2548 Status
= dev_ioctl(fileobj
->DeviceObject
, IOCTL_DISK_GET_LENGTH_INFO
, NULL
, 0,
2549 &gli
, sizeof(gli
), TRUE
, NULL
);
2550 if (!NT_SUCCESS(Status
)) {
2551 ERR("error reading length information: %08x\n", Status
);
2552 ObDereferenceObject(fileobj
);
2556 if (gli
.Length
.QuadPart
< 0x100000) {
2557 ERR("device was not large enough to hold FS (%llx bytes, need at least 1 MB)\n", gli
.Length
.QuadPart
);
2558 ObDereferenceObject(fileobj
);
2559 return STATUS_INTERNAL_ERROR
;
2562 Status
= dev_ioctl(fileobj
->DeviceObject
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0,
2563 &mdn1
, sizeof(MOUNTDEV_NAME
), TRUE
, NULL
);
2564 if (Status
== STATUS_BUFFER_OVERFLOW
) {
2565 mdn2
= ExAllocatePoolWithTag(PagedPool
, offsetof(MOUNTDEV_NAME
, Name
[0]) + mdn1
.NameLength
, ALLOC_TAG
);
2567 ERR("out of memory\n");
2568 ObDereferenceObject(fileobj
);
2569 return STATUS_INTERNAL_ERROR
;
2572 Status
= dev_ioctl(fileobj
->DeviceObject
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0,
2573 mdn2
, offsetof(MOUNTDEV_NAME
, Name
[0]) + mdn1
.NameLength
, TRUE
, NULL
);
2575 if (!NT_SUCCESS(Status
)) {
2576 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status
);
2577 ObDereferenceObject(fileobj
);
2580 } else if (NT_SUCCESS(Status
)) {
2581 mdn2
= ExAllocatePoolWithTag(PagedPool
, sizeof(MOUNTDEV_NAME
), ALLOC_TAG
);
2583 ERR("out of memory\n");
2584 ObDereferenceObject(fileobj
);
2585 return STATUS_INTERNAL_ERROR
;
2588 RtlCopyMemory(mdn2
, &mdn1
, sizeof(MOUNTDEV_NAME
));
2590 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status
);
2591 ObDereferenceObject(fileobj
);
2595 if (mdn2
->NameLength
== 0) {
2596 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned zero-length name\n");
2597 ObDereferenceObject(fileobj
);
2599 return STATUS_INTERNAL_ERROR
;
2602 volname
.Length
= volname
.MaximumLength
= mdn2
->NameLength
;
2603 volname
.Buffer
= ExAllocatePoolWithTag(PagedPool
, volname
.MaximumLength
, ALLOC_TAG
);
2604 if (!volname
.Buffer
) {
2605 ERR("out of memory\n");
2606 ObDereferenceObject(fileobj
);
2608 return STATUS_INSUFFICIENT_RESOURCES
;
2611 RtlCopyMemory(volname
.Buffer
, mdn2
->Name
, volname
.Length
);
2614 InitializeListHead(&rollback
);
2616 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
2618 if (Vcb
->need_write
) {
2619 Status
= do_write(Vcb
, Irp
, &rollback
);
2620 if (!NT_SUCCESS(Status
)) {
2621 ERR("do_write returned %08x\n", Status
);
2622 do_rollback(Vcb
, &rollback
);
2629 clear_rollback(Vcb
, &rollback
);
2631 dev
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(device
), ALLOC_TAG
);
2633 ERR("out of memory\n");
2634 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2638 RtlZeroMemory(dev
, sizeof(device
));
2640 dev
->devobj
= fileobj
->DeviceObject
;
2641 dev
->seeding
= FALSE
;
2642 dev
->length
= gli
.Length
.QuadPart
;
2643 init_device(Vcb
, dev
, FALSE
, TRUE
);
2645 InitializeListHead(&dev
->space
);
2647 if (gli
.Length
.QuadPart
> 0x100000) { // add disk hole - the first MB is marked as used
2648 Status
= add_space_entry(&dev
->space
, NULL
, 0x100000, gli
.Length
.QuadPart
- 0x100000);
2649 if (!NT_SUCCESS(Status
)) {
2650 ERR("add_space_entry returned %08x\n", Status
);
2651 Status
= STATUS_INTERNAL_ERROR
;
2658 le
= Vcb
->devices
.Flink
;
2659 while (le
!= &Vcb
->devices
) {
2660 device
* dev
= CONTAINING_RECORD(le
, device
, list_entry
);
2662 if (dev
->devitem
.dev_id
> dev_id
)
2663 dev_id
= dev
->devitem
.dev_id
;
2670 dev
->devitem
.dev_id
= dev_id
;
2671 dev
->devitem
.num_bytes
= gli
.Length
.QuadPart
;
2672 dev
->devitem
.bytes_used
= 0;
2673 dev
->devitem
.optimal_io_align
= Vcb
->superblock
.sector_size
;
2674 dev
->devitem
.optimal_io_width
= Vcb
->superblock
.sector_size
;
2675 dev
->devitem
.minimal_io_size
= Vcb
->superblock
.sector_size
;
2676 dev
->devitem
.type
= 0;
2677 dev
->devitem
.generation
= 0;
2678 dev
->devitem
.start_offset
= 0;
2679 dev
->devitem
.dev_group
= 0;
2680 dev
->devitem
.seek_speed
= 0;
2681 dev
->devitem
.bandwidth
= 0;
2682 get_uuid(&dev
->devitem
.device_uuid
);
2683 dev
->devitem
.fs_uuid
= Vcb
->superblock
.uuid
;
2685 di
= ExAllocatePoolWithTag(PagedPool
, sizeof(DEV_ITEM
), ALLOC_TAG
);
2687 ERR("out of memory\n");
2691 RtlCopyMemory(di
, &dev
->devitem
, sizeof(DEV_ITEM
));
2693 if (!insert_tree_item(Vcb
, Vcb
->chunk_root
, 1, TYPE_DEV_ITEM
, di
->dev_id
, di
, sizeof(DEV_ITEM
), NULL
, Irp
, &rollback
)) {
2694 ERR("insert_tree_item failed\n");
2696 Status
= STATUS_INTERNAL_ERROR
;
2700 // add stats entry to dev tree
2701 stats
= ExAllocatePoolWithTag(PagedPool
, sizeof(UINT64
) * 5, ALLOC_TAG
);
2703 ERR("out of memory\n");
2704 Status
= STATUS_INTERNAL_ERROR
;
2708 RtlZeroMemory(stats
, sizeof(UINT64
) * 5);
2710 searchkey
.obj_id
= 0;
2711 searchkey
.obj_type
= TYPE_DEV_STATS
;
2712 searchkey
.offset
= di
->dev_id
;
2714 Status
= find_item(Vcb
, Vcb
->dev_root
, &tp
, &searchkey
, FALSE
, Irp
);
2715 if (!NT_SUCCESS(Status
)) {
2716 ERR("error - find_item returned %08x\n", Status
);
2720 if (!keycmp(tp
.item
->key
, searchkey
))
2721 delete_tree_item(Vcb
, &tp
, &rollback
);
2723 if (!insert_tree_item(Vcb
, Vcb
->dev_root
, 0, TYPE_DEV_STATS
, di
->dev_id
, stats
, sizeof(UINT64
) * 5, NULL
, Irp
, &rollback
)) {
2724 ERR("insert_tree_item failed\n");
2726 Status
= STATUS_INTERNAL_ERROR
;
2730 // We clear the first megabyte of the device, so Windows doesn't identify it as another FS
2731 mb
= ExAllocatePoolWithTag(PagedPool
, 0x100000, ALLOC_TAG
);
2733 ERR("out of memory\n");
2734 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2738 RtlZeroMemory(mb
, 0x100000);
2740 Status
= write_data_phys(fileobj
->DeviceObject
, 0, mb
, 0x100000);
2741 if (!NT_SUCCESS(Status
)) {
2742 ERR("write_data_phys returned %08x\n", Status
);
2748 v
= ExAllocatePoolWithTag(PagedPool
, sizeof(volume
), ALLOC_TAG
);
2750 ERR("out of memory\n");
2751 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2755 v
->fsuuid
= Vcb
->superblock
.uuid
;
2756 v
->devuuid
= dev
->devitem
.device_uuid
;
2758 v
->devpath
= volname
;
2759 v
->length
= gli
.Length
.QuadPart
;
2760 v
->gen1
= v
->gen2
= Vcb
->superblock
.generation
;
2762 v
->processed
= TRUE
;
2764 ExAcquireResourceExclusiveLite(&volumes_lock
, TRUE
);
2765 InsertTailList(&volumes
, &v
->list_entry
);
2766 ExReleaseResourceLite(&volumes_lock
);
2768 volname
.Buffer
= NULL
;
2770 Status
= dev_ioctl(fileobj
->DeviceObject
, IOCTL_STORAGE_GET_DEVICE_NUMBER
, NULL
, 0,
2771 &sdn
, sizeof(STORAGE_DEVICE_NUMBER
), TRUE
, NULL
);
2772 if (!NT_SUCCESS(Status
)) {
2773 WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status
);
2777 v
->disk_num
= sdn
.DeviceNumber
;
2778 v
->part_num
= sdn
.PartitionNumber
;
2781 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
2782 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &mountmgrfo
, &mountmgr
);
2783 if (!NT_SUCCESS(Status
))
2784 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
2786 remove_drive_letter(mountmgr
, v
);
2788 ObDereferenceObject(mountmgrfo
);
2791 Vcb
->superblock
.num_devices
++;
2792 Vcb
->superblock
.total_bytes
+= gli
.Length
.QuadPart
;
2793 Vcb
->devices_loaded
++;
2794 InsertTailList(&Vcb
->devices
, &dev
->list_entry
);
2796 ObReferenceObject(fileobj
->DeviceObject
);
2798 do_write(Vcb
, Irp
, &rollback
);
2802 clear_rollback(Vcb
, &rollback
);
2804 Status
= STATUS_SUCCESS
;
2807 ExReleaseResourceLite(&Vcb
->tree_lock
);
2808 ObDereferenceObject(fileobj
);
2811 ExFreePool(volname
.Buffer
);
2816 static NTSTATUS
allow_extended_dasd_io(device_extension
* Vcb
, PFILE_OBJECT FileObject
) {
2820 TRACE("FSCTL_ALLOW_EXTENDED_DASD_IO\n");
2823 return STATUS_INVALID_PARAMETER
;
2825 fcb
= FileObject
->FsContext
;
2826 ccb
= FileObject
->FsContext2
;
2829 return STATUS_INVALID_PARAMETER
;
2831 if (fcb
!= Vcb
->volume_fcb
)
2832 return STATUS_INVALID_PARAMETER
;
2835 return STATUS_INVALID_PARAMETER
;
2837 ccb
->allow_extended_dasd_io
= TRUE
;
2839 return STATUS_SUCCESS
;
2842 static NTSTATUS
query_uuid(device_extension
* Vcb
, void* data
, ULONG length
) {
2843 if (length
< sizeof(BTRFS_UUID
))
2844 return STATUS_BUFFER_OVERFLOW
;
2846 RtlCopyMemory(data
, &Vcb
->superblock
.uuid
, sizeof(BTRFS_UUID
));
2848 return STATUS_SUCCESS
;
2851 NTSTATUS
fsctl_request(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, UINT32 type
, BOOL user
) {
2852 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2856 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
2857 WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
2858 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2861 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
2862 WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
2863 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2866 case FSCTL_REQUEST_BATCH_OPLOCK
:
2867 WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
2868 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2871 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
2872 WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
2873 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2876 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
2877 WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
2878 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2881 case FSCTL_OPLOCK_BREAK_NOTIFY
:
2882 WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
2883 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2886 case FSCTL_LOCK_VOLUME
:
2887 Status
= lock_volume(DeviceObject
->DeviceExtension
, Irp
);
2890 case FSCTL_UNLOCK_VOLUME
:
2891 Status
= unlock_volume(DeviceObject
->DeviceExtension
, Irp
);
2894 case FSCTL_DISMOUNT_VOLUME
:
2895 Status
= dismount_volume(DeviceObject
->DeviceExtension
, Irp
);
2898 case FSCTL_IS_VOLUME_MOUNTED
:
2899 Status
= is_volume_mounted(DeviceObject
->DeviceExtension
, Irp
);
2902 case FSCTL_IS_PATHNAME_VALID
:
2903 WARN("STUB: FSCTL_IS_PATHNAME_VALID\n");
2904 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2907 case FSCTL_MARK_VOLUME_DIRTY
:
2908 WARN("STUB: FSCTL_MARK_VOLUME_DIRTY\n");
2909 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2912 case FSCTL_QUERY_RETRIEVAL_POINTERS
:
2913 WARN("STUB: FSCTL_QUERY_RETRIEVAL_POINTERS\n");
2914 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2917 case FSCTL_GET_COMPRESSION
:
2918 Status
= get_compression(DeviceObject
->DeviceExtension
, Irp
);
2921 case FSCTL_SET_COMPRESSION
:
2922 WARN("STUB: FSCTL_SET_COMPRESSION\n");
2923 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2926 case FSCTL_SET_BOOTLOADER_ACCESSED
:
2927 WARN("STUB: FSCTL_SET_BOOTLOADER_ACCESSED\n");
2928 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2931 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
2932 WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
2933 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2936 case FSCTL_INVALIDATE_VOLUMES
:
2937 Status
= invalidate_volumes(Irp
);
2940 case FSCTL_QUERY_FAT_BPB
:
2941 WARN("STUB: FSCTL_QUERY_FAT_BPB\n");
2942 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2945 case FSCTL_REQUEST_FILTER_OPLOCK
:
2946 WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
2947 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2950 case FSCTL_FILESYSTEM_GET_STATISTICS
:
2951 Status
= fs_get_statistics(DeviceObject
, IrpSp
->FileObject
, Irp
->AssociatedIrp
.SystemBuffer
,
2952 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
2955 case FSCTL_GET_NTFS_VOLUME_DATA
:
2956 WARN("STUB: FSCTL_GET_NTFS_VOLUME_DATA\n");
2957 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2960 case FSCTL_GET_NTFS_FILE_RECORD
:
2961 WARN("STUB: FSCTL_GET_NTFS_FILE_RECORD\n");
2962 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2965 case FSCTL_GET_VOLUME_BITMAP
:
2966 WARN("STUB: FSCTL_GET_VOLUME_BITMAP\n");
2967 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2970 case FSCTL_GET_RETRIEVAL_POINTERS
:
2971 WARN("STUB: FSCTL_GET_RETRIEVAL_POINTERS\n");
2972 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2975 case FSCTL_MOVE_FILE
:
2976 WARN("STUB: FSCTL_MOVE_FILE\n");
2977 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2980 case FSCTL_IS_VOLUME_DIRTY
:
2981 Status
= is_volume_dirty(DeviceObject
->DeviceExtension
, Irp
);
2984 case FSCTL_ALLOW_EXTENDED_DASD_IO
:
2985 Status
= allow_extended_dasd_io(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
);
2988 case FSCTL_FIND_FILES_BY_SID
:
2989 WARN("STUB: FSCTL_FIND_FILES_BY_SID\n");
2990 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2993 case FSCTL_SET_OBJECT_ID
:
2994 WARN("STUB: FSCTL_SET_OBJECT_ID\n");
2995 Status
= STATUS_INVALID_DEVICE_REQUEST
;
2998 case FSCTL_GET_OBJECT_ID
:
2999 Status
= get_object_id(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, Irp
->UserBuffer
,
3000 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
3003 case FSCTL_DELETE_OBJECT_ID
:
3004 WARN("STUB: FSCTL_DELETE_OBJECT_ID\n");
3005 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3008 case FSCTL_SET_REPARSE_POINT
:
3009 Status
= set_reparse_point(DeviceObject
, Irp
);
3012 case FSCTL_GET_REPARSE_POINT
:
3013 Status
= get_reparse_point(DeviceObject
, IrpSp
->FileObject
, Irp
->AssociatedIrp
.SystemBuffer
,
3014 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
3017 case FSCTL_DELETE_REPARSE_POINT
:
3018 Status
= delete_reparse_point(DeviceObject
, Irp
);
3021 case FSCTL_ENUM_USN_DATA
:
3022 WARN("STUB: FSCTL_ENUM_USN_DATA\n");
3023 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3026 case FSCTL_SECURITY_ID_CHECK
:
3027 WARN("STUB: FSCTL_SECURITY_ID_CHECK\n");
3028 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3031 case FSCTL_READ_USN_JOURNAL
:
3032 WARN("STUB: FSCTL_READ_USN_JOURNAL\n");
3033 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3036 case FSCTL_SET_OBJECT_ID_EXTENDED
:
3037 WARN("STUB: FSCTL_SET_OBJECT_ID_EXTENDED\n");
3038 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3041 case FSCTL_CREATE_OR_GET_OBJECT_ID
:
3042 Status
= get_object_id(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, Irp
->UserBuffer
,
3043 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
3046 case FSCTL_SET_SPARSE
:
3047 Status
= set_sparse(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, Irp
->AssociatedIrp
.SystemBuffer
,
3048 IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
);
3051 case FSCTL_SET_ZERO_DATA
:
3052 Status
= set_zero_data(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, Irp
->AssociatedIrp
.SystemBuffer
,
3053 IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
);
3056 case FSCTL_QUERY_ALLOCATED_RANGES
:
3057 Status
= query_ranges(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, IrpSp
->Parameters
.FileSystemControl
.Type3InputBuffer
,
3058 IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
->UserBuffer
,
3059 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
3062 case FSCTL_ENABLE_UPGRADE
:
3063 WARN("STUB: FSCTL_ENABLE_UPGRADE\n");
3064 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3067 case FSCTL_SET_ENCRYPTION
:
3068 WARN("STUB: FSCTL_SET_ENCRYPTION\n");
3069 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3072 case FSCTL_ENCRYPTION_FSCTL_IO
:
3073 WARN("STUB: FSCTL_ENCRYPTION_FSCTL_IO\n");
3074 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3077 case FSCTL_WRITE_RAW_ENCRYPTED
:
3078 WARN("STUB: FSCTL_WRITE_RAW_ENCRYPTED\n");
3079 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3082 case FSCTL_READ_RAW_ENCRYPTED
:
3083 WARN("STUB: FSCTL_READ_RAW_ENCRYPTED\n");
3084 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3087 case FSCTL_CREATE_USN_JOURNAL
:
3088 WARN("STUB: FSCTL_CREATE_USN_JOURNAL\n");
3089 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3092 case FSCTL_READ_FILE_USN_DATA
:
3093 WARN("STUB: FSCTL_READ_FILE_USN_DATA\n");
3094 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3097 case FSCTL_WRITE_USN_CLOSE_RECORD
:
3098 WARN("STUB: FSCTL_WRITE_USN_CLOSE_RECORD\n");
3099 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3102 case FSCTL_EXTEND_VOLUME
:
3103 WARN("STUB: FSCTL_EXTEND_VOLUME\n");
3104 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3107 case FSCTL_QUERY_USN_JOURNAL
:
3108 WARN("STUB: FSCTL_QUERY_USN_JOURNAL\n");
3109 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3112 case FSCTL_DELETE_USN_JOURNAL
:
3113 WARN("STUB: FSCTL_DELETE_USN_JOURNAL\n");
3114 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3117 case FSCTL_MARK_HANDLE
:
3118 WARN("STUB: FSCTL_MARK_HANDLE\n");
3119 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3122 case FSCTL_SIS_COPYFILE
:
3123 WARN("STUB: FSCTL_SIS_COPYFILE\n");
3124 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3127 case FSCTL_SIS_LINK_FILES
:
3128 WARN("STUB: FSCTL_SIS_LINK_FILES\n");
3129 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3132 case FSCTL_RECALL_FILE
:
3133 WARN("STUB: FSCTL_RECALL_FILE\n");
3134 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3137 case FSCTL_READ_FROM_PLEX
:
3138 WARN("STUB: FSCTL_READ_FROM_PLEX\n");
3139 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3142 case FSCTL_FILE_PREFETCH
:
3143 WARN("STUB: FSCTL_FILE_PREFETCH\n");
3144 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3147 #if WIN32_WINNT >= 0x0600
3148 case FSCTL_MAKE_MEDIA_COMPATIBLE
:
3149 WARN("STUB: FSCTL_MAKE_MEDIA_COMPATIBLE\n");
3150 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3153 case FSCTL_SET_DEFECT_MANAGEMENT
:
3154 WARN("STUB: FSCTL_SET_DEFECT_MANAGEMENT\n");
3155 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3158 case FSCTL_QUERY_SPARING_INFO
:
3159 WARN("STUB: FSCTL_QUERY_SPARING_INFO\n");
3160 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3163 case FSCTL_QUERY_ON_DISK_VOLUME_INFO
:
3164 WARN("STUB: FSCTL_QUERY_ON_DISK_VOLUME_INFO\n");
3165 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3168 case FSCTL_SET_VOLUME_COMPRESSION_STATE
:
3169 WARN("STUB: FSCTL_SET_VOLUME_COMPRESSION_STATE\n");
3170 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3173 case FSCTL_TXFS_MODIFY_RM
:
3174 WARN("STUB: FSCTL_TXFS_MODIFY_RM\n");
3175 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3178 case FSCTL_TXFS_QUERY_RM_INFORMATION
:
3179 WARN("STUB: FSCTL_TXFS_QUERY_RM_INFORMATION\n");
3180 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3183 case FSCTL_TXFS_ROLLFORWARD_REDO
:
3184 WARN("STUB: FSCTL_TXFS_ROLLFORWARD_REDO\n");
3185 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3188 case FSCTL_TXFS_ROLLFORWARD_UNDO
:
3189 WARN("STUB: FSCTL_TXFS_ROLLFORWARD_UNDO\n");
3190 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3193 case FSCTL_TXFS_START_RM
:
3194 WARN("STUB: FSCTL_TXFS_START_RM\n");
3195 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3198 case FSCTL_TXFS_SHUTDOWN_RM
:
3199 WARN("STUB: FSCTL_TXFS_SHUTDOWN_RM\n");
3200 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3203 case FSCTL_TXFS_READ_BACKUP_INFORMATION
:
3204 WARN("STUB: FSCTL_TXFS_READ_BACKUP_INFORMATION\n");
3205 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3208 case FSCTL_TXFS_WRITE_BACKUP_INFORMATION
:
3209 WARN("STUB: FSCTL_TXFS_WRITE_BACKUP_INFORMATION\n");
3210 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3213 case FSCTL_TXFS_CREATE_SECONDARY_RM
:
3214 WARN("STUB: FSCTL_TXFS_CREATE_SECONDARY_RM\n");
3215 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3218 case FSCTL_TXFS_GET_METADATA_INFO
:
3219 WARN("STUB: FSCTL_TXFS_GET_METADATA_INFO\n");
3220 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3223 case FSCTL_TXFS_GET_TRANSACTED_VERSION
:
3224 WARN("STUB: FSCTL_TXFS_GET_TRANSACTED_VERSION\n");
3225 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3228 case FSCTL_TXFS_SAVEPOINT_INFORMATION
:
3229 WARN("STUB: FSCTL_TXFS_SAVEPOINT_INFORMATION\n");
3230 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3233 case FSCTL_TXFS_CREATE_MINIVERSION
:
3234 WARN("STUB: FSCTL_TXFS_CREATE_MINIVERSION\n");
3235 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3238 case FSCTL_TXFS_TRANSACTION_ACTIVE
:
3239 WARN("STUB: FSCTL_TXFS_TRANSACTION_ACTIVE\n");
3240 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3243 case FSCTL_SET_ZERO_ON_DEALLOCATION
:
3244 WARN("STUB: FSCTL_SET_ZERO_ON_DEALLOCATION\n");
3245 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3248 case FSCTL_SET_REPAIR
:
3249 WARN("STUB: FSCTL_SET_REPAIR\n");
3250 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3253 case FSCTL_GET_REPAIR
:
3254 WARN("STUB: FSCTL_GET_REPAIR\n");
3255 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3258 case FSCTL_WAIT_FOR_REPAIR
:
3259 WARN("STUB: FSCTL_WAIT_FOR_REPAIR\n");
3260 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3263 case FSCTL_INITIATE_REPAIR
:
3264 WARN("STUB: FSCTL_INITIATE_REPAIR\n");
3265 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3268 case FSCTL_CSC_INTERNAL
:
3269 WARN("STUB: FSCTL_CSC_INTERNAL\n");
3270 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3273 case FSCTL_SHRINK_VOLUME
:
3274 WARN("STUB: FSCTL_SHRINK_VOLUME\n");
3275 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3278 case FSCTL_SET_SHORT_NAME_BEHAVIOR
:
3279 WARN("STUB: FSCTL_SET_SHORT_NAME_BEHAVIOR\n");
3280 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3283 case FSCTL_DFSR_SET_GHOST_HANDLE_STATE
:
3284 WARN("STUB: FSCTL_DFSR_SET_GHOST_HANDLE_STATE\n");
3285 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3288 case FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES
:
3289 WARN("STUB: FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES\n");
3290 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3293 case FSCTL_TXFS_LIST_TRANSACTIONS
:
3294 WARN("STUB: FSCTL_TXFS_LIST_TRANSACTIONS\n");
3295 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3298 case FSCTL_QUERY_PAGEFILE_ENCRYPTION
:
3299 WARN("STUB: FSCTL_QUERY_PAGEFILE_ENCRYPTION\n");
3300 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3303 case FSCTL_RESET_VOLUME_ALLOCATION_HINTS
:
3304 WARN("STUB: FSCTL_RESET_VOLUME_ALLOCATION_HINTS\n");
3305 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3308 case FSCTL_TXFS_READ_BACKUP_INFORMATION2
:
3309 WARN("STUB: FSCTL_TXFS_READ_BACKUP_INFORMATION2\n");
3310 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3313 case FSCTL_CSV_CONTROL
:
3314 WARN("STUB: FSCTL_CSV_CONTROL\n");
3315 Status
= STATUS_INVALID_DEVICE_REQUEST
;
3318 case FSCTL_BTRFS_GET_FILE_IDS
:
3319 Status
= get_file_ids(IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3322 case FSCTL_BTRFS_CREATE_SUBVOL
:
3323 Status
= create_subvol(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, Irp
);
3326 case FSCTL_BTRFS_CREATE_SNAPSHOT
:
3327 Status
= create_snapshot(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
, Irp
);
3330 case FSCTL_BTRFS_GET_INODE_INFO
:
3331 Status
= get_inode_info(IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3334 case FSCTL_BTRFS_SET_INODE_INFO
:
3335 Status
= set_inode_info(IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3338 case FSCTL_BTRFS_GET_DEVICES
:
3339 Status
= get_devices(DeviceObject
->DeviceExtension
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3342 case FSCTL_BTRFS_GET_USAGE
:
3343 Status
= get_usage(DeviceObject
->DeviceExtension
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3346 case FSCTL_BTRFS_START_BALANCE
:
3347 Status
= start_balance(DeviceObject
->DeviceExtension
, Irp
->AssociatedIrp
.SystemBuffer
, IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
->RequestorMode
);
3350 case FSCTL_BTRFS_QUERY_BALANCE
:
3351 Status
= query_balance(DeviceObject
->DeviceExtension
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3354 case FSCTL_BTRFS_PAUSE_BALANCE
:
3355 Status
= pause_balance(DeviceObject
->DeviceExtension
, Irp
->RequestorMode
);
3358 case FSCTL_BTRFS_RESUME_BALANCE
:
3359 Status
= resume_balance(DeviceObject
->DeviceExtension
, Irp
->RequestorMode
);
3362 case FSCTL_BTRFS_STOP_BALANCE
:
3363 Status
= stop_balance(DeviceObject
->DeviceExtension
, Irp
->RequestorMode
);
3366 case FSCTL_BTRFS_ADD_DEVICE
:
3367 Status
= add_device(DeviceObject
->DeviceExtension
, Irp
, Irp
->AssociatedIrp
.SystemBuffer
, IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
->RequestorMode
);
3370 case FSCTL_BTRFS_REMOVE_DEVICE
:
3371 Status
= remove_device(DeviceObject
->DeviceExtension
, Irp
->AssociatedIrp
.SystemBuffer
, IrpSp
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
->RequestorMode
);
3374 case FSCTL_BTRFS_GET_UUID
:
3375 Status
= query_uuid(DeviceObject
->DeviceExtension
, map_user_buffer(Irp
), IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
3379 TRACE("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",
3380 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
, (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0xff0000) >> 16,
3381 (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0xc000) >> 14, (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0x3ffc) >> 2,
3382 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0x3);
3383 Status
= STATUS_INVALID_DEVICE_REQUEST
;