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 static NTSTATUS
get_file_ids(PFILE_OBJECT FileObject
, void* data
, ULONG length
) {
31 btrfs_get_file_ids
* bgfi
;
34 if (length
< sizeof(btrfs_get_file_ids
))
35 return STATUS_BUFFER_OVERFLOW
;
38 return STATUS_INVALID_PARAMETER
;
40 fcb
= FileObject
->FsContext
;
43 return STATUS_INVALID_PARAMETER
;
47 bgfi
->subvol
= fcb
->subvol
->id
;
48 bgfi
->inode
= fcb
->inode
;
49 bgfi
->top
= fcb
->Vcb
->root_fileref
->fcb
== fcb
? TRUE
: FALSE
;
51 return STATUS_SUCCESS
;
54 static void get_uuid(BTRFS_UUID
* uuid
) {
58 seed
= KeQueryPerformanceCounter(NULL
);
60 for (i
= 0; i
< 16; i
+=2) {
61 ULONG rand
= RtlRandomEx(&seed
.LowPart
);
63 uuid
->uuid
[i
] = (rand
& 0xff00) >> 8;
64 uuid
->uuid
[i
+1] = rand
& 0xff;
68 static NTSTATUS
snapshot_tree_copy(device_extension
* Vcb
, UINT64 addr
, root
* subvol
, UINT64 dupflags
, UINT64
* newaddr
, LIST_ENTRY
* rollback
) {
71 write_tree_context
* wtc
;
77 buf
= ExAllocatePoolWithTag(NonPagedPool
, Vcb
->superblock
.node_size
, ALLOC_TAG
);
79 ERR("out of memory\n");
80 return STATUS_INSUFFICIENT_RESOURCES
;
83 wtc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(write_tree_context
), ALLOC_TAG
);
85 ERR("out of memory\n");
87 return STATUS_INSUFFICIENT_RESOURCES
;
90 Status
= read_tree(Vcb
, addr
, buf
);
91 if (!NT_SUCCESS(Status
)) {
92 ERR("read_tree returned %08x\n", Status
);
96 th
= (tree_header
*)buf
;
98 RtlZeroMemory(&t
, sizeof(tree
));
101 t
.header
.level
= th
->level
;
102 t
.header
.tree_id
= t
.root
->id
;
104 Status
= get_tree_new_address(Vcb
, &t
, rollback
);
105 if (!NT_SUCCESS(Status
)) {
106 ERR("get_tree_new_address returned %08x\n", Status
);
110 if (!t
.has_new_address
) {
111 ERR("tree new address not set\n");
112 Status
= STATUS_INTERNAL_ERROR
;
116 c
= get_chunk_from_address(Vcb
, t
.new_address
);
119 increase_chunk_usage(c
, Vcb
->superblock
.node_size
);
121 ERR("could not find chunk for address %llx\n", t
.new_address
);
122 Status
= STATUS_INTERNAL_ERROR
;
126 th
->address
= t
.new_address
;
127 th
->tree_id
= subvol
->id
;
128 th
->generation
= Vcb
->superblock
.generation
;
130 if (th
->level
== 0) {
132 leaf_node
* ln
= (leaf_node
*)&th
[1];
134 for (i
= 0; i
< th
->num_items
; i
++) {
135 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
)) {
136 EXTENT_DATA
* ed
= (EXTENT_DATA
*)(((UINT8
*)&th
[1]) + ln
[i
].offset
);
138 // FIXME - what are we supposed to do with prealloc here? Replace it with sparse extents, or do new preallocation?
139 if (ed
->type
== EXTENT_TYPE_REGULAR
&& ln
[i
].size
>= sizeof(EXTENT_DATA
) - 1 + sizeof(EXTENT_DATA2
)) {
140 EXTENT_DATA2
* ed2
= (EXTENT_DATA2
*)&ed
->data
[0];
142 if (ed2
->size
!= 0) { // not sparse
143 Status
= increase_extent_refcount_data(Vcb
, ed2
->address
, ed2
->size
, subvol
, ln
[i
].key
.obj_id
, ln
[i
].key
.offset
- ed2
->offset
, 1, rollback
);
145 if (!NT_SUCCESS(Status
)) {
146 ERR("increase_extent_refcount_data returned %08x\n", Status
);
156 internal_node
* in
= (internal_node
*)&th
[1];
158 for (i
= 0; i
< th
->num_items
; i
++) {
159 Status
= snapshot_tree_copy(Vcb
, in
[i
].address
, subvol
, dupflags
, &newaddr
, rollback
);
161 if (!NT_SUCCESS(Status
)) {
162 ERR("snapshot_tree_copy returned %08x\n", Status
);
166 in
[i
].generation
= Vcb
->superblock
.generation
;
167 in
[i
].address
= newaddr
;
171 *((UINT32
*)buf
) = ~calc_crc32c(0xffffffff, (UINT8
*)&th
->fs_uuid
, Vcb
->superblock
.node_size
- sizeof(th
->csum
));
173 KeInitializeEvent(&wtc
->Event
, NotificationEvent
, FALSE
);
174 InitializeListHead(&wtc
->stripes
);
176 Status
= write_tree(Vcb
, t
.new_address
, buf
, wtc
);
177 if (!NT_SUCCESS(Status
)) {
178 ERR("write_tree returned %08x\n", Status
);
182 if (wtc
->stripes
.Flink
!= &wtc
->stripes
) {
183 // launch writes and wait
184 le
= wtc
->stripes
.Flink
;
185 while (le
!= &wtc
->stripes
) {
186 write_tree_stripe
* stripe
= CONTAINING_RECORD(le
, write_tree_stripe
, list_entry
);
188 IoCallDriver(stripe
->device
->devobj
, stripe
->Irp
);
193 KeWaitForSingleObject(&wtc
->Event
, Executive
, KernelMode
, FALSE
, NULL
);
195 le
= wtc
->stripes
.Flink
;
196 while (le
!= &wtc
->stripes
) {
197 write_tree_stripe
* stripe
= CONTAINING_RECORD(le
, write_tree_stripe
, list_entry
);
199 if (!NT_SUCCESS(stripe
->iosb
.Status
)) {
200 Status
= stripe
->iosb
.Status
;
207 free_write_tree_stripes(wtc
);
211 if (NT_SUCCESS(Status
))
212 *newaddr
= t
.new_address
;
223 static void flush_subvol_fcbs(root
* subvol
) {
224 LIST_ENTRY
* le
= subvol
->fcbs
.Flink
;
226 if (IsListEmpty(&subvol
->fcbs
))
229 while (le
!= &subvol
->fcbs
) {
230 struct _fcb
* fcb
= CONTAINING_RECORD(le
, struct _fcb
, list_entry
);
231 IO_STATUS_BLOCK iosb
;
233 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
&& !fcb
->deleted
)
234 CcFlushCache(&fcb
->nonpaged
->segment_object
, NULL
, 0, &iosb
);
240 static NTSTATUS
do_create_snapshot(device_extension
* Vcb
, PFILE_OBJECT parent
, fcb
* subvol_fcb
, UINT32 crc32
, PANSI_STRING utf8
) {
244 root
*r
, *subvol
= subvol_fcb
->subvol
;
247 UINT64 address
, dirpos
, *root_num
;
250 fcb
* fcb
= parent
->FsContext
;
251 ULONG disize
, rrsize
;
256 InitializeListHead(&rollback
);
258 acquire_tree_lock(Vcb
, TRUE
);
260 // flush open files on this subvol
262 flush_subvol_fcbs(subvol
);
266 if (Vcb
->write_trees
> 0)
267 do_write(Vcb
, &rollback
);
271 clear_rollback(&rollback
);
273 InitializeListHead(&rollback
);
277 if (Vcb
->root_root
->lastinode
== 0)
278 get_last_inode(Vcb
, Vcb
->root_root
);
280 id
= Vcb
->root_root
->lastinode
> 0x100 ? (Vcb
->root_root
->lastinode
+ 1) : 0x101;
281 Status
= create_root(Vcb
, id
, &r
, TRUE
, Vcb
->superblock
.generation
, &rollback
);
283 if (!NT_SUCCESS(Status
)) {
284 ERR("create_root returned %08x\n", Status
);
288 if (!Vcb
->uuid_root
) {
291 TRACE("uuid root doesn't exist, creating it\n");
293 Status
= create_root(Vcb
, BTRFS_ROOT_UUID
, &uuid_root
, FALSE
, 0, &rollback
);
295 if (!NT_SUCCESS(Status
)) {
296 ERR("create_root returned %08x\n", Status
);
300 Vcb
->uuid_root
= uuid_root
;
303 root_num
= ExAllocatePoolWithTag(PagedPool
, sizeof(UINT64
), ALLOC_TAG
);
305 ERR("out of memory\n");
306 Status
= STATUS_INSUFFICIENT_RESOURCES
;
313 get_uuid(&r
->root_item
.uuid
);
315 RtlCopyMemory(&searchkey
.obj_id
, &r
->root_item
.uuid
, sizeof(UINT64
));
316 searchkey
.obj_type
= TYPE_SUBVOL_UUID
;
317 RtlCopyMemory(&searchkey
.offset
, &r
->root_item
.uuid
.uuid
[sizeof(UINT64
)], sizeof(UINT64
));
319 Status
= find_item(Vcb
, Vcb
->uuid_root
, &tp
, &searchkey
, FALSE
);
320 } while (NT_SUCCESS(Status
) && !keycmp(&searchkey
, &tp
.item
->key
));
324 if (!insert_tree_item(Vcb
, Vcb
->uuid_root
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, root_num
, sizeof(UINT64
), NULL
, &rollback
)) {
325 ERR("insert_tree_item failed\n");
326 ExFreePool(root_num
);
327 Status
= STATUS_INTERNAL_ERROR
;
331 searchkey
.obj_id
= r
->id
;
332 searchkey
.obj_type
= TYPE_ROOT_ITEM
;
333 searchkey
.offset
= 0xffffffffffffffff;
335 Status
= find_item(Vcb
, Vcb
->root_root
, &tp
, &searchkey
, FALSE
);
336 if (!NT_SUCCESS(Status
)) {
337 ERR("error - find_item returned %08x\n", Status
);
341 Status
= snapshot_tree_copy(Vcb
, subvol
->root_item
.block_number
, r
, tp
.tree
->flags
, &address
, &rollback
);
342 if (!NT_SUCCESS(Status
)) {
343 ERR("snapshot_tree_copy returned %08x\n", Status
);
347 KeQuerySystemTime(&time
);
348 win_time_to_unix(time
, &now
);
350 r
->root_item
.inode
.generation
= 1;
351 r
->root_item
.inode
.st_size
= 3;
352 r
->root_item
.inode
.st_blocks
= subvol
->root_item
.inode
.st_blocks
;
353 r
->root_item
.inode
.st_nlink
= 1;
354 r
->root_item
.inode
.st_mode
= __S_IFDIR
| S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
; // 40755
355 r
->root_item
.inode
.flags
= 0xffffffff80000000; // FIXME - find out what these mean
356 r
->root_item
.generation
= Vcb
->superblock
.generation
;
357 r
->root_item
.objid
= subvol
->root_item
.objid
;
358 r
->root_item
.block_number
= address
;
359 r
->root_item
.bytes_used
= subvol
->root_item
.bytes_used
;
360 r
->root_item
.last_snapshot_generation
= Vcb
->superblock
.generation
;
361 r
->root_item
.root_level
= subvol
->root_item
.root_level
;
362 r
->root_item
.generation2
= Vcb
->superblock
.generation
;
363 r
->root_item
.parent_uuid
= subvol
->root_item
.uuid
;
364 r
->root_item
.ctransid
= subvol
->root_item
.ctransid
;
365 r
->root_item
.otransid
= Vcb
->superblock
.generation
;
366 r
->root_item
.ctime
= subvol
->root_item
.ctime
;
367 r
->root_item
.otime
= now
;
369 r
->treeholder
.address
= address
;
371 // FIXME - do we need to copy over the send and receive fields too?
373 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) {
374 ERR("error - could not find ROOT_ITEM for subvol %llx\n", r
->id
);
375 Status
= STATUS_INTERNAL_ERROR
;
379 RtlCopyMemory(tp
.item
->data
, &r
->root_item
, sizeof(ROOT_ITEM
));
380 Vcb
->root_root
->lastinode
= r
->id
;
382 // update ROOT_ITEM of original subvol
384 subvol
->root_item
.last_snapshot_generation
= Vcb
->superblock
.generation
;
386 // We also rewrite the top of the old subvolume tree, for some reason
387 searchkey
.obj_id
= 0;
388 searchkey
.obj_type
= 0;
389 searchkey
.offset
= 0;
391 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
392 if (!NT_SUCCESS(Status
)) {
393 ERR("error - find_item returned %08x\n", Status
);
397 if (!subvol
->treeholder
.tree
->write
) {
398 subvol
->treeholder
.tree
->write
= TRUE
;
404 dirpos
= find_next_dir_index(Vcb
, fcb
->subvol
, fcb
->inode
);
406 ERR("find_next_dir_index failed\n");
407 Status
= STATUS_INTERNAL_ERROR
;
411 disize
= sizeof(DIR_ITEM
) - 1 + utf8
->Length
;
412 di
= ExAllocatePoolWithTag(PagedPool
, disize
, ALLOC_TAG
);
414 ERR("out of memory\n");
415 Status
= STATUS_INSUFFICIENT_RESOURCES
;
419 di2
= ExAllocatePoolWithTag(PagedPool
, disize
, ALLOC_TAG
);
421 ERR("out of memory\n");
422 Status
= STATUS_INSUFFICIENT_RESOURCES
;
428 di
->key
.obj_type
= TYPE_ROOT_ITEM
;
429 di
->key
.offset
= 0xffffffffffffffff;
430 di
->transid
= Vcb
->superblock
.generation
;
432 di
->n
= utf8
->Length
;
433 di
->type
= BTRFS_TYPE_DIRECTORY
;
434 RtlCopyMemory(di
->name
, utf8
->Buffer
, utf8
->Length
);
436 RtlCopyMemory(di2
, di
, disize
);
438 Status
= add_dir_item(Vcb
, fcb
->subvol
, fcb
->inode
, crc32
, di
, disize
, &rollback
);
439 if (!NT_SUCCESS(Status
)) {
440 ERR("add_dir_item returned %08x\n", Status
);
446 if (!insert_tree_item(Vcb
, fcb
->subvol
, fcb
->inode
, TYPE_DIR_INDEX
, dirpos
, di2
, disize
, NULL
, &rollback
)) {
447 ERR("insert_tree_item failed\n");
448 Status
= STATUS_INTERNAL_ERROR
;
454 rrsize
= sizeof(ROOT_REF
) - 1 + utf8
->Length
;
455 rr
= ExAllocatePoolWithTag(PagedPool
, rrsize
, ALLOC_TAG
);
457 ERR("out of memory\n");
458 Status
= STATUS_INSUFFICIENT_RESOURCES
;
462 rr
->dir
= fcb
->inode
;
464 rr
->n
= utf8
->Length
;
465 RtlCopyMemory(rr
->name
, utf8
->Buffer
, utf8
->Length
);
467 if (!insert_tree_item(Vcb
, Vcb
->root_root
, fcb
->subvol
->id
, TYPE_ROOT_REF
, r
->id
, rr
, rrsize
, NULL
, &rollback
)) {
468 ERR("insert_tree_item failed\n");
469 Status
= STATUS_INTERNAL_ERROR
;
475 rr2
= ExAllocatePoolWithTag(PagedPool
, rrsize
, ALLOC_TAG
);
477 ERR("out of memory\n");
478 Status
= STATUS_INSUFFICIENT_RESOURCES
;
482 RtlCopyMemory(rr2
, rr
, rrsize
);
484 if (!insert_tree_item(Vcb
, Vcb
->root_root
, r
->id
, TYPE_ROOT_BACKREF
, fcb
->subvol
->id
, rr2
, rrsize
, NULL
, &rollback
)) {
485 ERR("insert_tree_item failed\n");
486 Status
= STATUS_INTERNAL_ERROR
;
490 // change fcb's INODE_ITEM
492 // unlike when we create a file normally, the seq of the parent doesn't appear to change
493 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
494 fcb
->inode_item
.st_size
+= utf8
->Length
* 2;
495 fcb
->inode_item
.st_ctime
= now
;
496 fcb
->inode_item
.st_mtime
= now
;
498 searchkey
.obj_id
= fcb
->inode
;
499 searchkey
.obj_type
= TYPE_INODE_ITEM
;
500 searchkey
.offset
= 0;
502 Status
= find_item(Vcb
, fcb
->subvol
, &tp
, &searchkey
, FALSE
);
503 if (!NT_SUCCESS(Status
)) {
504 ERR("error - find_item returned %08x\n", Status
);
508 if (keycmp(&searchkey
, &tp
.item
->key
)) {
509 ERR("error - could not find INODE_ITEM for directory %llx in subvol %llx\n", fcb
->inode
, fcb
->subvol
->id
);
510 Status
= STATUS_INTERNAL_ERROR
;
514 ii
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_ITEM
), ALLOC_TAG
);
516 ERR("out of memory\n");
517 Status
= STATUS_INSUFFICIENT_RESOURCES
;
521 RtlCopyMemory(ii
, &fcb
->inode_item
, sizeof(INODE_ITEM
));
522 delete_tree_item(Vcb
, &tp
, &rollback
);
524 insert_tree_item(Vcb
, fcb
->subvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, ii
, sizeof(INODE_ITEM
), NULL
, &rollback
);
526 fcb
->subvol
->root_item
.ctime
= now
;
527 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
529 if (Vcb
->write_trees
> 0)
530 do_write(Vcb
, &rollback
);
534 Status
= STATUS_SUCCESS
;
537 if (NT_SUCCESS(Status
))
538 clear_rollback(&rollback
);
540 do_rollback(Vcb
, &rollback
);
542 release_tree_lock(Vcb
, TRUE
);
547 static NTSTATUS
create_snapshot(device_extension
* Vcb
, PFILE_OBJECT FileObject
, void* data
, ULONG length
) {
548 PFILE_OBJECT subvol_obj
;
550 btrfs_create_snapshot
* bcs
= data
;
553 UNICODE_STRING nameus
;
560 if (length
< offsetof(btrfs_create_snapshot
, name
))
561 return STATUS_INVALID_PARAMETER
;
563 if (length
< offsetof(btrfs_create_snapshot
, name
) + bcs
->namelen
)
564 return STATUS_INVALID_PARAMETER
;
567 return STATUS_INVALID_PARAMETER
;
569 if (!FileObject
|| !FileObject
->FsContext
)
570 return STATUS_INVALID_PARAMETER
;
572 fcb
= FileObject
->FsContext
;
573 ccb
= FileObject
->FsContext2
;
575 if (!fcb
|| !ccb
|| fcb
->type
!= BTRFS_TYPE_DIRECTORY
)
576 return STATUS_INVALID_PARAMETER
;
578 fileref
= ccb
->fileref
;
580 if (!(ccb
->access
& FILE_ADD_SUBDIRECTORY
)) {
581 WARN("insufficient privileges\n");
582 return STATUS_ACCESS_DENIED
;
585 nameus
.Buffer
= bcs
->name
;
586 nameus
.Length
= nameus
.MaximumLength
= bcs
->namelen
;
588 if (!is_file_name_valid(&nameus
))
589 return STATUS_OBJECT_NAME_INVALID
;
593 Status
= RtlUnicodeToUTF8N(NULL
, 0, &len
, bcs
->name
, bcs
->namelen
);
594 if (!NT_SUCCESS(Status
)) {
595 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
600 ERR("RtlUnicodeToUTF8N returned a length of 0\n");
601 return STATUS_INTERNAL_ERROR
;
604 utf8
.MaximumLength
= utf8
.Length
= len
;
605 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.Length
, ALLOC_TAG
);
608 ERR("out of memory\n");
609 return STATUS_INSUFFICIENT_RESOURCES
;
612 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, len
, &len
, bcs
->name
, bcs
->namelen
);
613 if (!NT_SUCCESS(Status
)) {
614 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
618 crc32
= calc_crc32c(0xfffffffe, (UINT8
*)utf8
.Buffer
, utf8
.Length
);
620 if (find_file_in_dir_with_crc32(Vcb
, &nameus
, crc32
, fcb
->subvol
, fcb
->inode
, NULL
, NULL
, NULL
, NULL
)) {
621 WARN("file already exists\n");
622 Status
= STATUS_OBJECT_NAME_COLLISION
;
626 Status
= ObReferenceObjectByHandle(bcs
->subvol
, 0, *IoFileObjectType
, UserMode
, (void**)&subvol_obj
, NULL
);
627 if (!NT_SUCCESS(Status
)) {
628 ERR("ObReferenceObjectByHandle returned %08x\n", Status
);
632 subvol_fcb
= subvol_obj
->FsContext
;
634 Status
= STATUS_INVALID_PARAMETER
;
638 if (subvol_fcb
->inode
!= subvol_fcb
->subvol
->root_item
.objid
) {
639 WARN("handle inode was %llx, expected %llx\n", subvol_fcb
->inode
, subvol_fcb
->subvol
->root_item
.objid
);
640 Status
= STATUS_INVALID_PARAMETER
;
644 ccb
= subvol_obj
->FsContext2
;
647 Status
= STATUS_INVALID_PARAMETER
;
651 if (!(ccb
->access
& FILE_TRAVERSE
)) {
652 WARN("insufficient privileges\n");
653 Status
= STATUS_ACCESS_DENIED
;
657 Status
= do_create_snapshot(Vcb
, FileObject
, subvol_fcb
, crc32
, &utf8
);
659 if (NT_SUCCESS(Status
)) {
662 ffn
.Length
= fileref
->full_filename
.Length
+ bcs
->namelen
;
663 if (fcb
!= fcb
->Vcb
->root_fileref
->fcb
)
664 ffn
.Length
+= sizeof(WCHAR
);
666 ffn
.MaximumLength
= ffn
.Length
;
667 ffn
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ffn
.Length
, ALLOC_TAG
);
672 RtlCopyMemory(ffn
.Buffer
, fileref
->full_filename
.Buffer
, fileref
->full_filename
.Length
);
673 i
= fileref
->full_filename
.Length
;
675 if (fcb
!= fcb
->Vcb
->root_fileref
->fcb
) {
676 ffn
.Buffer
[i
/ sizeof(WCHAR
)] = '\\';
680 RtlCopyMemory(&ffn
.Buffer
[i
/ sizeof(WCHAR
)], bcs
->name
, bcs
->namelen
);
682 TRACE("full filename = %.*S\n", ffn
.Length
/ sizeof(WCHAR
), ffn
.Buffer
);
684 FsRtlNotifyFullReportChange(Vcb
->NotifySync
, &Vcb
->DirNotifyList
, (PSTRING
)&ffn
, i
, NULL
, NULL
,
685 FILE_NOTIFY_CHANGE_DIR_NAME
, FILE_ACTION_ADDED
, NULL
);
687 ExFreePool(ffn
.Buffer
);
689 ERR("out of memory\n");
693 ObDereferenceObject(subvol_obj
);
696 ExFreePool(utf8
.Buffer
);
701 static NTSTATUS
create_subvol(device_extension
* Vcb
, PFILE_OBJECT FileObject
, WCHAR
* name
, ULONG length
) {
711 ULONG len
, disize
, rrsize
, irsize
;
712 UNICODE_STRING nameus
;
722 SECURITY_DESCRIPTOR
* sd
= NULL
;
723 SECURITY_SUBJECT_CONTEXT subjcont
;
728 fcb
= FileObject
->FsContext
;
730 ERR("error - fcb was NULL\n");
731 return STATUS_INTERNAL_ERROR
;
734 ccb
= FileObject
->FsContext2
;
736 ERR("error - ccb was NULL\n");
737 return STATUS_INTERNAL_ERROR
;
740 fileref
= ccb
->fileref
;
742 if (fcb
->type
!= BTRFS_TYPE_DIRECTORY
) {
743 ERR("parent FCB was not a directory\n");
744 return STATUS_NOT_A_DIRECTORY
;
747 if (fileref
->deleted
|| fcb
->deleted
) {
748 ERR("parent has been deleted\n");
749 return STATUS_FILE_DELETED
;
752 if (!(ccb
->access
& FILE_ADD_SUBDIRECTORY
)) {
753 WARN("insufficient privileges\n");
754 return STATUS_ACCESS_DENIED
;
757 nameus
.Length
= nameus
.MaximumLength
= length
;
758 nameus
.Buffer
= name
;
760 if (!is_file_name_valid(&nameus
))
761 return STATUS_OBJECT_NAME_INVALID
;
765 Status
= RtlUnicodeToUTF8N(NULL
, 0, &len
, name
, length
);
766 if (!NT_SUCCESS(Status
)) {
767 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
772 ERR("RtlUnicodeToUTF8N returned a length of 0\n");
773 return STATUS_INTERNAL_ERROR
;
776 utf8
.MaximumLength
= utf8
.Length
= len
;
777 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.Length
, ALLOC_TAG
);
780 ERR("out of memory\n");
781 return STATUS_INSUFFICIENT_RESOURCES
;
784 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, len
, &len
, name
, length
);
785 if (!NT_SUCCESS(Status
)) {
786 ERR("RtlUnicodeToUTF8N failed with error %08x\n", Status
);
790 acquire_tree_lock(Vcb
, TRUE
);
792 KeQuerySystemTime(&time
);
793 win_time_to_unix(time
, &now
);
795 InitializeListHead(&rollback
);
797 crc32
= calc_crc32c(0xfffffffe, (UINT8
*)utf8
.Buffer
, utf8
.Length
);
799 if (find_file_in_dir_with_crc32(fcb
->Vcb
, &nameus
, crc32
, fcb
->subvol
, fcb
->inode
, NULL
, NULL
, NULL
, NULL
)) {
800 WARN("file already exists\n");
801 Status
= STATUS_OBJECT_NAME_COLLISION
;
805 if (Vcb
->root_root
->lastinode
== 0)
806 get_last_inode(Vcb
, Vcb
->root_root
);
808 // FIXME - make sure rollback removes new roots from internal structures
810 id
= Vcb
->root_root
->lastinode
> 0x100 ? (Vcb
->root_root
->lastinode
+ 1) : 0x101;
811 Status
= create_root(Vcb
, id
, &r
, FALSE
, 0, &rollback
);
813 if (!NT_SUCCESS(Status
)) {
814 ERR("create_root returned %08x\n", Status
);
818 TRACE("created root %llx\n", id
);
820 if (!Vcb
->uuid_root
) {
823 TRACE("uuid root doesn't exist, creating it\n");
825 Status
= create_root(Vcb
, BTRFS_ROOT_UUID
, &uuid_root
, FALSE
, 0, &rollback
);
827 if (!NT_SUCCESS(Status
)) {
828 ERR("create_root returned %08x\n", Status
);
832 Vcb
->uuid_root
= uuid_root
;
835 root_num
= ExAllocatePoolWithTag(PagedPool
, sizeof(UINT64
), ALLOC_TAG
);
837 ERR("out of memory\n");
838 Status
= STATUS_INSUFFICIENT_RESOURCES
;
845 get_uuid(&r
->root_item
.uuid
);
847 RtlCopyMemory(&searchkey
.obj_id
, &r
->root_item
.uuid
, sizeof(UINT64
));
848 searchkey
.obj_type
= TYPE_SUBVOL_UUID
;
849 RtlCopyMemory(&searchkey
.offset
, &r
->root_item
.uuid
.uuid
[sizeof(UINT64
)], sizeof(UINT64
));
851 Status
= find_item(Vcb
, Vcb
->uuid_root
, &tp
, &searchkey
, FALSE
);
852 } while (NT_SUCCESS(Status
) && !keycmp(&searchkey
, &tp
.item
->key
));
856 if (!insert_tree_item(Vcb
, Vcb
->uuid_root
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, root_num
, sizeof(UINT64
), NULL
, &rollback
)) {
857 ERR("insert_tree_item failed\n");
858 Status
= STATUS_INTERNAL_ERROR
;
862 r
->root_item
.inode
.generation
= 1;
863 r
->root_item
.inode
.st_size
= 3;
864 r
->root_item
.inode
.st_blocks
= Vcb
->superblock
.node_size
;
865 r
->root_item
.inode
.st_nlink
= 1;
866 r
->root_item
.inode
.st_mode
= __S_IFDIR
| S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
; // 40755
867 r
->root_item
.inode
.flags
= 0xffffffff80000000; // FIXME - find out what these mean
869 r
->root_item
.objid
= SUBVOL_ROOT_INODE
;
870 r
->root_item
.bytes_used
= Vcb
->superblock
.node_size
;
871 r
->root_item
.ctransid
= Vcb
->superblock
.generation
;
872 r
->root_item
.otransid
= Vcb
->superblock
.generation
;
873 r
->root_item
.ctime
= now
;
874 r
->root_item
.otime
= now
;
876 // add .. inode to new subvol
878 ii
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_ITEM
), ALLOC_TAG
);
880 ERR("out of memory\n");
881 Status
= STATUS_INSUFFICIENT_RESOURCES
;
885 RtlZeroMemory(ii
, sizeof(INODE_ITEM
));
886 ii
->generation
= Vcb
->superblock
.generation
;
887 ii
->transid
= Vcb
->superblock
.generation
;
889 ii
->st_mode
= __S_IFDIR
| S_IRUSR
| S_IWUSR
| S_IXUSR
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
; // 40755
890 ii
->st_atime
= ii
->st_ctime
= ii
->st_mtime
= ii
->otime
= now
;
891 ii
->st_gid
= GID_NOBODY
; // FIXME?
893 SeCaptureSubjectContext(&subjcont
);
895 Status
= SeAssignSecurity(fcb
->sd
, NULL
, (void**)&sd
, TRUE
, &subjcont
, IoGetFileObjectGenericMapping(), PagedPool
);
897 if (!NT_SUCCESS(Status
)) {
898 ERR("SeAssignSecurity returned %08x\n", Status
);
903 ERR("SeAssignSecurity returned NULL security descriptor\n");
904 Status
= STATUS_INTERNAL_ERROR
;
908 Status
= RtlGetOwnerSecurityDescriptor(sd
, &owner
, &defaulted
);
909 if (!NT_SUCCESS(Status
)) {
910 ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status
);
911 ii
->st_uid
= UID_NOBODY
;
913 ii
->st_uid
= sid_to_uid(&owner
);
916 if (!insert_tree_item(Vcb
, r
, r
->root_item
.objid
, TYPE_INODE_ITEM
, 0, ii
, sizeof(INODE_ITEM
), NULL
, &rollback
)) {
917 ERR("insert_tree_item failed\n");
918 Status
= STATUS_INTERNAL_ERROR
;
922 // add security.NTACL xattr
924 Status
= set_xattr(Vcb
, r
, r
->root_item
.objid
, EA_NTACL
, EA_NTACL_HASH
, (UINT8
*)sd
, RtlLengthSecurityDescriptor(fcb
->sd
), &rollback
);
925 if (!NT_SUCCESS(Status
)) {
926 ERR("set_xattr returned %08x\n", Status
);
934 irsize
= sizeof(INODE_REF
) - 1 + strlen(DOTDOT
);
935 ir
= ExAllocatePoolWithTag(PagedPool
, irsize
, ALLOC_TAG
);
937 ERR("out of memory\n");
938 Status
= STATUS_INSUFFICIENT_RESOURCES
;
943 ir
->n
= strlen(DOTDOT
);
944 RtlCopyMemory(ir
->name
, DOTDOT
, ir
->n
);
946 if (!insert_tree_item(Vcb
, r
, r
->root_item
.objid
, TYPE_INODE_REF
, r
->root_item
.objid
, ir
, irsize
, NULL
, &rollback
)) {
947 ERR("insert_tree_item failed\n");
948 Status
= STATUS_INTERNAL_ERROR
;
954 dirpos
= find_next_dir_index(Vcb
, fcb
->subvol
, fcb
->inode
);
956 ERR("find_next_dir_index failed\n");
957 Status
= STATUS_INTERNAL_ERROR
;
961 disize
= sizeof(DIR_ITEM
) - 1 + utf8
.Length
;
962 di
= ExAllocatePoolWithTag(PagedPool
, disize
, ALLOC_TAG
);
964 ERR("out of memory\n");
965 Status
= STATUS_INSUFFICIENT_RESOURCES
;
969 di2
= ExAllocatePoolWithTag(PagedPool
, disize
, ALLOC_TAG
);
971 ERR("out of memory\n");
972 Status
= STATUS_INSUFFICIENT_RESOURCES
;
978 di
->key
.obj_type
= TYPE_ROOT_ITEM
;
980 di
->transid
= Vcb
->superblock
.generation
;
983 di
->type
= BTRFS_TYPE_DIRECTORY
;
984 RtlCopyMemory(di
->name
, utf8
.Buffer
, utf8
.Length
);
986 RtlCopyMemory(di2
, di
, disize
);
988 Status
= add_dir_item(Vcb
, fcb
->subvol
, fcb
->inode
, crc32
, di
, disize
, &rollback
);
989 if (!NT_SUCCESS(Status
)) {
990 ERR("add_dir_item returned %08x\n", Status
);
996 if (!insert_tree_item(Vcb
, fcb
->subvol
, fcb
->inode
, TYPE_DIR_INDEX
, dirpos
, di2
, disize
, NULL
, &rollback
)) {
997 ERR("insert_tree_item failed\n");
998 Status
= STATUS_INTERNAL_ERROR
;
1004 rrsize
= sizeof(ROOT_REF
) - 1 + utf8
.Length
;
1005 rr
= ExAllocatePoolWithTag(PagedPool
, rrsize
, ALLOC_TAG
);
1007 ERR("out of memory\n");
1008 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1012 rr
->dir
= fcb
->inode
;
1014 rr
->n
= utf8
.Length
;
1015 RtlCopyMemory(rr
->name
, utf8
.Buffer
, utf8
.Length
);
1017 if (!insert_tree_item(Vcb
, Vcb
->root_root
, fcb
->subvol
->id
, TYPE_ROOT_REF
, r
->id
, rr
, rrsize
, NULL
, &rollback
)) {
1018 ERR("insert_tree_item failed\n");
1019 Status
= STATUS_INTERNAL_ERROR
;
1025 rr2
= ExAllocatePoolWithTag(PagedPool
, rrsize
, ALLOC_TAG
);
1027 ERR("out of memory\n");
1028 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1032 RtlCopyMemory(rr2
, rr
, rrsize
);
1034 if (!insert_tree_item(Vcb
, Vcb
->root_root
, r
->id
, TYPE_ROOT_BACKREF
, fcb
->subvol
->id
, rr2
, rrsize
, NULL
, &rollback
)) {
1035 ERR("insert_tree_item failed\n");
1036 Status
= STATUS_INTERNAL_ERROR
;
1040 // change fcb->subvol's ROOT_ITEM
1042 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
1043 fcb
->subvol
->root_item
.ctime
= now
;
1045 // change fcb's INODE_ITEM
1047 // unlike when we create a file normally, the times and seq of the parent don't appear to change
1048 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1049 fcb
->inode_item
.st_size
+= utf8
.Length
* 2;
1051 searchkey
.obj_id
= fcb
->inode
;
1052 searchkey
.obj_type
= TYPE_INODE_ITEM
;
1053 searchkey
.offset
= 0;
1055 Status
= find_item(Vcb
, fcb
->subvol
, &tp
, &searchkey
, FALSE
);
1056 if (!NT_SUCCESS(Status
)) {
1057 ERR("error - find_item returned %08x\n", Status
);
1061 if (keycmp(&searchkey
, &tp
.item
->key
)) {
1062 ERR("error - could not find INODE_ITEM for directory %llx in subvol %llx\n", fcb
->inode
, fcb
->subvol
->id
);
1063 Status
= STATUS_INTERNAL_ERROR
;
1067 ii
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_ITEM
), ALLOC_TAG
);
1069 ERR("out of memory\n");
1070 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1074 RtlCopyMemory(ii
, &fcb
->inode_item
, sizeof(INODE_ITEM
));
1075 delete_tree_item(Vcb
, &tp
, &rollback
);
1077 insert_tree_item(Vcb
, fcb
->subvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, ii
, sizeof(INODE_ITEM
), NULL
, &rollback
);
1079 Vcb
->root_root
->lastinode
= id
;
1081 Status
= STATUS_SUCCESS
;
1084 if (NT_SUCCESS(Status
))
1085 Status
= consider_write(Vcb
);
1087 if (!NT_SUCCESS(Status
))
1088 do_rollback(Vcb
, &rollback
);
1090 clear_rollback(&rollback
);
1092 release_tree_lock(Vcb
, TRUE
);
1094 if (NT_SUCCESS(Status
)) {
1097 ffn
.Length
= fileref
->full_filename
.Length
+ length
;
1098 if (fcb
!= fcb
->Vcb
->root_fileref
->fcb
)
1099 ffn
.Length
+= sizeof(WCHAR
);
1101 ffn
.MaximumLength
= ffn
.Length
;
1102 ffn
.Buffer
= ExAllocatePoolWithTag(PagedPool
, ffn
.Length
, ALLOC_TAG
);
1107 RtlCopyMemory(ffn
.Buffer
, fileref
->full_filename
.Buffer
, fileref
->full_filename
.Length
);
1108 i
= fileref
->full_filename
.Length
;
1110 if (fcb
!= fcb
->Vcb
->root_fileref
->fcb
) {
1111 ffn
.Buffer
[i
/ sizeof(WCHAR
)] = '\\';
1115 RtlCopyMemory(&ffn
.Buffer
[i
/ sizeof(WCHAR
)], name
, length
);
1117 TRACE("full filename = %.*S\n", ffn
.Length
/ sizeof(WCHAR
), ffn
.Buffer
);
1119 FsRtlNotifyFullReportChange(Vcb
->NotifySync
, &Vcb
->DirNotifyList
, (PSTRING
)&ffn
, i
, NULL
, NULL
,
1120 FILE_NOTIFY_CHANGE_DIR_NAME
, FILE_ACTION_ADDED
, NULL
);
1122 ExFreePool(ffn
.Buffer
);
1124 ERR("out of memory\n");
1129 ExFreePool(utf8
.Buffer
);
1134 static NTSTATUS
is_volume_mounted(device_extension
* Vcb
, PIRP Irp
) {
1135 UINT64 i
, num_devices
;
1138 IO_STATUS_BLOCK iosb
;
1139 BOOL verify
= FALSE
;
1141 num_devices
= Vcb
->superblock
.num_devices
;
1142 for (i
= 0; i
< num_devices
; i
++) {
1143 if (Vcb
->devices
[i
].devobj
&& Vcb
->devices
[i
].removable
) {
1144 Status
= dev_ioctl(Vcb
->devices
[i
].devobj
, IOCTL_STORAGE_CHECK_VERIFY
, NULL
, 0, &cc
, sizeof(ULONG
), FALSE
, &iosb
);
1146 if (iosb
.Information
!= sizeof(ULONG
))
1149 if (Status
== STATUS_VERIFY_REQUIRED
|| (NT_SUCCESS(Status
) && cc
!= Vcb
->devices
[i
].change_count
)) {
1150 Vcb
->devices
[i
].devobj
->Flags
|= DO_VERIFY_VOLUME
;
1154 if (NT_SUCCESS(Status
) && iosb
.Information
== sizeof(ULONG
))
1155 Vcb
->devices
[i
].change_count
= cc
;
1157 if (!NT_SUCCESS(Status
) || verify
) {
1158 IoSetHardErrorOrVerifyDevice(Irp
, Vcb
->devices
[i
].devobj
);
1160 return verify
? STATUS_VERIFY_REQUIRED
: Status
;
1165 return STATUS_SUCCESS
;
1168 static NTSTATUS
fs_get_statistics(PDEVICE_OBJECT DeviceObject
, PFILE_OBJECT FileObject
, void* buffer
, DWORD buflen
, DWORD
* retlen
) {
1169 FILESYSTEM_STATISTICS
* fss
;
1171 WARN("STUB: FSCTL_FILESYSTEM_GET_STATISTICS\n");
1173 // This is hideously wrong, but at least it stops SMB from breaking
1175 if (buflen
< sizeof(FILESYSTEM_STATISTICS
))
1176 return STATUS_BUFFER_TOO_SMALL
;
1179 RtlZeroMemory(fss
, sizeof(FILESYSTEM_STATISTICS
));
1182 fss
->FileSystemType
= FILESYSTEM_STATISTICS_TYPE_NTFS
;
1183 fss
->SizeOfCompleteStructure
= sizeof(FILESYSTEM_STATISTICS
);
1185 *retlen
= sizeof(FILESYSTEM_STATISTICS
);
1187 return STATUS_SUCCESS
;
1190 NTSTATUS
fsctl_request(PDEVICE_OBJECT DeviceObject
, PIRP Irp
, UINT32 type
, BOOL user
) {
1191 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1195 case FSCTL_REQUEST_OPLOCK_LEVEL_1
:
1196 WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
1197 Status
= STATUS_NOT_IMPLEMENTED
;
1200 case FSCTL_REQUEST_OPLOCK_LEVEL_2
:
1201 WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
1202 Status
= STATUS_NOT_IMPLEMENTED
;
1205 case FSCTL_REQUEST_BATCH_OPLOCK
:
1206 WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
1207 Status
= STATUS_NOT_IMPLEMENTED
;
1210 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE
:
1211 WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
1212 Status
= STATUS_NOT_IMPLEMENTED
;
1215 case FSCTL_OPBATCH_ACK_CLOSE_PENDING
:
1216 WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
1217 Status
= STATUS_NOT_IMPLEMENTED
;
1220 case FSCTL_OPLOCK_BREAK_NOTIFY
:
1221 WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
1222 Status
= STATUS_NOT_IMPLEMENTED
;
1225 case FSCTL_LOCK_VOLUME
:
1226 WARN("STUB: FSCTL_LOCK_VOLUME\n");
1227 Status
= STATUS_NOT_IMPLEMENTED
;
1230 case FSCTL_UNLOCK_VOLUME
:
1231 WARN("STUB: FSCTL_UNLOCK_VOLUME\n");
1232 Status
= STATUS_NOT_IMPLEMENTED
;
1235 case FSCTL_DISMOUNT_VOLUME
:
1236 WARN("STUB: FSCTL_DISMOUNT_VOLUME\n");
1237 Status
= STATUS_NOT_IMPLEMENTED
;
1240 case FSCTL_IS_VOLUME_MOUNTED
:
1241 Status
= is_volume_mounted(DeviceObject
->DeviceExtension
, Irp
);
1244 case FSCTL_IS_PATHNAME_VALID
:
1245 WARN("STUB: FSCTL_IS_PATHNAME_VALID\n");
1246 Status
= STATUS_NOT_IMPLEMENTED
;
1249 case FSCTL_MARK_VOLUME_DIRTY
:
1250 WARN("STUB: FSCTL_MARK_VOLUME_DIRTY\n");
1251 Status
= STATUS_NOT_IMPLEMENTED
;
1254 case FSCTL_QUERY_RETRIEVAL_POINTERS
:
1255 WARN("STUB: FSCTL_QUERY_RETRIEVAL_POINTERS\n");
1256 Status
= STATUS_NOT_IMPLEMENTED
;
1259 case FSCTL_GET_COMPRESSION
:
1260 WARN("STUB: FSCTL_GET_COMPRESSION\n");
1261 Status
= STATUS_NOT_IMPLEMENTED
;
1264 case FSCTL_SET_COMPRESSION
:
1265 WARN("STUB: FSCTL_SET_COMPRESSION\n");
1266 Status
= STATUS_NOT_IMPLEMENTED
;
1269 case FSCTL_SET_BOOTLOADER_ACCESSED
:
1270 WARN("STUB: FSCTL_SET_BOOTLOADER_ACCESSED\n");
1271 Status
= STATUS_NOT_IMPLEMENTED
;
1274 case FSCTL_OPLOCK_BREAK_ACK_NO_2
:
1275 WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
1276 Status
= STATUS_NOT_IMPLEMENTED
;
1279 case FSCTL_INVALIDATE_VOLUMES
:
1280 WARN("STUB: FSCTL_INVALIDATE_VOLUMES\n");
1281 Status
= STATUS_NOT_IMPLEMENTED
;
1284 case FSCTL_QUERY_FAT_BPB
:
1285 WARN("STUB: FSCTL_QUERY_FAT_BPB\n");
1286 Status
= STATUS_NOT_IMPLEMENTED
;
1289 case FSCTL_REQUEST_FILTER_OPLOCK
:
1290 WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
1291 Status
= STATUS_NOT_IMPLEMENTED
;
1294 case FSCTL_FILESYSTEM_GET_STATISTICS
:
1295 Status
= fs_get_statistics(DeviceObject
, IrpSp
->FileObject
, Irp
->AssociatedIrp
.SystemBuffer
,
1296 IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
1299 case FSCTL_GET_NTFS_VOLUME_DATA
:
1300 WARN("STUB: FSCTL_GET_NTFS_VOLUME_DATA\n");
1301 Status
= STATUS_NOT_IMPLEMENTED
;
1304 case FSCTL_GET_NTFS_FILE_RECORD
:
1305 WARN("STUB: FSCTL_GET_NTFS_FILE_RECORD\n");
1306 Status
= STATUS_NOT_IMPLEMENTED
;
1309 case FSCTL_GET_VOLUME_BITMAP
:
1310 WARN("STUB: FSCTL_GET_VOLUME_BITMAP\n");
1311 Status
= STATUS_NOT_IMPLEMENTED
;
1314 case FSCTL_GET_RETRIEVAL_POINTERS
:
1315 WARN("STUB: FSCTL_GET_RETRIEVAL_POINTERS\n");
1316 Status
= STATUS_NOT_IMPLEMENTED
;
1319 case FSCTL_MOVE_FILE
:
1320 WARN("STUB: FSCTL_MOVE_FILE\n");
1321 Status
= STATUS_NOT_IMPLEMENTED
;
1324 case FSCTL_IS_VOLUME_DIRTY
:
1325 WARN("STUB: FSCTL_IS_VOLUME_DIRTY\n");
1326 Status
= STATUS_NOT_IMPLEMENTED
;
1329 case FSCTL_ALLOW_EXTENDED_DASD_IO
:
1330 WARN("STUB: FSCTL_ALLOW_EXTENDED_DASD_IO\n");
1331 Status
= STATUS_NOT_IMPLEMENTED
;
1334 case FSCTL_FIND_FILES_BY_SID
:
1335 WARN("STUB: FSCTL_FIND_FILES_BY_SID\n");
1336 Status
= STATUS_NOT_IMPLEMENTED
;
1339 case FSCTL_SET_OBJECT_ID
:
1340 WARN("STUB: FSCTL_SET_OBJECT_ID\n");
1341 Status
= STATUS_NOT_IMPLEMENTED
;
1344 case FSCTL_GET_OBJECT_ID
:
1345 WARN("STUB: FSCTL_GET_OBJECT_ID\n");
1346 Status
= STATUS_NOT_IMPLEMENTED
;
1349 case FSCTL_DELETE_OBJECT_ID
:
1350 WARN("STUB: FSCTL_DELETE_OBJECT_ID\n");
1351 Status
= STATUS_NOT_IMPLEMENTED
;
1354 case FSCTL_SET_REPARSE_POINT
:
1355 Status
= set_reparse_point(DeviceObject
, Irp
);
1358 case FSCTL_GET_REPARSE_POINT
:
1359 Status
= get_reparse_point(DeviceObject
, IrpSp
->FileObject
, Irp
->AssociatedIrp
.SystemBuffer
,
1360 IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
, &Irp
->IoStatus
.Information
);
1363 case FSCTL_DELETE_REPARSE_POINT
:
1364 Status
= delete_reparse_point(DeviceObject
, Irp
);
1367 case FSCTL_ENUM_USN_DATA
:
1368 WARN("STUB: FSCTL_ENUM_USN_DATA\n");
1369 Status
= STATUS_NOT_IMPLEMENTED
;
1372 case FSCTL_SECURITY_ID_CHECK
:
1373 WARN("STUB: FSCTL_SECURITY_ID_CHECK\n");
1374 Status
= STATUS_NOT_IMPLEMENTED
;
1377 case FSCTL_READ_USN_JOURNAL
:
1378 WARN("STUB: FSCTL_READ_USN_JOURNAL\n");
1379 Status
= STATUS_NOT_IMPLEMENTED
;
1382 case FSCTL_SET_OBJECT_ID_EXTENDED
:
1383 WARN("STUB: FSCTL_SET_OBJECT_ID_EXTENDED\n");
1384 Status
= STATUS_NOT_IMPLEMENTED
;
1387 case FSCTL_CREATE_OR_GET_OBJECT_ID
:
1388 WARN("STUB: FSCTL_CREATE_OR_GET_OBJECT_ID\n");
1389 Status
= STATUS_NOT_IMPLEMENTED
;
1392 case FSCTL_SET_SPARSE
:
1393 WARN("STUB: FSCTL_SET_SPARSE\n");
1394 Status
= STATUS_NOT_IMPLEMENTED
;
1397 case FSCTL_SET_ZERO_DATA
:
1398 WARN("STUB: FSCTL_SET_ZERO_DATA\n");
1399 Status
= STATUS_NOT_IMPLEMENTED
;
1402 case FSCTL_QUERY_ALLOCATED_RANGES
:
1403 WARN("STUB: FSCTL_QUERY_ALLOCATED_RANGES\n");
1404 Status
= STATUS_NOT_IMPLEMENTED
;
1407 case FSCTL_ENABLE_UPGRADE
:
1408 WARN("STUB: FSCTL_ENABLE_UPGRADE\n");
1409 Status
= STATUS_NOT_IMPLEMENTED
;
1412 case FSCTL_SET_ENCRYPTION
:
1413 WARN("STUB: FSCTL_SET_ENCRYPTION\n");
1414 Status
= STATUS_NOT_IMPLEMENTED
;
1417 case FSCTL_ENCRYPTION_FSCTL_IO
:
1418 WARN("STUB: FSCTL_ENCRYPTION_FSCTL_IO\n");
1419 Status
= STATUS_NOT_IMPLEMENTED
;
1422 case FSCTL_WRITE_RAW_ENCRYPTED
:
1423 WARN("STUB: FSCTL_WRITE_RAW_ENCRYPTED\n");
1424 Status
= STATUS_NOT_IMPLEMENTED
;
1427 case FSCTL_READ_RAW_ENCRYPTED
:
1428 WARN("STUB: FSCTL_READ_RAW_ENCRYPTED\n");
1429 Status
= STATUS_NOT_IMPLEMENTED
;
1432 case FSCTL_CREATE_USN_JOURNAL
:
1433 WARN("STUB: FSCTL_CREATE_USN_JOURNAL\n");
1434 Status
= STATUS_NOT_IMPLEMENTED
;
1437 case FSCTL_READ_FILE_USN_DATA
:
1438 WARN("STUB: FSCTL_READ_FILE_USN_DATA\n");
1439 Status
= STATUS_NOT_IMPLEMENTED
;
1442 case FSCTL_WRITE_USN_CLOSE_RECORD
:
1443 WARN("STUB: FSCTL_WRITE_USN_CLOSE_RECORD\n");
1444 Status
= STATUS_NOT_IMPLEMENTED
;
1447 case FSCTL_EXTEND_VOLUME
:
1448 WARN("STUB: FSCTL_EXTEND_VOLUME\n");
1449 Status
= STATUS_NOT_IMPLEMENTED
;
1452 case FSCTL_QUERY_USN_JOURNAL
:
1453 WARN("STUB: FSCTL_QUERY_USN_JOURNAL\n");
1454 Status
= STATUS_NOT_IMPLEMENTED
;
1457 case FSCTL_DELETE_USN_JOURNAL
:
1458 WARN("STUB: FSCTL_DELETE_USN_JOURNAL\n");
1459 Status
= STATUS_NOT_IMPLEMENTED
;
1462 case FSCTL_MARK_HANDLE
:
1463 WARN("STUB: FSCTL_MARK_HANDLE\n");
1464 Status
= STATUS_NOT_IMPLEMENTED
;
1467 case FSCTL_SIS_COPYFILE
:
1468 WARN("STUB: FSCTL_SIS_COPYFILE\n");
1469 Status
= STATUS_NOT_IMPLEMENTED
;
1472 case FSCTL_SIS_LINK_FILES
:
1473 WARN("STUB: FSCTL_SIS_LINK_FILES\n");
1474 Status
= STATUS_NOT_IMPLEMENTED
;
1477 case FSCTL_RECALL_FILE
:
1478 WARN("STUB: FSCTL_RECALL_FILE\n");
1479 Status
= STATUS_NOT_IMPLEMENTED
;
1482 case FSCTL_READ_FROM_PLEX
:
1483 WARN("STUB: FSCTL_READ_FROM_PLEX\n");
1484 Status
= STATUS_NOT_IMPLEMENTED
;
1487 case FSCTL_FILE_PREFETCH
:
1488 WARN("STUB: FSCTL_FILE_PREFETCH\n");
1489 Status
= STATUS_NOT_IMPLEMENTED
;
1492 #if WIN32_WINNT >= 0x0600
1493 case FSCTL_MAKE_MEDIA_COMPATIBLE
:
1494 WARN("STUB: FSCTL_MAKE_MEDIA_COMPATIBLE\n");
1495 Status
= STATUS_NOT_IMPLEMENTED
;
1498 case FSCTL_SET_DEFECT_MANAGEMENT
:
1499 WARN("STUB: FSCTL_SET_DEFECT_MANAGEMENT\n");
1500 Status
= STATUS_NOT_IMPLEMENTED
;
1503 case FSCTL_QUERY_SPARING_INFO
:
1504 WARN("STUB: FSCTL_QUERY_SPARING_INFO\n");
1505 Status
= STATUS_NOT_IMPLEMENTED
;
1508 case FSCTL_QUERY_ON_DISK_VOLUME_INFO
:
1509 WARN("STUB: FSCTL_QUERY_ON_DISK_VOLUME_INFO\n");
1510 Status
= STATUS_NOT_IMPLEMENTED
;
1513 case FSCTL_SET_VOLUME_COMPRESSION_STATE
:
1514 WARN("STUB: FSCTL_SET_VOLUME_COMPRESSION_STATE\n");
1515 Status
= STATUS_NOT_IMPLEMENTED
;
1518 case FSCTL_TXFS_MODIFY_RM
:
1519 WARN("STUB: FSCTL_TXFS_MODIFY_RM\n");
1520 Status
= STATUS_NOT_IMPLEMENTED
;
1523 case FSCTL_TXFS_QUERY_RM_INFORMATION
:
1524 WARN("STUB: FSCTL_TXFS_QUERY_RM_INFORMATION\n");
1525 Status
= STATUS_NOT_IMPLEMENTED
;
1528 case FSCTL_TXFS_ROLLFORWARD_REDO
:
1529 WARN("STUB: FSCTL_TXFS_ROLLFORWARD_REDO\n");
1530 Status
= STATUS_NOT_IMPLEMENTED
;
1533 case FSCTL_TXFS_ROLLFORWARD_UNDO
:
1534 WARN("STUB: FSCTL_TXFS_ROLLFORWARD_UNDO\n");
1535 Status
= STATUS_NOT_IMPLEMENTED
;
1538 case FSCTL_TXFS_START_RM
:
1539 WARN("STUB: FSCTL_TXFS_START_RM\n");
1540 Status
= STATUS_NOT_IMPLEMENTED
;
1543 case FSCTL_TXFS_SHUTDOWN_RM
:
1544 WARN("STUB: FSCTL_TXFS_SHUTDOWN_RM\n");
1545 Status
= STATUS_NOT_IMPLEMENTED
;
1548 case FSCTL_TXFS_READ_BACKUP_INFORMATION
:
1549 WARN("STUB: FSCTL_TXFS_READ_BACKUP_INFORMATION\n");
1550 Status
= STATUS_NOT_IMPLEMENTED
;
1553 case FSCTL_TXFS_WRITE_BACKUP_INFORMATION
:
1554 WARN("STUB: FSCTL_TXFS_WRITE_BACKUP_INFORMATION\n");
1555 Status
= STATUS_NOT_IMPLEMENTED
;
1558 case FSCTL_TXFS_CREATE_SECONDARY_RM
:
1559 WARN("STUB: FSCTL_TXFS_CREATE_SECONDARY_RM\n");
1560 Status
= STATUS_NOT_IMPLEMENTED
;
1563 case FSCTL_TXFS_GET_METADATA_INFO
:
1564 WARN("STUB: FSCTL_TXFS_GET_METADATA_INFO\n");
1565 Status
= STATUS_NOT_IMPLEMENTED
;
1568 case FSCTL_TXFS_GET_TRANSACTED_VERSION
:
1569 WARN("STUB: FSCTL_TXFS_GET_TRANSACTED_VERSION\n");
1570 Status
= STATUS_NOT_IMPLEMENTED
;
1573 case FSCTL_TXFS_SAVEPOINT_INFORMATION
:
1574 WARN("STUB: FSCTL_TXFS_SAVEPOINT_INFORMATION\n");
1575 Status
= STATUS_NOT_IMPLEMENTED
;
1578 case FSCTL_TXFS_CREATE_MINIVERSION
:
1579 WARN("STUB: FSCTL_TXFS_CREATE_MINIVERSION\n");
1580 Status
= STATUS_NOT_IMPLEMENTED
;
1583 case FSCTL_TXFS_TRANSACTION_ACTIVE
:
1584 WARN("STUB: FSCTL_TXFS_TRANSACTION_ACTIVE\n");
1585 Status
= STATUS_NOT_IMPLEMENTED
;
1588 case FSCTL_SET_ZERO_ON_DEALLOCATION
:
1589 WARN("STUB: FSCTL_SET_ZERO_ON_DEALLOCATION\n");
1590 Status
= STATUS_NOT_IMPLEMENTED
;
1593 case FSCTL_SET_REPAIR
:
1594 WARN("STUB: FSCTL_SET_REPAIR\n");
1595 Status
= STATUS_NOT_IMPLEMENTED
;
1598 case FSCTL_GET_REPAIR
:
1599 WARN("STUB: FSCTL_GET_REPAIR\n");
1600 Status
= STATUS_NOT_IMPLEMENTED
;
1603 case FSCTL_WAIT_FOR_REPAIR
:
1604 WARN("STUB: FSCTL_WAIT_FOR_REPAIR\n");
1605 Status
= STATUS_NOT_IMPLEMENTED
;
1608 case FSCTL_INITIATE_REPAIR
:
1609 WARN("STUB: FSCTL_INITIATE_REPAIR\n");
1610 Status
= STATUS_NOT_IMPLEMENTED
;
1613 case FSCTL_CSC_INTERNAL
:
1614 WARN("STUB: FSCTL_CSC_INTERNAL\n");
1615 Status
= STATUS_NOT_IMPLEMENTED
;
1618 case FSCTL_SHRINK_VOLUME
:
1619 WARN("STUB: FSCTL_SHRINK_VOLUME\n");
1620 Status
= STATUS_NOT_IMPLEMENTED
;
1623 case FSCTL_SET_SHORT_NAME_BEHAVIOR
:
1624 WARN("STUB: FSCTL_SET_SHORT_NAME_BEHAVIOR\n");
1625 Status
= STATUS_NOT_IMPLEMENTED
;
1628 case FSCTL_DFSR_SET_GHOST_HANDLE_STATE
:
1629 WARN("STUB: FSCTL_DFSR_SET_GHOST_HANDLE_STATE\n");
1630 Status
= STATUS_NOT_IMPLEMENTED
;
1633 case FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES
:
1634 WARN("STUB: FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES\n");
1635 Status
= STATUS_NOT_IMPLEMENTED
;
1638 case FSCTL_TXFS_LIST_TRANSACTIONS
:
1639 WARN("STUB: FSCTL_TXFS_LIST_TRANSACTIONS\n");
1640 Status
= STATUS_NOT_IMPLEMENTED
;
1643 case FSCTL_QUERY_PAGEFILE_ENCRYPTION
:
1644 WARN("STUB: FSCTL_QUERY_PAGEFILE_ENCRYPTION\n");
1645 Status
= STATUS_NOT_IMPLEMENTED
;
1648 case FSCTL_RESET_VOLUME_ALLOCATION_HINTS
:
1649 WARN("STUB: FSCTL_RESET_VOLUME_ALLOCATION_HINTS\n");
1650 Status
= STATUS_NOT_IMPLEMENTED
;
1653 case FSCTL_TXFS_READ_BACKUP_INFORMATION2
:
1654 WARN("STUB: FSCTL_TXFS_READ_BACKUP_INFORMATION2\n");
1655 Status
= STATUS_NOT_IMPLEMENTED
;
1658 case FSCTL_CSV_CONTROL
:
1659 WARN("STUB: FSCTL_CSV_CONTROL\n");
1660 Status
= STATUS_NOT_IMPLEMENTED
;
1663 case FSCTL_BTRFS_GET_FILE_IDS
:
1664 Status
= get_file_ids(IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
);
1667 case FSCTL_BTRFS_CREATE_SUBVOL
:
1668 Status
= create_subvol(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
);
1671 case FSCTL_BTRFS_CREATE_SNAPSHOT
:
1672 Status
= create_snapshot(DeviceObject
->DeviceExtension
, IrpSp
->FileObject
, map_user_buffer(Irp
), IrpSp
->Parameters
.DeviceIoControl
.OutputBufferLength
);
1676 TRACE("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",
1677 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
, (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0xff0000) >> 16,
1678 (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0xc000) >> 14, (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0x3ffc) >> 2,
1679 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
& 0x3);
1680 Status
= STATUS_NOT_IMPLEMENTED
;