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"
20 #if (NTDDI_VERSION >= NTDDI_WIN10)
21 // not currently in mingw - introduced with Windows 10
22 #ifndef FileIdInformation
23 #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
27 static NTSTATUS
get_inode_dir_path(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, PUNICODE_STRING us
);
29 static NTSTATUS STDCALL
set_basic_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
) {
30 FILE_BASIC_INFORMATION
* fbi
= Irp
->AssociatedIrp
.SystemBuffer
;
31 fcb
* fcb
= FileObject
->FsContext
;
32 ccb
* ccb
= FileObject
->FsContext2
;
33 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
34 ULONG defda
, filter
= 0;
35 BOOL inode_item_changed
= FALSE
;
39 if (fileref
&& fileref
->parent
)
40 fcb
= fileref
->parent
->fcb
;
42 ERR("stream did not have fileref\n");
43 return STATUS_INTERNAL_ERROR
;
47 TRACE("file = %S, attributes = %x\n", file_desc(FileObject
), fbi
->FileAttributes
);
49 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
51 if (fbi
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
&& fcb
->type
!= BTRFS_TYPE_DIRECTORY
) {
52 WARN("attempted to set FILE_ATTRIBUTE_DIRECTORY on non-directory\n");
53 Status
= STATUS_INVALID_PARAMETER
;
57 // FIXME - what if FCB is volume or root?
58 // FIXME - what about subvol roots?
60 // FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
61 // FIXME - handle times == -1
63 // FileAttributes == 0 means don't set - undocumented, but seen in fastfat
64 if (fbi
->FileAttributes
!= 0) {
68 defda
= get_file_attributes(Vcb
, &fcb
->inode_item
, fcb
->subvol
, fcb
->inode
, fcb
->type
, fileref
->filepart
.Length
> 0 && fileref
->filepart
.Buffer
[0] == '.', TRUE
);
70 if (fcb
->type
== BTRFS_TYPE_DIRECTORY
)
71 fbi
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
72 else if (fcb
->type
== BTRFS_TYPE_SYMLINK
)
73 fbi
->FileAttributes
|= FILE_ATTRIBUTE_REPARSE_POINT
;
75 fcb
->atts_changed
= TRUE
;
77 if (defda
== fbi
->FileAttributes
)
78 fcb
->atts_deleted
= TRUE
;
80 fcb
->atts
= fbi
->FileAttributes
;
82 KeQuerySystemTime(&time
);
83 win_time_to_unix(time
, &now
);
85 fcb
->inode_item
.st_ctime
= now
;
86 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
87 fcb
->subvol
->root_item
.ctime
= now
;
89 inode_item_changed
= TRUE
;
91 filter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
94 // FIXME - CreationTime
95 // FIXME - LastAccessTime
96 // FIXME - LastWriteTime
99 if (inode_item_changed
) {
100 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
101 fcb
->inode_item
.sequence
++;
107 send_notification_fcb(fileref
, filter
, FILE_ACTION_MODIFIED
);
109 Status
= STATUS_SUCCESS
;
112 ExReleaseResourceLite(fcb
->Header
.Resource
);
117 static NTSTATUS STDCALL
set_disposition_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
) {
118 FILE_DISPOSITION_INFORMATION
* fdi
= Irp
->AssociatedIrp
.SystemBuffer
;
119 fcb
* fcb
= FileObject
->FsContext
;
120 ccb
* ccb
= FileObject
->FsContext2
;
121 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
126 return STATUS_INVALID_PARAMETER
;
128 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
130 TRACE("changing delete_on_close to %s for %S (fcb %p)\n", fdi
->DeleteFile
? "TRUE" : "FALSE", file_desc(FileObject
), fcb
);
134 atts
= fileref
->parent
->fcb
->atts
;
136 ERR("no fileref for stream\n");
137 Status
= STATUS_INTERNAL_ERROR
;
143 TRACE("atts = %x\n", atts
);
145 if (atts
& FILE_ATTRIBUTE_READONLY
) {
146 Status
= STATUS_CANNOT_DELETE
;
150 // FIXME - can we skip this bit for subvols?
151 if (fcb
->type
== BTRFS_TYPE_DIRECTORY
&& fcb
->inode_item
.st_size
> 0) {
152 Status
= STATUS_DIRECTORY_NOT_EMPTY
;
156 if (!MmFlushImageSection(&fcb
->nonpaged
->segment_object
, MmFlushForDelete
)) {
157 WARN("trying to delete file which is being mapped as an image\n");
158 Status
= STATUS_CANNOT_DELETE
;
162 ccb
->fileref
->delete_on_close
= fdi
->DeleteFile
;
164 FileObject
->DeletePending
= fdi
->DeleteFile
;
166 Status
= STATUS_SUCCESS
;
169 ExReleaseResourceLite(fcb
->Header
.Resource
);
174 static NTSTATUS
add_inode_extref(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, UINT64 parinode
, UINT64 index
, PANSI_STRING utf8
, LIST_ENTRY
* rollback
) {
180 searchkey
.obj_id
= inode
;
181 searchkey
.obj_type
= TYPE_INODE_EXTREF
;
182 searchkey
.offset
= calc_crc32c((UINT32
)parinode
, (UINT8
*)utf8
->Buffer
, utf8
->Length
);
184 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
185 if (!NT_SUCCESS(Status
)) {
186 ERR("error - find_item returned %08x\n", Status
);
190 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
191 ULONG iersize
= tp
.item
->size
+ sizeof(INODE_EXTREF
) - 1 + utf8
->Length
;
193 UINT32 maxlen
= Vcb
->superblock
.node_size
- sizeof(tree_header
) - sizeof(leaf_node
);
195 if (iersize
> maxlen
) {
196 ERR("item would be too long (%u > %u)\n", iersize
, maxlen
);
197 return STATUS_INTERNAL_ERROR
;
200 ier2
= ExAllocatePoolWithTag(PagedPool
, iersize
, ALLOC_TAG
);
202 ERR("out of memory\n");
203 return STATUS_INSUFFICIENT_RESOURCES
;
206 if (tp
.item
->size
> 0)
207 RtlCopyMemory(ier2
, tp
.item
->data
, tp
.item
->size
);
209 ier
= (INODE_EXTREF
*)&ier2
[tp
.item
->size
];
212 ier
->n
= utf8
->Length
;
213 RtlCopyMemory(ier
->name
, utf8
->Buffer
, utf8
->Length
);
215 delete_tree_item(Vcb
, &tp
, rollback
);
217 if (!insert_tree_item(Vcb
, subvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, ier2
, iersize
, NULL
, rollback
)) {
218 ERR("error - failed to insert item\n");
219 return STATUS_INTERNAL_ERROR
;
222 ier
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_EXTREF
) - 1 + utf8
->Length
, ALLOC_TAG
);
224 ERR("out of memory\n");
225 return STATUS_INSUFFICIENT_RESOURCES
;
230 ier
->n
= utf8
->Length
;
231 RtlCopyMemory(ier
->name
, utf8
->Buffer
, utf8
->Length
);
233 if (!insert_tree_item(Vcb
, subvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, ier
, sizeof(INODE_EXTREF
) - 1 + utf8
->Length
, NULL
, rollback
)) {
234 ERR("error - failed to insert item\n");
235 return STATUS_INTERNAL_ERROR
;
239 return STATUS_SUCCESS
;
242 NTSTATUS
add_inode_ref(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, UINT64 parinode
, UINT64 index
, PANSI_STRING utf8
, LIST_ENTRY
* rollback
) {
248 searchkey
.obj_id
= inode
;
249 searchkey
.obj_type
= TYPE_INODE_REF
;
250 searchkey
.offset
= parinode
;
252 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
253 if (!NT_SUCCESS(Status
)) {
254 ERR("error - find_item returned %08x\n", Status
);
258 if (!keycmp(&searchkey
, &tp
.item
->key
)) {
259 ULONG irsize
= tp
.item
->size
+ sizeof(INODE_REF
) - 1 + utf8
->Length
;
261 UINT32 maxlen
= Vcb
->superblock
.node_size
- sizeof(tree_header
) - sizeof(leaf_node
);
263 if (irsize
> maxlen
) {
264 if (Vcb
->superblock
.incompat_flags
& BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF
) {
265 TRACE("INODE_REF too long, creating INODE_EXTREF\n");
266 return add_inode_extref(Vcb
, subvol
, inode
, parinode
, index
, utf8
, rollback
);
268 ERR("item would be too long (%u > %u)\n", irsize
, maxlen
);
269 return STATUS_INTERNAL_ERROR
;
273 ir2
= ExAllocatePoolWithTag(PagedPool
, irsize
, ALLOC_TAG
);
275 ERR("out of memory\n");
276 return STATUS_INSUFFICIENT_RESOURCES
;
279 if (tp
.item
->size
> 0)
280 RtlCopyMemory(ir2
, tp
.item
->data
, tp
.item
->size
);
282 ir
= (INODE_REF
*)&ir2
[tp
.item
->size
];
284 ir
->n
= utf8
->Length
;
285 RtlCopyMemory(ir
->name
, utf8
->Buffer
, utf8
->Length
);
287 delete_tree_item(Vcb
, &tp
, rollback
);
289 if (!insert_tree_item(Vcb
, subvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, ir2
, irsize
, NULL
, rollback
)) {
290 ERR("error - failed to insert item\n");
291 return STATUS_INTERNAL_ERROR
;
294 ir
= ExAllocatePoolWithTag(PagedPool
, sizeof(INODE_REF
) - 1 + utf8
->Length
, ALLOC_TAG
);
296 ERR("out of memory\n");
297 return STATUS_INSUFFICIENT_RESOURCES
;
301 ir
->n
= utf8
->Length
;
302 RtlCopyMemory(ir
->name
, utf8
->Buffer
, utf8
->Length
);
304 if (!insert_tree_item(Vcb
, subvol
, searchkey
.obj_id
, searchkey
.obj_type
, searchkey
.offset
, ir
, sizeof(INODE_REF
) - 1 + ir
->n
, NULL
, rollback
)) {
305 ERR("error - failed to insert item\n");
306 return STATUS_INTERNAL_ERROR
;
310 return STATUS_SUCCESS
;
313 BOOL
has_open_children(file_ref
* fileref
) {
314 LIST_ENTRY
* le
= fileref
->children
.Flink
;
316 if (IsListEmpty(&fileref
->children
))
319 while (le
!= &fileref
->children
) {
320 file_ref
* c
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
322 if (c
->fcb
->open_count
> 0)
325 if (has_open_children(c
))
334 static NTSTATUS
duplicate_fcb(fcb
* oldfcb
, fcb
** pfcb
) {
338 // FIXME - we can skip a lot of this if the inode is about to be deleted
342 ERR("out of memory\n");
343 return STATUS_INSUFFICIENT_RESOURCES
;
346 fcb
->Vcb
= oldfcb
->Vcb
;
348 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
349 fcb
->Header
.AllocationSize
= oldfcb
->Header
.AllocationSize
;
350 fcb
->Header
.FileSize
= oldfcb
->Header
.FileSize
;
351 fcb
->Header
.ValidDataLength
= oldfcb
->Header
.ValidDataLength
;
353 fcb
->type
= oldfcb
->type
;
357 fcb
->adshash
= oldfcb
->adshash
;
359 if (oldfcb
->adsxattr
.Buffer
&& oldfcb
->adsxattr
.Length
> 0) {
360 fcb
->adsxattr
.Length
= oldfcb
->adsxattr
.Length
;
361 fcb
->adsxattr
.MaximumLength
= fcb
->adsxattr
.Length
+ 1;
362 fcb
->adsxattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsxattr
.MaximumLength
, ALLOC_TAG
);
364 if (!fcb
->adsxattr
.Buffer
) {
365 ERR("out of memory\n");
367 return STATUS_INSUFFICIENT_RESOURCES
;
370 RtlCopyMemory(fcb
->adsxattr
.Buffer
, oldfcb
->adsxattr
.Buffer
, fcb
->adsxattr
.Length
);
371 fcb
->adsxattr
.Buffer
[fcb
->adsxattr
.Length
] = 0;
374 if (oldfcb
->adsdata
.Buffer
&& oldfcb
->adsdata
.Length
> 0) {
375 fcb
->adsdata
.Length
= fcb
->adsdata
.MaximumLength
= oldfcb
->adsdata
.Length
;
376 fcb
->adsdata
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsdata
.MaximumLength
, ALLOC_TAG
);
378 if (!fcb
->adsdata
.Buffer
) {
379 ERR("out of memory\n");
381 return STATUS_INSUFFICIENT_RESOURCES
;
384 RtlCopyMemory(fcb
->adsdata
.Buffer
, oldfcb
->adsdata
.Buffer
, fcb
->adsdata
.Length
);
390 RtlCopyMemory(&fcb
->inode_item
, &oldfcb
->inode_item
, sizeof(INODE_ITEM
));
392 if (oldfcb
->sd
&& RtlLengthSecurityDescriptor(oldfcb
->sd
) > 0) {
393 fcb
->sd
= ExAllocatePoolWithTag(PagedPool
, RtlLengthSecurityDescriptor(oldfcb
->sd
), ALLOC_TAG
);
395 ERR("out of memory\n");
397 return STATUS_INSUFFICIENT_RESOURCES
;
400 RtlCopyMemory(fcb
->sd
, oldfcb
->sd
, RtlLengthSecurityDescriptor(oldfcb
->sd
));
403 fcb
->atts
= oldfcb
->atts
;
405 le
= oldfcb
->extents
.Flink
;
406 while (le
!= &oldfcb
->extents
) {
407 extent
* ext
= CONTAINING_RECORD(le
, extent
, list_entry
);
410 extent
* ext2
= ExAllocatePoolWithTag(PagedPool
, sizeof(extent
), ALLOC_TAG
);
413 ERR("out of memory\n");
415 return STATUS_INSUFFICIENT_RESOURCES
;
418 ext2
->offset
= ext
->offset
;
419 ext2
->datalen
= ext
->datalen
;
421 if (ext2
->datalen
> 0) {
422 ext2
->data
= ExAllocatePoolWithTag(PagedPool
, ext2
->datalen
, ALLOC_TAG
);
425 ERR("out of memory\n");
427 return STATUS_INSUFFICIENT_RESOURCES
;
430 RtlCopyMemory(ext2
->data
, ext
->data
, ext2
->datalen
);
434 ext2
->unique
= FALSE
;
435 ext2
->ignore
= FALSE
;
437 InsertTailList(&fcb
->extents
, &ext2
->list_entry
);
443 le
= oldfcb
->hardlinks
.Flink
;
444 while (le
!= &oldfcb
->hardlinks
) {
445 hardlink
*hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
), *hl2
;
447 hl2
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
450 ERR("out of memory\n");
452 return STATUS_INSUFFICIENT_RESOURCES
;
455 hl2
->parent
= hl
->parent
;
456 hl2
->index
= hl
->index
;
458 hl2
->name
.Length
= hl2
->name
.MaximumLength
= hl
->name
.Length
;
459 hl2
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl2
->name
.MaximumLength
, ALLOC_TAG
);
461 if (!hl2
->name
.Buffer
) {
462 ERR("out of memory\n");
465 return STATUS_INSUFFICIENT_RESOURCES
;
468 RtlCopyMemory(hl2
->name
.Buffer
, hl
->name
.Buffer
, hl
->name
.Length
);
470 hl2
->utf8
.Length
= hl2
->utf8
.MaximumLength
= hl
->utf8
.Length
;
471 hl2
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl2
->utf8
.MaximumLength
, ALLOC_TAG
);
473 if (!hl2
->utf8
.Buffer
) {
474 ERR("out of memory\n");
475 ExFreePool(hl2
->name
.Buffer
);
478 return STATUS_INSUFFICIENT_RESOURCES
;
481 RtlCopyMemory(hl2
->utf8
.Buffer
, hl
->utf8
.Buffer
, hl
->utf8
.Length
);
483 InsertTailList(&fcb
->hardlinks
, &hl2
->list_entry
);
488 fcb
->last_dir_index
= oldfcb
->last_dir_index
;
490 if (oldfcb
->reparse_xattr
.Buffer
&& oldfcb
->reparse_xattr
.Length
> 0) {
491 fcb
->reparse_xattr
.Length
= fcb
->reparse_xattr
.MaximumLength
= oldfcb
->reparse_xattr
.Length
;
493 fcb
->reparse_xattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->reparse_xattr
.MaximumLength
, ALLOC_TAG
);
494 if (!fcb
->reparse_xattr
.Buffer
) {
495 ERR("out of memory\n");
497 return STATUS_INSUFFICIENT_RESOURCES
;
500 RtlCopyMemory(fcb
->reparse_xattr
.Buffer
, oldfcb
->reparse_xattr
.Buffer
, fcb
->reparse_xattr
.Length
);
505 fcb
->adshash
= oldfcb
->adshash
;
507 if (oldfcb
->adsxattr
.Buffer
&& oldfcb
->adsxattr
.Length
> 0) {
508 fcb
->adsxattr
.Length
= fcb
->adsxattr
.MaximumLength
= oldfcb
->adsxattr
.Length
;
509 fcb
->adsxattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsxattr
.MaximumLength
, ALLOC_TAG
);
510 if (!fcb
->adsxattr
.Buffer
) {
511 ERR("out of memory\n");
513 return STATUS_INSUFFICIENT_RESOURCES
;
516 RtlCopyMemory(fcb
->adsxattr
.Buffer
, oldfcb
->adsxattr
.Buffer
, fcb
->adsxattr
.Length
);
519 if (oldfcb
->adsdata
.Buffer
&& oldfcb
->adsdata
.Length
> 0) {
520 fcb
->adsdata
.Length
= fcb
->adsdata
.MaximumLength
= oldfcb
->adsdata
.Length
;
521 fcb
->adsdata
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsdata
.MaximumLength
, ALLOC_TAG
);
522 if (!fcb
->adsdata
.Buffer
) {
523 ERR("out of memory\n");
525 return STATUS_INSUFFICIENT_RESOURCES
;
528 RtlCopyMemory(fcb
->adsdata
.Buffer
, oldfcb
->adsdata
.Buffer
, fcb
->adsdata
.Length
);
535 return STATUS_SUCCESS
;
538 typedef struct _move_entry
{
541 file_ref
* dummyfileref
;
542 struct _move_entry
* parent
;
543 LIST_ENTRY list_entry
;
546 static NTSTATUS
add_children_to_move_list(move_entry
* me
) {
554 static char xapref
[] = "user.";
555 ULONG xapreflen
= strlen(xapref
);
557 ExAcquireResourceSharedLite(&me
->fileref
->nonpaged
->children_lock
, TRUE
);
559 le
= me
->fileref
->children
.Flink
;
560 while (le
!= &me
->fileref
->children
) {
561 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
564 me2
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
566 ERR("out of memory\n");
567 Status
= STATUS_INSUFFICIENT_RESOURCES
;
573 increase_fileref_refcount(fr
);
575 me2
->dummyfcb
= NULL
;
576 me2
->dummyfileref
= NULL
;
579 InsertHeadList(&me
->list_entry
, &me2
->list_entry
);
585 searchkey
.obj_id
= me
->fileref
->fcb
->inode
;
586 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
587 searchkey
.offset
= 0;
589 Status
= find_item(me
->fileref
->fcb
->Vcb
, me
->fileref
->fcb
->subvol
, &tp
, &searchkey
, FALSE
);
590 if (!NT_SUCCESS(Status
)) {
591 ERR("error - find_item returned %08x\n", Status
);
596 traverse_ptr next_tp
;
598 if (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
== searchkey
.obj_type
) {
599 DIR_ITEM
* xa
= (DIR_ITEM
*)tp
.item
->data
;
602 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
603 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
604 Status
= STATUS_INTERNAL_ERROR
;
611 if (len
< sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
) {
612 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
613 Status
= STATUS_INTERNAL_ERROR
;
617 if (xa
->n
> xapreflen
&& RtlCompareMemory(xa
->name
, xapref
, xapreflen
) == xapreflen
&&
618 (tp
.item
->key
.offset
!= EA_DOSATTRIB_HASH
|| xa
->n
!= strlen(EA_DOSATTRIB
) || RtlCompareMemory(xa
->name
, EA_DOSATTRIB
, xa
->n
) != xa
->n
)
622 le
= me
->fileref
->children
.Flink
;
624 while (le
!= &me
->fileref
->children
) {
625 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
627 if (fr
->fcb
->ads
&& fr
->fcb
->adshash
== tp
.item
->key
.offset
&& fr
->fcb
->adsxattr
.Length
== xa
->n
&&
628 RtlCompareMemory(fr
->fcb
->adsxattr
.Buffer
, xa
->name
, xa
->n
) == xa
->n
) {
642 xattr
.Length
= xa
->n
;
643 xattr
.MaximumLength
= xattr
.Length
+ 1;
644 xattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, xattr
.MaximumLength
, ALLOC_TAG
);
647 ERR("out of memory\n");
648 Status
= STATUS_INSUFFICIENT_RESOURCES
;
652 RtlCopyMemory(xattr
.Buffer
, xa
->name
, xa
->n
);
653 xattr
.Buffer
[xa
->n
] = 0;
655 Status
= open_fcb_stream(me
->fileref
->fcb
->Vcb
, me
->fileref
->fcb
->subvol
, me
->fileref
->fcb
->inode
, &xattr
,
656 tp
.item
->key
.offset
, me
->fileref
->fcb
, &fcb
);
657 if (!NT_SUCCESS(Status
)) {
658 ERR("open_fcb_stream returned %08x\n", Status
);
659 ExFreePool(xattr
.Buffer
);
663 fr
= create_fileref();
665 ERR("out of memory\n");
667 Status
= STATUS_INSUFFICIENT_RESOURCES
;
673 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &stringlen
, &xa
->name
[xapreflen
], xa
->n
- xapreflen
);
674 if (!NT_SUCCESS(Status
)) {
675 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status
);
680 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, stringlen
, ALLOC_TAG
);
681 if (!fr
->filepart
.Buffer
) {
682 ERR("out of memory\n");
683 Status
= STATUS_INSUFFICIENT_RESOURCES
;
688 Status
= RtlUTF8ToUnicodeN(fr
->filepart
.Buffer
, stringlen
, &stringlen
, &xa
->name
[xapreflen
], xa
->n
- xapreflen
);
689 if (!NT_SUCCESS(Status
)) {
690 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status
);
695 fr
->filepart
.Length
= fr
->filepart
.MaximumLength
= stringlen
;
697 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
698 if (!NT_SUCCESS(Status
)) {
699 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
704 fr
->parent
= (struct _file_ref
*)me
->fileref
;
705 increase_fileref_refcount(fr
->parent
);
707 insert_fileref_child(me
->fileref
, fr
, FALSE
);
709 me2
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
711 ERR("out of memory\n");
712 Status
= STATUS_INSUFFICIENT_RESOURCES
;
718 me2
->dummyfcb
= NULL
;
719 me2
->dummyfileref
= NULL
;
722 InsertHeadList(&me
->list_entry
, &me2
->list_entry
);
726 len
-= sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
;
729 xa
= (DIR_ITEM
*)&xa
->name
[xa
->m
+ xa
->n
];
733 b
= find_next_item(me
->fileref
->fcb
->Vcb
, &tp
, &next_tp
, FALSE
);
737 if (next_tp
.item
->key
.obj_id
> searchkey
.obj_id
|| (next_tp
.item
->key
.obj_id
== searchkey
.obj_id
&& next_tp
.item
->key
.obj_type
> searchkey
.obj_type
))
742 if (me
->fileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
&& me
->fileref
->fcb
->inode_item
.st_size
!= 0) {
743 searchkey
.obj_id
= me
->fileref
->fcb
->inode
;
744 searchkey
.obj_type
= TYPE_DIR_INDEX
;
745 searchkey
.offset
= 2;
747 Status
= find_item(me
->fileref
->fcb
->Vcb
, me
->fileref
->fcb
->subvol
, &tp
, &searchkey
, FALSE
);
748 if (!NT_SUCCESS(Status
)) {
749 ERR("error - find_item returned %08x\n", Status
);
754 traverse_ptr next_tp
;
756 // FIXME - both lists are ordered; we can make this more efficient
758 if (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
== searchkey
.obj_type
) {
761 le
= me
->fileref
->children
.Flink
;
763 while (le
!= &me
->fileref
->children
) {
764 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
767 if (fr
->index
== tp
.item
->key
.offset
) {
770 } else if (fr
->index
> tp
.item
->key
.offset
)
778 DIR_ITEM
* di
= (DIR_ITEM
*)tp
.item
->data
;
780 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
781 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
782 Status
= STATUS_INTERNAL_ERROR
;
786 if (tp
.item
->size
< sizeof(DIR_ITEM
) - 1 + di
->m
+ di
->n
) {
787 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
) - 1 + di
->m
+ di
->n
);
788 Status
= STATUS_INTERNAL_ERROR
;
793 ERR("(%llx,%x,%llx): filename length was 0\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
794 Status
= STATUS_INTERNAL_ERROR
;
798 if (di
->key
.obj_type
== TYPE_INODE_ITEM
|| di
->key
.obj_type
== TYPE_ROOT_ITEM
) {
806 utf8
.Length
= utf8
.MaximumLength
= di
->n
;
807 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.MaximumLength
, ALLOC_TAG
);
809 ERR("out of memory\n");
810 Status
= STATUS_INSUFFICIENT_RESOURCES
;
814 RtlCopyMemory(utf8
.Buffer
, di
->name
, di
->n
);
816 if (di
->key
.obj_type
== TYPE_ROOT_ITEM
) {
821 le2
= me
->fileref
->fcb
->Vcb
->roots
.Flink
;
822 while (le2
!= &me
->fileref
->fcb
->Vcb
->roots
) {
823 root
* r2
= CONTAINING_RECORD(le2
, root
, list_entry
);
825 if (r2
->id
== di
->key
.obj_id
) {
834 ERR("could not find subvol %llx\n", di
->key
.obj_id
);
835 Status
= STATUS_INTERNAL_ERROR
;
839 inode
= SUBVOL_ROOT_INODE
;
841 subvol
= me
->fileref
->fcb
->subvol
;
842 inode
= di
->key
.obj_id
;
845 Status
= open_fcb(me
->fileref
->fcb
->Vcb
, subvol
, inode
, di
->type
, &utf8
, me
->fileref
->fcb
, &fcb
);
847 if (!NT_SUCCESS(Status
)) {
848 ERR("open_fcb returned %08x\n", Status
);
849 ExFreePool(utf8
.Buffer
);
853 fr
= create_fileref();
855 ERR("out of memory\n");
856 Status
= STATUS_INSUFFICIENT_RESOURCES
;
857 ExFreePool(utf8
.Buffer
);
865 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &stringlen
, utf8
.Buffer
, utf8
.Length
);
866 if (!NT_SUCCESS(Status
)) {
867 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status
);
872 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, stringlen
, ALLOC_TAG
);
873 if (!fr
->filepart
.Buffer
) {
874 ERR("out of memory\n");
875 Status
= STATUS_INSUFFICIENT_RESOURCES
;
880 Status
= RtlUTF8ToUnicodeN(fr
->filepart
.Buffer
, stringlen
, &stringlen
, utf8
.Buffer
, utf8
.Length
);
882 if (!NT_SUCCESS(Status
)) {
883 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status
);
888 fr
->filepart
.Length
= fr
->filepart
.MaximumLength
= stringlen
;
890 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
892 if (!NT_SUCCESS(Status
)) {
893 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
898 fr
->parent
= me
->fileref
;
900 fr
->index
= tp
.item
->key
.offset
;
901 increase_fileref_refcount(me
->fileref
);
903 insert_fileref_child(fr
->parent
, fr
, FALSE
);
905 if (fr
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
906 fr
->fcb
->fileref
= fr
;
908 me2
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
910 ERR("out of memory\n");
911 Status
= STATUS_INSUFFICIENT_RESOURCES
;
917 me2
->dummyfcb
= NULL
;
918 me2
->dummyfileref
= NULL
;
921 InsertHeadList(&me
->list_entry
, &me2
->list_entry
);
923 ERR("unrecognized key (%llx,%x,%llx)\n", di
->key
.obj_id
, di
->key
.obj_type
, di
->key
.offset
);
924 Status
= STATUS_INTERNAL_ERROR
;
930 b
= find_next_item(me
->fileref
->fcb
->Vcb
, &tp
, &next_tp
, FALSE
);
934 if (next_tp
.item
->key
.obj_id
> searchkey
.obj_id
|| (next_tp
.item
->key
.obj_id
== searchkey
.obj_id
&& next_tp
.item
->key
.obj_type
> searchkey
.obj_type
))
940 Status
= STATUS_SUCCESS
;
943 ExReleaseResourceLite(&me
->fileref
->nonpaged
->children_lock
);
948 static NTSTATUS
move_across_subvols(file_ref
* fileref
, file_ref
* destdir
, PANSI_STRING utf8
, PUNICODE_STRING fnus
, LIST_ENTRY
* rollback
) {
950 LIST_ENTRY move_list
, *le
;
954 file_ref
* origparent
;
956 InitializeListHead(&move_list
);
958 me
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
961 ERR("out of memory\n");
962 Status
= STATUS_INSUFFICIENT_RESOURCES
;
966 origparent
= fileref
->parent
;
968 me
->fileref
= fileref
;
969 increase_fileref_refcount(me
->fileref
);
971 me
->dummyfileref
= NULL
;
974 InsertTailList(&move_list
, &me
->list_entry
);
976 le
= move_list
.Flink
;
977 while (le
!= &move_list
) {
978 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
980 ExAcquireResourceSharedLite(me
->fileref
->fcb
->Header
.Resource
, TRUE
);
982 if (!me
->fileref
->fcb
->ads
&& me
->fileref
->fcb
->subvol
== origparent
->fcb
->subvol
) {
983 Status
= add_children_to_move_list(me
);
985 if (!NT_SUCCESS(Status
)) {
986 ERR("add_children_to_move_list returned %08x\n", Status
);
991 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
996 // loop through list and create new inodes
998 le
= move_list
.Flink
;
999 while (le
!= &move_list
) {
1000 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1002 if (me
->fileref
->fcb
->inode
!= SUBVOL_ROOT_INODE
) {
1003 if (!me
->dummyfcb
) {
1006 ExAcquireResourceExclusiveLite(me
->fileref
->fcb
->Header
.Resource
, TRUE
);
1008 Status
= duplicate_fcb(me
->fileref
->fcb
, &me
->dummyfcb
);
1009 if (!NT_SUCCESS(Status
)) {
1010 ERR("duplicate_fcb returned %08x\n", Status
);
1011 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1015 me
->dummyfcb
->subvol
= me
->fileref
->fcb
->subvol
;
1016 me
->dummyfcb
->inode
= me
->fileref
->fcb
->inode
;
1018 if (!me
->dummyfcb
->ads
) {
1019 me
->dummyfcb
->sd_dirty
= me
->fileref
->fcb
->sd_dirty
;
1020 me
->dummyfcb
->atts_changed
= me
->fileref
->fcb
->atts_changed
;
1021 me
->dummyfcb
->atts_deleted
= me
->fileref
->fcb
->atts_deleted
;
1022 me
->dummyfcb
->extents_changed
= me
->fileref
->fcb
->extents_changed
;
1023 me
->dummyfcb
->reparse_xattr_changed
= me
->fileref
->fcb
->reparse_xattr_changed
;
1026 me
->dummyfcb
->created
= me
->fileref
->fcb
->created
;
1027 me
->dummyfcb
->deleted
= me
->fileref
->fcb
->deleted
;
1028 mark_fcb_dirty(me
->dummyfcb
);
1030 if (!me
->fileref
->fcb
->ads
) {
1033 if (destdir
->fcb
->subvol
->lastinode
== 0)
1034 get_last_inode(destdir
->fcb
->Vcb
, destdir
->fcb
->subvol
);
1036 me
->fileref
->fcb
->subvol
= destdir
->fcb
->subvol
;
1037 me
->fileref
->fcb
->inode
= ++destdir
->fcb
->subvol
->lastinode
; // FIXME - do proper function for this
1038 me
->fileref
->fcb
->inode_item
.st_nlink
= 1;
1040 defda
= get_file_attributes(me
->fileref
->fcb
->Vcb
, &me
->fileref
->fcb
->inode_item
, me
->fileref
->fcb
->subvol
, me
->fileref
->fcb
->inode
,
1041 me
->fileref
->fcb
->type
, me
->fileref
->filepart
.Length
> 0 && me
->fileref
->filepart
.Buffer
[0] == '.', TRUE
);
1043 me
->fileref
->fcb
->sd_dirty
= !!me
->fileref
->fcb
->sd
;
1044 me
->fileref
->fcb
->atts_changed
= defda
!= me
->fileref
->fcb
->atts
;
1045 me
->fileref
->fcb
->extents_changed
= !IsListEmpty(&me
->fileref
->fcb
->extents
);
1046 me
->fileref
->fcb
->reparse_xattr_changed
= !!me
->fileref
->fcb
->reparse_xattr
.Buffer
;
1048 le2
= me
->fileref
->fcb
->extents
.Flink
;
1049 while (le2
!= &me
->fileref
->fcb
->extents
) {
1050 extent
* ext
= CONTAINING_RECORD(le2
, extent
, list_entry
);
1052 if (!ext
->ignore
&& ext
->datalen
>= sizeof(EXTENT_DATA
) - 1 + sizeof(EXTENT_DATA2
) &&
1053 (ext
->data
->type
== EXTENT_TYPE_REGULAR
|| ext
->data
->type
== EXTENT_TYPE_PREALLOC
)) {
1054 EXTENT_DATA2
* ed2
= (EXTENT_DATA2
*)ext
->data
->data
;
1056 if (ed2
->size
!= 0) {
1057 chunk
* c
= get_chunk_from_address(me
->fileref
->fcb
->Vcb
, ed2
->address
);
1060 ERR("get_chunk_from_address(%llx) failed\n", ed2
->address
);
1062 Status
= update_changed_extent_ref(me
->fileref
->fcb
->Vcb
, c
, ed2
->address
, ed2
->size
, me
->fileref
->fcb
->subvol
->id
, me
->fileref
->fcb
->inode
,
1063 ext
->offset
- ed2
->offset
, 1, me
->fileref
->fcb
->inode_item
.flags
& BTRFS_INODE_NODATASUM
, ed2
->size
);
1065 if (!NT_SUCCESS(Status
)) {
1066 ERR("update_changed_extent_ref returned %08x\n", Status
);
1067 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1078 me
->fileref
->fcb
->subvol
= me
->parent
->fileref
->fcb
->subvol
;
1079 me
->fileref
->fcb
->inode
= me
->parent
->fileref
->fcb
->inode
;
1082 me
->fileref
->fcb
->created
= TRUE
;
1084 InsertHeadList(&me
->fileref
->fcb
->list_entry
, &me
->dummyfcb
->list_entry
);
1085 RemoveEntryList(&me
->fileref
->fcb
->list_entry
);
1087 InsertTailList(&destdir
->fcb
->subvol
->fcbs
, &me
->fileref
->fcb
->list_entry
);
1089 InsertTailList(&me
->fileref
->fcb
->Vcb
->all_fcbs
, &me
->dummyfcb
->list_entry_all
);
1091 while (!IsListEmpty(&me
->fileref
->fcb
->hardlinks
)) {
1092 LIST_ENTRY
* le
= RemoveHeadList(&me
->fileref
->fcb
->hardlinks
);
1093 hardlink
* hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
);
1095 if (hl
->name
.Buffer
)
1096 ExFreePool(hl
->name
.Buffer
);
1098 if (hl
->utf8
.Buffer
)
1099 ExFreePool(hl
->utf8
.Buffer
);
1104 mark_fcb_dirty(me
->fileref
->fcb
);
1106 if ((!me
->dummyfcb
->ads
&& me
->dummyfcb
->inode_item
.st_nlink
> 1) || (me
->dummyfcb
->ads
&& me
->parent
->dummyfcb
->inode_item
.st_nlink
> 1)) {
1107 LIST_ENTRY
* le2
= le
->Flink
;
1109 while (le2
!= &move_list
) {
1110 move_entry
* me2
= CONTAINING_RECORD(le2
, move_entry
, list_entry
);
1112 if (me2
->fileref
->fcb
== me
->fileref
->fcb
&& !me2
->fileref
->fcb
->ads
) {
1113 me2
->dummyfcb
= me
->dummyfcb
;
1114 InterlockedIncrement(&me
->dummyfcb
->refcount
);
1121 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1123 ExAcquireResourceExclusiveLite(me
->fileref
->fcb
->Header
.Resource
, TRUE
);
1124 me
->fileref
->fcb
->inode_item
.st_nlink
++;
1125 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1132 KeQuerySystemTime(&time
);
1133 win_time_to_unix(time
, &now
);
1135 fileref
->fcb
->subvol
->root_item
.ctransid
= fileref
->fcb
->Vcb
->superblock
.generation
;
1136 fileref
->fcb
->subvol
->root_item
.ctime
= now
;
1138 // loop through list and create new filerefs
1140 le
= move_list
.Flink
;
1141 while (le
!= &move_list
) {
1144 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1146 me
->dummyfileref
= create_fileref();
1147 if (!me
->dummyfileref
) {
1148 ERR("out of memory\n");
1149 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1153 if (me
->fileref
->fcb
->inode
== SUBVOL_ROOT_INODE
)
1154 me
->dummyfileref
->fcb
= me
->fileref
->fcb
;
1156 me
->dummyfileref
->fcb
= me
->dummyfcb
;
1158 InterlockedIncrement(&me
->dummyfileref
->fcb
->refcount
);
1160 me
->dummyfileref
->filepart
= me
->fileref
->filepart
;
1162 if (le
== move_list
.Flink
) // first item
1163 me
->fileref
->filepart
.Length
= me
->fileref
->filepart
.MaximumLength
= fnus
->Length
;
1165 me
->fileref
->filepart
.MaximumLength
= me
->fileref
->filepart
.MaximumLength
;
1167 me
->fileref
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, me
->fileref
->filepart
.MaximumLength
, ALLOC_TAG
);
1169 if (!me
->fileref
->filepart
.Buffer
) {
1170 ERR("out of memory\n");
1171 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1175 RtlCopyMemory(me
->fileref
->filepart
.Buffer
, le
== move_list
.Flink
? fnus
->Buffer
: me
->dummyfileref
->filepart
.Buffer
, me
->fileref
->filepart
.Length
);
1177 Status
= RtlUpcaseUnicodeString(&me
->fileref
->filepart_uc
, &me
->fileref
->filepart
, TRUE
);
1178 if (!NT_SUCCESS(Status
)) {
1179 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1183 me
->dummyfileref
->utf8
= me
->fileref
->utf8
;
1184 me
->dummyfileref
->oldutf8
= me
->fileref
->oldutf8
;
1186 if (le
== move_list
.Flink
)
1187 me
->fileref
->utf8
.Length
= me
->fileref
->utf8
.MaximumLength
= utf8
->Length
;
1189 me
->fileref
->utf8
.MaximumLength
= me
->fileref
->utf8
.Length
;
1191 if (me
->fileref
->utf8
.MaximumLength
> 0) {
1192 me
->fileref
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, me
->fileref
->utf8
.MaximumLength
, ALLOC_TAG
);
1194 if (!me
->fileref
->utf8
.Buffer
) {
1195 ERR("out of memory\n");
1196 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1200 RtlCopyMemory(me
->fileref
->utf8
.Buffer
, le
== move_list
.Flink
? utf8
->Buffer
: me
->dummyfileref
->utf8
.Buffer
, me
->fileref
->utf8
.Length
);
1203 me
->dummyfileref
->delete_on_close
= me
->fileref
->delete_on_close
;
1204 me
->dummyfileref
->deleted
= me
->fileref
->deleted
;
1206 me
->dummyfileref
->created
= me
->fileref
->created
;
1207 me
->fileref
->created
= TRUE
;
1209 me
->dummyfileref
->parent
= me
->parent
? me
->parent
->dummyfileref
: origparent
;
1210 increase_fileref_refcount(me
->dummyfileref
->parent
);
1212 me
->dummyfileref
->index
= me
->fileref
->index
;
1214 insert_fileref_child(me
->dummyfileref
->parent
, me
->dummyfileref
, TRUE
);
1216 me
->dummyfileref
->debug_desc
= me
->fileref
->debug_desc
;
1218 if (me
->dummyfileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
1219 me
->dummyfileref
->fcb
->fileref
= me
->dummyfileref
;
1222 RemoveEntryList(&me
->fileref
->list_entry
);
1224 free_fileref(me
->fileref
->parent
);
1226 me
->fileref
->parent
= destdir
;
1228 increase_fileref_refcount(destdir
);
1230 Status
= fcb_get_last_dir_index(me
->fileref
->parent
->fcb
, &me
->fileref
->index
);
1231 if (!NT_SUCCESS(Status
)) {
1232 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
1236 insert_fileref_child(me
->fileref
->parent
, me
->fileref
, TRUE
);
1238 TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", me
->fileref
->parent
->fcb
->inode
, me
->fileref
->parent
->fcb
->inode_item
.st_size
);
1239 me
->fileref
->parent
->fcb
->inode_item
.st_size
+= me
->fileref
->utf8
.Length
* 2;
1240 TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", me
->fileref
->parent
->fcb
->inode
, me
->fileref
->parent
->fcb
->inode_item
.st_size
);
1241 me
->fileref
->parent
->fcb
->inode_item
.transid
= me
->fileref
->fcb
->Vcb
->superblock
.generation
;
1242 me
->fileref
->parent
->fcb
->inode_item
.sequence
++;
1243 me
->fileref
->parent
->fcb
->inode_item
.st_ctime
= now
;
1244 me
->fileref
->parent
->fcb
->inode_item
.st_mtime
= now
;
1245 mark_fcb_dirty(me
->fileref
->parent
->fcb
);
1248 if (me
->fileref
->fcb
->inode
== SUBVOL_ROOT_INODE
)
1249 me
->fileref
->fcb
->subvol
->root_item
.num_references
++;
1251 if (!me
->dummyfileref
->fcb
->ads
) {
1252 Status
= delete_fileref(me
->dummyfileref
, NULL
, rollback
);
1253 if (!NT_SUCCESS(Status
)) {
1254 ERR("delete_fileref returned %08x\n", Status
);
1259 hl
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
1261 ERR("out of memory\n");
1262 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1266 hl
->parent
= me
->fileref
->parent
->fcb
->inode
;
1267 hl
->index
= me
->fileref
->index
;
1269 hl
->utf8
.Length
= hl
->utf8
.MaximumLength
= me
->fileref
->utf8
.Length
;
1270 hl
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->utf8
.MaximumLength
, ALLOC_TAG
);
1271 if (!hl
->utf8
.Buffer
) {
1272 ERR("out of memory\n");
1273 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1278 RtlCopyMemory(hl
->utf8
.Buffer
, me
->fileref
->utf8
.Buffer
, me
->fileref
->utf8
.Length
);
1280 hl
->name
.Length
= hl
->name
.MaximumLength
= me
->fileref
->filepart
.Length
;
1281 hl
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->name
.MaximumLength
, ALLOC_TAG
);
1282 if (!hl
->name
.Buffer
) {
1283 ERR("out of memory\n");
1284 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1285 ExFreePool(hl
->utf8
.Buffer
);
1290 RtlCopyMemory(hl
->name
.Buffer
, me
->fileref
->filepart
.Buffer
, me
->fileref
->filepart
.Length
);
1292 InsertTailList(&me
->fileref
->fcb
->hardlinks
, &hl
->list_entry
);
1294 mark_fileref_dirty(me
->fileref
);
1299 // loop through, and only mark streams as deleted if their parent inodes are also deleted
1301 le
= move_list
.Flink
;
1302 while (le
!= &move_list
) {
1303 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1305 if (me
->dummyfileref
->fcb
->ads
&& me
->parent
->dummyfileref
->fcb
->deleted
) {
1306 Status
= delete_fileref(me
->dummyfileref
, NULL
, rollback
);
1307 if (!NT_SUCCESS(Status
)) {
1308 ERR("delete_fileref returned %08x\n", Status
);
1316 destdir
->fcb
->subvol
->root_item
.ctransid
= destdir
->fcb
->Vcb
->superblock
.generation
;
1317 destdir
->fcb
->subvol
->root_item
.ctime
= now
;
1319 me
= CONTAINING_RECORD(move_list
.Flink
, move_entry
, list_entry
);
1320 send_notification_fileref(me
->dummyfileref
, fileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_REMOVED
);
1321 send_notification_fileref(fileref
, fileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_ADDED
);
1322 send_notification_fileref(me
->dummyfileref
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1323 send_notification_fileref(fileref
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1325 Status
= STATUS_SUCCESS
;
1328 while (!IsListEmpty(&move_list
)) {
1329 le
= RemoveHeadList(&move_list
);
1330 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1333 free_fcb(me
->dummyfcb
);
1335 if (me
->dummyfileref
)
1336 free_fileref(me
->dummyfileref
);
1338 free_fileref(me
->fileref
);
1345 static NTSTATUS STDCALL
set_rename_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
, PFILE_OBJECT tfo
, BOOL ReplaceIfExists
) {
1346 FILE_RENAME_INFORMATION
* fri
= Irp
->AssociatedIrp
.SystemBuffer
;
1347 fcb
*fcb
= FileObject
->FsContext
;
1348 ccb
* ccb
= FileObject
->FsContext2
;
1349 file_ref
*fileref
= ccb
? ccb
->fileref
: NULL
, *oldfileref
= NULL
, *related
= NULL
, *fr2
= NULL
;
1352 ULONG fnlen
, utf8len
;
1353 UNICODE_STRING fnus
;
1358 LIST_ENTRY rollback
, *le
;
1361 InitializeListHead(&rollback
);
1363 // FIXME - check fri length
1364 // FIXME - don't ignore fri->RootDirectory
1366 TRACE("tfo = %p\n", tfo
);
1367 TRACE("ReplaceIfExists = %u\n", ReplaceIfExists
);
1368 TRACE("RootDirectory = %p\n", fri
->RootDirectory
);
1369 TRACE("FileName = %.*S\n", fri
->FileNameLength
/ sizeof(WCHAR
), fri
->FileName
);
1372 fnlen
= fri
->FileNameLength
/ sizeof(WCHAR
);
1375 if (!fileref
|| !fileref
->parent
) {
1376 ERR("no fileref set and no directory given\n");
1377 return STATUS_INVALID_PARAMETER
;
1382 for (i
= fnlen
- 1; i
>= 0; i
--) {
1383 if (fri
->FileName
[i
] == '\\' || fri
->FileName
[i
] == '/') {
1384 fn
= &fri
->FileName
[i
+1];
1385 fnlen
= (fri
->FileNameLength
/ sizeof(WCHAR
)) - i
- 1;
1391 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1392 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1395 FIXME("FIXME - renaming streams\n"); // FIXME
1396 Status
= STATUS_NOT_IMPLEMENTED
;
1401 fnus
.Length
= fnus
.MaximumLength
= fnlen
* sizeof(WCHAR
);
1403 TRACE("fnus = %.*S\n", fnus
.Length
/ sizeof(WCHAR
), fnus
.Buffer
);
1405 Status
= RtlUnicodeToUTF8N(NULL
, 0, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
1406 if (!NT_SUCCESS(Status
))
1409 utf8
.MaximumLength
= utf8
.Length
= utf8len
;
1410 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.MaximumLength
, ALLOC_TAG
);
1412 ERR("out of memory\n");
1413 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1417 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, utf8len
, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
1418 if (!NT_SUCCESS(Status
))
1421 if (tfo
&& tfo
->FsContext2
) {
1422 struct _ccb
* relatedccb
= tfo
->FsContext2
;
1424 related
= relatedccb
->fileref
;
1425 increase_fileref_refcount(related
);
1428 Status
= open_fileref(Vcb
, &oldfileref
, &fnus
, related
, FALSE
, NULL
);
1430 if (NT_SUCCESS(Status
)) {
1431 TRACE("destination file %S already exists\n", file_desc_fileref(oldfileref
));
1433 if (fileref
!= oldfileref
&& !oldfileref
->deleted
) {
1434 if (!ReplaceIfExists
) {
1435 Status
= STATUS_OBJECT_NAME_COLLISION
;
1437 } else if ((oldfileref
->fcb
->open_count
>= 1 || has_open_children(oldfileref
)) && !oldfileref
->deleted
) {
1438 WARN("trying to overwrite open file\n");
1439 Status
= STATUS_ACCESS_DENIED
;
1443 if (oldfileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
) {
1444 WARN("trying to overwrite directory\n");
1445 Status
= STATUS_ACCESS_DENIED
;
1450 if (fileref
== oldfileref
|| !oldfileref
->deleted
) {
1451 free_fileref(oldfileref
);
1457 Status
= open_fileref(Vcb
, &related
, &fnus
, NULL
, TRUE
, NULL
);
1459 if (!NT_SUCCESS(Status
)) {
1460 ERR("open_fileref returned %08x\n", Status
);
1465 if (has_open_children(fileref
)) {
1466 WARN("trying to rename file with open children\n");
1467 Status
= STATUS_ACCESS_DENIED
;
1472 // FIXME - check we have permissions for this
1473 Status
= delete_fileref(oldfileref
, NULL
, &rollback
);
1474 if (!NT_SUCCESS(Status
)) {
1475 ERR("delete_fileref returned %08x\n", Status
);
1480 if (fileref
->parent
->fcb
->subvol
!= related
->fcb
->subvol
&& fileref
->fcb
->subvol
== fileref
->parent
->fcb
->subvol
) {
1481 Status
= move_across_subvols(fileref
, related
, &utf8
, &fnus
, &rollback
);
1482 if (!NT_SUCCESS(Status
)) {
1483 ERR("move_across_subvols returned %08x\n", Status
);
1488 if (related
== fileref
->parent
) { // keeping file in same directory
1489 UNICODE_STRING fnus2
, oldfn
, newfn
;
1493 fnus2
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fnus
.Length
, ALLOC_TAG
);
1494 if (!fnus2
.Buffer
) {
1495 ERR("out of memory\n");
1496 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1500 Status
= fileref_get_filename(fileref
, &oldfn
, &name_offset
);
1501 if (!NT_SUCCESS(Status
)) {
1502 ERR("fileref_get_filename returned %08x\n", Status
);
1506 fnus2
.Length
= fnus2
.MaximumLength
= fnus
.Length
;
1507 RtlCopyMemory(fnus2
.Buffer
, fnus
.Buffer
, fnus
.Length
);
1509 oldutf8len
= fileref
->utf8
.Length
;
1511 if (!fileref
->created
&& !fileref
->oldutf8
.Buffer
)
1512 fileref
->oldutf8
= fileref
->utf8
;
1514 ExFreePool(fileref
->utf8
.Buffer
);
1516 TRACE("renaming %.*S to %.*S\n", fileref
->filepart
.Length
/ sizeof(WCHAR
), fileref
->filepart
.Buffer
, fnus2
.Length
/ sizeof(WCHAR
), fnus
.Buffer
);
1518 fileref
->utf8
= utf8
;
1519 fileref
->filepart
= fnus2
;
1521 Status
= fileref_get_filename(fileref
, &newfn
, &name_offset
);
1522 if (!NT_SUCCESS(Status
)) {
1523 ERR("fileref_get_filename returned %08x\n", Status
);
1524 ExFreePool(oldfn
.Buffer
);
1528 if (fileref
->filepart_uc
.Buffer
)
1529 ExFreePool(fileref
->filepart_uc
.Buffer
);
1531 Status
= RtlUpcaseUnicodeString(&fileref
->filepart_uc
, &fileref
->filepart
, TRUE
);
1532 if (!NT_SUCCESS(Status
)) {
1533 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1534 ExFreePool(oldfn
.Buffer
);
1535 ExFreePool(newfn
.Buffer
);
1539 mark_fileref_dirty(fileref
);
1541 KeQuerySystemTime(&time
);
1542 win_time_to_unix(time
, &now
);
1544 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1545 fcb
->inode_item
.sequence
++;
1546 fcb
->inode_item
.st_ctime
= now
;
1548 mark_fcb_dirty(fcb
);
1550 // update parent's INODE_ITEM
1552 related
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1553 TRACE("related->fcb->inode_item.st_size (inode %llx) was %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1554 related
->fcb
->inode_item
.st_size
= related
->fcb
->inode_item
.st_size
+ (2 * utf8
.Length
) - (2* oldutf8len
);
1555 TRACE("related->fcb->inode_item.st_size (inode %llx) now %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1556 related
->fcb
->inode_item
.sequence
++;
1557 related
->fcb
->inode_item
.st_ctime
= now
;
1558 related
->fcb
->inode_item
.st_mtime
= now
;
1560 mark_fcb_dirty(related
->fcb
);
1561 send_notification_fileref(related
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1563 FsRtlNotifyFilterReportChange(fcb
->Vcb
->NotifySync
, &fcb
->Vcb
->DirNotifyList
, (PSTRING
)&oldfn
, name_offset
, NULL
, NULL
,
1564 fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_RENAMED_OLD_NAME
, NULL
, NULL
);
1565 FsRtlNotifyFilterReportChange(fcb
->Vcb
->NotifySync
, &fcb
->Vcb
->DirNotifyList
, (PSTRING
)&newfn
, name_offset
, NULL
, NULL
,
1566 fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_RENAMED_NEW_NAME
, NULL
, NULL
);
1568 ExFreePool(oldfn
.Buffer
);
1569 ExFreePool(newfn
.Buffer
);
1571 Status
= STATUS_SUCCESS
;
1575 // We move files by moving the existing fileref to the new directory, and
1576 // replacing it with a dummy fileref with the same original values, but marked as deleted.
1578 fr2
= create_fileref();
1580 fr2
->fcb
= fileref
->fcb
;
1581 fr2
->fcb
->refcount
++;
1583 fr2
->filepart
= fileref
->filepart
;
1584 fr2
->filepart_uc
= fileref
->filepart_uc
;
1585 fr2
->utf8
= fileref
->utf8
;
1586 fr2
->oldutf8
= fileref
->oldutf8
;
1587 fr2
->index
= fileref
->index
;
1588 fr2
->delete_on_close
= fileref
->delete_on_close
;
1589 fr2
->deleted
= TRUE
;
1590 fr2
->created
= fileref
->created
;
1591 fr2
->parent
= fileref
->parent
;
1593 if (fr2
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
1594 fr2
->fcb
->fileref
= fr2
;
1596 Status
= fcb_get_last_dir_index(related
->fcb
, &index
);
1597 if (!NT_SUCCESS(Status
)) {
1598 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
1602 fileref
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fnus
.Length
, ALLOC_TAG
);
1603 if (!fileref
->filepart
.Buffer
) {
1604 ERR("out of memory\n");
1605 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1609 fileref
->filepart
.Length
= fileref
->filepart
.MaximumLength
= fnus
.Length
;
1610 RtlCopyMemory(fileref
->filepart
.Buffer
, fnus
.Buffer
, fnus
.Length
);
1612 Status
= RtlUpcaseUnicodeString(&fileref
->filepart_uc
, &fileref
->filepart
, TRUE
);
1613 if (!NT_SUCCESS(Status
)) {
1614 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1618 fileref
->utf8
= utf8
;
1619 fileref
->oldutf8
.Buffer
= NULL
;
1620 fileref
->index
= index
;
1621 fileref
->deleted
= FALSE
;
1622 fileref
->created
= TRUE
;
1623 fileref
->parent
= related
;
1625 ExAcquireResourceExclusiveLite(&fileref
->parent
->nonpaged
->children_lock
, TRUE
);
1626 InsertHeadList(&fileref
->list_entry
, &fr2
->list_entry
);
1627 RemoveEntryList(&fileref
->list_entry
);
1628 ExReleaseResourceLite(&fileref
->parent
->nonpaged
->children_lock
);
1630 insert_fileref_child(related
, fileref
, TRUE
);
1632 mark_fileref_dirty(fr2
);
1633 mark_fileref_dirty(fileref
);
1635 // add new hardlink entry to fcb
1637 hl
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
1639 ERR("out of memory\n");
1640 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1644 hl
->parent
= related
->fcb
->inode
;
1647 hl
->name
.Length
= hl
->name
.MaximumLength
= fileref
->filepart
.Length
;
1648 hl
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->name
.MaximumLength
, ALLOC_TAG
);
1650 if (!hl
->name
.Buffer
) {
1651 ERR("out of memory\n");
1653 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1657 RtlCopyMemory(hl
->name
.Buffer
, fileref
->filepart
.Buffer
, fileref
->filepart
.Length
);
1659 hl
->utf8
.Length
= hl
->utf8
.MaximumLength
= fileref
->utf8
.Length
;
1660 hl
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->utf8
.MaximumLength
, ALLOC_TAG
);
1662 if (!hl
->utf8
.Buffer
) {
1663 ERR("out of memory\n");
1664 ExFreePool(hl
->name
.Buffer
);
1666 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1670 RtlCopyMemory(hl
->utf8
.Buffer
, fileref
->utf8
.Buffer
, fileref
->utf8
.Length
);
1672 InsertTailList(&fcb
->hardlinks
, &hl
->list_entry
);
1674 // delete old hardlink entry from fcb
1676 le
= fcb
->hardlinks
.Flink
;
1677 while (le
!= &fcb
->hardlinks
) {
1678 hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
);
1680 if (hl
->parent
== fr2
->parent
->fcb
->inode
&& hl
->index
== fr2
->index
) {
1681 RemoveEntryList(&hl
->list_entry
);
1683 if (hl
->utf8
.Buffer
)
1684 ExFreePool(hl
->utf8
.Buffer
);
1686 if (hl
->name
.Buffer
)
1687 ExFreePool(hl
->name
.Buffer
);
1696 // update inode's INODE_ITEM
1698 KeQuerySystemTime(&time
);
1699 win_time_to_unix(time
, &now
);
1701 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1702 fcb
->inode_item
.sequence
++;
1703 fcb
->inode_item
.st_ctime
= now
;
1705 mark_fcb_dirty(fcb
);
1707 // update new parent's INODE_ITEM
1709 related
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1710 TRACE("related->fcb->inode_item.st_size (inode %llx) was %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1711 related
->fcb
->inode_item
.st_size
+= 2 * utf8len
;
1712 TRACE("related->fcb->inode_item.st_size (inode %llx) now %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1713 related
->fcb
->inode_item
.sequence
++;
1714 related
->fcb
->inode_item
.st_ctime
= now
;
1715 related
->fcb
->inode_item
.st_mtime
= now
;
1717 mark_fcb_dirty(related
->fcb
);
1719 // update old parent's INODE_ITEM
1721 fr2
->parent
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1722 TRACE("fr2->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fr2
->parent
->fcb
->inode
, fr2
->parent
->fcb
->inode_item
.st_size
);
1723 fr2
->parent
->fcb
->inode_item
.st_size
-= 2 * fr2
->utf8
.Length
;
1724 TRACE("fr2->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fr2
->parent
->fcb
->inode
, fr2
->parent
->fcb
->inode_item
.st_size
);
1725 fr2
->parent
->fcb
->inode_item
.sequence
++;
1726 fr2
->parent
->fcb
->inode_item
.st_ctime
= now
;
1727 fr2
->parent
->fcb
->inode_item
.st_mtime
= now
;
1731 mark_fcb_dirty(fr2
->parent
->fcb
);
1733 send_notification_fileref(fr2
, fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_REMOVED
);
1734 send_notification_fileref(fileref
, fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_ADDED
);
1735 send_notification_fileref(related
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1736 send_notification_fileref(fr2
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1738 Status
= STATUS_SUCCESS
;
1742 free_fileref(oldfileref
);
1744 if (!NT_SUCCESS(Status
) && related
)
1745 free_fileref(related
);
1747 if (!NT_SUCCESS(Status
) && fr2
)
1750 if (NT_SUCCESS(Status
))
1751 clear_rollback(&rollback
);
1753 do_rollback(Vcb
, &rollback
);
1755 ExReleaseResourceLite(fcb
->Header
.Resource
);
1756 ExReleaseResourceLite(&Vcb
->tree_lock
);
1761 NTSTATUS STDCALL
stream_set_end_of_file_information(device_extension
* Vcb
, UINT64 end
, fcb
* fcb
, file_ref
* fileref
, PFILE_OBJECT FileObject
, BOOL advance_only
, LIST_ENTRY
* rollback
) {
1766 TRACE("setting new end to %llx bytes (currently %x)\n", end
, fcb
->adsdata
.Length
);
1768 if (!fileref
|| !fileref
->parent
) {
1769 ERR("no fileref for stream\n");
1770 return STATUS_INTERNAL_ERROR
;
1773 if (end
< fcb
->adsdata
.Length
) {
1775 return STATUS_SUCCESS
;
1777 TRACE("truncating stream to %llx bytes\n", end
);
1779 fcb
->adsdata
.Length
= end
;
1780 } else if (end
> fcb
->adsdata
.Length
) {
1783 TRACE("extending stream to %llx bytes\n", end
);
1785 // // find maximum length of xattr
1786 // maxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node);
1788 // searchkey.obj_id = fcb->inode;
1789 // searchkey.obj_type = TYPE_XATTR_ITEM;
1790 // searchkey.offset = fcb->adshash;
1792 // Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
1793 // if (!NT_SUCCESS(Status)) {
1794 // ERR("error - find_item returned %08x\n", Status);
1798 // if (keycmp(&tp.item->key, &searchkey)) {
1799 // ERR("error - could not find key for xattr\n");
1800 // return STATUS_INTERNAL_ERROR;
1803 // if (!get_xattr(Vcb, fcb->subvol, fcb->inode, fcb->adsxattr.Buffer, fcb->adshash, &data, &datalen)) {
1804 // ERR("get_xattr failed\n");
1805 // return STATUS_INTERNAL_ERROR;
1808 // maxlen -= tp.item->size - datalen; // subtract XATTR_ITEM overhead
1810 // if (end > maxlen) {
1811 // ERR("error - xattr too long (%llu > %u)\n", end, maxlen);
1812 // return STATUS_DISK_FULL;
1815 if (end
> fcb
->adsdata
.MaximumLength
) {
1816 char* data
= ExAllocatePoolWithTag(PagedPool
, end
, ALLOC_TAG
);
1818 ERR("out of memory\n");
1820 return STATUS_INSUFFICIENT_RESOURCES
;
1823 if (fcb
->adsdata
.Buffer
) {
1824 RtlCopyMemory(data
, fcb
->adsdata
.Buffer
, fcb
->adsdata
.Length
);
1825 ExFreePool(fcb
->adsdata
.Buffer
);
1828 fcb
->adsdata
.Buffer
= data
;
1829 fcb
->adsdata
.MaximumLength
= end
;
1832 RtlZeroMemory(&fcb
->adsdata
.Buffer
[fcb
->adsdata
.Length
], end
- fcb
->adsdata
.Length
);
1834 fcb
->adsdata
.Length
= end
;
1837 mark_fcb_dirty(fcb
);
1839 fcb
->Header
.AllocationSize
.QuadPart
= end
;
1840 fcb
->Header
.FileSize
.QuadPart
= end
;
1841 fcb
->Header
.ValidDataLength
.QuadPart
= end
;
1844 ccfs
.AllocationSize
= fcb
->Header
.AllocationSize
;
1845 ccfs
.FileSize
= fcb
->Header
.FileSize
;
1846 ccfs
.ValidDataLength
= fcb
->Header
.ValidDataLength
;
1848 CcSetFileSizes(FileObject
, &ccfs
);
1851 KeQuerySystemTime(&time
);
1852 win_time_to_unix(time
, &now
);
1854 fileref
->parent
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1855 fileref
->parent
->fcb
->inode_item
.sequence
++;
1856 fileref
->parent
->fcb
->inode_item
.st_ctime
= now
;
1858 mark_fcb_dirty(fileref
->parent
->fcb
);
1860 fileref
->parent
->fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
1861 fileref
->parent
->fcb
->subvol
->root_item
.ctime
= now
;
1863 return STATUS_SUCCESS
;
1866 static NTSTATUS STDCALL
set_end_of_file_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
, BOOL advance_only
) {
1867 FILE_END_OF_FILE_INFORMATION
* feofi
= Irp
->AssociatedIrp
.SystemBuffer
;
1868 fcb
* fcb
= FileObject
->FsContext
;
1869 ccb
* ccb
= FileObject
->FsContext2
;
1870 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
1874 LIST_ENTRY rollback
;
1877 ERR("fileref is NULL\n");
1878 return STATUS_INVALID_PARAMETER
;
1881 InitializeListHead(&rollback
);
1883 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1885 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1887 if (fileref
? fileref
->deleted
: fcb
->deleted
) {
1888 Status
= STATUS_FILE_CLOSED
;
1893 Status
= stream_set_end_of_file_information(Vcb
, feofi
->EndOfFile
.QuadPart
, fcb
, fileref
, FileObject
, advance_only
, &rollback
);
1897 TRACE("file: %S\n", file_desc(FileObject
));
1898 TRACE("paging IO: %s\n", Irp
->Flags
& IRP_PAGING_IO
? "TRUE" : "FALSE");
1899 TRACE("FileObject: AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx\n",
1900 fcb
->Header
.AllocationSize
.QuadPart
, fcb
->Header
.FileSize
.QuadPart
, fcb
->Header
.ValidDataLength
.QuadPart
);
1903 TRACE("setting new end to %llx bytes (currently %llx)\n", feofi
->EndOfFile
.QuadPart
, fcb
->inode_item
.st_size
);
1905 // if (feofi->EndOfFile.QuadPart==0x36c000)
1908 if (feofi
->EndOfFile
.QuadPart
< fcb
->inode_item
.st_size
) {
1910 Status
= STATUS_SUCCESS
;
1914 TRACE("truncating file to %llx bytes\n", feofi
->EndOfFile
.QuadPart
);
1916 Status
= truncate_file(fcb
, feofi
->EndOfFile
.QuadPart
, &rollback
);
1917 if (!NT_SUCCESS(Status
)) {
1918 ERR("error - truncate_file failed\n");
1921 } else if (feofi
->EndOfFile
.QuadPart
> fcb
->inode_item
.st_size
) {
1922 if (Irp
->Flags
& IRP_PAGING_IO
) {
1923 TRACE("paging IO tried to extend file size\n");
1924 Status
= STATUS_SUCCESS
;
1928 TRACE("extending file to %llx bytes\n", feofi
->EndOfFile
.QuadPart
);
1930 Status
= extend_file(fcb
, fileref
, feofi
->EndOfFile
.QuadPart
, TRUE
, NULL
, &rollback
);
1931 if (!NT_SUCCESS(Status
)) {
1932 ERR("error - extend_file failed\n");
1937 ccfs
.AllocationSize
= fcb
->Header
.AllocationSize
;
1938 ccfs
.FileSize
= fcb
->Header
.FileSize
;
1939 ccfs
.ValidDataLength
= fcb
->Header
.ValidDataLength
;
1941 CcSetFileSizes(FileObject
, &ccfs
);
1942 TRACE("setting FileSize for %S to %llx\n", file_desc(FileObject
), ccfs
.FileSize
);
1944 KeQuerySystemTime(&time
);
1946 win_time_to_unix(time
, &fcb
->inode_item
.st_mtime
);
1948 mark_fcb_dirty(fcb
);
1949 send_notification_fcb(fileref
, FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_SIZE
, FILE_ACTION_MODIFIED
);
1951 Status
= STATUS_SUCCESS
;
1954 if (NT_SUCCESS(Status
))
1955 clear_rollback(&rollback
);
1957 do_rollback(Vcb
, &rollback
);
1959 ExReleaseResourceLite(fcb
->Header
.Resource
);
1961 ExReleaseResourceLite(&Vcb
->tree_lock
);
1966 // static NTSTATUS STDCALL set_allocation_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject) {
1967 // FILE_ALLOCATION_INFORMATION* fai = (FILE_ALLOCATION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
1968 // fcb* fcb = FileObject->FsContext;
1970 // FIXME("FIXME\n");
1971 // ERR("fcb = %p (%.*S)\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1972 // ERR("AllocationSize = %llx\n", fai->AllocationSize.QuadPart);
1974 // return STATUS_NOT_IMPLEMENTED;
1977 static NTSTATUS STDCALL
set_position_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
) {
1978 FILE_POSITION_INFORMATION
* fpi
= (FILE_POSITION_INFORMATION
*)Irp
->AssociatedIrp
.SystemBuffer
;
1980 TRACE("setting the position on %S to %llx\n", file_desc(FileObject
), fpi
->CurrentByteOffset
.QuadPart
);
1982 // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
1984 FileObject
->CurrentByteOffset
= fpi
->CurrentByteOffset
;
1986 return STATUS_SUCCESS
;
1989 static NTSTATUS STDCALL
set_link_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
, PFILE_OBJECT tfo
) {
1990 FILE_LINK_INFORMATION
* fli
= Irp
->AssociatedIrp
.SystemBuffer
;
1991 fcb
*fcb
= FileObject
->FsContext
, *tfofcb
, *parfcb
;
1992 ccb
* ccb
= FileObject
->FsContext2
;
1993 file_ref
*fileref
= ccb
? ccb
->fileref
: NULL
, *oldfileref
= NULL
, *related
= NULL
, *fr2
= NULL
;
1996 ULONG fnlen
, utf8len
;
1997 UNICODE_STRING fnus
;
2002 LIST_ENTRY rollback
;
2005 SECURITY_SUBJECT_CONTEXT subjcont
;
2007 InitializeListHead(&rollback
);
2009 // FIXME - check fli length
2010 // FIXME - don't ignore fli->RootDirectory
2012 TRACE("ReplaceIfExists = %x\n", fli
->ReplaceIfExists
);
2013 TRACE("RootDirectory = %p\n", fli
->RootDirectory
);
2014 TRACE("FileNameLength = %x\n", fli
->FileNameLength
);
2015 TRACE("FileName = %.*S\n", fli
->FileNameLength
/ sizeof(WCHAR
), fli
->FileName
);
2018 fnlen
= fli
->FileNameLength
/ sizeof(WCHAR
);
2021 if (!fileref
|| !fileref
->parent
) {
2022 ERR("no fileref set and no directory given\n");
2023 return STATUS_INVALID_PARAMETER
;
2026 parfcb
= fileref
->parent
->fcb
;
2031 tfofcb
= tfo
->FsContext
;
2034 for (i
= fnlen
- 1; i
>= 0; i
--) {
2035 if (fli
->FileName
[i
] == '\\' || fli
->FileName
[i
] == '/') {
2036 fn
= &fli
->FileName
[i
+1];
2037 fnlen
= (fli
->FileNameLength
/ sizeof(WCHAR
)) - i
- 1;
2043 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
2044 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
2046 if (fcb
->type
== BTRFS_TYPE_DIRECTORY
) {
2047 WARN("tried to create hard link on directory\n");
2048 Status
= STATUS_FILE_IS_A_DIRECTORY
;
2053 WARN("tried to create hard link on stream\n");
2054 Status
= STATUS_INVALID_PARAMETER
;
2059 fnus
.Length
= fnus
.MaximumLength
= fnlen
* sizeof(WCHAR
);
2061 TRACE("fnus = %.*S\n", fnus
.Length
/ sizeof(WCHAR
), fnus
.Buffer
);
2063 Status
= RtlUnicodeToUTF8N(NULL
, 0, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
2064 if (!NT_SUCCESS(Status
))
2067 utf8
.MaximumLength
= utf8
.Length
= utf8len
;
2068 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.MaximumLength
, ALLOC_TAG
);
2070 ERR("out of memory\n");
2071 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2075 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, utf8len
, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
2076 if (!NT_SUCCESS(Status
))
2079 if (tfo
&& tfo
->FsContext2
) {
2080 struct _ccb
* relatedccb
= tfo
->FsContext2
;
2082 related
= relatedccb
->fileref
;
2083 increase_fileref_refcount(related
);
2086 Status
= open_fileref(Vcb
, &oldfileref
, &fnus
, related
, FALSE
, NULL
);
2088 if (NT_SUCCESS(Status
)) {
2089 if (!oldfileref
->deleted
) {
2090 WARN("destination file %S already exists\n", file_desc_fileref(oldfileref
));
2092 if (!fli
->ReplaceIfExists
) {
2093 Status
= STATUS_OBJECT_NAME_COLLISION
;
2095 } else if (oldfileref
->fcb
->open_count
>= 1 && !oldfileref
->deleted
) {
2096 WARN("trying to overwrite open file\n");
2097 Status
= STATUS_ACCESS_DENIED
;
2099 } else if (fileref
== oldfileref
) {
2100 Status
= STATUS_ACCESS_DENIED
;
2104 if (oldfileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
) {
2105 WARN("trying to overwrite directory\n");
2106 Status
= STATUS_ACCESS_DENIED
;
2110 free_fileref(oldfileref
);
2116 Status
= open_fileref(Vcb
, &related
, &fnus
, NULL
, TRUE
, NULL
);
2118 if (!NT_SUCCESS(Status
)) {
2119 ERR("open_fileref returned %08x\n", Status
);
2124 SeCaptureSubjectContext(&subjcont
);
2126 if (!SeAccessCheck(related
->fcb
->sd
, &subjcont
, FALSE
, FILE_ADD_FILE
, 0, NULL
,
2127 IoGetFileObjectGenericMapping(), Irp
->RequestorMode
, &access
, &Status
)) {
2128 SeReleaseSubjectContext(&subjcont
);
2129 WARN("SeAccessCheck failed, returning %08x\n", Status
);
2133 SeReleaseSubjectContext(&subjcont
);
2135 if (fcb
->subvol
!= parfcb
->subvol
) {
2136 WARN("can't create hard link over subvolume boundary\n");
2137 Status
= STATUS_INVALID_PARAMETER
;
2142 SeCaptureSubjectContext(&subjcont
);
2144 if (!SeAccessCheck(oldfileref
->fcb
->sd
, &subjcont
, FALSE
, DELETE
, 0, NULL
,
2145 IoGetFileObjectGenericMapping(), Irp
->RequestorMode
, &access
, &Status
)) {
2146 SeReleaseSubjectContext(&subjcont
);
2147 WARN("SeAccessCheck failed, returning %08x\n", Status
);
2151 SeReleaseSubjectContext(&subjcont
);
2153 Status
= delete_fileref(oldfileref
, NULL
, &rollback
);
2154 if (!NT_SUCCESS(Status
)) {
2155 ERR("delete_fileref returned %08x\n", Status
);
2160 Status
= fcb_get_last_dir_index(related
->fcb
, &index
);
2161 if (!NT_SUCCESS(Status
)) {
2162 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
2166 fr2
= create_fileref();
2173 fr2
->created
= TRUE
;
2174 fr2
->parent
= related
;
2176 fr2
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fnus
.Length
, ALLOC_TAG
);
2177 if (!fr2
->filepart
.Buffer
) {
2178 ERR("out of memory\n");
2179 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2183 fr2
->filepart
.Length
= fr2
->filepart
.MaximumLength
= fnus
.Length
;
2184 RtlCopyMemory(fr2
->filepart
.Buffer
, fnus
.Buffer
, fnus
.Length
);
2186 Status
= RtlUpcaseUnicodeString(&fr2
->filepart_uc
, &fr2
->filepart
, TRUE
);
2187 if (!NT_SUCCESS(Status
)) {
2188 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
2192 insert_fileref_child(related
, fr2
, TRUE
);
2194 hl
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
2196 ERR("out of memory\n");
2197 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2201 hl
->parent
= related
->fcb
->inode
;
2204 hl
->name
.Length
= hl
->name
.MaximumLength
= fnus
.Length
;
2205 hl
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->name
.MaximumLength
, ALLOC_TAG
);
2207 if (!hl
->name
.Buffer
) {
2208 ERR("out of memory\n");
2210 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2214 RtlCopyMemory(hl
->name
.Buffer
, fnus
.Buffer
, fnus
.Length
);
2216 hl
->utf8
.Length
= hl
->utf8
.MaximumLength
= utf8
.Length
;
2217 hl
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->utf8
.MaximumLength
, ALLOC_TAG
);
2219 if (!hl
->utf8
.Buffer
) {
2220 ERR("out of memory\n");
2221 ExFreePool(hl
->name
.Buffer
);
2223 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2227 RtlCopyMemory(hl
->utf8
.Buffer
, utf8
.Buffer
, utf8
.Length
);
2229 InsertTailList(&fcb
->hardlinks
, &hl
->list_entry
);
2231 mark_fileref_dirty(fr2
);
2234 // update inode's INODE_ITEM
2236 KeQuerySystemTime(&time
);
2237 win_time_to_unix(time
, &now
);
2239 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
2240 fcb
->inode_item
.sequence
++;
2241 fcb
->inode_item
.st_nlink
++;
2242 fcb
->inode_item
.st_ctime
= now
;
2244 mark_fcb_dirty(fcb
);
2246 // update parent's INODE_ITEM
2248 parfcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
2249 TRACE("parfcb->inode_item.st_size (inode %llx) was %llx\n", parfcb
->inode
, parfcb
->inode_item
.st_size
);
2250 parfcb
->inode_item
.st_size
+= 2 * utf8len
;
2251 TRACE("parfcb->inode_item.st_size (inode %llx) now %llx\n", parfcb
->inode
, parfcb
->inode_item
.st_size
);
2252 parfcb
->inode_item
.sequence
++;
2253 parfcb
->inode_item
.st_ctime
= now
;
2255 mark_fcb_dirty(parfcb
);
2257 send_notification_fileref(fr2
, FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_ADDED
);
2259 Status
= STATUS_SUCCESS
;
2263 free_fileref(oldfileref
);
2265 if (!NT_SUCCESS(Status
) && related
)
2266 free_fileref(related
);
2268 if (!NT_SUCCESS(Status
) && fr2
)
2271 if (NT_SUCCESS(Status
))
2272 clear_rollback(&rollback
);
2274 do_rollback(Vcb
, &rollback
);
2276 ExReleaseResourceLite(fcb
->Header
.Resource
);
2277 ExReleaseResourceLite(&Vcb
->tree_lock
);
2282 NTSTATUS STDCALL
drv_set_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
2284 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2285 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
2286 fcb
* fcb
= IrpSp
->FileObject
->FsContext
;
2287 ccb
* ccb
= IrpSp
->FileObject
->FsContext2
;
2290 FsRtlEnterFileSystem();
2292 top_level
= is_top_level(Irp
);
2294 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
2295 Status
= part0_passthrough(DeviceObject
, Irp
);
2299 if (Vcb
->readonly
) {
2300 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2306 Status
= STATUS_INVALID_PARAMETER
;
2312 Status
= STATUS_INVALID_PARAMETER
;
2316 if (fcb
->subvol
->root_item
.flags
& BTRFS_SUBVOL_READONLY
) {
2317 Status
= STATUS_ACCESS_DENIED
;
2321 Irp
->IoStatus
.Information
= 0;
2323 Status
= STATUS_NOT_IMPLEMENTED
;
2325 TRACE("set information\n");
2327 switch (IrpSp
->Parameters
.SetFile
.FileInformationClass
) {
2328 case FileAllocationInformation
:
2330 TRACE("FileAllocationInformation\n");
2332 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_DATA
)) {
2333 WARN("insufficient privileges\n");
2334 Status
= STATUS_ACCESS_DENIED
;
2338 Status
= set_end_of_file_information(Vcb
, Irp
, IrpSp
->FileObject
, FALSE
);
2342 case FileBasicInformation
:
2344 TRACE("FileBasicInformation\n");
2346 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_ATTRIBUTES
)) {
2347 WARN("insufficient privileges\n");
2348 Status
= STATUS_ACCESS_DENIED
;
2352 Status
= set_basic_information(Vcb
, Irp
, IrpSp
->FileObject
);
2357 case FileDispositionInformation
:
2359 TRACE("FileDispositionInformation\n");
2361 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& DELETE
)) {
2362 WARN("insufficient privileges\n");
2363 Status
= STATUS_ACCESS_DENIED
;
2367 Status
= set_disposition_information(Vcb
, Irp
, IrpSp
->FileObject
);
2372 case FileEndOfFileInformation
:
2374 TRACE("FileEndOfFileInformation\n");
2376 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
))) {
2377 WARN("insufficient privileges\n");
2378 Status
= STATUS_ACCESS_DENIED
;
2382 Status
= set_end_of_file_information(Vcb
, Irp
, IrpSp
->FileObject
, IrpSp
->Parameters
.SetFile
.AdvanceOnly
);
2387 case FileLinkInformation
:
2388 TRACE("FileLinkInformation\n");
2389 Status
= set_link_information(Vcb
, Irp
, IrpSp
->FileObject
, IrpSp
->Parameters
.SetFile
.FileObject
);
2392 case FilePositionInformation
:
2394 TRACE("FilePositionInformation\n");
2396 if (Irp
->RequestorMode
== UserMode
&&
2397 (!(ccb
->access
& (FILE_READ_DATA
| FILE_WRITE_DATA
)) || !(ccb
->options
& (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
)))) {
2398 WARN("insufficient privileges\n");
2399 Status
= STATUS_ACCESS_DENIED
;
2403 Status
= set_position_information(Vcb
, Irp
, IrpSp
->FileObject
);
2408 case FileRenameInformation
:
2409 TRACE("FileRenameInformation\n");
2410 // FIXME - make this work with streams
2411 Status
= set_rename_information(Vcb
, Irp
, IrpSp
->FileObject
, IrpSp
->Parameters
.SetFile
.FileObject
, IrpSp
->Parameters
.SetFile
.ReplaceIfExists
);
2414 case FileValidDataLengthInformation
:
2415 FIXME("STUB: FileValidDataLengthInformation\n");
2418 #if (NTDDI_VERSION >= NTDDI_VISTA)
2419 case FileNormalizedNameInformation
:
2420 FIXME("STUB: FileNormalizedNameInformation\n");
2424 #if (NTDDI_VERSION >= NTDDI_WIN7)
2425 case FileStandardLinkInformation
:
2426 FIXME("STUB: FileStandardLinkInformation\n");
2429 case FileRemoteProtocolInformation
:
2430 TRACE("FileRemoteProtocolInformation\n");
2435 WARN("unknown FileInformationClass %u\n", IrpSp
->Parameters
.SetFile
.FileInformationClass
);
2439 Irp
->IoStatus
.Status
= Status
;
2441 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2445 IoSetTopLevelIrp(NULL
);
2447 FsRtlExitFileSystem();
2452 static NTSTATUS STDCALL
fill_in_file_basic_information(FILE_BASIC_INFORMATION
* fbi
, INODE_ITEM
* ii
, LONG
* length
, fcb
* fcb
, file_ref
* fileref
) {
2453 RtlZeroMemory(fbi
, sizeof(FILE_BASIC_INFORMATION
));
2455 *length
-= sizeof(FILE_BASIC_INFORMATION
);
2457 fbi
->CreationTime
.QuadPart
= unix_time_to_win(&ii
->otime
);
2458 fbi
->LastAccessTime
.QuadPart
= unix_time_to_win(&ii
->st_atime
);
2459 fbi
->LastWriteTime
.QuadPart
= unix_time_to_win(&ii
->st_mtime
);
2460 fbi
->ChangeTime
.QuadPart
= 0;
2463 if (!fileref
|| !fileref
->parent
) {
2464 ERR("no fileref for stream\n");
2465 return STATUS_INTERNAL_ERROR
;
2467 fbi
->FileAttributes
= fileref
->parent
->fcb
->atts
;
2469 fbi
->FileAttributes
= fcb
->atts
;
2471 return STATUS_SUCCESS
;
2474 static NTSTATUS STDCALL
fill_in_file_network_open_information(FILE_NETWORK_OPEN_INFORMATION
* fnoi
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2477 if (*length
< sizeof(FILE_NETWORK_OPEN_INFORMATION
)) {
2479 return STATUS_BUFFER_OVERFLOW
;
2482 RtlZeroMemory(fnoi
, sizeof(FILE_NETWORK_OPEN_INFORMATION
));
2484 *length
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
2487 if (!fileref
|| !fileref
->parent
) {
2488 ERR("no fileref for stream\n");
2489 return STATUS_INTERNAL_ERROR
;
2492 ii
= &fileref
->parent
->fcb
->inode_item
;
2494 ii
= &fcb
->inode_item
;
2496 fnoi
->CreationTime
.QuadPart
= unix_time_to_win(&ii
->otime
);
2497 fnoi
->LastAccessTime
.QuadPart
= unix_time_to_win(&ii
->st_atime
);
2498 fnoi
->LastWriteTime
.QuadPart
= unix_time_to_win(&ii
->st_mtime
);
2499 fnoi
->ChangeTime
.QuadPart
= 0;
2502 fnoi
->AllocationSize
.QuadPart
= fnoi
->EndOfFile
.QuadPart
= fcb
->adsdata
.Length
;
2503 fnoi
->FileAttributes
= fileref
->parent
->fcb
->atts
;
2505 fnoi
->AllocationSize
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : sector_align(fcb
->inode_item
.st_size
, fcb
->Vcb
->superblock
.sector_size
);
2506 fnoi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
2507 fnoi
->FileAttributes
= fcb
->atts
;
2510 return STATUS_SUCCESS
;
2513 static NTSTATUS STDCALL
fill_in_file_standard_information(FILE_STANDARD_INFORMATION
* fsi
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2514 RtlZeroMemory(fsi
, sizeof(FILE_STANDARD_INFORMATION
));
2516 *length
-= sizeof(FILE_STANDARD_INFORMATION
);
2519 if (!fileref
|| !fileref
->parent
) {
2520 ERR("no fileref for stream\n");
2521 return STATUS_INTERNAL_ERROR
;
2524 fsi
->AllocationSize
.QuadPart
= fsi
->EndOfFile
.QuadPart
= fcb
->adsdata
.Length
;
2525 fsi
->NumberOfLinks
= fileref
->parent
->fcb
->inode_item
.st_nlink
;
2526 fsi
->Directory
= S_ISDIR(fileref
->parent
->fcb
->inode_item
.st_mode
);
2528 fsi
->AllocationSize
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : sector_align(fcb
->inode_item
.st_size
, fcb
->Vcb
->superblock
.sector_size
);
2529 fsi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
2530 fsi
->NumberOfLinks
= fcb
->inode_item
.st_nlink
;
2531 fsi
->Directory
= S_ISDIR(fcb
->inode_item
.st_mode
);
2534 TRACE("length = %llu\n", fsi
->EndOfFile
.QuadPart
);
2536 fsi
->DeletePending
= fileref
? fileref
->delete_on_close
: FALSE
;
2538 return STATUS_SUCCESS
;
2541 static NTSTATUS STDCALL
fill_in_file_internal_information(FILE_INTERNAL_INFORMATION
* fii
, UINT64 inode
, LONG
* length
) {
2542 *length
-= sizeof(FILE_INTERNAL_INFORMATION
);
2544 fii
->IndexNumber
.QuadPart
= inode
;
2546 return STATUS_SUCCESS
;
2549 static NTSTATUS STDCALL
fill_in_file_ea_information(FILE_EA_INFORMATION
* eai
, LONG
* length
) {
2550 *length
-= sizeof(FILE_EA_INFORMATION
);
2552 // FIXME - should this be the reparse tag for symlinks?
2555 return STATUS_SUCCESS
;
2558 static NTSTATUS STDCALL
fill_in_file_access_information(FILE_ACCESS_INFORMATION
* fai
, LONG
* length
) {
2559 *length
-= sizeof(FILE_ACCESS_INFORMATION
);
2561 fai
->AccessFlags
= GENERIC_READ
;
2563 return STATUS_NOT_IMPLEMENTED
;
2566 static NTSTATUS STDCALL
fill_in_file_position_information(FILE_POSITION_INFORMATION
* fpi
, PFILE_OBJECT FileObject
, LONG
* length
) {
2567 RtlZeroMemory(fpi
, sizeof(FILE_POSITION_INFORMATION
));
2569 *length
-= sizeof(FILE_POSITION_INFORMATION
);
2571 fpi
->CurrentByteOffset
= FileObject
->CurrentByteOffset
;
2573 return STATUS_SUCCESS
;
2576 static NTSTATUS STDCALL
fill_in_file_mode_information(FILE_MODE_INFORMATION
* fmi
, ccb
* ccb
, LONG
* length
) {
2577 RtlZeroMemory(fmi
, sizeof(FILE_MODE_INFORMATION
));
2579 *length
-= sizeof(FILE_MODE_INFORMATION
);
2581 if (ccb
->options
& FILE_WRITE_THROUGH
)
2582 fmi
->Mode
|= FILE_WRITE_THROUGH
;
2584 if (ccb
->options
& FILE_SEQUENTIAL_ONLY
)
2585 fmi
->Mode
|= FILE_SEQUENTIAL_ONLY
;
2587 if (ccb
->options
& FILE_NO_INTERMEDIATE_BUFFERING
)
2588 fmi
->Mode
|= FILE_NO_INTERMEDIATE_BUFFERING
;
2590 if (ccb
->options
& FILE_SYNCHRONOUS_IO_ALERT
)
2591 fmi
->Mode
|= FILE_SYNCHRONOUS_IO_ALERT
;
2593 if (ccb
->options
& FILE_SYNCHRONOUS_IO_NONALERT
)
2594 fmi
->Mode
|= FILE_SYNCHRONOUS_IO_NONALERT
;
2596 if (ccb
->options
& FILE_DELETE_ON_CLOSE
)
2597 fmi
->Mode
|= FILE_DELETE_ON_CLOSE
;
2599 return STATUS_SUCCESS
;
2602 static NTSTATUS STDCALL
fill_in_file_alignment_information(FILE_ALIGNMENT_INFORMATION
* fai
, device_extension
* Vcb
, LONG
* length
) {
2603 RtlZeroMemory(fai
, sizeof(FILE_ALIGNMENT_INFORMATION
));
2605 *length
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
2607 fai
->AlignmentRequirement
= Vcb
->devices
[0].devobj
->AlignmentRequirement
;
2609 return STATUS_SUCCESS
;
2614 LIST_ENTRY list_entry
;
2617 NTSTATUS
fileref_get_filename(file_ref
* fileref
, PUNICODE_STRING fn
, USHORT
* name_offset
) {
2618 LIST_ENTRY fr_list
, *le
;
2623 // FIXME - we need a lock on filerefs' filepart
2625 if (fileref
== fileref
->fcb
->Vcb
->root_fileref
) {
2626 fn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(WCHAR
), ALLOC_TAG
);
2628 ERR("out of memory\n");
2629 return STATUS_INSUFFICIENT_RESOURCES
;
2632 fn
->Length
= fn
->MaximumLength
= sizeof(WCHAR
);
2633 fn
->Buffer
[0] = '\\';
2634 return STATUS_SUCCESS
;
2637 InitializeListHead(&fr_list
);
2645 frl
= ExAllocatePoolWithTag(PagedPool
, sizeof(fileref_list
), ALLOC_TAG
);
2647 ERR("out of memory\n");
2648 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2653 InsertTailList(&fr_list
, &frl
->list_entry
);
2655 len
+= fr
->filepart
.Length
;
2657 if (fr
!= fileref
->fcb
->Vcb
->root_fileref
)
2658 len
+= sizeof(WCHAR
);
2663 fn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, len
, ALLOC_TAG
);
2665 ERR("out of memory\n");
2666 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2670 fn
->Length
= fn
->MaximumLength
= len
;
2675 while (le
!= &fr_list
) {
2676 fileref_list
* frl
= CONTAINING_RECORD(le
, fileref_list
, list_entry
);
2678 if (frl
->fileref
!= fileref
->fcb
->Vcb
->root_fileref
) {
2679 fn
->Buffer
[i
] = frl
->fileref
->fcb
->ads
? ':' : '\\';
2682 if (name_offset
&& frl
->fileref
== fileref
)
2683 *name_offset
= i
* sizeof(WCHAR
);
2685 RtlCopyMemory(&fn
->Buffer
[i
], frl
->fileref
->filepart
.Buffer
, frl
->fileref
->filepart
.Length
);
2686 i
+= frl
->fileref
->filepart
.Length
/ sizeof(WCHAR
);
2692 Status
= STATUS_SUCCESS
;
2695 while (!IsListEmpty(&fr_list
)) {
2698 le
= RemoveHeadList(&fr_list
);
2699 frl
= CONTAINING_RECORD(le
, fileref_list
, list_entry
);
2707 static NTSTATUS STDCALL
fill_in_file_name_information(FILE_NAME_INFORMATION
* fni
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2713 static WCHAR datasuf
[] = {':','$','D','A','T','A',0};
2714 ULONG datasuflen
= wcslen(datasuf
) * sizeof(WCHAR
);
2717 ERR("called without fileref\n");
2718 return STATUS_INVALID_PARAMETER
;
2721 RtlZeroMemory(fni
, sizeof(FILE_NAME_INFORMATION
));
2723 *length
-= (LONG
)offsetof(FILE_NAME_INFORMATION
, FileName
[0]);
2725 TRACE("maximum length is %u\n", *length
);
2726 fni
->FileNameLength
= 0;
2728 fni
->FileName
[0] = 0;
2730 Status
= fileref_get_filename(fileref
, &fn
, NULL
);
2731 if (!NT_SUCCESS(Status
)) {
2732 ERR("fileref_get_filename returned %08x\n", Status
);
2736 if (*length
>= (LONG
)fn
.Length
) {
2737 RtlCopyMemory(fni
->FileName
, fn
.Buffer
, fn
.Length
);
2741 *length
-= fn
.Length
;
2744 RtlCopyMemory(fni
->FileName
, fn
.Buffer
, *length
);
2752 fni
->FileNameLength
= fn
.Length
;
2755 if (*length
>= (LONG
)datasuflen
) {
2756 RtlCopyMemory(&fni
->FileName
[fn
.Length
/ sizeof(WCHAR
)], datasuf
, datasuflen
);
2758 retlen
+= datasuflen
;
2760 *length
-= datasuflen
;
2763 RtlCopyMemory(&fni
->FileName
[fn
.Length
/ sizeof(WCHAR
)], datasuf
, *length
);
2772 ExFreePool(fn
.Buffer
);
2774 TRACE("%.*S\n", retlen
/ sizeof(WCHAR
), fni
->FileName
);
2776 return STATUS_SUCCESS
;
2779 static NTSTATUS STDCALL
fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATION
* ati
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2780 *length
-= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
);
2783 if (!fileref
|| !fileref
->parent
) {
2784 ERR("no fileref for stream\n");
2785 return STATUS_INTERNAL_ERROR
;
2788 ati
->FileAttributes
= fileref
->parent
->fcb
->atts
;
2790 ati
->FileAttributes
= fcb
->atts
;
2792 ati
->ReparseTag
= 0; // FIXME
2794 return STATUS_SUCCESS
;
2798 UNICODE_STRING name
;
2801 LIST_ENTRY list_entry
;
2804 static NTSTATUS STDCALL
fill_in_file_stream_information(FILE_STREAM_INFORMATION
* fsi
, file_ref
* fileref
, LONG
* length
) {
2806 LIST_ENTRY streamlist
, *le
;
2807 FILE_STREAM_INFORMATION
*entry
, *lastentry
;
2810 traverse_ptr tp
, next_tp
;
2814 static WCHAR datasuf
[] = {':','$','D','A','T','A',0};
2815 static char xapref
[] = "user.";
2819 ERR("fileref was NULL\n");
2820 return STATUS_INVALID_PARAMETER
;
2823 InitializeListHead(&streamlist
);
2825 ExAcquireResourceSharedLite(&fileref
->fcb
->Vcb
->tree_lock
, TRUE
);
2826 ExAcquireResourceSharedLite(fileref
->fcb
->Header
.Resource
, TRUE
);
2828 suf
.Buffer
= datasuf
;
2829 suf
.Length
= suf
.MaximumLength
= wcslen(datasuf
) * sizeof(WCHAR
);
2831 searchkey
.obj_id
= fileref
->fcb
->inode
;
2832 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
2833 searchkey
.offset
= 0;
2835 Status
= find_item(fileref
->fcb
->Vcb
, fileref
->fcb
->subvol
, &tp
, &searchkey
, FALSE
);
2836 if (!NT_SUCCESS(Status
)) {
2837 ERR("error - find_item returned %08x\n", Status
);
2841 si
= ExAllocatePoolWithTag(PagedPool
, sizeof(stream_info
), ALLOC_TAG
);
2843 ERR("out of memory\n");
2844 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2848 si
->name
.Length
= si
->name
.MaximumLength
= 0;
2849 si
->name
.Buffer
= NULL
;
2850 si
->size
= fileref
->fcb
->inode_item
.st_size
;
2853 InsertTailList(&streamlist
, &si
->list_entry
);
2856 if (tp
.item
->key
.obj_id
== fileref
->fcb
->inode
&& tp
.item
->key
.obj_type
== TYPE_XATTR_ITEM
) {
2857 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
2858 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(DIR_ITEM
));
2860 ULONG len
= tp
.item
->size
;
2861 DIR_ITEM
* xa
= (DIR_ITEM
*)tp
.item
->data
;
2865 if (len
< sizeof(DIR_ITEM
) || len
< sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
) {
2866 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2870 if (xa
->n
> strlen(xapref
) && RtlCompareMemory(xa
->name
, xapref
, strlen(xapref
)) == strlen(xapref
) &&
2871 (tp
.item
->key
.offset
!= EA_DOSATTRIB_HASH
|| xa
->n
!= strlen(EA_DOSATTRIB
) || RtlCompareMemory(xa
->name
, EA_DOSATTRIB
, xa
->n
) != xa
->n
)) {
2872 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &stringlen
, &xa
->name
[strlen(xapref
)], xa
->n
- strlen(xapref
));
2873 if (!NT_SUCCESS(Status
)) {
2874 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status
);
2878 si
= ExAllocatePoolWithTag(PagedPool
, sizeof(stream_info
), ALLOC_TAG
);
2880 ERR("out of memory\n");
2881 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2885 si
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, stringlen
, ALLOC_TAG
);
2886 if (!si
->name
.Buffer
) {
2887 ERR("out of memory\n");
2888 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2893 Status
= RtlUTF8ToUnicodeN(si
->name
.Buffer
, stringlen
, &stringlen
, &xa
->name
[strlen(xapref
)], xa
->n
- strlen(xapref
));
2895 if (!NT_SUCCESS(Status
)) {
2896 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status
);
2897 ExFreePool(si
->name
.Buffer
);
2902 si
->name
.Length
= si
->name
.MaximumLength
= stringlen
;
2908 TRACE("stream name = %.*S (length = %u)\n", si
->name
.Length
/ sizeof(WCHAR
), si
->name
.Buffer
, si
->name
.Length
/ sizeof(WCHAR
));
2910 InsertTailList(&streamlist
, &si
->list_entry
);
2913 len
-= sizeof(DIR_ITEM
) - sizeof(char) + xa
->n
+ xa
->m
;
2914 xa
= (DIR_ITEM
*)&xa
->name
[xa
->n
+ xa
->m
]; // FIXME - test xattr hash collisions work
2919 b
= find_next_item(fileref
->fcb
->Vcb
, &tp
, &next_tp
, FALSE
);
2923 if (next_tp
.item
->key
.obj_id
> fileref
->fcb
->inode
|| next_tp
.item
->key
.obj_type
> TYPE_XATTR_ITEM
)
2928 ExAcquireResourceSharedLite(&fileref
->nonpaged
->children_lock
, TRUE
);
2930 le
= fileref
->children
.Flink
;
2931 while (le
!= &fileref
->children
) {
2932 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
2934 if (fr
->fcb
&& fr
->fcb
->ads
) {
2935 LIST_ENTRY
* le2
= streamlist
.Flink
;
2938 while (le2
!= &streamlist
) {
2939 si
= CONTAINING_RECORD(le2
, stream_info
, list_entry
);
2941 if (si
&& si
->name
.Buffer
&& si
->name
.Length
== fr
->filepart
.Length
&&
2942 RtlCompareMemory(si
->name
.Buffer
, fr
->filepart
.Buffer
, si
->name
.Length
) == si
->name
.Length
) {
2944 si
->size
= fr
->fcb
->adsdata
.Length
;
2945 si
->ignore
= fr
->fcb
->deleted
;
2954 if (!found
&& !fr
->fcb
->deleted
) {
2955 si
= ExAllocatePoolWithTag(PagedPool
, sizeof(stream_info
), ALLOC_TAG
);
2957 ERR("out of memory\n");
2958 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2962 si
->name
.Length
= si
->name
.MaximumLength
= fr
->filepart
.Length
;
2964 si
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, si
->name
.MaximumLength
, ALLOC_TAG
);
2965 if (!si
->name
.Buffer
) {
2966 ERR("out of memory\n");
2967 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2972 RtlCopyMemory(si
->name
.Buffer
, fr
->filepart
.Buffer
, fr
->filepart
.Length
);
2974 si
->size
= fr
->fcb
->adsdata
.Length
;
2977 InsertTailList(&streamlist
, &si
->list_entry
);
2984 ExReleaseResourceLite(&fileref
->nonpaged
->children_lock
);
2988 le
= streamlist
.Flink
;
2989 while (le
!= &streamlist
) {
2990 si
= CONTAINING_RECORD(le
, stream_info
, list_entry
);
2993 reqsize
= sector_align(reqsize
, sizeof(LONGLONG
));
2994 reqsize
+= sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
) + suf
.Length
+ sizeof(WCHAR
) + si
->name
.Length
;
3000 TRACE("length = %i, reqsize = %u\n", *length
, reqsize
);
3002 if (reqsize
> *length
) {
3003 Status
= STATUS_BUFFER_OVERFLOW
;
3010 le
= streamlist
.Flink
;
3011 while (le
!= &streamlist
) {
3012 si
= CONTAINING_RECORD(le
, stream_info
, list_entry
);
3017 entry
->NextEntryOffset
= 0;
3018 entry
->StreamNameLength
= si
->name
.Length
+ suf
.Length
+ sizeof(WCHAR
);
3019 entry
->StreamSize
.QuadPart
= si
->size
;
3021 if (le
== streamlist
.Flink
)
3022 entry
->StreamAllocationSize
.QuadPart
= sector_align(fileref
->fcb
->inode_item
.st_size
, fileref
->fcb
->Vcb
->superblock
.sector_size
);
3024 entry
->StreamAllocationSize
.QuadPart
= si
->size
;
3026 entry
->StreamName
[0] = ':';
3028 if (si
->name
.Length
> 0)
3029 RtlCopyMemory(&entry
->StreamName
[1], si
->name
.Buffer
, si
->name
.Length
);
3031 RtlCopyMemory(&entry
->StreamName
[1 + (si
->name
.Length
/ sizeof(WCHAR
))], suf
.Buffer
, suf
.Length
);
3034 lastentry
->NextEntryOffset
= (UINT8
*)entry
- (UINT8
*)lastentry
;
3036 off
= sector_align(sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
) + suf
.Length
+ sizeof(WCHAR
) + si
->name
.Length
, sizeof(LONGLONG
));
3039 entry
= (FILE_STREAM_INFORMATION
*)((UINT8
*)entry
+ off
);
3047 Status
= STATUS_SUCCESS
;
3050 while (!IsListEmpty(&streamlist
)) {
3051 le
= RemoveHeadList(&streamlist
);
3052 si
= CONTAINING_RECORD(le
, stream_info
, list_entry
);
3054 if (si
->name
.Buffer
)
3055 ExFreePool(si
->name
.Buffer
);
3060 ExReleaseResourceLite(fileref
->fcb
->Header
.Resource
);
3061 ExReleaseResourceLite(&fileref
->fcb
->Vcb
->tree_lock
);
3067 static NTSTATUS STDCALL
fill_in_file_standard_link_information(FILE_STANDARD_LINK_INFORMATION
* fsli
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
3068 TRACE("FileStandardLinkInformation\n");
3070 // FIXME - NumberOfAccessibleLinks should subtract open links which have been marked as delete_on_close
3072 fsli
->NumberOfAccessibleLinks
= fcb
->inode_item
.st_nlink
;
3073 fsli
->TotalNumberOfLinks
= fcb
->inode_item
.st_nlink
;
3074 fsli
->DeletePending
= fileref
? fileref
->delete_on_close
: FALSE
;
3075 fsli
->Directory
= fcb
->type
== BTRFS_TYPE_DIRECTORY
? TRUE
: FALSE
;
3077 *length
-= sizeof(FILE_STANDARD_LINK_INFORMATION
);
3079 return STATUS_SUCCESS
;
3081 #endif /* __REACTOS__ */
3084 UNICODE_STRING name
;
3086 LIST_ENTRY list_entry
;
3089 static NTSTATUS
get_subvol_path(device_extension
* Vcb
, root
* subvol
) {
3095 UNICODE_STRING dirpath
;
3099 // FIXME - add subvol->parent field
3101 if (subvol
== Vcb
->root_fileref
->fcb
->subvol
) {
3102 subvol
->path
.Length
= subvol
->path
.MaximumLength
= sizeof(WCHAR
);
3103 subvol
->path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, subvol
->path
.Length
, ALLOC_TAG
);
3104 subvol
->path
.Buffer
[0] = '\\';
3105 return STATUS_SUCCESS
;
3108 searchkey
.obj_id
= subvol
->id
;
3109 searchkey
.obj_type
= TYPE_ROOT_BACKREF
;
3110 searchkey
.offset
= 0xffffffffffffffff;
3112 Status
= find_item(Vcb
, Vcb
->root_root
, &tp
, &searchkey
, FALSE
);
3113 if (!NT_SUCCESS(Status
)) {
3114 ERR("error - find_item returned %08x\n", Status
);
3118 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) { // top subvol
3119 subvol
->path
.Length
= subvol
->path
.MaximumLength
= sizeof(WCHAR
);
3120 subvol
->path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, subvol
->path
.Length
, ALLOC_TAG
);
3121 subvol
->path
.Buffer
[0] = '\\';
3122 return STATUS_SUCCESS
;
3125 if (tp
.item
->size
< sizeof(ROOT_REF
)) {
3126 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(ROOT_REF
));
3127 return STATUS_INTERNAL_ERROR
;
3130 rr
= (ROOT_REF
*)tp
.item
->data
;
3132 if (tp
.item
->size
< sizeof(ROOT_REF
) - 1 + rr
->n
) {
3133 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(ROOT_REF
) - 1 + rr
->n
);
3134 return STATUS_INTERNAL_ERROR
;
3137 le
= Vcb
->roots
.Flink
;
3141 while (le
!= &Vcb
->roots
) {
3142 root
* r2
= CONTAINING_RECORD(le
, root
, list_entry
);
3144 if (r2
->id
== tp
.item
->key
.offset
) {
3153 ERR("unable to find subvol %llx\n", tp
.item
->key
.offset
);
3154 return STATUS_INTERNAL_ERROR
;
3157 // FIXME - recursion
3159 Status
= get_inode_dir_path(Vcb
, parsubvol
, rr
->dir
, &dirpath
);
3160 if (!NT_SUCCESS(Status
)) {
3161 ERR("get_inode_dir_path returned %08x\n", Status
);
3165 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &namelen
, rr
->name
, rr
->n
);
3166 if (!NT_SUCCESS(Status
)) {
3167 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3172 ERR("length was 0\n");
3173 Status
= STATUS_INTERNAL_ERROR
;
3177 subvol
->path
.Length
= subvol
->path
.MaximumLength
= dirpath
.Length
+ namelen
;
3178 subvol
->path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, subvol
->path
.Length
, ALLOC_TAG
);
3180 if (!subvol
->path
.Buffer
) {
3181 ERR("out of memory\n");
3183 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3187 RtlCopyMemory(subvol
->path
.Buffer
, dirpath
.Buffer
, dirpath
.Length
);
3189 Status
= RtlUTF8ToUnicodeN(&subvol
->path
.Buffer
[dirpath
.Length
/ sizeof(WCHAR
)], namelen
, &namelen
, rr
->name
, rr
->n
);
3190 if (!NT_SUCCESS(Status
)) {
3191 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3195 Status
= STATUS_SUCCESS
;
3199 ExFreePool(dirpath
.Buffer
);
3201 if (!NT_SUCCESS(Status
) && subvol
->path
.Buffer
) {
3202 ExFreePool(subvol
->path
.Buffer
);
3203 subvol
->path
.Buffer
= NULL
;
3209 static NTSTATUS
get_inode_dir_path(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, PUNICODE_STRING us
) {
3214 LIST_ENTRY name_trail
, *le
;
3219 InitializeListHead(&name_trail
);
3223 // FIXME - start with subvol prefix
3224 if (!subvol
->path
.Buffer
) {
3225 Status
= get_subvol_path(Vcb
, subvol
);
3226 if (!NT_SUCCESS(Status
)) {
3227 ERR("get_subvol_path returned %08x\n", Status
);
3232 while (in
!= subvol
->root_item
.objid
) {
3233 searchkey
.obj_id
= in
;
3234 searchkey
.obj_type
= TYPE_INODE_EXTREF
;
3235 searchkey
.offset
= 0xffffffffffffffff;
3237 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
);
3238 if (!NT_SUCCESS(Status
)) {
3239 ERR("error - find_item returned %08x\n", Status
);
3243 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
) {
3244 ERR("could not find INODE_REF for inode %llx in subvol %llx\n", searchkey
.obj_id
, subvol
->id
);
3245 Status
= STATUS_INTERNAL_ERROR
;
3249 if (tp
.item
->key
.obj_type
== TYPE_INODE_REF
) {
3250 INODE_REF
* ir
= (INODE_REF
*)tp
.item
->data
;
3254 if (tp
.item
->size
< sizeof(INODE_REF
)) {
3255 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(INODE_REF
));
3256 Status
= STATUS_INTERNAL_ERROR
;
3260 if (tp
.item
->size
< sizeof(INODE_REF
) - 1 + ir
->n
) {
3261 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
, tp
.item
->size
, sizeof(INODE_REF
) - 1 + ir
->n
);
3262 Status
= STATUS_INTERNAL_ERROR
;
3266 nb
= ExAllocatePoolWithTag(PagedPool
, sizeof(name_bit
), ALLOC_TAG
);
3268 ERR("out of memory\n");
3269 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3273 nb
->name
.Buffer
= NULL
;
3275 InsertTailList(&name_trail
, &nb
->list_entry
);
3278 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &len
, ir
->name
, ir
->n
);
3279 if (!NT_SUCCESS(Status
)) {
3280 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3285 ERR("length was 0\n");
3286 Status
= STATUS_INTERNAL_ERROR
;
3290 nb
->name
.Length
= nb
->name
.MaximumLength
= len
;
3292 nb
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, nb
->name
.Length
, ALLOC_TAG
);
3293 if (!nb
->name
.Buffer
) {
3294 ERR("out of memory\n");
3296 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3300 Status
= RtlUTF8ToUnicodeN(nb
->name
.Buffer
, len
, &len
, ir
->name
, ir
->n
);
3301 if (!NT_SUCCESS(Status
)) {
3302 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3306 in
= tp
.item
->key
.offset
;
3307 namelen
+= nb
->name
.Length
;
3309 // } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
3312 ERR("could not find INODE_REF for inode %llx in subvol %llx\n", searchkey
.obj_id
, subvol
->id
);
3313 Status
= STATUS_INTERNAL_ERROR
;
3318 namelen
+= (levels
+ 1) * sizeof(WCHAR
);
3320 us
->Length
= us
->MaximumLength
= namelen
;
3321 us
->Buffer
= ExAllocatePoolWithTag(PagedPool
, us
->Length
, ALLOC_TAG
);
3324 ERR("out of memory\n");
3325 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3329 us
->Buffer
[0] = '\\';
3330 usbuf
= &us
->Buffer
[1];
3332 le
= name_trail
.Blink
;
3333 while (le
!= &name_trail
) {
3334 name_bit
* nb
= CONTAINING_RECORD(le
, name_bit
, list_entry
);
3336 RtlCopyMemory(usbuf
, nb
->name
.Buffer
, nb
->name
.Length
);
3337 usbuf
+= nb
->name
.Length
/ sizeof(WCHAR
);
3345 Status
= STATUS_SUCCESS
;
3348 while (!IsListEmpty(&name_trail
)) {
3349 name_bit
* nb
= CONTAINING_RECORD(name_trail
.Flink
, name_bit
, list_entry
);
3351 if (nb
->name
.Buffer
)
3352 ExFreePool(nb
->name
.Buffer
);
3354 RemoveEntryList(&nb
->list_entry
);
3362 NTSTATUS
open_fileref_by_inode(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, file_ref
** pfr
) {
3366 file_ref
*parfr
, *fr
;
3368 Status
= open_fcb(Vcb
, subvol
, inode
, 0, NULL
, NULL
, &fcb
);
3369 if (!NT_SUCCESS(Status
)) {
3370 ERR("open_fcb returned %08x\n", Status
);
3375 *pfr
= fcb
->fileref
;
3376 increase_fileref_refcount(fcb
->fileref
);
3377 return STATUS_SUCCESS
;
3380 if (IsListEmpty(&fcb
->hardlinks
)) {
3381 ERR("subvol %llx, inode %llx has no hardlinks\n", subvol
->id
, inode
);
3383 return STATUS_INTERNAL_ERROR
;
3386 hl
= CONTAINING_RECORD(fcb
->hardlinks
.Flink
, hardlink
, list_entry
);
3388 // FIXME - does this work with subvols?
3390 if (hl
->parent
== inode
) // root of subvol
3393 Status
= open_fileref_by_inode(Vcb
, subvol
, hl
->parent
, &parfr
);
3394 if (!NT_SUCCESS(Status
)) {
3395 ERR("open_fileref_by_inode returned %08x\n", Status
);
3401 fr
= create_fileref();
3403 ERR("out of memory\n");
3405 return STATUS_INSUFFICIENT_RESOURCES
;
3411 fr
->index
= hl
->index
;
3413 fr
->utf8
.Length
= fr
->utf8
.MaximumLength
= hl
->utf8
.Length
;
3414 if (fr
->utf8
.Length
> 0) {
3415 fr
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->utf8
.Length
, ALLOC_TAG
);
3417 if (!fr
->utf8
.Buffer
) {
3418 ERR("out of memory\n");
3420 return STATUS_INSUFFICIENT_RESOURCES
;
3423 RtlCopyMemory(fr
->utf8
.Buffer
, hl
->utf8
.Buffer
, hl
->utf8
.Length
);
3426 fr
->filepart
.MaximumLength
= fr
->filepart
.Length
= hl
->name
.Length
;
3428 if (fr
->filepart
.Length
> 0) {
3429 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->filepart
.MaximumLength
, ALLOC_TAG
);
3430 if (!fr
->filepart
.Buffer
) {
3431 ERR("out of memory\n");
3433 return STATUS_INSUFFICIENT_RESOURCES
;
3436 RtlCopyMemory(fr
->filepart
.Buffer
, hl
->name
.Buffer
, hl
->name
.Length
);
3439 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
3440 if (!NT_SUCCESS(Status
)) {
3441 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
3448 insert_fileref_child(parfr
, fr
, TRUE
);
3452 return STATUS_SUCCESS
;
3456 static NTSTATUS STDCALL
fill_in_hard_link_information(FILE_LINKS_INFORMATION
* fli
, file_ref
* fileref
, LONG
* length
) {
3460 FILE_LINK_ENTRY_INFORMATION
* feli
;
3461 BOOL overflow
= FALSE
;
3462 fcb
* fcb
= fileref
->fcb
;
3466 return STATUS_INVALID_PARAMETER
;
3468 if (*length
< offsetof(FILE_LINKS_INFORMATION
, Entry
))
3469 return STATUS_INVALID_PARAMETER
;
3471 RtlZeroMemory(fli
, *length
);
3473 bytes_needed
= offsetof(FILE_LINKS_INFORMATION
, Entry
);
3477 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, TRUE
);
3479 if (fcb
->inode
== SUBVOL_ROOT_INODE
) {
3482 if (fcb
== fcb
->Vcb
->root_fileref
->fcb
)
3483 namelen
= sizeof(WCHAR
);
3485 namelen
= fileref
->filepart
.Length
;
3487 bytes_needed
+= sizeof(FILE_LINK_ENTRY_INFORMATION
) - sizeof(WCHAR
) + namelen
;
3489 if (bytes_needed
> *length
)
3495 feli
->NextEntryOffset
= 0;
3496 feli
->ParentFileId
= 0; // we use an inode of 0 to mean the parent of a subvolume
3498 if (fcb
== fcb
->Vcb
->root_fileref
->fcb
) {
3499 feli
->FileNameLength
= 1;
3500 feli
->FileName
[0] = '.';
3502 feli
->FileNameLength
= fileref
->filepart
.Length
/ sizeof(WCHAR
);
3503 RtlCopyMemory(feli
->FileName
, fileref
->filepart
.Buffer
, fileref
->filepart
.Length
);
3506 fli
->EntriesReturned
++;
3511 ExAcquireResourceExclusiveLite(&fcb
->Vcb
->fcb_lock
, TRUE
);
3513 le
= fcb
->hardlinks
.Flink
;
3514 while (le
!= &fcb
->hardlinks
) {
3515 hardlink
* hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
);
3518 TRACE("parent %llx, index %llx, name %.*S\n", hl
->parent
, hl
->index
, hl
->name
.Length
/ sizeof(WCHAR
), hl
->name
.Buffer
);
3520 Status
= open_fileref_by_inode(fcb
->Vcb
, fcb
->subvol
, hl
->parent
, &parfr
);
3522 if (!NT_SUCCESS(Status
)) {
3523 ERR("open_fileref_by_inode returned %08x\n", Status
);
3524 } else if (!parfr
->deleted
) {
3526 BOOL found
= FALSE
, deleted
= FALSE
;
3529 le2
= parfr
->children
.Flink
;
3530 while (le2
!= &parfr
->children
) {
3531 file_ref
* fr2
= CONTAINING_RECORD(le2
, file_ref
, list_entry
);
3533 if (fr2
->index
== hl
->index
) {
3535 deleted
= fr2
->deleted
;
3538 fn
= &fr2
->filepart
;
3550 TRACE("fn = %.*S (found = %u)\n", fn
->Length
/ sizeof(WCHAR
), fn
->Buffer
, found
);
3553 bytes_needed
= sector_align(bytes_needed
, 8);
3555 bytes_needed
+= sizeof(FILE_LINK_ENTRY_INFORMATION
) + fn
->Length
- sizeof(WCHAR
);
3557 if (bytes_needed
> *length
)
3562 feli
->NextEntryOffset
= sector_align(sizeof(FILE_LINK_ENTRY_INFORMATION
) + ((feli
->FileNameLength
- 1) * sizeof(WCHAR
)), 8);
3563 feli
= (FILE_LINK_ENTRY_INFORMATION
*)((UINT8
*)feli
+ feli
->NextEntryOffset
);
3567 feli
->NextEntryOffset
= 0;
3568 feli
->ParentFileId
= parfr
->fcb
->inode
;
3569 feli
->FileNameLength
= fn
->Length
/ sizeof(WCHAR
);
3570 RtlCopyMemory(feli
->FileName
, fn
->Buffer
, fn
->Length
);
3572 fli
->EntriesReturned
++;
3578 free_fileref(parfr
);
3584 ExReleaseResourceLite(&fcb
->Vcb
->fcb_lock
);
3587 fli
->BytesNeeded
= bytes_needed
;
3591 Status
= overflow
? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
;
3593 ExReleaseResourceLite(fcb
->Header
.Resource
);
3597 #endif /* __REACTOS__ */
3599 #if (NTDDI_VERSION >= NTDDI_WIN10)
3601 typedef struct _FILE_ID_128
{
3602 UCHAR Identifier
[16];
3603 } FILE_ID_128
, *PFILE_ID_128
;
3605 typedef struct _FILE_ID_INFORMATION
{
3606 ULONGLONG VolumeSerialNumber
;
3608 } FILE_ID_INFORMATION
, *PFILE_ID_INFORMATION
;
3611 static NTSTATUS
fill_in_file_id_information(FILE_ID_INFORMATION
* fii
, fcb
* fcb
, LONG
* length
) {
3612 RtlCopyMemory(&fii
->VolumeSerialNumber
, &fcb
->Vcb
->superblock
.uuid
.uuid
[8], sizeof(UINT64
));
3613 RtlCopyMemory(&fii
->FileId
.Identifier
[0], &fcb
->inode
, sizeof(UINT64
));
3614 RtlCopyMemory(&fii
->FileId
.Identifier
[sizeof(UINT64
)], &fcb
->subvol
->id
, sizeof(UINT64
));
3616 *length
-= sizeof(FILE_ID_INFORMATION
);
3618 return STATUS_SUCCESS
;
3622 static NTSTATUS STDCALL
query_info(device_extension
* Vcb
, PFILE_OBJECT FileObject
, PIRP Irp
) {
3623 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3624 LONG length
= IrpSp
->Parameters
.QueryFile
.Length
;
3625 fcb
* fcb
= FileObject
->FsContext
;
3626 ccb
* ccb
= FileObject
->FsContext2
;
3627 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
3630 TRACE("(%p, %p, %p)\n", Vcb
, FileObject
, Irp
);
3631 TRACE("fcb = %p\n", fcb
);
3633 if (fcb
== Vcb
->volume_fcb
)
3634 return STATUS_INVALID_PARAMETER
;
3637 ERR("ccb is NULL\n");
3638 return STATUS_INVALID_PARAMETER
;
3641 switch (IrpSp
->Parameters
.QueryFile
.FileInformationClass
) {
3642 case FileAllInformation
:
3644 FILE_ALL_INFORMATION
* fai
= Irp
->AssociatedIrp
.SystemBuffer
;
3647 TRACE("FileAllInformation\n");
3649 if (!(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3650 WARN("insufficient privileges\n");
3651 Status
= STATUS_ACCESS_DENIED
;
3656 if (!fileref
|| !fileref
->parent
) {
3657 ERR("no fileref for stream\n");
3658 Status
= STATUS_INTERNAL_ERROR
;
3662 ii
= &fileref
->parent
->fcb
->inode_item
;
3664 ii
= &fcb
->inode_item
;
3667 fill_in_file_basic_information(&fai
->BasicInformation
, ii
, &length
, fcb
, fileref
);
3670 fill_in_file_standard_information(&fai
->StandardInformation
, fcb
, fileref
, &length
);
3673 fill_in_file_internal_information(&fai
->InternalInformation
, fcb
->inode
, &length
);
3676 fill_in_file_ea_information(&fai
->EaInformation
, &length
);
3679 fill_in_file_access_information(&fai
->AccessInformation
, &length
);
3682 fill_in_file_position_information(&fai
->PositionInformation
, FileObject
, &length
);
3685 fill_in_file_mode_information(&fai
->ModeInformation
, ccb
, &length
);
3688 fill_in_file_alignment_information(&fai
->AlignmentInformation
, Vcb
, &length
);
3691 fill_in_file_name_information(&fai
->NameInformation
, fcb
, fileref
, &length
);
3693 Status
= STATUS_SUCCESS
;
3698 case FileAttributeTagInformation
:
3700 FILE_ATTRIBUTE_TAG_INFORMATION
* ati
= Irp
->AssociatedIrp
.SystemBuffer
;
3702 TRACE("FileAttributeTagInformation\n");
3704 if (!(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3705 WARN("insufficient privileges\n");
3706 Status
= STATUS_ACCESS_DENIED
;
3710 Status
= fill_in_file_attribute_information(ati
, fcb
, fileref
, &length
);
3715 case FileBasicInformation
:
3717 FILE_BASIC_INFORMATION
* fbi
= Irp
->AssociatedIrp
.SystemBuffer
;
3720 TRACE("FileBasicInformation\n");
3722 if (!(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3723 WARN("insufficient privileges\n");
3724 Status
= STATUS_ACCESS_DENIED
;
3728 if (IrpSp
->Parameters
.QueryFile
.Length
< sizeof(FILE_BASIC_INFORMATION
)) {
3730 Status
= STATUS_BUFFER_OVERFLOW
;
3735 if (!fileref
|| !fileref
->parent
) {
3736 ERR("no fileref for stream\n");
3737 Status
= STATUS_INTERNAL_ERROR
;
3741 ii
= &fileref
->parent
->fcb
->inode_item
;
3743 ii
= &fcb
->inode_item
;
3745 Status
= fill_in_file_basic_information(fbi
, ii
, &length
, fcb
, fileref
);
3749 case FileCompressionInformation
:
3750 FIXME("STUB: FileCompressionInformation\n");
3751 Status
= STATUS_INVALID_PARAMETER
;
3754 case FileEaInformation
:
3756 FILE_EA_INFORMATION
* eai
= Irp
->AssociatedIrp
.SystemBuffer
;
3758 TRACE("FileEaInformation\n");
3760 Status
= fill_in_file_ea_information(eai
, &length
);
3765 case FileInternalInformation
:
3767 FILE_INTERNAL_INFORMATION
* fii
= Irp
->AssociatedIrp
.SystemBuffer
;
3769 TRACE("FileInternalInformation\n");
3771 Status
= fill_in_file_internal_information(fii
, fcb
->inode
, &length
);
3776 case FileNameInformation
:
3778 FILE_NAME_INFORMATION
* fni
= Irp
->AssociatedIrp
.SystemBuffer
;
3780 TRACE("FileNameInformation\n");
3782 Status
= fill_in_file_name_information(fni
, fcb
, fileref
, &length
);
3787 case FileNetworkOpenInformation
:
3789 FILE_NETWORK_OPEN_INFORMATION
* fnoi
= Irp
->AssociatedIrp
.SystemBuffer
;
3791 TRACE("FileNetworkOpenInformation\n");
3793 if (!(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3794 WARN("insufficient privileges\n");
3795 Status
= STATUS_ACCESS_DENIED
;
3799 Status
= fill_in_file_network_open_information(fnoi
, fcb
, fileref
, &length
);
3804 case FilePositionInformation
:
3806 FILE_POSITION_INFORMATION
* fpi
= Irp
->AssociatedIrp
.SystemBuffer
;
3808 TRACE("FilePositionInformation\n");
3810 if (!(ccb
->access
& (FILE_READ_DATA
| FILE_WRITE_DATA
)) || !(ccb
->options
& (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
))) {
3811 WARN("insufficient privileges\n");
3812 Status
= STATUS_ACCESS_DENIED
;
3816 Status
= fill_in_file_position_information(fpi
, FileObject
, &length
);
3821 case FileStandardInformation
:
3823 FILE_STANDARD_INFORMATION
* fsi
= Irp
->AssociatedIrp
.SystemBuffer
;
3825 TRACE("FileStandardInformation\n");
3827 if (IrpSp
->Parameters
.QueryFile
.Length
< sizeof(FILE_STANDARD_INFORMATION
)) {
3829 Status
= STATUS_BUFFER_OVERFLOW
;
3833 Status
= fill_in_file_standard_information(fsi
, fcb
, ccb
->fileref
, &length
);
3838 case FileStreamInformation
:
3840 FILE_STREAM_INFORMATION
* fsi
= Irp
->AssociatedIrp
.SystemBuffer
;
3842 TRACE("FileStreamInformation\n");
3844 Status
= fill_in_file_stream_information(fsi
, fileref
, &length
);
3849 #if (NTDDI_VERSION >= NTDDI_VISTA)
3850 case FileHardLinkInformation
:
3852 FILE_LINKS_INFORMATION
* fli
= Irp
->AssociatedIrp
.SystemBuffer
;
3854 TRACE("FileHardLinkInformation\n");
3856 Status
= fill_in_hard_link_information(fli
, fileref
, &length
);
3861 case FileNormalizedNameInformation
:
3863 FILE_NAME_INFORMATION
* fni
= Irp
->AssociatedIrp
.SystemBuffer
;
3865 TRACE("FileNormalizedNameInformation\n");
3867 Status
= fill_in_file_name_information(fni
, fcb
, fileref
, &length
);
3873 #if (NTDDI_VERSION >= NTDDI_WIN7)
3874 case FileStandardLinkInformation
:
3876 FILE_STANDARD_LINK_INFORMATION
* fsli
= Irp
->AssociatedIrp
.SystemBuffer
;
3878 TRACE("FileStandardLinkInformation\n");
3880 Status
= fill_in_file_standard_link_information(fsli
, fcb
, ccb
->fileref
, &length
);
3885 case FileRemoteProtocolInformation
:
3886 TRACE("FileRemoteProtocolInformation\n");
3887 Status
= STATUS_INVALID_PARAMETER
;
3891 #if (NTDDI_VERSION >= NTDDI_WIN10)
3892 #pragma GCC diagnostic push
3893 #pragma GCC diagnostic ignored "-Wswitch"
3894 case FileIdInformation
:
3896 FILE_ID_INFORMATION
* fii
= Irp
->AssociatedIrp
.SystemBuffer
;
3898 if (IrpSp
->Parameters
.QueryFile
.Length
< sizeof(FILE_ID_INFORMATION
)) {
3900 Status
= STATUS_BUFFER_OVERFLOW
;
3904 TRACE("FileIdInformation\n");
3906 Status
= fill_in_file_id_information(fii
, fcb
, &length
);
3910 #pragma GCC diagnostic pop
3914 WARN("unknown FileInformationClass %u\n", IrpSp
->Parameters
.QueryFile
.FileInformationClass
);
3915 Status
= STATUS_INVALID_PARAMETER
;
3921 Status
= STATUS_BUFFER_OVERFLOW
;
3924 Irp
->IoStatus
.Information
= IrpSp
->Parameters
.QueryFile
.Length
- length
;
3927 TRACE("query_info returning %08x\n", Status
);
3932 NTSTATUS STDCALL
drv_query_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3933 PIO_STACK_LOCATION IrpSp
;
3936 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
3939 FsRtlEnterFileSystem();
3941 top_level
= is_top_level(Irp
);
3943 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
3944 Status
= part0_passthrough(DeviceObject
, Irp
);
3948 Irp
->IoStatus
.Information
= 0;
3950 TRACE("query information\n");
3952 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3954 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
3956 fcb
= IrpSp
->FileObject
->FsContext
;
3957 TRACE("fcb = %p\n", fcb
);
3958 TRACE("fcb->subvol = %p\n", fcb
->subvol
);
3960 Status
= query_info(fcb
->Vcb
, IrpSp
->FileObject
, Irp
);
3962 TRACE("returning %08x\n", Status
);
3964 Irp
->IoStatus
.Status
= Status
;
3966 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
3968 ExReleaseResourceLite(&Vcb
->tree_lock
);
3972 IoSetTopLevelIrp(NULL
);
3974 FsRtlExitFileSystem();