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
, PIRP Irp
);
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
62 if (fbi
->CreationTime
.QuadPart
== -1)
63 ccb
->user_set_creation_time
= TRUE
;
64 else if (fbi
->CreationTime
.QuadPart
!= 0) {
65 win_time_to_unix(fbi
->CreationTime
, &fcb
->inode_item
.otime
);
66 inode_item_changed
= TRUE
;
67 filter
|= FILE_NOTIFY_CHANGE_CREATION
;
69 ccb
->user_set_creation_time
= TRUE
;
72 if (fbi
->LastAccessTime
.QuadPart
== -1)
73 ccb
->user_set_access_time
= TRUE
;
74 else if (fbi
->LastAccessTime
.QuadPart
!= 0) {
75 win_time_to_unix(fbi
->LastAccessTime
, &fcb
->inode_item
.st_atime
);
76 inode_item_changed
= TRUE
;
77 filter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
79 ccb
->user_set_access_time
= TRUE
;
82 if (fbi
->LastWriteTime
.QuadPart
== -1)
83 ccb
->user_set_write_time
= TRUE
;
84 else if (fbi
->LastWriteTime
.QuadPart
!= 0) {
85 win_time_to_unix(fbi
->LastWriteTime
, &fcb
->inode_item
.st_mtime
);
86 inode_item_changed
= TRUE
;
87 filter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
89 ccb
->user_set_write_time
= TRUE
;
92 if (fbi
->ChangeTime
.QuadPart
== -1)
93 ccb
->user_set_change_time
= TRUE
;
94 else if (fbi
->ChangeTime
.QuadPart
!= 0) {
95 win_time_to_unix(fbi
->ChangeTime
, &fcb
->inode_item
.st_ctime
);
96 inode_item_changed
= TRUE
;
99 ccb
->user_set_change_time
= TRUE
;
102 // FileAttributes == 0 means don't set - undocumented, but seen in fastfat
103 if (fbi
->FileAttributes
!= 0) {
107 defda
= get_file_attributes(Vcb
, &fcb
->inode_item
, fcb
->subvol
, fcb
->inode
, fcb
->type
, fileref
->filepart
.Length
> 0 && fileref
->filepart
.Buffer
[0] == '.', TRUE
, Irp
);
109 if (fcb
->type
== BTRFS_TYPE_DIRECTORY
)
110 fbi
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
111 else if (fcb
->type
== BTRFS_TYPE_SYMLINK
)
112 fbi
->FileAttributes
|= FILE_ATTRIBUTE_REPARSE_POINT
;
114 fcb
->atts_changed
= TRUE
;
116 if (fcb
->atts
& FILE_ATTRIBUTE_REPARSE_POINT
)
117 fbi
->FileAttributes
|= FILE_ATTRIBUTE_REPARSE_POINT
;
119 if (defda
== fbi
->FileAttributes
)
120 fcb
->atts_deleted
= TRUE
;
122 fcb
->atts
= fbi
->FileAttributes
;
124 KeQuerySystemTime(&time
);
125 win_time_to_unix(time
, &now
);
127 if (!ccb
->user_set_change_time
)
128 fcb
->inode_item
.st_ctime
= now
;
130 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
131 fcb
->subvol
->root_item
.ctime
= now
;
133 inode_item_changed
= TRUE
;
135 filter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
138 if (inode_item_changed
) {
139 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
140 fcb
->inode_item
.sequence
++;
141 fcb
->inode_item_changed
= TRUE
;
147 send_notification_fcb(fileref
, filter
, FILE_ACTION_MODIFIED
);
149 Status
= STATUS_SUCCESS
;
152 ExReleaseResourceLite(fcb
->Header
.Resource
);
157 static NTSTATUS STDCALL
set_disposition_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
) {
158 FILE_DISPOSITION_INFORMATION
* fdi
= Irp
->AssociatedIrp
.SystemBuffer
;
159 fcb
* fcb
= FileObject
->FsContext
;
160 ccb
* ccb
= FileObject
->FsContext2
;
161 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
166 return STATUS_INVALID_PARAMETER
;
168 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
170 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
172 TRACE("changing delete_on_close to %s for %S (fcb %p)\n", fdi
->DeleteFile
? "TRUE" : "FALSE", file_desc(FileObject
), fcb
);
176 atts
= fileref
->parent
->fcb
->atts
;
178 ERR("no fileref for stream\n");
179 Status
= STATUS_INTERNAL_ERROR
;
185 TRACE("atts = %x\n", atts
);
187 if (atts
& FILE_ATTRIBUTE_READONLY
) {
188 Status
= STATUS_CANNOT_DELETE
;
192 // FIXME - can we skip this bit for subvols?
193 if (fcb
->type
== BTRFS_TYPE_DIRECTORY
&& fcb
->inode_item
.st_size
> 0) {
194 Status
= STATUS_DIRECTORY_NOT_EMPTY
;
198 if (!MmFlushImageSection(&fcb
->nonpaged
->segment_object
, MmFlushForDelete
)) {
199 WARN("trying to delete file which is being mapped as an image\n");
200 Status
= STATUS_CANNOT_DELETE
;
204 ccb
->fileref
->delete_on_close
= fdi
->DeleteFile
;
206 FileObject
->DeletePending
= fdi
->DeleteFile
;
208 Status
= STATUS_SUCCESS
;
211 ExReleaseResourceLite(fcb
->Header
.Resource
);
213 ExReleaseResourceLite(&Vcb
->fcb_lock
);
218 BOOL
has_open_children(file_ref
* fileref
) {
219 LIST_ENTRY
* le
= fileref
->children
.Flink
;
221 if (IsListEmpty(&fileref
->children
))
224 while (le
!= &fileref
->children
) {
225 file_ref
* c
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
227 if (c
->open_count
> 0)
230 if (has_open_children(c
))
239 static NTSTATUS
duplicate_fcb(fcb
* oldfcb
, fcb
** pfcb
) {
240 device_extension
* Vcb
= oldfcb
->Vcb
;
244 // FIXME - we can skip a lot of this if the inode is about to be deleted
246 fcb
= create_fcb(PagedPool
); // FIXME - what if we duplicate the paging file?
248 ERR("out of memory\n");
249 return STATUS_INSUFFICIENT_RESOURCES
;
254 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
255 fcb
->Header
.AllocationSize
= oldfcb
->Header
.AllocationSize
;
256 fcb
->Header
.FileSize
= oldfcb
->Header
.FileSize
;
257 fcb
->Header
.ValidDataLength
= oldfcb
->Header
.ValidDataLength
;
259 fcb
->type
= oldfcb
->type
;
263 fcb
->adshash
= oldfcb
->adshash
;
264 fcb
->adsmaxlen
= oldfcb
->adsmaxlen
;
266 if (oldfcb
->adsxattr
.Buffer
&& oldfcb
->adsxattr
.Length
> 0) {
267 fcb
->adsxattr
.Length
= oldfcb
->adsxattr
.Length
;
268 fcb
->adsxattr
.MaximumLength
= fcb
->adsxattr
.Length
+ 1;
269 fcb
->adsxattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsxattr
.MaximumLength
, ALLOC_TAG
);
271 if (!fcb
->adsxattr
.Buffer
) {
272 ERR("out of memory\n");
274 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
276 ExReleaseResourceLite(&Vcb
->fcb_lock
);
278 return STATUS_INSUFFICIENT_RESOURCES
;
281 RtlCopyMemory(fcb
->adsxattr
.Buffer
, oldfcb
->adsxattr
.Buffer
, fcb
->adsxattr
.Length
);
282 fcb
->adsxattr
.Buffer
[fcb
->adsxattr
.Length
] = 0;
285 if (oldfcb
->adsdata
.Buffer
&& oldfcb
->adsdata
.Length
> 0) {
286 fcb
->adsdata
.Length
= fcb
->adsdata
.MaximumLength
= oldfcb
->adsdata
.Length
;
287 fcb
->adsdata
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->adsdata
.MaximumLength
, ALLOC_TAG
);
289 if (!fcb
->adsdata
.Buffer
) {
290 ERR("out of memory\n");
292 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
294 ExReleaseResourceLite(&Vcb
->fcb_lock
);
296 return STATUS_INSUFFICIENT_RESOURCES
;
299 RtlCopyMemory(fcb
->adsdata
.Buffer
, oldfcb
->adsdata
.Buffer
, fcb
->adsdata
.Length
);
305 RtlCopyMemory(&fcb
->inode_item
, &oldfcb
->inode_item
, sizeof(INODE_ITEM
));
306 fcb
->inode_item_changed
= TRUE
;
308 if (oldfcb
->sd
&& RtlLengthSecurityDescriptor(oldfcb
->sd
) > 0) {
309 fcb
->sd
= ExAllocatePoolWithTag(PagedPool
, RtlLengthSecurityDescriptor(oldfcb
->sd
), ALLOC_TAG
);
311 ERR("out of memory\n");
313 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
315 ExReleaseResourceLite(&Vcb
->fcb_lock
);
317 return STATUS_INSUFFICIENT_RESOURCES
;
320 RtlCopyMemory(fcb
->sd
, oldfcb
->sd
, RtlLengthSecurityDescriptor(oldfcb
->sd
));
323 fcb
->atts
= oldfcb
->atts
;
325 le
= oldfcb
->extents
.Flink
;
326 while (le
!= &oldfcb
->extents
) {
327 extent
* ext
= CONTAINING_RECORD(le
, extent
, list_entry
);
330 extent
* ext2
= ExAllocatePoolWithTag(PagedPool
, sizeof(extent
), ALLOC_TAG
);
333 ERR("out of memory\n");
335 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
337 ExReleaseResourceLite(&Vcb
->fcb_lock
);
339 return STATUS_INSUFFICIENT_RESOURCES
;
342 ext2
->offset
= ext
->offset
;
343 ext2
->datalen
= ext
->datalen
;
345 if (ext2
->datalen
> 0) {
346 ext2
->data
= ExAllocatePoolWithTag(PagedPool
, ext2
->datalen
, ALLOC_TAG
);
349 ERR("out of memory\n");
351 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
353 ExReleaseResourceLite(&Vcb
->fcb_lock
);
355 return STATUS_INSUFFICIENT_RESOURCES
;
358 RtlCopyMemory(ext2
->data
, ext
->data
, ext2
->datalen
);
362 ext2
->unique
= FALSE
;
363 ext2
->ignore
= FALSE
;
365 InsertTailList(&fcb
->extents
, &ext2
->list_entry
);
371 le
= oldfcb
->hardlinks
.Flink
;
372 while (le
!= &oldfcb
->hardlinks
) {
373 hardlink
*hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
), *hl2
;
375 hl2
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
378 ERR("out of memory\n");
380 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
382 ExReleaseResourceLite(&Vcb
->fcb_lock
);
384 return STATUS_INSUFFICIENT_RESOURCES
;
387 hl2
->parent
= hl
->parent
;
388 hl2
->index
= hl
->index
;
390 hl2
->name
.Length
= hl2
->name
.MaximumLength
= hl
->name
.Length
;
391 hl2
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl2
->name
.MaximumLength
, ALLOC_TAG
);
393 if (!hl2
->name
.Buffer
) {
394 ERR("out of memory\n");
397 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
399 ExReleaseResourceLite(&Vcb
->fcb_lock
);
401 return STATUS_INSUFFICIENT_RESOURCES
;
404 RtlCopyMemory(hl2
->name
.Buffer
, hl
->name
.Buffer
, hl
->name
.Length
);
406 hl2
->utf8
.Length
= hl2
->utf8
.MaximumLength
= hl
->utf8
.Length
;
407 hl2
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl2
->utf8
.MaximumLength
, ALLOC_TAG
);
409 if (!hl2
->utf8
.Buffer
) {
410 ERR("out of memory\n");
411 ExFreePool(hl2
->name
.Buffer
);
414 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
416 ExReleaseResourceLite(&Vcb
->fcb_lock
);
418 return STATUS_INSUFFICIENT_RESOURCES
;
421 RtlCopyMemory(hl2
->utf8
.Buffer
, hl
->utf8
.Buffer
, hl
->utf8
.Length
);
423 InsertTailList(&fcb
->hardlinks
, &hl2
->list_entry
);
428 fcb
->last_dir_index
= oldfcb
->last_dir_index
;
430 if (oldfcb
->reparse_xattr
.Buffer
&& oldfcb
->reparse_xattr
.Length
> 0) {
431 fcb
->reparse_xattr
.Length
= fcb
->reparse_xattr
.MaximumLength
= oldfcb
->reparse_xattr
.Length
;
433 fcb
->reparse_xattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->reparse_xattr
.MaximumLength
, ALLOC_TAG
);
434 if (!fcb
->reparse_xattr
.Buffer
) {
435 ERR("out of memory\n");
437 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
439 ExReleaseResourceLite(&Vcb
->fcb_lock
);
441 return STATUS_INSUFFICIENT_RESOURCES
;
444 RtlCopyMemory(fcb
->reparse_xattr
.Buffer
, oldfcb
->reparse_xattr
.Buffer
, fcb
->reparse_xattr
.Length
);
447 if (oldfcb
->ea_xattr
.Buffer
&& oldfcb
->ea_xattr
.Length
> 0) {
448 fcb
->ea_xattr
.Length
= fcb
->ea_xattr
.MaximumLength
= oldfcb
->ea_xattr
.Length
;
450 fcb
->ea_xattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fcb
->ea_xattr
.MaximumLength
, ALLOC_TAG
);
451 if (!fcb
->ea_xattr
.Buffer
) {
452 ERR("out of memory\n");
454 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
456 ExReleaseResourceLite(&Vcb
->fcb_lock
);
458 return STATUS_INSUFFICIENT_RESOURCES
;
461 RtlCopyMemory(fcb
->ea_xattr
.Buffer
, oldfcb
->ea_xattr
.Buffer
, fcb
->ea_xattr
.Length
);
467 return STATUS_SUCCESS
;
470 typedef struct _move_entry
{
473 file_ref
* dummyfileref
;
474 struct _move_entry
* parent
;
475 LIST_ENTRY list_entry
;
478 static NTSTATUS
add_children_to_move_list(move_entry
* me
, PIRP Irp
) {
486 static char xapref
[] = "user.";
487 ULONG xapreflen
= strlen(xapref
);
489 ExAcquireResourceSharedLite(&me
->fileref
->nonpaged
->children_lock
, TRUE
);
491 le
= me
->fileref
->children
.Flink
;
492 while (le
!= &me
->fileref
->children
) {
493 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
496 me2
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
498 ERR("out of memory\n");
499 Status
= STATUS_INSUFFICIENT_RESOURCES
;
505 increase_fileref_refcount(fr
);
507 me2
->dummyfcb
= NULL
;
508 me2
->dummyfileref
= NULL
;
511 InsertHeadList(&me
->list_entry
, &me2
->list_entry
);
517 searchkey
.obj_id
= me
->fileref
->fcb
->inode
;
518 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
519 searchkey
.offset
= 0;
521 Status
= find_item(me
->fileref
->fcb
->Vcb
, me
->fileref
->fcb
->subvol
, &tp
, &searchkey
, FALSE
, Irp
);
522 if (!NT_SUCCESS(Status
)) {
523 ERR("error - find_item returned %08x\n", Status
);
528 traverse_ptr next_tp
;
530 if (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
== searchkey
.obj_type
) {
531 DIR_ITEM
* xa
= (DIR_ITEM
*)tp
.item
->data
;
534 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
535 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
));
536 Status
= STATUS_INTERNAL_ERROR
;
543 if (len
< sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
) {
544 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
545 Status
= STATUS_INTERNAL_ERROR
;
549 if (xa
->n
> xapreflen
&& RtlCompareMemory(xa
->name
, xapref
, xapreflen
) == xapreflen
&&
550 (tp
.item
->key
.offset
!= EA_DOSATTRIB_HASH
|| xa
->n
!= strlen(EA_DOSATTRIB
) || RtlCompareMemory(xa
->name
, EA_DOSATTRIB
, xa
->n
) != xa
->n
) &&
551 (tp
.item
->key
.offset
!= EA_EA_HASH
|| xa
->n
!= strlen(EA_EA
) || RtlCompareMemory(xa
->name
, EA_EA
, xa
->n
) != xa
->n
)
555 le
= me
->fileref
->children
.Flink
;
557 while (le
!= &me
->fileref
->children
) {
558 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
560 if (fr
->fcb
->ads
&& fr
->fcb
->adshash
== tp
.item
->key
.offset
&& fr
->fcb
->adsxattr
.Length
== xa
->n
&&
561 RtlCompareMemory(fr
->fcb
->adsxattr
.Buffer
, xa
->name
, xa
->n
) == xa
->n
) {
575 xattr
.Length
= xa
->n
;
576 xattr
.MaximumLength
= xattr
.Length
+ 1;
577 xattr
.Buffer
= ExAllocatePoolWithTag(PagedPool
, xattr
.MaximumLength
, ALLOC_TAG
);
580 ERR("out of memory\n");
581 Status
= STATUS_INSUFFICIENT_RESOURCES
;
585 RtlCopyMemory(xattr
.Buffer
, xa
->name
, xa
->n
);
586 xattr
.Buffer
[xa
->n
] = 0;
588 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
589 Status
= open_fcb_stream(me
->fileref
->fcb
->Vcb
, me
->fileref
->fcb
->subvol
, me
->fileref
->fcb
->inode
, &xattr
,
590 tp
.item
->key
.offset
, me
->fileref
->fcb
, &fcb
, Irp
);
591 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
593 if (!NT_SUCCESS(Status
)) {
594 ERR("open_fcb_stream returned %08x\n", Status
);
595 ExFreePool(xattr
.Buffer
);
599 fr
= create_fileref();
601 ERR("out of memory\n");
603 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
605 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
607 Status
= STATUS_INSUFFICIENT_RESOURCES
;
613 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &stringlen
, &xa
->name
[xapreflen
], xa
->n
- xapreflen
);
614 if (!NT_SUCCESS(Status
)) {
615 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status
);
617 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
619 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
624 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, stringlen
, ALLOC_TAG
);
625 if (!fr
->filepart
.Buffer
) {
626 ERR("out of memory\n");
627 Status
= STATUS_INSUFFICIENT_RESOURCES
;
629 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
631 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
636 Status
= RtlUTF8ToUnicodeN(fr
->filepart
.Buffer
, stringlen
, &stringlen
, &xa
->name
[xapreflen
], xa
->n
- xapreflen
);
637 if (!NT_SUCCESS(Status
)) {
638 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status
);
640 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
642 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
647 fr
->filepart
.Length
= fr
->filepart
.MaximumLength
= stringlen
;
649 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
650 if (!NT_SUCCESS(Status
)) {
651 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
653 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
655 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
660 fr
->parent
= (struct _file_ref
*)me
->fileref
;
661 increase_fileref_refcount(fr
->parent
);
663 insert_fileref_child(me
->fileref
, fr
, FALSE
);
665 me2
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
667 ERR("out of memory\n");
668 Status
= STATUS_INSUFFICIENT_RESOURCES
;
670 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
672 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
678 me2
->dummyfcb
= NULL
;
679 me2
->dummyfileref
= NULL
;
682 InsertHeadList(&me
->list_entry
, &me2
->list_entry
);
686 len
-= sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
;
689 xa
= (DIR_ITEM
*)&xa
->name
[xa
->m
+ xa
->n
];
693 b
= find_next_item(me
->fileref
->fcb
->Vcb
, &tp
, &next_tp
, FALSE
, Irp
);
697 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
))
702 if (me
->fileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
&& me
->fileref
->fcb
->inode_item
.st_size
!= 0) {
703 searchkey
.obj_id
= me
->fileref
->fcb
->inode
;
704 searchkey
.obj_type
= TYPE_DIR_INDEX
;
705 searchkey
.offset
= 2;
707 Status
= find_item(me
->fileref
->fcb
->Vcb
, me
->fileref
->fcb
->subvol
, &tp
, &searchkey
, FALSE
, Irp
);
708 if (!NT_SUCCESS(Status
)) {
709 ERR("error - find_item returned %08x\n", Status
);
714 traverse_ptr next_tp
;
716 // FIXME - both lists are ordered; we can make this more efficient
718 if (tp
.item
->key
.obj_id
== searchkey
.obj_id
&& tp
.item
->key
.obj_type
== searchkey
.obj_type
) {
721 le
= me
->fileref
->children
.Flink
;
723 while (le
!= &me
->fileref
->children
) {
724 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
727 if (fr
->index
== tp
.item
->key
.offset
) {
730 } else if (fr
->index
> tp
.item
->key
.offset
)
738 DIR_ITEM
* di
= (DIR_ITEM
*)tp
.item
->data
;
740 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
741 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
));
742 Status
= STATUS_INTERNAL_ERROR
;
746 if (tp
.item
->size
< sizeof(DIR_ITEM
) - 1 + di
->m
+ di
->n
) {
747 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
);
748 Status
= STATUS_INTERNAL_ERROR
;
753 ERR("(%llx,%x,%llx): filename length was 0\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
754 Status
= STATUS_INTERNAL_ERROR
;
758 if (di
->key
.obj_type
== TYPE_INODE_ITEM
|| di
->key
.obj_type
== TYPE_ROOT_ITEM
) {
766 utf8
.Length
= utf8
.MaximumLength
= di
->n
;
767 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.MaximumLength
, ALLOC_TAG
);
769 ERR("out of memory\n");
770 Status
= STATUS_INSUFFICIENT_RESOURCES
;
774 RtlCopyMemory(utf8
.Buffer
, di
->name
, di
->n
);
776 if (di
->key
.obj_type
== TYPE_ROOT_ITEM
) {
781 le2
= me
->fileref
->fcb
->Vcb
->roots
.Flink
;
782 while (le2
!= &me
->fileref
->fcb
->Vcb
->roots
) {
783 root
* r2
= CONTAINING_RECORD(le2
, root
, list_entry
);
785 if (r2
->id
== di
->key
.obj_id
) {
794 ERR("could not find subvol %llx\n", di
->key
.obj_id
);
795 Status
= STATUS_INTERNAL_ERROR
;
799 inode
= SUBVOL_ROOT_INODE
;
801 subvol
= me
->fileref
->fcb
->subvol
;
802 inode
= di
->key
.obj_id
;
805 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
806 Status
= open_fcb(me
->fileref
->fcb
->Vcb
, subvol
, inode
, di
->type
, &utf8
, me
->fileref
->fcb
, &fcb
, PagedPool
, Irp
);
807 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
809 if (!NT_SUCCESS(Status
)) {
810 ERR("open_fcb returned %08x\n", Status
);
811 ExFreePool(utf8
.Buffer
);
815 fr
= create_fileref();
817 ERR("out of memory\n");
818 Status
= STATUS_INSUFFICIENT_RESOURCES
;
819 ExFreePool(utf8
.Buffer
);
821 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
823 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
831 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &stringlen
, utf8
.Buffer
, utf8
.Length
);
832 if (!NT_SUCCESS(Status
)) {
833 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status
);
835 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
837 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
842 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, stringlen
, ALLOC_TAG
);
843 if (!fr
->filepart
.Buffer
) {
844 ERR("out of memory\n");
845 Status
= STATUS_INSUFFICIENT_RESOURCES
;
847 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
849 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
854 Status
= RtlUTF8ToUnicodeN(fr
->filepart
.Buffer
, stringlen
, &stringlen
, utf8
.Buffer
, utf8
.Length
);
856 if (!NT_SUCCESS(Status
)) {
857 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status
);
859 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
861 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
866 fr
->filepart
.Length
= fr
->filepart
.MaximumLength
= stringlen
;
868 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
870 if (!NT_SUCCESS(Status
)) {
871 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
873 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
875 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
880 fr
->parent
= me
->fileref
;
882 fr
->index
= tp
.item
->key
.offset
;
883 increase_fileref_refcount(me
->fileref
);
885 insert_fileref_child(fr
->parent
, fr
, FALSE
);
887 if (fr
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
888 fr
->fcb
->fileref
= fr
;
890 me2
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
892 ERR("out of memory\n");
893 Status
= STATUS_INSUFFICIENT_RESOURCES
;
895 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
897 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
903 me2
->dummyfcb
= NULL
;
904 me2
->dummyfileref
= NULL
;
907 InsertHeadList(&me
->list_entry
, &me2
->list_entry
);
909 ERR("unrecognized key (%llx,%x,%llx)\n", di
->key
.obj_id
, di
->key
.obj_type
, di
->key
.offset
);
910 Status
= STATUS_INTERNAL_ERROR
;
916 b
= find_next_item(me
->fileref
->fcb
->Vcb
, &tp
, &next_tp
, FALSE
, Irp
);
920 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
))
926 Status
= STATUS_SUCCESS
;
929 ExReleaseResourceLite(&me
->fileref
->nonpaged
->children_lock
);
934 static NTSTATUS
move_across_subvols(file_ref
* fileref
, file_ref
* destdir
, PANSI_STRING utf8
, PUNICODE_STRING fnus
, PIRP Irp
, LIST_ENTRY
* rollback
) {
936 LIST_ENTRY move_list
, *le
;
940 file_ref
* origparent
;
942 InitializeListHead(&move_list
);
944 me
= ExAllocatePoolWithTag(PagedPool
, sizeof(move_entry
), ALLOC_TAG
);
947 ERR("out of memory\n");
948 Status
= STATUS_INSUFFICIENT_RESOURCES
;
952 origparent
= fileref
->parent
;
954 me
->fileref
= fileref
;
955 increase_fileref_refcount(me
->fileref
);
957 me
->dummyfileref
= NULL
;
960 InsertTailList(&move_list
, &me
->list_entry
);
962 le
= move_list
.Flink
;
963 while (le
!= &move_list
) {
964 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
966 ExAcquireResourceSharedLite(me
->fileref
->fcb
->Header
.Resource
, TRUE
);
968 if (!me
->fileref
->fcb
->ads
&& me
->fileref
->fcb
->subvol
== origparent
->fcb
->subvol
) {
969 Status
= add_children_to_move_list(me
, Irp
);
971 if (!NT_SUCCESS(Status
)) {
972 ERR("add_children_to_move_list returned %08x\n", Status
);
977 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
982 // loop through list and create new inodes
984 le
= move_list
.Flink
;
985 while (le
!= &move_list
) {
986 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
988 if (me
->fileref
->fcb
->inode
!= SUBVOL_ROOT_INODE
) {
992 ExAcquireResourceExclusiveLite(me
->fileref
->fcb
->Header
.Resource
, TRUE
);
994 Status
= duplicate_fcb(me
->fileref
->fcb
, &me
->dummyfcb
);
995 if (!NT_SUCCESS(Status
)) {
996 ERR("duplicate_fcb returned %08x\n", Status
);
997 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1001 me
->dummyfcb
->subvol
= me
->fileref
->fcb
->subvol
;
1002 me
->dummyfcb
->inode
= me
->fileref
->fcb
->inode
;
1004 if (!me
->dummyfcb
->ads
) {
1005 me
->dummyfcb
->sd_dirty
= me
->fileref
->fcb
->sd_dirty
;
1006 me
->dummyfcb
->atts_changed
= me
->fileref
->fcb
->atts_changed
;
1007 me
->dummyfcb
->atts_deleted
= me
->fileref
->fcb
->atts_deleted
;
1008 me
->dummyfcb
->extents_changed
= me
->fileref
->fcb
->extents_changed
;
1009 me
->dummyfcb
->reparse_xattr_changed
= me
->fileref
->fcb
->reparse_xattr_changed
;
1010 me
->dummyfcb
->ea_changed
= me
->fileref
->fcb
->ea_changed
;
1013 me
->dummyfcb
->created
= me
->fileref
->fcb
->created
;
1014 me
->dummyfcb
->deleted
= me
->fileref
->fcb
->deleted
;
1015 mark_fcb_dirty(me
->dummyfcb
);
1017 if (!me
->fileref
->fcb
->ads
) {
1020 me
->fileref
->fcb
->subvol
= destdir
->fcb
->subvol
;
1021 me
->fileref
->fcb
->inode
= InterlockedIncrement64(&destdir
->fcb
->subvol
->lastinode
);
1022 me
->fileref
->fcb
->inode_item
.st_nlink
= 1;
1024 defda
= get_file_attributes(me
->fileref
->fcb
->Vcb
, &me
->fileref
->fcb
->inode_item
, me
->fileref
->fcb
->subvol
, me
->fileref
->fcb
->inode
,
1025 me
->fileref
->fcb
->type
, me
->fileref
->filepart
.Length
> 0 && me
->fileref
->filepart
.Buffer
[0] == '.', TRUE
, Irp
);
1027 me
->fileref
->fcb
->sd_dirty
= !!me
->fileref
->fcb
->sd
;
1028 me
->fileref
->fcb
->atts_changed
= defda
!= me
->fileref
->fcb
->atts
;
1029 me
->fileref
->fcb
->extents_changed
= !IsListEmpty(&me
->fileref
->fcb
->extents
);
1030 me
->fileref
->fcb
->reparse_xattr_changed
= !!me
->fileref
->fcb
->reparse_xattr
.Buffer
;
1031 me
->fileref
->fcb
->ea_changed
= !!me
->fileref
->fcb
->ea_xattr
.Buffer
;
1032 me
->fileref
->fcb
->inode_item_changed
= TRUE
;
1034 le2
= me
->fileref
->fcb
->extents
.Flink
;
1035 while (le2
!= &me
->fileref
->fcb
->extents
) {
1036 extent
* ext
= CONTAINING_RECORD(le2
, extent
, list_entry
);
1038 if (!ext
->ignore
&& ext
->datalen
>= sizeof(EXTENT_DATA
) - 1 + sizeof(EXTENT_DATA2
) &&
1039 (ext
->data
->type
== EXTENT_TYPE_REGULAR
|| ext
->data
->type
== EXTENT_TYPE_PREALLOC
)) {
1040 EXTENT_DATA2
* ed2
= (EXTENT_DATA2
*)ext
->data
->data
;
1042 if (ed2
->size
!= 0) {
1043 chunk
* c
= get_chunk_from_address(me
->fileref
->fcb
->Vcb
, ed2
->address
);
1046 ERR("get_chunk_from_address(%llx) failed\n", ed2
->address
);
1048 Status
= update_changed_extent_ref(me
->fileref
->fcb
->Vcb
, c
, ed2
->address
, ed2
->size
, me
->fileref
->fcb
->subvol
->id
, me
->fileref
->fcb
->inode
,
1049 ext
->offset
- ed2
->offset
, 1, me
->fileref
->fcb
->inode_item
.flags
& BTRFS_INODE_NODATASUM
, FALSE
, Irp
);
1051 if (!NT_SUCCESS(Status
)) {
1052 ERR("update_changed_extent_ref returned %08x\n", Status
);
1053 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1064 me
->fileref
->fcb
->subvol
= me
->parent
->fileref
->fcb
->subvol
;
1065 me
->fileref
->fcb
->inode
= me
->parent
->fileref
->fcb
->inode
;
1068 me
->fileref
->fcb
->created
= TRUE
;
1070 InsertHeadList(&me
->fileref
->fcb
->list_entry
, &me
->dummyfcb
->list_entry
);
1071 RemoveEntryList(&me
->fileref
->fcb
->list_entry
);
1073 InsertTailList(&destdir
->fcb
->subvol
->fcbs
, &me
->fileref
->fcb
->list_entry
);
1075 InsertTailList(&me
->fileref
->fcb
->Vcb
->all_fcbs
, &me
->dummyfcb
->list_entry_all
);
1077 while (!IsListEmpty(&me
->fileref
->fcb
->hardlinks
)) {
1078 LIST_ENTRY
* le
= RemoveHeadList(&me
->fileref
->fcb
->hardlinks
);
1079 hardlink
* hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
);
1081 if (hl
->name
.Buffer
)
1082 ExFreePool(hl
->name
.Buffer
);
1084 if (hl
->utf8
.Buffer
)
1085 ExFreePool(hl
->utf8
.Buffer
);
1090 me
->fileref
->fcb
->inode_item_changed
= TRUE
;
1091 mark_fcb_dirty(me
->fileref
->fcb
);
1093 if ((!me
->dummyfcb
->ads
&& me
->dummyfcb
->inode_item
.st_nlink
> 1) || (me
->dummyfcb
->ads
&& me
->parent
->dummyfcb
->inode_item
.st_nlink
> 1)) {
1094 LIST_ENTRY
* le2
= le
->Flink
;
1096 while (le2
!= &move_list
) {
1097 move_entry
* me2
= CONTAINING_RECORD(le2
, move_entry
, list_entry
);
1099 if (me2
->fileref
->fcb
== me
->fileref
->fcb
&& !me2
->fileref
->fcb
->ads
) {
1100 me2
->dummyfcb
= me
->dummyfcb
;
1101 InterlockedIncrement(&me
->dummyfcb
->refcount
);
1108 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1110 ExAcquireResourceExclusiveLite(me
->fileref
->fcb
->Header
.Resource
, TRUE
);
1111 me
->fileref
->fcb
->inode_item
.st_nlink
++;
1112 me
->fileref
->fcb
->inode_item_changed
= TRUE
;
1113 ExReleaseResourceLite(me
->fileref
->fcb
->Header
.Resource
);
1120 KeQuerySystemTime(&time
);
1121 win_time_to_unix(time
, &now
);
1123 fileref
->fcb
->subvol
->root_item
.ctransid
= fileref
->fcb
->Vcb
->superblock
.generation
;
1124 fileref
->fcb
->subvol
->root_item
.ctime
= now
;
1126 // loop through list and create new filerefs
1128 le
= move_list
.Flink
;
1129 while (le
!= &move_list
) {
1132 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1134 me
->dummyfileref
= create_fileref();
1135 if (!me
->dummyfileref
) {
1136 ERR("out of memory\n");
1137 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1141 if (me
->fileref
->fcb
->inode
== SUBVOL_ROOT_INODE
)
1142 me
->dummyfileref
->fcb
= me
->fileref
->fcb
;
1144 me
->dummyfileref
->fcb
= me
->dummyfcb
;
1146 InterlockedIncrement(&me
->dummyfileref
->fcb
->refcount
);
1148 me
->dummyfileref
->filepart
= me
->fileref
->filepart
;
1150 if (le
== move_list
.Flink
) // first item
1151 me
->fileref
->filepart
.Length
= me
->fileref
->filepart
.MaximumLength
= fnus
->Length
;
1153 me
->fileref
->filepart
.MaximumLength
= me
->fileref
->filepart
.MaximumLength
;
1155 me
->fileref
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, me
->fileref
->filepart
.MaximumLength
, ALLOC_TAG
);
1157 if (!me
->fileref
->filepart
.Buffer
) {
1158 ERR("out of memory\n");
1159 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1163 RtlCopyMemory(me
->fileref
->filepart
.Buffer
, le
== move_list
.Flink
? fnus
->Buffer
: me
->dummyfileref
->filepart
.Buffer
, me
->fileref
->filepart
.Length
);
1165 Status
= RtlUpcaseUnicodeString(&me
->fileref
->filepart_uc
, &me
->fileref
->filepart
, TRUE
);
1166 if (!NT_SUCCESS(Status
)) {
1167 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1171 me
->dummyfileref
->utf8
= me
->fileref
->utf8
;
1172 me
->dummyfileref
->oldutf8
= me
->fileref
->oldutf8
;
1174 if (le
== move_list
.Flink
)
1175 me
->fileref
->utf8
.Length
= me
->fileref
->utf8
.MaximumLength
= utf8
->Length
;
1177 me
->fileref
->utf8
.MaximumLength
= me
->fileref
->utf8
.Length
;
1179 if (me
->fileref
->utf8
.MaximumLength
> 0) {
1180 me
->fileref
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, me
->fileref
->utf8
.MaximumLength
, ALLOC_TAG
);
1182 if (!me
->fileref
->utf8
.Buffer
) {
1183 ERR("out of memory\n");
1184 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1188 RtlCopyMemory(me
->fileref
->utf8
.Buffer
, le
== move_list
.Flink
? utf8
->Buffer
: me
->dummyfileref
->utf8
.Buffer
, me
->fileref
->utf8
.Length
);
1191 me
->dummyfileref
->delete_on_close
= me
->fileref
->delete_on_close
;
1192 me
->dummyfileref
->deleted
= me
->fileref
->deleted
;
1194 me
->dummyfileref
->created
= me
->fileref
->created
;
1195 me
->fileref
->created
= TRUE
;
1197 me
->dummyfileref
->parent
= me
->parent
? me
->parent
->dummyfileref
: origparent
;
1198 increase_fileref_refcount(me
->dummyfileref
->parent
);
1200 me
->dummyfileref
->index
= me
->fileref
->index
;
1202 insert_fileref_child(me
->dummyfileref
->parent
, me
->dummyfileref
, TRUE
);
1204 me
->dummyfileref
->debug_desc
= me
->fileref
->debug_desc
;
1206 if (me
->dummyfileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
1207 me
->dummyfileref
->fcb
->fileref
= me
->dummyfileref
;
1210 RemoveEntryList(&me
->fileref
->list_entry
);
1212 ExAcquireResourceExclusiveLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
, TRUE
);
1213 free_fileref(me
->fileref
->parent
);
1214 ExReleaseResourceLite(&me
->fileref
->fcb
->Vcb
->fcb_lock
);
1216 me
->fileref
->parent
= destdir
;
1218 increase_fileref_refcount(destdir
);
1220 Status
= fcb_get_last_dir_index(me
->fileref
->parent
->fcb
, &me
->fileref
->index
, Irp
);
1221 if (!NT_SUCCESS(Status
)) {
1222 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
1226 insert_fileref_child(me
->fileref
->parent
, me
->fileref
, TRUE
);
1228 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
);
1229 me
->fileref
->parent
->fcb
->inode_item
.st_size
+= me
->fileref
->utf8
.Length
* 2;
1230 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
);
1231 me
->fileref
->parent
->fcb
->inode_item
.transid
= me
->fileref
->fcb
->Vcb
->superblock
.generation
;
1232 me
->fileref
->parent
->fcb
->inode_item
.sequence
++;
1233 me
->fileref
->parent
->fcb
->inode_item
.st_ctime
= now
;
1234 me
->fileref
->parent
->fcb
->inode_item
.st_mtime
= now
;
1235 me
->fileref
->parent
->fcb
->inode_item_changed
= TRUE
;
1236 mark_fcb_dirty(me
->fileref
->parent
->fcb
);
1239 if (me
->fileref
->fcb
->inode
== SUBVOL_ROOT_INODE
)
1240 me
->fileref
->fcb
->subvol
->root_item
.num_references
++;
1242 if (!me
->dummyfileref
->fcb
->ads
) {
1243 Status
= delete_fileref(me
->dummyfileref
, NULL
, Irp
, rollback
);
1244 if (!NT_SUCCESS(Status
)) {
1245 ERR("delete_fileref returned %08x\n", Status
);
1250 hl
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
1252 ERR("out of memory\n");
1253 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1257 hl
->parent
= me
->fileref
->parent
->fcb
->inode
;
1258 hl
->index
= me
->fileref
->index
;
1260 hl
->utf8
.Length
= hl
->utf8
.MaximumLength
= me
->fileref
->utf8
.Length
;
1261 hl
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->utf8
.MaximumLength
, ALLOC_TAG
);
1262 if (!hl
->utf8
.Buffer
) {
1263 ERR("out of memory\n");
1264 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1269 RtlCopyMemory(hl
->utf8
.Buffer
, me
->fileref
->utf8
.Buffer
, me
->fileref
->utf8
.Length
);
1271 hl
->name
.Length
= hl
->name
.MaximumLength
= me
->fileref
->filepart
.Length
;
1272 hl
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->name
.MaximumLength
, ALLOC_TAG
);
1273 if (!hl
->name
.Buffer
) {
1274 ERR("out of memory\n");
1275 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1276 ExFreePool(hl
->utf8
.Buffer
);
1281 RtlCopyMemory(hl
->name
.Buffer
, me
->fileref
->filepart
.Buffer
, me
->fileref
->filepart
.Length
);
1283 InsertTailList(&me
->fileref
->fcb
->hardlinks
, &hl
->list_entry
);
1285 mark_fileref_dirty(me
->fileref
);
1290 // loop through, and only mark streams as deleted if their parent inodes are also deleted
1292 le
= move_list
.Flink
;
1293 while (le
!= &move_list
) {
1294 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1296 if (me
->dummyfileref
->fcb
->ads
&& me
->parent
->dummyfileref
->fcb
->deleted
) {
1297 Status
= delete_fileref(me
->dummyfileref
, NULL
, Irp
, rollback
);
1298 if (!NT_SUCCESS(Status
)) {
1299 ERR("delete_fileref returned %08x\n", Status
);
1307 destdir
->fcb
->subvol
->root_item
.ctransid
= destdir
->fcb
->Vcb
->superblock
.generation
;
1308 destdir
->fcb
->subvol
->root_item
.ctime
= now
;
1310 me
= CONTAINING_RECORD(move_list
.Flink
, move_entry
, list_entry
);
1311 send_notification_fileref(me
->dummyfileref
, fileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_REMOVED
);
1312 send_notification_fileref(fileref
, fileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_ADDED
);
1313 send_notification_fileref(me
->dummyfileref
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1314 send_notification_fileref(fileref
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1316 Status
= STATUS_SUCCESS
;
1319 while (!IsListEmpty(&move_list
)) {
1320 device_extension
* Vcb
;
1322 le
= RemoveHeadList(&move_list
);
1323 me
= CONTAINING_RECORD(le
, move_entry
, list_entry
);
1324 Vcb
= me
->fileref
->fcb
->Vcb
;
1327 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1328 free_fcb(me
->dummyfcb
);
1329 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1332 if (me
->dummyfileref
) {
1333 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1334 free_fileref(me
->dummyfileref
);
1335 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1338 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1339 free_fileref(me
->fileref
);
1340 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1348 static NTSTATUS STDCALL
set_rename_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
, PFILE_OBJECT tfo
) {
1349 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1350 FILE_RENAME_INFORMATION
* fri
= Irp
->AssociatedIrp
.SystemBuffer
;
1351 fcb
*fcb
= FileObject
->FsContext
;
1352 ccb
* ccb
= FileObject
->FsContext2
;
1353 file_ref
*fileref
= ccb
? ccb
->fileref
: NULL
, *oldfileref
= NULL
, *related
= NULL
, *fr2
= NULL
;
1356 ULONG fnlen
, utf8len
;
1357 UNICODE_STRING fnus
;
1362 LIST_ENTRY rollback
, *le
;
1365 InitializeListHead(&rollback
);
1367 TRACE("tfo = %p\n", tfo
);
1368 TRACE("ReplaceIfExists = %u\n", IrpSp
->Parameters
.SetFile
.ReplaceIfExists
);
1369 TRACE("RootDirectory = %p\n", fri
->RootDirectory
);
1370 TRACE("FileName = %.*S\n", fri
->FileNameLength
/ sizeof(WCHAR
), fri
->FileName
);
1373 fnlen
= fri
->FileNameLength
/ sizeof(WCHAR
);
1376 if (!fileref
|| !fileref
->parent
) {
1377 ERR("no fileref set and no directory given\n");
1378 return STATUS_INVALID_PARAMETER
;
1383 while (fnlen
> 0 && (fri
->FileName
[fnlen
- 1] == '/' || fri
->FileName
[fnlen
- 1] == '\\'))
1387 return STATUS_INVALID_PARAMETER
;
1389 for (i
= fnlen
- 1; i
>= 0; i
--) {
1390 if (fri
->FileName
[i
] == '\\' || fri
->FileName
[i
] == '/') {
1391 fn
= &fri
->FileName
[i
+1];
1392 fnlen
= (fri
->FileNameLength
/ sizeof(WCHAR
)) - i
- 1;
1398 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1399 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1402 FIXME("FIXME - renaming streams\n"); // FIXME
1403 Status
= STATUS_NOT_IMPLEMENTED
;
1408 fnus
.Length
= fnus
.MaximumLength
= fnlen
* sizeof(WCHAR
);
1410 TRACE("fnus = %.*S\n", fnus
.Length
/ sizeof(WCHAR
), fnus
.Buffer
);
1412 Status
= RtlUnicodeToUTF8N(NULL
, 0, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
1413 if (!NT_SUCCESS(Status
))
1416 utf8
.MaximumLength
= utf8
.Length
= utf8len
;
1417 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.MaximumLength
, ALLOC_TAG
);
1419 ERR("out of memory\n");
1420 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1424 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, utf8len
, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
1425 if (!NT_SUCCESS(Status
))
1428 if (tfo
&& tfo
->FsContext2
) {
1429 struct _ccb
* relatedccb
= tfo
->FsContext2
;
1431 related
= relatedccb
->fileref
;
1432 increase_fileref_refcount(related
);
1433 } else if (fnus
.Length
>= sizeof(WCHAR
) && fnus
.Buffer
[0] != '\\') {
1434 related
= fileref
->parent
;
1435 increase_fileref_refcount(related
);
1438 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1439 Status
= open_fileref(Vcb
, &oldfileref
, &fnus
, related
, FALSE
, NULL
, NULL
, PagedPool
, ccb
->case_sensitive
, Irp
);
1440 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1442 if (NT_SUCCESS(Status
)) {
1443 TRACE("destination file %S already exists\n", file_desc_fileref(oldfileref
));
1445 if (fileref
!= oldfileref
&& !oldfileref
->deleted
) {
1446 if (!IrpSp
->Parameters
.SetFile
.ReplaceIfExists
) {
1447 Status
= STATUS_OBJECT_NAME_COLLISION
;
1449 } else if ((oldfileref
->open_count
>= 1 || has_open_children(oldfileref
)) && !oldfileref
->deleted
) {
1450 WARN("trying to overwrite open file\n");
1451 Status
= STATUS_ACCESS_DENIED
;
1455 if (oldfileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
) {
1456 WARN("trying to overwrite directory\n");
1457 Status
= STATUS_ACCESS_DENIED
;
1462 if (fileref
== oldfileref
|| oldfileref
->deleted
) {
1463 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1464 free_fileref(oldfileref
);
1465 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1471 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1472 Status
= open_fileref(Vcb
, &related
, &fnus
, NULL
, TRUE
, NULL
, NULL
, PagedPool
, ccb
->case_sensitive
, Irp
);
1473 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1475 if (!NT_SUCCESS(Status
)) {
1476 ERR("open_fileref returned %08x\n", Status
);
1481 if (has_open_children(fileref
)) {
1482 WARN("trying to rename file with open children\n");
1483 Status
= STATUS_ACCESS_DENIED
;
1489 SECURITY_SUBJECT_CONTEXT subjcont
;
1491 SeCaptureSubjectContext(&subjcont
);
1493 if (!SeAccessCheck(oldfileref
->fcb
->sd
, &subjcont
, FALSE
, DELETE
, 0, NULL
,
1494 IoGetFileObjectGenericMapping(), Irp
->RequestorMode
, &access
, &Status
)) {
1495 SeReleaseSubjectContext(&subjcont
);
1496 WARN("SeAccessCheck failed, returning %08x\n", Status
);
1500 SeReleaseSubjectContext(&subjcont
);
1502 Status
= delete_fileref(oldfileref
, NULL
, Irp
, &rollback
);
1503 if (!NT_SUCCESS(Status
)) {
1504 ERR("delete_fileref returned %08x\n", Status
);
1509 if (fileref
->parent
->fcb
->subvol
!= related
->fcb
->subvol
&& fileref
->fcb
->subvol
== fileref
->parent
->fcb
->subvol
) {
1510 Status
= move_across_subvols(fileref
, related
, &utf8
, &fnus
, Irp
, &rollback
);
1511 if (!NT_SUCCESS(Status
)) {
1512 ERR("move_across_subvols returned %08x\n", Status
);
1517 if (related
== fileref
->parent
) { // keeping file in same directory
1518 UNICODE_STRING fnus2
, oldfn
, newfn
;
1522 fnus2
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fnus
.Length
, ALLOC_TAG
);
1523 if (!fnus2
.Buffer
) {
1524 ERR("out of memory\n");
1525 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1529 Status
= fileref_get_filename(fileref
, &oldfn
, &name_offset
);
1530 if (!NT_SUCCESS(Status
)) {
1531 ERR("fileref_get_filename returned %08x\n", Status
);
1535 fnus2
.Length
= fnus2
.MaximumLength
= fnus
.Length
;
1536 RtlCopyMemory(fnus2
.Buffer
, fnus
.Buffer
, fnus
.Length
);
1538 oldutf8len
= fileref
->utf8
.Length
;
1540 if (!fileref
->created
&& !fileref
->oldutf8
.Buffer
)
1541 fileref
->oldutf8
= fileref
->utf8
;
1543 ExFreePool(fileref
->utf8
.Buffer
);
1545 TRACE("renaming %.*S to %.*S\n", fileref
->filepart
.Length
/ sizeof(WCHAR
), fileref
->filepart
.Buffer
, fnus2
.Length
/ sizeof(WCHAR
), fnus
.Buffer
);
1547 fileref
->utf8
= utf8
;
1548 fileref
->filepart
= fnus2
;
1550 Status
= fileref_get_filename(fileref
, &newfn
, &name_offset
);
1551 if (!NT_SUCCESS(Status
)) {
1552 ERR("fileref_get_filename returned %08x\n", Status
);
1553 ExFreePool(oldfn
.Buffer
);
1557 if (fileref
->filepart_uc
.Buffer
)
1558 ExFreePool(fileref
->filepart_uc
.Buffer
);
1560 Status
= RtlUpcaseUnicodeString(&fileref
->filepart_uc
, &fileref
->filepart
, TRUE
);
1561 if (!NT_SUCCESS(Status
)) {
1562 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1563 ExFreePool(oldfn
.Buffer
);
1564 ExFreePool(newfn
.Buffer
);
1568 mark_fileref_dirty(fileref
);
1570 KeQuerySystemTime(&time
);
1571 win_time_to_unix(time
, &now
);
1573 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1574 fcb
->inode_item
.sequence
++;
1576 if (!ccb
->user_set_change_time
)
1577 fcb
->inode_item
.st_ctime
= now
;
1579 fcb
->inode_item_changed
= TRUE
;
1580 mark_fcb_dirty(fcb
);
1582 // update parent's INODE_ITEM
1584 related
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1585 TRACE("related->fcb->inode_item.st_size (inode %llx) was %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1586 related
->fcb
->inode_item
.st_size
= related
->fcb
->inode_item
.st_size
+ (2 * utf8
.Length
) - (2* oldutf8len
);
1587 TRACE("related->fcb->inode_item.st_size (inode %llx) now %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1588 related
->fcb
->inode_item
.sequence
++;
1589 related
->fcb
->inode_item
.st_ctime
= now
;
1590 related
->fcb
->inode_item
.st_mtime
= now
;
1592 related
->fcb
->inode_item_changed
= TRUE
;
1593 mark_fcb_dirty(related
->fcb
);
1594 send_notification_fileref(related
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1596 FsRtlNotifyFilterReportChange(fcb
->Vcb
->NotifySync
, &fcb
->Vcb
->DirNotifyList
, (PSTRING
)&oldfn
, name_offset
, NULL
, NULL
,
1597 fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_RENAMED_OLD_NAME
, NULL
, NULL
);
1598 FsRtlNotifyFilterReportChange(fcb
->Vcb
->NotifySync
, &fcb
->Vcb
->DirNotifyList
, (PSTRING
)&newfn
, name_offset
, NULL
, NULL
,
1599 fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_RENAMED_NEW_NAME
, NULL
, NULL
);
1601 ExFreePool(oldfn
.Buffer
);
1602 ExFreePool(newfn
.Buffer
);
1604 Status
= STATUS_SUCCESS
;
1608 // We move files by moving the existing fileref to the new directory, and
1609 // replacing it with a dummy fileref with the same original values, but marked as deleted.
1611 fr2
= create_fileref();
1613 fr2
->fcb
= fileref
->fcb
;
1614 fr2
->fcb
->refcount
++;
1616 fr2
->filepart
= fileref
->filepart
;
1617 fr2
->filepart_uc
= fileref
->filepart_uc
;
1618 fr2
->utf8
= fileref
->utf8
;
1619 fr2
->oldutf8
= fileref
->oldutf8
;
1620 fr2
->index
= fileref
->index
;
1621 fr2
->delete_on_close
= fileref
->delete_on_close
;
1622 fr2
->deleted
= TRUE
;
1623 fr2
->created
= fileref
->created
;
1624 fr2
->parent
= fileref
->parent
;
1626 if (fr2
->fcb
->type
== BTRFS_TYPE_DIRECTORY
)
1627 fr2
->fcb
->fileref
= fr2
;
1629 Status
= fcb_get_last_dir_index(related
->fcb
, &index
, Irp
);
1630 if (!NT_SUCCESS(Status
)) {
1631 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
1635 fileref
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fnus
.Length
, ALLOC_TAG
);
1636 if (!fileref
->filepart
.Buffer
) {
1637 ERR("out of memory\n");
1638 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1642 fileref
->filepart
.Length
= fileref
->filepart
.MaximumLength
= fnus
.Length
;
1643 RtlCopyMemory(fileref
->filepart
.Buffer
, fnus
.Buffer
, fnus
.Length
);
1645 Status
= RtlUpcaseUnicodeString(&fileref
->filepart_uc
, &fileref
->filepart
, TRUE
);
1646 if (!NT_SUCCESS(Status
)) {
1647 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
1651 fileref
->utf8
= utf8
;
1652 fileref
->oldutf8
.Buffer
= NULL
;
1653 fileref
->index
= index
;
1654 fileref
->deleted
= FALSE
;
1655 fileref
->created
= TRUE
;
1656 fileref
->parent
= related
;
1658 ExAcquireResourceExclusiveLite(&fileref
->parent
->nonpaged
->children_lock
, TRUE
);
1659 InsertHeadList(&fileref
->list_entry
, &fr2
->list_entry
);
1660 RemoveEntryList(&fileref
->list_entry
);
1661 ExReleaseResourceLite(&fileref
->parent
->nonpaged
->children_lock
);
1663 insert_fileref_child(related
, fileref
, TRUE
);
1665 mark_fileref_dirty(fr2
);
1666 mark_fileref_dirty(fileref
);
1668 // add new hardlink entry to fcb
1670 hl
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
1672 ERR("out of memory\n");
1673 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1677 hl
->parent
= related
->fcb
->inode
;
1680 hl
->name
.Length
= hl
->name
.MaximumLength
= fileref
->filepart
.Length
;
1681 hl
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->name
.MaximumLength
, ALLOC_TAG
);
1683 if (!hl
->name
.Buffer
) {
1684 ERR("out of memory\n");
1686 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1690 RtlCopyMemory(hl
->name
.Buffer
, fileref
->filepart
.Buffer
, fileref
->filepart
.Length
);
1692 hl
->utf8
.Length
= hl
->utf8
.MaximumLength
= fileref
->utf8
.Length
;
1693 hl
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->utf8
.MaximumLength
, ALLOC_TAG
);
1695 if (!hl
->utf8
.Buffer
) {
1696 ERR("out of memory\n");
1697 ExFreePool(hl
->name
.Buffer
);
1699 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1703 RtlCopyMemory(hl
->utf8
.Buffer
, fileref
->utf8
.Buffer
, fileref
->utf8
.Length
);
1705 InsertTailList(&fcb
->hardlinks
, &hl
->list_entry
);
1707 // delete old hardlink entry from fcb
1709 le
= fcb
->hardlinks
.Flink
;
1710 while (le
!= &fcb
->hardlinks
) {
1711 hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
);
1713 if (hl
->parent
== fr2
->parent
->fcb
->inode
&& hl
->index
== fr2
->index
) {
1714 RemoveEntryList(&hl
->list_entry
);
1716 if (hl
->utf8
.Buffer
)
1717 ExFreePool(hl
->utf8
.Buffer
);
1719 if (hl
->name
.Buffer
)
1720 ExFreePool(hl
->name
.Buffer
);
1729 // update inode's INODE_ITEM
1731 KeQuerySystemTime(&time
);
1732 win_time_to_unix(time
, &now
);
1734 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1735 fcb
->inode_item
.sequence
++;
1737 if (!ccb
->user_set_change_time
)
1738 fcb
->inode_item
.st_ctime
= now
;
1740 fcb
->inode_item_changed
= TRUE
;
1741 mark_fcb_dirty(fcb
);
1743 // update new parent's INODE_ITEM
1745 related
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1746 TRACE("related->fcb->inode_item.st_size (inode %llx) was %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1747 related
->fcb
->inode_item
.st_size
+= 2 * utf8len
;
1748 TRACE("related->fcb->inode_item.st_size (inode %llx) now %llx\n", related
->fcb
->inode
, related
->fcb
->inode_item
.st_size
);
1749 related
->fcb
->inode_item
.sequence
++;
1750 related
->fcb
->inode_item
.st_ctime
= now
;
1751 related
->fcb
->inode_item
.st_mtime
= now
;
1753 related
->fcb
->inode_item_changed
= TRUE
;
1754 mark_fcb_dirty(related
->fcb
);
1756 // update old parent's INODE_ITEM
1758 fr2
->parent
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1759 TRACE("fr2->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fr2
->parent
->fcb
->inode
, fr2
->parent
->fcb
->inode_item
.st_size
);
1760 fr2
->parent
->fcb
->inode_item
.st_size
-= 2 * fr2
->utf8
.Length
;
1761 TRACE("fr2->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fr2
->parent
->fcb
->inode
, fr2
->parent
->fcb
->inode_item
.st_size
);
1762 fr2
->parent
->fcb
->inode_item
.sequence
++;
1763 fr2
->parent
->fcb
->inode_item
.st_ctime
= now
;
1764 fr2
->parent
->fcb
->inode_item
.st_mtime
= now
;
1766 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1768 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1770 fr2
->parent
->fcb
->inode_item_changed
= TRUE
;
1771 mark_fcb_dirty(fr2
->parent
->fcb
);
1773 send_notification_fileref(fr2
, fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_REMOVED
);
1774 send_notification_fileref(fileref
, fcb
->type
== BTRFS_TYPE_DIRECTORY
? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_ADDED
);
1775 send_notification_fileref(related
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1776 send_notification_fileref(fr2
->parent
, FILE_NOTIFY_CHANGE_LAST_WRITE
, FILE_ACTION_MODIFIED
);
1778 Status
= STATUS_SUCCESS
;
1782 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1783 free_fileref(oldfileref
);
1784 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1787 if (!NT_SUCCESS(Status
) && related
) {
1788 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1789 free_fileref(related
);
1790 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1793 if (!NT_SUCCESS(Status
) && fr2
) {
1794 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
1796 ExReleaseResourceLite(&Vcb
->fcb_lock
);
1799 if (NT_SUCCESS(Status
))
1800 clear_rollback(Vcb
, &rollback
);
1802 do_rollback(Vcb
, &rollback
);
1804 ExReleaseResourceLite(fcb
->Header
.Resource
);
1805 ExReleaseResourceLite(&Vcb
->tree_lock
);
1810 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
) {
1815 TRACE("setting new end to %llx bytes (currently %x)\n", end
, fcb
->adsdata
.Length
);
1817 if (!fileref
|| !fileref
->parent
) {
1818 ERR("no fileref for stream\n");
1819 return STATUS_INTERNAL_ERROR
;
1822 if (end
< fcb
->adsdata
.Length
) {
1824 return STATUS_SUCCESS
;
1826 TRACE("truncating stream to %llx bytes\n", end
);
1828 fcb
->adsdata
.Length
= end
;
1829 } else if (end
> fcb
->adsdata
.Length
) {
1830 TRACE("extending stream to %llx bytes\n", end
);
1832 if (end
> fcb
->adsmaxlen
) {
1833 ERR("error - xattr too long (%llu > %u)\n", end
, fcb
->adsmaxlen
);
1834 return STATUS_DISK_FULL
;
1837 if (end
> fcb
->adsdata
.MaximumLength
) {
1838 char* data
= ExAllocatePoolWithTag(PagedPool
, end
, ALLOC_TAG
);
1840 ERR("out of memory\n");
1842 return STATUS_INSUFFICIENT_RESOURCES
;
1845 if (fcb
->adsdata
.Buffer
) {
1846 RtlCopyMemory(data
, fcb
->adsdata
.Buffer
, fcb
->adsdata
.Length
);
1847 ExFreePool(fcb
->adsdata
.Buffer
);
1850 fcb
->adsdata
.Buffer
= data
;
1851 fcb
->adsdata
.MaximumLength
= end
;
1854 RtlZeroMemory(&fcb
->adsdata
.Buffer
[fcb
->adsdata
.Length
], end
- fcb
->adsdata
.Length
);
1856 fcb
->adsdata
.Length
= end
;
1859 mark_fcb_dirty(fcb
);
1861 fcb
->Header
.AllocationSize
.QuadPart
= end
;
1862 fcb
->Header
.FileSize
.QuadPart
= end
;
1863 fcb
->Header
.ValidDataLength
.QuadPart
= end
;
1866 ccfs
.AllocationSize
= fcb
->Header
.AllocationSize
;
1867 ccfs
.FileSize
= fcb
->Header
.FileSize
;
1868 ccfs
.ValidDataLength
= fcb
->Header
.ValidDataLength
;
1870 CcSetFileSizes(FileObject
, &ccfs
);
1873 KeQuerySystemTime(&time
);
1874 win_time_to_unix(time
, &now
);
1876 fileref
->parent
->fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
1877 fileref
->parent
->fcb
->inode_item
.sequence
++;
1878 fileref
->parent
->fcb
->inode_item
.st_ctime
= now
;
1880 fileref
->parent
->fcb
->inode_item_changed
= TRUE
;
1881 mark_fcb_dirty(fileref
->parent
->fcb
);
1883 fileref
->parent
->fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
1884 fileref
->parent
->fcb
->subvol
->root_item
.ctime
= now
;
1886 return STATUS_SUCCESS
;
1889 static NTSTATUS STDCALL
set_end_of_file_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
, BOOL advance_only
) {
1890 FILE_END_OF_FILE_INFORMATION
* feofi
= Irp
->AssociatedIrp
.SystemBuffer
;
1891 fcb
* fcb
= FileObject
->FsContext
;
1892 ccb
* ccb
= FileObject
->FsContext2
;
1893 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
1897 LIST_ENTRY rollback
;
1900 ERR("fileref is NULL\n");
1901 return STATUS_INVALID_PARAMETER
;
1904 InitializeListHead(&rollback
);
1906 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
1908 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
1910 if (fileref
? fileref
->deleted
: fcb
->deleted
) {
1911 Status
= STATUS_FILE_CLOSED
;
1916 Status
= stream_set_end_of_file_information(Vcb
, feofi
->EndOfFile
.QuadPart
, fcb
, fileref
, FileObject
, advance_only
, &rollback
);
1920 TRACE("file: %S\n", file_desc(FileObject
));
1921 TRACE("paging IO: %s\n", Irp
->Flags
& IRP_PAGING_IO
? "TRUE" : "FALSE");
1922 TRACE("FileObject: AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx\n",
1923 fcb
->Header
.AllocationSize
.QuadPart
, fcb
->Header
.FileSize
.QuadPart
, fcb
->Header
.ValidDataLength
.QuadPart
);
1926 TRACE("setting new end to %llx bytes (currently %llx)\n", feofi
->EndOfFile
.QuadPart
, fcb
->inode_item
.st_size
);
1928 // if (feofi->EndOfFile.QuadPart==0x36c000)
1931 if (feofi
->EndOfFile
.QuadPart
< fcb
->inode_item
.st_size
) {
1933 Status
= STATUS_SUCCESS
;
1937 TRACE("truncating file to %llx bytes\n", feofi
->EndOfFile
.QuadPart
);
1939 Status
= truncate_file(fcb
, feofi
->EndOfFile
.QuadPart
, Irp
, &rollback
);
1940 if (!NT_SUCCESS(Status
)) {
1941 ERR("error - truncate_file failed\n");
1944 } else if (feofi
->EndOfFile
.QuadPart
> fcb
->inode_item
.st_size
) {
1945 if (Irp
->Flags
& IRP_PAGING_IO
) {
1946 TRACE("paging IO tried to extend file size\n");
1947 Status
= STATUS_SUCCESS
;
1951 TRACE("extending file to %llx bytes\n", feofi
->EndOfFile
.QuadPart
);
1953 Status
= extend_file(fcb
, fileref
, feofi
->EndOfFile
.QuadPart
, TRUE
, NULL
, &rollback
);
1954 if (!NT_SUCCESS(Status
)) {
1955 ERR("error - extend_file failed\n");
1960 ccfs
.AllocationSize
= fcb
->Header
.AllocationSize
;
1961 ccfs
.FileSize
= fcb
->Header
.FileSize
;
1962 ccfs
.ValidDataLength
= fcb
->Header
.ValidDataLength
;
1964 CcSetFileSizes(FileObject
, &ccfs
);
1965 TRACE("setting FileSize for %S to %llx\n", file_desc(FileObject
), ccfs
.FileSize
);
1967 if (!ccb
->user_set_write_time
) {
1968 KeQuerySystemTime(&time
);
1969 win_time_to_unix(time
, &fcb
->inode_item
.st_mtime
);
1972 fcb
->inode_item_changed
= TRUE
;
1973 mark_fcb_dirty(fcb
);
1974 send_notification_fcb(fileref
, FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_SIZE
, FILE_ACTION_MODIFIED
);
1976 Status
= STATUS_SUCCESS
;
1979 if (NT_SUCCESS(Status
))
1980 clear_rollback(Vcb
, &rollback
);
1982 do_rollback(Vcb
, &rollback
);
1984 ExReleaseResourceLite(fcb
->Header
.Resource
);
1986 ExReleaseResourceLite(&Vcb
->tree_lock
);
1991 // static NTSTATUS STDCALL set_allocation_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject) {
1992 // FILE_ALLOCATION_INFORMATION* fai = (FILE_ALLOCATION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
1993 // fcb* fcb = FileObject->FsContext;
1995 // FIXME("FIXME\n");
1996 // ERR("fcb = %p (%.*S)\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
1997 // ERR("AllocationSize = %llx\n", fai->AllocationSize.QuadPart);
1999 // return STATUS_NOT_IMPLEMENTED;
2002 static NTSTATUS STDCALL
set_position_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
) {
2003 FILE_POSITION_INFORMATION
* fpi
= (FILE_POSITION_INFORMATION
*)Irp
->AssociatedIrp
.SystemBuffer
;
2005 TRACE("setting the position on %S to %llx\n", file_desc(FileObject
), fpi
->CurrentByteOffset
.QuadPart
);
2007 // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
2009 FileObject
->CurrentByteOffset
= fpi
->CurrentByteOffset
;
2011 return STATUS_SUCCESS
;
2014 static NTSTATUS STDCALL
set_link_information(device_extension
* Vcb
, PIRP Irp
, PFILE_OBJECT FileObject
, PFILE_OBJECT tfo
) {
2015 FILE_LINK_INFORMATION
* fli
= Irp
->AssociatedIrp
.SystemBuffer
;
2016 fcb
*fcb
= FileObject
->FsContext
, *tfofcb
, *parfcb
;
2017 ccb
* ccb
= FileObject
->FsContext2
;
2018 file_ref
*fileref
= ccb
? ccb
->fileref
: NULL
, *oldfileref
= NULL
, *related
= NULL
, *fr2
= NULL
;
2021 ULONG fnlen
, utf8len
;
2022 UNICODE_STRING fnus
;
2027 LIST_ENTRY rollback
;
2030 SECURITY_SUBJECT_CONTEXT subjcont
;
2032 InitializeListHead(&rollback
);
2034 // FIXME - check fli length
2035 // FIXME - don't ignore fli->RootDirectory
2037 TRACE("ReplaceIfExists = %x\n", fli
->ReplaceIfExists
);
2038 TRACE("RootDirectory = %p\n", fli
->RootDirectory
);
2039 TRACE("FileNameLength = %x\n", fli
->FileNameLength
);
2040 TRACE("FileName = %.*S\n", fli
->FileNameLength
/ sizeof(WCHAR
), fli
->FileName
);
2043 fnlen
= fli
->FileNameLength
/ sizeof(WCHAR
);
2046 if (!fileref
|| !fileref
->parent
) {
2047 ERR("no fileref set and no directory given\n");
2048 return STATUS_INVALID_PARAMETER
;
2051 parfcb
= fileref
->parent
->fcb
;
2056 tfofcb
= tfo
->FsContext
;
2059 while (fnlen
> 0 && (fli
->FileName
[fnlen
- 1] == '/' || fli
->FileName
[fnlen
- 1] == '\\'))
2063 return STATUS_INVALID_PARAMETER
;
2065 for (i
= fnlen
- 1; i
>= 0; i
--) {
2066 if (fli
->FileName
[i
] == '\\' || fli
->FileName
[i
] == '/') {
2067 fn
= &fli
->FileName
[i
+1];
2068 fnlen
= (fli
->FileNameLength
/ sizeof(WCHAR
)) - i
- 1;
2074 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
2075 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
2077 if (fcb
->type
== BTRFS_TYPE_DIRECTORY
) {
2078 WARN("tried to create hard link on directory\n");
2079 Status
= STATUS_FILE_IS_A_DIRECTORY
;
2084 WARN("tried to create hard link on stream\n");
2085 Status
= STATUS_INVALID_PARAMETER
;
2090 fnus
.Length
= fnus
.MaximumLength
= fnlen
* sizeof(WCHAR
);
2092 TRACE("fnus = %.*S\n", fnus
.Length
/ sizeof(WCHAR
), fnus
.Buffer
);
2094 Status
= RtlUnicodeToUTF8N(NULL
, 0, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
2095 if (!NT_SUCCESS(Status
))
2098 utf8
.MaximumLength
= utf8
.Length
= utf8len
;
2099 utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, utf8
.MaximumLength
, ALLOC_TAG
);
2101 ERR("out of memory\n");
2102 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2106 Status
= RtlUnicodeToUTF8N(utf8
.Buffer
, utf8len
, &utf8len
, fn
, (ULONG
)fnlen
* sizeof(WCHAR
));
2107 if (!NT_SUCCESS(Status
))
2110 if (tfo
&& tfo
->FsContext2
) {
2111 struct _ccb
* relatedccb
= tfo
->FsContext2
;
2113 related
= relatedccb
->fileref
;
2114 increase_fileref_refcount(related
);
2117 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2118 Status
= open_fileref(Vcb
, &oldfileref
, &fnus
, related
, FALSE
, NULL
, NULL
, PagedPool
, ccb
->case_sensitive
, Irp
);
2119 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2121 if (NT_SUCCESS(Status
)) {
2122 if (!oldfileref
->deleted
) {
2123 WARN("destination file %S already exists\n", file_desc_fileref(oldfileref
));
2125 if (!fli
->ReplaceIfExists
) {
2126 Status
= STATUS_OBJECT_NAME_COLLISION
;
2128 } else if (oldfileref
->open_count
>= 1 && !oldfileref
->deleted
) {
2129 WARN("trying to overwrite open file\n");
2130 Status
= STATUS_ACCESS_DENIED
;
2132 } else if (fileref
== oldfileref
) {
2133 Status
= STATUS_ACCESS_DENIED
;
2137 if (oldfileref
->fcb
->type
== BTRFS_TYPE_DIRECTORY
) {
2138 WARN("trying to overwrite directory\n");
2139 Status
= STATUS_ACCESS_DENIED
;
2143 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2144 free_fileref(oldfileref
);
2145 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2151 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2152 Status
= open_fileref(Vcb
, &related
, &fnus
, NULL
, TRUE
, NULL
, NULL
, PagedPool
, ccb
->case_sensitive
, Irp
);
2153 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2155 if (!NT_SUCCESS(Status
)) {
2156 ERR("open_fileref returned %08x\n", Status
);
2161 SeCaptureSubjectContext(&subjcont
);
2163 if (!SeAccessCheck(related
->fcb
->sd
, &subjcont
, FALSE
, FILE_ADD_FILE
, 0, NULL
,
2164 IoGetFileObjectGenericMapping(), Irp
->RequestorMode
, &access
, &Status
)) {
2165 SeReleaseSubjectContext(&subjcont
);
2166 WARN("SeAccessCheck failed, returning %08x\n", Status
);
2170 SeReleaseSubjectContext(&subjcont
);
2172 if (fcb
->subvol
!= parfcb
->subvol
) {
2173 WARN("can't create hard link over subvolume boundary\n");
2174 Status
= STATUS_INVALID_PARAMETER
;
2179 SeCaptureSubjectContext(&subjcont
);
2181 if (!SeAccessCheck(oldfileref
->fcb
->sd
, &subjcont
, FALSE
, DELETE
, 0, NULL
,
2182 IoGetFileObjectGenericMapping(), Irp
->RequestorMode
, &access
, &Status
)) {
2183 SeReleaseSubjectContext(&subjcont
);
2184 WARN("SeAccessCheck failed, returning %08x\n", Status
);
2188 SeReleaseSubjectContext(&subjcont
);
2190 Status
= delete_fileref(oldfileref
, NULL
, Irp
, &rollback
);
2191 if (!NT_SUCCESS(Status
)) {
2192 ERR("delete_fileref returned %08x\n", Status
);
2197 Status
= fcb_get_last_dir_index(related
->fcb
, &index
, Irp
);
2198 if (!NT_SUCCESS(Status
)) {
2199 ERR("fcb_get_last_dir_index returned %08x\n", Status
);
2203 fr2
= create_fileref();
2210 fr2
->created
= TRUE
;
2211 fr2
->parent
= related
;
2213 fr2
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fnus
.Length
, ALLOC_TAG
);
2214 if (!fr2
->filepart
.Buffer
) {
2215 ERR("out of memory\n");
2216 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2220 fr2
->filepart
.Length
= fr2
->filepart
.MaximumLength
= fnus
.Length
;
2221 RtlCopyMemory(fr2
->filepart
.Buffer
, fnus
.Buffer
, fnus
.Length
);
2223 Status
= RtlUpcaseUnicodeString(&fr2
->filepart_uc
, &fr2
->filepart
, TRUE
);
2224 if (!NT_SUCCESS(Status
)) {
2225 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
2229 insert_fileref_child(related
, fr2
, TRUE
);
2231 hl
= ExAllocatePoolWithTag(PagedPool
, sizeof(hardlink
), ALLOC_TAG
);
2233 ERR("out of memory\n");
2234 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2238 hl
->parent
= related
->fcb
->inode
;
2241 hl
->name
.Length
= hl
->name
.MaximumLength
= fnus
.Length
;
2242 hl
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->name
.MaximumLength
, ALLOC_TAG
);
2244 if (!hl
->name
.Buffer
) {
2245 ERR("out of memory\n");
2247 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2251 RtlCopyMemory(hl
->name
.Buffer
, fnus
.Buffer
, fnus
.Length
);
2253 hl
->utf8
.Length
= hl
->utf8
.MaximumLength
= utf8
.Length
;
2254 hl
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, hl
->utf8
.MaximumLength
, ALLOC_TAG
);
2256 if (!hl
->utf8
.Buffer
) {
2257 ERR("out of memory\n");
2258 ExFreePool(hl
->name
.Buffer
);
2260 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2264 RtlCopyMemory(hl
->utf8
.Buffer
, utf8
.Buffer
, utf8
.Length
);
2266 InsertTailList(&fcb
->hardlinks
, &hl
->list_entry
);
2268 mark_fileref_dirty(fr2
);
2271 // update inode's INODE_ITEM
2273 KeQuerySystemTime(&time
);
2274 win_time_to_unix(time
, &now
);
2276 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
2277 fcb
->inode_item
.sequence
++;
2278 fcb
->inode_item
.st_nlink
++;
2280 if (!ccb
->user_set_change_time
)
2281 fcb
->inode_item
.st_ctime
= now
;
2283 fcb
->inode_item_changed
= TRUE
;
2284 mark_fcb_dirty(fcb
);
2286 // update parent's INODE_ITEM
2288 parfcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
2289 TRACE("parfcb->inode_item.st_size (inode %llx) was %llx\n", parfcb
->inode
, parfcb
->inode_item
.st_size
);
2290 parfcb
->inode_item
.st_size
+= 2 * utf8len
;
2291 TRACE("parfcb->inode_item.st_size (inode %llx) now %llx\n", parfcb
->inode
, parfcb
->inode_item
.st_size
);
2292 parfcb
->inode_item
.sequence
++;
2293 parfcb
->inode_item
.st_ctime
= now
;
2295 parfcb
->inode_item_changed
= TRUE
;
2296 mark_fcb_dirty(parfcb
);
2298 send_notification_fileref(fr2
, FILE_NOTIFY_CHANGE_FILE_NAME
, FILE_ACTION_ADDED
);
2300 Status
= STATUS_SUCCESS
;
2304 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2305 free_fileref(oldfileref
);
2306 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2309 if (!NT_SUCCESS(Status
) && related
) {
2310 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2311 free_fileref(related
);
2312 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2315 if (!NT_SUCCESS(Status
) && fr2
) {
2316 ExAcquireResourceExclusiveLite(&Vcb
->fcb_lock
, TRUE
);
2318 ExReleaseResourceLite(&Vcb
->fcb_lock
);
2321 if (NT_SUCCESS(Status
))
2322 clear_rollback(Vcb
, &rollback
);
2324 do_rollback(Vcb
, &rollback
);
2326 ExReleaseResourceLite(fcb
->Header
.Resource
);
2327 ExReleaseResourceLite(&Vcb
->tree_lock
);
2332 NTSTATUS STDCALL
drv_set_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
2334 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
2335 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
2336 fcb
* fcb
= IrpSp
->FileObject
->FsContext
;
2337 ccb
* ccb
= IrpSp
->FileObject
->FsContext2
;
2340 FsRtlEnterFileSystem();
2342 top_level
= is_top_level(Irp
);
2344 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
2345 Status
= part0_passthrough(DeviceObject
, Irp
);
2349 if (!(Vcb
->Vpb
->Flags
& VPB_MOUNTED
)) {
2350 Status
= STATUS_ACCESS_DENIED
;
2354 if (Vcb
->readonly
&& IrpSp
->Parameters
.SetFile
.FileInformationClass
!= FilePositionInformation
) {
2355 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2361 Status
= STATUS_INVALID_PARAMETER
;
2367 Status
= STATUS_INVALID_PARAMETER
;
2371 if (fcb
->subvol
->root_item
.flags
& BTRFS_SUBVOL_READONLY
&& IrpSp
->Parameters
.SetFile
.FileInformationClass
!= FilePositionInformation
) {
2372 Status
= STATUS_ACCESS_DENIED
;
2376 Irp
->IoStatus
.Information
= 0;
2378 Status
= STATUS_NOT_IMPLEMENTED
;
2380 TRACE("set information\n");
2382 switch (IrpSp
->Parameters
.SetFile
.FileInformationClass
) {
2383 case FileAllocationInformation
:
2385 TRACE("FileAllocationInformation\n");
2387 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_DATA
)) {
2388 WARN("insufficient privileges\n");
2389 Status
= STATUS_ACCESS_DENIED
;
2393 Status
= set_end_of_file_information(Vcb
, Irp
, IrpSp
->FileObject
, FALSE
);
2397 case FileBasicInformation
:
2399 TRACE("FileBasicInformation\n");
2401 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_ATTRIBUTES
)) {
2402 WARN("insufficient privileges\n");
2403 Status
= STATUS_ACCESS_DENIED
;
2407 Status
= set_basic_information(Vcb
, Irp
, IrpSp
->FileObject
);
2412 case FileDispositionInformation
:
2414 TRACE("FileDispositionInformation\n");
2416 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& DELETE
)) {
2417 WARN("insufficient privileges\n");
2418 Status
= STATUS_ACCESS_DENIED
;
2422 Status
= set_disposition_information(Vcb
, Irp
, IrpSp
->FileObject
);
2427 case FileEndOfFileInformation
:
2429 TRACE("FileEndOfFileInformation\n");
2431 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
))) {
2432 WARN("insufficient privileges\n");
2433 Status
= STATUS_ACCESS_DENIED
;
2437 Status
= set_end_of_file_information(Vcb
, Irp
, IrpSp
->FileObject
, IrpSp
->Parameters
.SetFile
.AdvanceOnly
);
2442 case FileLinkInformation
:
2443 TRACE("FileLinkInformation\n");
2444 Status
= set_link_information(Vcb
, Irp
, IrpSp
->FileObject
, IrpSp
->Parameters
.SetFile
.FileObject
);
2447 case FilePositionInformation
:
2449 TRACE("FilePositionInformation\n");
2451 Status
= set_position_information(Vcb
, Irp
, IrpSp
->FileObject
);
2456 case FileRenameInformation
:
2457 TRACE("FileRenameInformation\n");
2458 // FIXME - make this work with streams
2459 Status
= set_rename_information(Vcb
, Irp
, IrpSp
->FileObject
, IrpSp
->Parameters
.SetFile
.FileObject
);
2462 case FileValidDataLengthInformation
:
2463 FIXME("STUB: FileValidDataLengthInformation\n");
2466 #if (NTDDI_VERSION >= NTDDI_VISTA)
2467 case FileNormalizedNameInformation
:
2468 FIXME("STUB: FileNormalizedNameInformation\n");
2472 #if (NTDDI_VERSION >= NTDDI_WIN7)
2473 case FileStandardLinkInformation
:
2474 FIXME("STUB: FileStandardLinkInformation\n");
2477 case FileRemoteProtocolInformation
:
2478 TRACE("FileRemoteProtocolInformation\n");
2483 WARN("unknown FileInformationClass %u\n", IrpSp
->Parameters
.SetFile
.FileInformationClass
);
2487 Irp
->IoStatus
.Status
= Status
;
2489 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
2493 IoSetTopLevelIrp(NULL
);
2495 FsRtlExitFileSystem();
2500 static NTSTATUS STDCALL
fill_in_file_basic_information(FILE_BASIC_INFORMATION
* fbi
, INODE_ITEM
* ii
, LONG
* length
, fcb
* fcb
, file_ref
* fileref
) {
2501 RtlZeroMemory(fbi
, sizeof(FILE_BASIC_INFORMATION
));
2503 *length
-= sizeof(FILE_BASIC_INFORMATION
);
2505 fbi
->CreationTime
.QuadPart
= unix_time_to_win(&ii
->otime
);
2506 fbi
->LastAccessTime
.QuadPart
= unix_time_to_win(&ii
->st_atime
);
2507 fbi
->LastWriteTime
.QuadPart
= unix_time_to_win(&ii
->st_mtime
);
2508 fbi
->ChangeTime
.QuadPart
= unix_time_to_win(&ii
->st_ctime
);
2511 if (!fileref
|| !fileref
->parent
) {
2512 ERR("no fileref for stream\n");
2513 return STATUS_INTERNAL_ERROR
;
2515 fbi
->FileAttributes
= fileref
->parent
->fcb
->atts
;
2517 fbi
->FileAttributes
= fcb
->atts
;
2519 return STATUS_SUCCESS
;
2522 static NTSTATUS STDCALL
fill_in_file_network_open_information(FILE_NETWORK_OPEN_INFORMATION
* fnoi
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2525 if (*length
< sizeof(FILE_NETWORK_OPEN_INFORMATION
)) {
2527 return STATUS_BUFFER_OVERFLOW
;
2530 RtlZeroMemory(fnoi
, sizeof(FILE_NETWORK_OPEN_INFORMATION
));
2532 *length
-= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
2535 if (!fileref
|| !fileref
->parent
) {
2536 ERR("no fileref for stream\n");
2537 return STATUS_INTERNAL_ERROR
;
2540 ii
= &fileref
->parent
->fcb
->inode_item
;
2542 ii
= &fcb
->inode_item
;
2544 fnoi
->CreationTime
.QuadPart
= unix_time_to_win(&ii
->otime
);
2545 fnoi
->LastAccessTime
.QuadPart
= unix_time_to_win(&ii
->st_atime
);
2546 fnoi
->LastWriteTime
.QuadPart
= unix_time_to_win(&ii
->st_mtime
);
2547 fnoi
->ChangeTime
.QuadPart
= unix_time_to_win(&ii
->st_ctime
);
2550 fnoi
->AllocationSize
.QuadPart
= fnoi
->EndOfFile
.QuadPart
= fcb
->adsdata
.Length
;
2551 fnoi
->FileAttributes
= fileref
->parent
->fcb
->atts
;
2553 fnoi
->AllocationSize
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : sector_align(fcb
->inode_item
.st_size
, fcb
->Vcb
->superblock
.sector_size
);
2554 fnoi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
2555 fnoi
->FileAttributes
= fcb
->atts
;
2558 return STATUS_SUCCESS
;
2561 static NTSTATUS STDCALL
fill_in_file_standard_information(FILE_STANDARD_INFORMATION
* fsi
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2562 RtlZeroMemory(fsi
, sizeof(FILE_STANDARD_INFORMATION
));
2564 *length
-= sizeof(FILE_STANDARD_INFORMATION
);
2567 if (!fileref
|| !fileref
->parent
) {
2568 ERR("no fileref for stream\n");
2569 return STATUS_INTERNAL_ERROR
;
2572 fsi
->AllocationSize
.QuadPart
= fsi
->EndOfFile
.QuadPart
= fcb
->adsdata
.Length
;
2573 fsi
->NumberOfLinks
= fileref
->parent
->fcb
->inode_item
.st_nlink
;
2574 fsi
->Directory
= S_ISDIR(fileref
->parent
->fcb
->inode_item
.st_mode
);
2576 fsi
->AllocationSize
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : sector_align(fcb
->inode_item
.st_size
, fcb
->Vcb
->superblock
.sector_size
);
2577 fsi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
2578 fsi
->NumberOfLinks
= fcb
->inode_item
.st_nlink
;
2579 fsi
->Directory
= S_ISDIR(fcb
->inode_item
.st_mode
);
2582 TRACE("length = %llu\n", fsi
->EndOfFile
.QuadPart
);
2584 fsi
->DeletePending
= fileref
? fileref
->delete_on_close
: FALSE
;
2586 return STATUS_SUCCESS
;
2589 static NTSTATUS STDCALL
fill_in_file_internal_information(FILE_INTERNAL_INFORMATION
* fii
, fcb
* fcb
, LONG
* length
) {
2590 *length
-= sizeof(FILE_INTERNAL_INFORMATION
);
2592 fii
->IndexNumber
.QuadPart
= make_file_id(fcb
->subvol
, fcb
->inode
);
2594 return STATUS_SUCCESS
;
2597 static NTSTATUS STDCALL
fill_in_file_ea_information(FILE_EA_INFORMATION
* eai
, fcb
* fcb
, LONG
* length
) {
2598 *length
-= sizeof(FILE_EA_INFORMATION
);
2600 /* This value appears to be the size of the structure NTFS stores on disk, and not,
2601 * as might be expected, the size of FILE_FULL_EA_INFORMATION (which is what we store).
2602 * The formula is 4 bytes as a header, followed by 5 + NameLength + ValueLength for each
2605 eai
->EaSize
= fcb
->ealen
;
2607 return STATUS_SUCCESS
;
2610 static NTSTATUS STDCALL
fill_in_file_access_information(FILE_ACCESS_INFORMATION
* fai
, LONG
* length
) {
2611 *length
-= sizeof(FILE_ACCESS_INFORMATION
);
2613 fai
->AccessFlags
= GENERIC_READ
;
2615 return STATUS_NOT_IMPLEMENTED
;
2618 static NTSTATUS STDCALL
fill_in_file_position_information(FILE_POSITION_INFORMATION
* fpi
, PFILE_OBJECT FileObject
, LONG
* length
) {
2619 RtlZeroMemory(fpi
, sizeof(FILE_POSITION_INFORMATION
));
2621 *length
-= sizeof(FILE_POSITION_INFORMATION
);
2623 fpi
->CurrentByteOffset
= FileObject
->CurrentByteOffset
;
2625 return STATUS_SUCCESS
;
2628 static NTSTATUS STDCALL
fill_in_file_mode_information(FILE_MODE_INFORMATION
* fmi
, ccb
* ccb
, LONG
* length
) {
2629 RtlZeroMemory(fmi
, sizeof(FILE_MODE_INFORMATION
));
2631 *length
-= sizeof(FILE_MODE_INFORMATION
);
2633 if (ccb
->options
& FILE_WRITE_THROUGH
)
2634 fmi
->Mode
|= FILE_WRITE_THROUGH
;
2636 if (ccb
->options
& FILE_SEQUENTIAL_ONLY
)
2637 fmi
->Mode
|= FILE_SEQUENTIAL_ONLY
;
2639 if (ccb
->options
& FILE_NO_INTERMEDIATE_BUFFERING
)
2640 fmi
->Mode
|= FILE_NO_INTERMEDIATE_BUFFERING
;
2642 if (ccb
->options
& FILE_SYNCHRONOUS_IO_ALERT
)
2643 fmi
->Mode
|= FILE_SYNCHRONOUS_IO_ALERT
;
2645 if (ccb
->options
& FILE_SYNCHRONOUS_IO_NONALERT
)
2646 fmi
->Mode
|= FILE_SYNCHRONOUS_IO_NONALERT
;
2648 if (ccb
->options
& FILE_DELETE_ON_CLOSE
)
2649 fmi
->Mode
|= FILE_DELETE_ON_CLOSE
;
2651 return STATUS_SUCCESS
;
2654 static NTSTATUS STDCALL
fill_in_file_alignment_information(FILE_ALIGNMENT_INFORMATION
* fai
, device_extension
* Vcb
, LONG
* length
) {
2655 RtlZeroMemory(fai
, sizeof(FILE_ALIGNMENT_INFORMATION
));
2657 *length
-= sizeof(FILE_ALIGNMENT_INFORMATION
);
2659 fai
->AlignmentRequirement
= Vcb
->devices
[0].devobj
->AlignmentRequirement
;
2661 return STATUS_SUCCESS
;
2666 LIST_ENTRY list_entry
;
2669 NTSTATUS
fileref_get_filename(file_ref
* fileref
, PUNICODE_STRING fn
, USHORT
* name_offset
) {
2670 LIST_ENTRY fr_list
, *le
;
2675 // FIXME - we need a lock on filerefs' filepart
2677 if (fileref
== fileref
->fcb
->Vcb
->root_fileref
) {
2678 fn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(WCHAR
), ALLOC_TAG
);
2680 ERR("out of memory\n");
2681 return STATUS_INSUFFICIENT_RESOURCES
;
2684 fn
->Length
= fn
->MaximumLength
= sizeof(WCHAR
);
2685 fn
->Buffer
[0] = '\\';
2686 return STATUS_SUCCESS
;
2689 InitializeListHead(&fr_list
);
2697 frl
= ExAllocatePoolWithTag(PagedPool
, sizeof(fileref_list
), ALLOC_TAG
);
2699 ERR("out of memory\n");
2700 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2705 InsertTailList(&fr_list
, &frl
->list_entry
);
2707 len
+= fr
->filepart
.Length
;
2709 if (fr
!= fileref
->fcb
->Vcb
->root_fileref
)
2710 len
+= sizeof(WCHAR
);
2715 fn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, len
, ALLOC_TAG
);
2717 ERR("out of memory\n");
2718 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2722 fn
->Length
= fn
->MaximumLength
= len
;
2727 while (le
!= &fr_list
) {
2728 fileref_list
* frl
= CONTAINING_RECORD(le
, fileref_list
, list_entry
);
2730 if (frl
->fileref
!= fileref
->fcb
->Vcb
->root_fileref
) {
2731 fn
->Buffer
[i
] = frl
->fileref
->fcb
->ads
? ':' : '\\';
2734 if (name_offset
&& frl
->fileref
== fileref
)
2735 *name_offset
= i
* sizeof(WCHAR
);
2737 RtlCopyMemory(&fn
->Buffer
[i
], frl
->fileref
->filepart
.Buffer
, frl
->fileref
->filepart
.Length
);
2738 i
+= frl
->fileref
->filepart
.Length
/ sizeof(WCHAR
);
2744 Status
= STATUS_SUCCESS
;
2747 while (!IsListEmpty(&fr_list
)) {
2750 le
= RemoveHeadList(&fr_list
);
2751 frl
= CONTAINING_RECORD(le
, fileref_list
, list_entry
);
2759 static NTSTATUS STDCALL
fill_in_file_name_information(FILE_NAME_INFORMATION
* fni
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
2765 static WCHAR datasuf
[] = {':','$','D','A','T','A',0};
2766 ULONG datasuflen
= wcslen(datasuf
) * sizeof(WCHAR
);
2769 ERR("called without fileref\n");
2770 return STATUS_INVALID_PARAMETER
;
2773 RtlZeroMemory(fni
, sizeof(FILE_NAME_INFORMATION
));
2775 *length
-= (LONG
)offsetof(FILE_NAME_INFORMATION
, FileName
[0]);
2777 TRACE("maximum length is %u\n", *length
);
2778 fni
->FileNameLength
= 0;
2780 fni
->FileName
[0] = 0;
2782 Status
= fileref_get_filename(fileref
, &fn
, NULL
);
2783 if (!NT_SUCCESS(Status
)) {
2784 ERR("fileref_get_filename returned %08x\n", Status
);
2788 if (*length
>= (LONG
)fn
.Length
) {
2789 RtlCopyMemory(fni
->FileName
, fn
.Buffer
, fn
.Length
);
2793 *length
-= fn
.Length
;
2796 RtlCopyMemory(fni
->FileName
, fn
.Buffer
, *length
);
2804 fni
->FileNameLength
= fn
.Length
;
2807 if (*length
>= (LONG
)datasuflen
) {
2808 RtlCopyMemory(&fni
->FileName
[fn
.Length
/ sizeof(WCHAR
)], datasuf
, datasuflen
);
2810 retlen
+= datasuflen
;
2812 *length
-= datasuflen
;
2815 RtlCopyMemory(&fni
->FileName
[fn
.Length
/ sizeof(WCHAR
)], datasuf
, *length
);
2824 ExFreePool(fn
.Buffer
);
2826 TRACE("%.*S\n", retlen
/ sizeof(WCHAR
), fni
->FileName
);
2828 return STATUS_SUCCESS
;
2831 static NTSTATUS STDCALL
fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATION
* ati
, fcb
* fcb
, file_ref
* fileref
, PIRP Irp
, LONG
* length
) {
2832 *length
-= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
);
2835 if (!fileref
|| !fileref
->parent
) {
2836 ERR("no fileref for stream\n");
2837 return STATUS_INTERNAL_ERROR
;
2840 ati
->FileAttributes
= fileref
->parent
->fcb
->atts
;
2842 ati
->FileAttributes
= fcb
->atts
;
2844 if (!(ati
->FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
))
2845 ati
->ReparseTag
= 0;
2847 ati
->ReparseTag
= get_reparse_tag(fcb
->Vcb
, fcb
->subvol
, fcb
->inode
, fcb
->type
, fcb
->atts
, Irp
);
2849 return STATUS_SUCCESS
;
2853 UNICODE_STRING name
;
2856 LIST_ENTRY list_entry
;
2859 static NTSTATUS STDCALL
fill_in_file_stream_information(FILE_STREAM_INFORMATION
* fsi
, file_ref
* fileref
, PIRP Irp
, LONG
* length
) {
2861 LIST_ENTRY streamlist
, *le
;
2862 FILE_STREAM_INFORMATION
*entry
, *lastentry
;
2865 traverse_ptr tp
, next_tp
;
2869 static WCHAR datasuf
[] = {':','$','D','A','T','A',0};
2870 static char xapref
[] = "user.";
2874 ERR("fileref was NULL\n");
2875 return STATUS_INVALID_PARAMETER
;
2878 InitializeListHead(&streamlist
);
2880 ExAcquireResourceSharedLite(&fileref
->fcb
->Vcb
->tree_lock
, TRUE
);
2881 ExAcquireResourceSharedLite(fileref
->fcb
->Header
.Resource
, TRUE
);
2883 suf
.Buffer
= datasuf
;
2884 suf
.Length
= suf
.MaximumLength
= wcslen(datasuf
) * sizeof(WCHAR
);
2886 searchkey
.obj_id
= fileref
->fcb
->inode
;
2887 searchkey
.obj_type
= TYPE_XATTR_ITEM
;
2888 searchkey
.offset
= 0;
2890 Status
= find_item(fileref
->fcb
->Vcb
, fileref
->fcb
->subvol
, &tp
, &searchkey
, FALSE
, Irp
);
2891 if (!NT_SUCCESS(Status
)) {
2892 ERR("error - find_item returned %08x\n", Status
);
2896 if (fileref
->fcb
->type
!= BTRFS_TYPE_DIRECTORY
) {
2897 si
= ExAllocatePoolWithTag(PagedPool
, sizeof(stream_info
), ALLOC_TAG
);
2899 ERR("out of memory\n");
2900 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2904 si
->name
.Length
= si
->name
.MaximumLength
= 0;
2905 si
->name
.Buffer
= NULL
;
2906 si
->size
= fileref
->fcb
->inode_item
.st_size
;
2909 InsertTailList(&streamlist
, &si
->list_entry
);
2913 if (tp
.item
->key
.obj_id
== fileref
->fcb
->inode
&& tp
.item
->key
.obj_type
== TYPE_XATTR_ITEM
) {
2914 if (tp
.item
->size
< sizeof(DIR_ITEM
)) {
2915 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
));
2917 ULONG len
= tp
.item
->size
;
2918 DIR_ITEM
* xa
= (DIR_ITEM
*)tp
.item
->data
;
2922 if (len
< sizeof(DIR_ITEM
) || len
< sizeof(DIR_ITEM
) - 1 + xa
->m
+ xa
->n
) {
2923 ERR("(%llx,%x,%llx) was truncated\n", tp
.item
->key
.obj_id
, tp
.item
->key
.obj_type
, tp
.item
->key
.offset
);
2927 if (xa
->n
> strlen(xapref
) && RtlCompareMemory(xa
->name
, xapref
, strlen(xapref
)) == strlen(xapref
) &&
2928 (tp
.item
->key
.offset
!= EA_DOSATTRIB_HASH
|| xa
->n
!= strlen(EA_DOSATTRIB
) || RtlCompareMemory(xa
->name
, EA_DOSATTRIB
, xa
->n
) != xa
->n
) &&
2929 (tp
.item
->key
.offset
!= EA_EA_HASH
|| xa
->n
!= strlen(EA_EA
) || RtlCompareMemory(xa
->name
, EA_EA
, xa
->n
) != xa
->n
)
2931 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &stringlen
, &xa
->name
[strlen(xapref
)], xa
->n
- strlen(xapref
));
2932 if (!NT_SUCCESS(Status
)) {
2933 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status
);
2937 si
= ExAllocatePoolWithTag(PagedPool
, sizeof(stream_info
), ALLOC_TAG
);
2939 ERR("out of memory\n");
2940 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2944 si
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, stringlen
, ALLOC_TAG
);
2945 if (!si
->name
.Buffer
) {
2946 ERR("out of memory\n");
2947 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2952 Status
= RtlUTF8ToUnicodeN(si
->name
.Buffer
, stringlen
, &stringlen
, &xa
->name
[strlen(xapref
)], xa
->n
- strlen(xapref
));
2954 if (!NT_SUCCESS(Status
)) {
2955 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status
);
2956 ExFreePool(si
->name
.Buffer
);
2961 si
->name
.Length
= si
->name
.MaximumLength
= stringlen
;
2967 TRACE("stream name = %.*S (length = %u)\n", si
->name
.Length
/ sizeof(WCHAR
), si
->name
.Buffer
, si
->name
.Length
/ sizeof(WCHAR
));
2969 InsertTailList(&streamlist
, &si
->list_entry
);
2972 len
-= sizeof(DIR_ITEM
) - sizeof(char) + xa
->n
+ xa
->m
;
2973 xa
= (DIR_ITEM
*)&xa
->name
[xa
->n
+ xa
->m
]; // FIXME - test xattr hash collisions work
2978 b
= find_next_item(fileref
->fcb
->Vcb
, &tp
, &next_tp
, FALSE
, Irp
);
2982 if (next_tp
.item
->key
.obj_id
> fileref
->fcb
->inode
|| next_tp
.item
->key
.obj_type
> TYPE_XATTR_ITEM
)
2987 ExAcquireResourceSharedLite(&fileref
->nonpaged
->children_lock
, TRUE
);
2989 le
= fileref
->children
.Flink
;
2990 while (le
!= &fileref
->children
) {
2991 file_ref
* fr
= CONTAINING_RECORD(le
, file_ref
, list_entry
);
2993 if (fr
->fcb
&& fr
->fcb
->ads
) {
2994 LIST_ENTRY
* le2
= streamlist
.Flink
;
2997 while (le2
!= &streamlist
) {
2998 si
= CONTAINING_RECORD(le2
, stream_info
, list_entry
);
3000 if (si
&& si
->name
.Buffer
&& si
->name
.Length
== fr
->filepart
.Length
&&
3001 RtlCompareMemory(si
->name
.Buffer
, fr
->filepart
.Buffer
, si
->name
.Length
) == si
->name
.Length
) {
3003 si
->size
= fr
->fcb
->adsdata
.Length
;
3004 si
->ignore
= fr
->fcb
->deleted
;
3013 if (!found
&& !fr
->fcb
->deleted
) {
3014 si
= ExAllocatePoolWithTag(PagedPool
, sizeof(stream_info
), ALLOC_TAG
);
3016 ERR("out of memory\n");
3017 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3021 si
->name
.Length
= si
->name
.MaximumLength
= fr
->filepart
.Length
;
3023 si
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, si
->name
.MaximumLength
, ALLOC_TAG
);
3024 if (!si
->name
.Buffer
) {
3025 ERR("out of memory\n");
3026 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3031 RtlCopyMemory(si
->name
.Buffer
, fr
->filepart
.Buffer
, fr
->filepart
.Length
);
3033 si
->size
= fr
->fcb
->adsdata
.Length
;
3036 InsertTailList(&streamlist
, &si
->list_entry
);
3043 ExReleaseResourceLite(&fileref
->nonpaged
->children_lock
);
3047 le
= streamlist
.Flink
;
3048 while (le
!= &streamlist
) {
3049 si
= CONTAINING_RECORD(le
, stream_info
, list_entry
);
3052 reqsize
= sector_align(reqsize
, sizeof(LONGLONG
));
3053 reqsize
+= sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
) + suf
.Length
+ sizeof(WCHAR
) + si
->name
.Length
;
3059 TRACE("length = %i, reqsize = %u\n", *length
, reqsize
);
3061 if (reqsize
> *length
) {
3062 Status
= STATUS_BUFFER_OVERFLOW
;
3069 le
= streamlist
.Flink
;
3070 while (le
!= &streamlist
) {
3071 si
= CONTAINING_RECORD(le
, stream_info
, list_entry
);
3076 entry
->NextEntryOffset
= 0;
3077 entry
->StreamNameLength
= si
->name
.Length
+ suf
.Length
+ sizeof(WCHAR
);
3078 entry
->StreamSize
.QuadPart
= si
->size
;
3080 if (le
== streamlist
.Flink
)
3081 entry
->StreamAllocationSize
.QuadPart
= sector_align(fileref
->fcb
->inode_item
.st_size
, fileref
->fcb
->Vcb
->superblock
.sector_size
);
3083 entry
->StreamAllocationSize
.QuadPart
= si
->size
;
3085 entry
->StreamName
[0] = ':';
3087 if (si
->name
.Length
> 0)
3088 RtlCopyMemory(&entry
->StreamName
[1], si
->name
.Buffer
, si
->name
.Length
);
3090 RtlCopyMemory(&entry
->StreamName
[1 + (si
->name
.Length
/ sizeof(WCHAR
))], suf
.Buffer
, suf
.Length
);
3093 lastentry
->NextEntryOffset
= (UINT8
*)entry
- (UINT8
*)lastentry
;
3095 off
= sector_align(sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
) + suf
.Length
+ sizeof(WCHAR
) + si
->name
.Length
, sizeof(LONGLONG
));
3098 entry
= (FILE_STREAM_INFORMATION
*)((UINT8
*)entry
+ off
);
3106 Status
= STATUS_SUCCESS
;
3109 while (!IsListEmpty(&streamlist
)) {
3110 le
= RemoveHeadList(&streamlist
);
3111 si
= CONTAINING_RECORD(le
, stream_info
, list_entry
);
3113 if (si
->name
.Buffer
)
3114 ExFreePool(si
->name
.Buffer
);
3119 ExReleaseResourceLite(fileref
->fcb
->Header
.Resource
);
3120 ExReleaseResourceLite(&fileref
->fcb
->Vcb
->tree_lock
);
3126 static NTSTATUS STDCALL
fill_in_file_standard_link_information(FILE_STANDARD_LINK_INFORMATION
* fsli
, fcb
* fcb
, file_ref
* fileref
, LONG
* length
) {
3127 TRACE("FileStandardLinkInformation\n");
3129 // FIXME - NumberOfAccessibleLinks should subtract open links which have been marked as delete_on_close
3131 fsli
->NumberOfAccessibleLinks
= fcb
->inode_item
.st_nlink
;
3132 fsli
->TotalNumberOfLinks
= fcb
->inode_item
.st_nlink
;
3133 fsli
->DeletePending
= fileref
? fileref
->delete_on_close
: FALSE
;
3134 fsli
->Directory
= fcb
->type
== BTRFS_TYPE_DIRECTORY
? TRUE
: FALSE
;
3136 *length
-= sizeof(FILE_STANDARD_LINK_INFORMATION
);
3138 return STATUS_SUCCESS
;
3140 #endif /* __REACTOS__ */
3143 UNICODE_STRING name
;
3145 LIST_ENTRY list_entry
;
3148 static NTSTATUS
get_subvol_path(device_extension
* Vcb
, root
* subvol
, PIRP Irp
) {
3154 UNICODE_STRING dirpath
;
3158 // FIXME - add subvol->parent field
3160 if (subvol
== Vcb
->root_fileref
->fcb
->subvol
) {
3161 subvol
->path
.Length
= subvol
->path
.MaximumLength
= sizeof(WCHAR
);
3162 subvol
->path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, subvol
->path
.Length
, ALLOC_TAG
);
3163 subvol
->path
.Buffer
[0] = '\\';
3164 return STATUS_SUCCESS
;
3167 searchkey
.obj_id
= subvol
->id
;
3168 searchkey
.obj_type
= TYPE_ROOT_BACKREF
;
3169 searchkey
.offset
= 0xffffffffffffffff;
3171 Status
= find_item(Vcb
, Vcb
->root_root
, &tp
, &searchkey
, FALSE
, Irp
);
3172 if (!NT_SUCCESS(Status
)) {
3173 ERR("error - find_item returned %08x\n", Status
);
3177 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
|| tp
.item
->key
.obj_type
!= searchkey
.obj_type
) { // top subvol
3178 subvol
->path
.Length
= subvol
->path
.MaximumLength
= sizeof(WCHAR
);
3179 subvol
->path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, subvol
->path
.Length
, ALLOC_TAG
);
3180 subvol
->path
.Buffer
[0] = '\\';
3181 return STATUS_SUCCESS
;
3184 if (tp
.item
->size
< sizeof(ROOT_REF
)) {
3185 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
));
3186 return STATUS_INTERNAL_ERROR
;
3189 rr
= (ROOT_REF
*)tp
.item
->data
;
3191 if (tp
.item
->size
< sizeof(ROOT_REF
) - 1 + rr
->n
) {
3192 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
);
3193 return STATUS_INTERNAL_ERROR
;
3196 le
= Vcb
->roots
.Flink
;
3200 while (le
!= &Vcb
->roots
) {
3201 root
* r2
= CONTAINING_RECORD(le
, root
, list_entry
);
3203 if (r2
->id
== tp
.item
->key
.offset
) {
3212 ERR("unable to find subvol %llx\n", tp
.item
->key
.offset
);
3213 return STATUS_INTERNAL_ERROR
;
3216 // FIXME - recursion
3218 Status
= get_inode_dir_path(Vcb
, parsubvol
, rr
->dir
, &dirpath
, Irp
);
3219 if (!NT_SUCCESS(Status
)) {
3220 ERR("get_inode_dir_path returned %08x\n", Status
);
3224 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &namelen
, rr
->name
, rr
->n
);
3225 if (!NT_SUCCESS(Status
)) {
3226 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3231 ERR("length was 0\n");
3232 Status
= STATUS_INTERNAL_ERROR
;
3236 subvol
->path
.Length
= subvol
->path
.MaximumLength
= dirpath
.Length
+ namelen
;
3237 subvol
->path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, subvol
->path
.Length
, ALLOC_TAG
);
3239 if (!subvol
->path
.Buffer
) {
3240 ERR("out of memory\n");
3242 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3246 RtlCopyMemory(subvol
->path
.Buffer
, dirpath
.Buffer
, dirpath
.Length
);
3248 Status
= RtlUTF8ToUnicodeN(&subvol
->path
.Buffer
[dirpath
.Length
/ sizeof(WCHAR
)], namelen
, &namelen
, rr
->name
, rr
->n
);
3249 if (!NT_SUCCESS(Status
)) {
3250 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3254 Status
= STATUS_SUCCESS
;
3258 ExFreePool(dirpath
.Buffer
);
3260 if (!NT_SUCCESS(Status
) && subvol
->path
.Buffer
) {
3261 ExFreePool(subvol
->path
.Buffer
);
3262 subvol
->path
.Buffer
= NULL
;
3268 static NTSTATUS
get_inode_dir_path(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, PUNICODE_STRING us
, PIRP Irp
) {
3273 LIST_ENTRY name_trail
, *le
;
3278 InitializeListHead(&name_trail
);
3282 // FIXME - start with subvol prefix
3283 if (!subvol
->path
.Buffer
) {
3284 Status
= get_subvol_path(Vcb
, subvol
, Irp
);
3285 if (!NT_SUCCESS(Status
)) {
3286 ERR("get_subvol_path returned %08x\n", Status
);
3291 while (in
!= subvol
->root_item
.objid
) {
3292 searchkey
.obj_id
= in
;
3293 searchkey
.obj_type
= TYPE_INODE_EXTREF
;
3294 searchkey
.offset
= 0xffffffffffffffff;
3296 Status
= find_item(Vcb
, subvol
, &tp
, &searchkey
, FALSE
, Irp
);
3297 if (!NT_SUCCESS(Status
)) {
3298 ERR("error - find_item returned %08x\n", Status
);
3302 if (tp
.item
->key
.obj_id
!= searchkey
.obj_id
) {
3303 ERR("could not find INODE_REF for inode %llx in subvol %llx\n", searchkey
.obj_id
, subvol
->id
);
3304 Status
= STATUS_INTERNAL_ERROR
;
3308 if (tp
.item
->key
.obj_type
== TYPE_INODE_REF
) {
3309 INODE_REF
* ir
= (INODE_REF
*)tp
.item
->data
;
3313 if (tp
.item
->size
< sizeof(INODE_REF
)) {
3314 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
));
3315 Status
= STATUS_INTERNAL_ERROR
;
3319 if (tp
.item
->size
< sizeof(INODE_REF
) - 1 + ir
->n
) {
3320 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
);
3321 Status
= STATUS_INTERNAL_ERROR
;
3325 nb
= ExAllocatePoolWithTag(PagedPool
, sizeof(name_bit
), ALLOC_TAG
);
3327 ERR("out of memory\n");
3328 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3332 nb
->name
.Buffer
= NULL
;
3334 InsertTailList(&name_trail
, &nb
->list_entry
);
3337 Status
= RtlUTF8ToUnicodeN(NULL
, 0, &len
, ir
->name
, ir
->n
);
3338 if (!NT_SUCCESS(Status
)) {
3339 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3344 ERR("length was 0\n");
3345 Status
= STATUS_INTERNAL_ERROR
;
3349 nb
->name
.Length
= nb
->name
.MaximumLength
= len
;
3351 nb
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, nb
->name
.Length
, ALLOC_TAG
);
3352 if (!nb
->name
.Buffer
) {
3353 ERR("out of memory\n");
3355 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3359 Status
= RtlUTF8ToUnicodeN(nb
->name
.Buffer
, len
, &len
, ir
->name
, ir
->n
);
3360 if (!NT_SUCCESS(Status
)) {
3361 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status
);
3365 in
= tp
.item
->key
.offset
;
3366 namelen
+= nb
->name
.Length
;
3368 // } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
3371 ERR("could not find INODE_REF for inode %llx in subvol %llx\n", searchkey
.obj_id
, subvol
->id
);
3372 Status
= STATUS_INTERNAL_ERROR
;
3377 namelen
+= (levels
+ 1) * sizeof(WCHAR
);
3379 us
->Length
= us
->MaximumLength
= namelen
;
3380 us
->Buffer
= ExAllocatePoolWithTag(PagedPool
, us
->Length
, ALLOC_TAG
);
3383 ERR("out of memory\n");
3384 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3388 us
->Buffer
[0] = '\\';
3389 usbuf
= &us
->Buffer
[1];
3391 le
= name_trail
.Blink
;
3392 while (le
!= &name_trail
) {
3393 name_bit
* nb
= CONTAINING_RECORD(le
, name_bit
, list_entry
);
3395 RtlCopyMemory(usbuf
, nb
->name
.Buffer
, nb
->name
.Length
);
3396 usbuf
+= nb
->name
.Length
/ sizeof(WCHAR
);
3404 Status
= STATUS_SUCCESS
;
3407 while (!IsListEmpty(&name_trail
)) {
3408 name_bit
* nb
= CONTAINING_RECORD(name_trail
.Flink
, name_bit
, list_entry
);
3410 if (nb
->name
.Buffer
)
3411 ExFreePool(nb
->name
.Buffer
);
3413 RemoveEntryList(&nb
->list_entry
);
3421 NTSTATUS
open_fileref_by_inode(device_extension
* Vcb
, root
* subvol
, UINT64 inode
, file_ref
** pfr
, PIRP Irp
) {
3425 file_ref
*parfr
, *fr
;
3427 Status
= open_fcb(Vcb
, subvol
, inode
, 0, NULL
, NULL
, &fcb
, PagedPool
, Irp
);
3428 if (!NT_SUCCESS(Status
)) {
3429 ERR("open_fcb returned %08x\n", Status
);
3434 *pfr
= fcb
->fileref
;
3435 increase_fileref_refcount(fcb
->fileref
);
3436 return STATUS_SUCCESS
;
3439 if (IsListEmpty(&fcb
->hardlinks
)) {
3440 ERR("subvol %llx, inode %llx has no hardlinks\n", subvol
->id
, inode
);
3442 return STATUS_INTERNAL_ERROR
;
3445 hl
= CONTAINING_RECORD(fcb
->hardlinks
.Flink
, hardlink
, list_entry
);
3447 // FIXME - does this work with subvols?
3449 if (hl
->parent
== inode
) // root of subvol
3452 Status
= open_fileref_by_inode(Vcb
, subvol
, hl
->parent
, &parfr
, Irp
);
3453 if (!NT_SUCCESS(Status
)) {
3454 ERR("open_fileref_by_inode returned %08x\n", Status
);
3460 fr
= create_fileref();
3462 ERR("out of memory\n");
3464 return STATUS_INSUFFICIENT_RESOURCES
;
3470 fr
->index
= hl
->index
;
3472 fr
->utf8
.Length
= fr
->utf8
.MaximumLength
= hl
->utf8
.Length
;
3473 if (fr
->utf8
.Length
> 0) {
3474 fr
->utf8
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->utf8
.Length
, ALLOC_TAG
);
3476 if (!fr
->utf8
.Buffer
) {
3477 ERR("out of memory\n");
3479 return STATUS_INSUFFICIENT_RESOURCES
;
3482 RtlCopyMemory(fr
->utf8
.Buffer
, hl
->utf8
.Buffer
, hl
->utf8
.Length
);
3485 fr
->filepart
.MaximumLength
= fr
->filepart
.Length
= hl
->name
.Length
;
3487 if (fr
->filepart
.Length
> 0) {
3488 fr
->filepart
.Buffer
= ExAllocatePoolWithTag(PagedPool
, fr
->filepart
.MaximumLength
, ALLOC_TAG
);
3489 if (!fr
->filepart
.Buffer
) {
3490 ERR("out of memory\n");
3492 return STATUS_INSUFFICIENT_RESOURCES
;
3495 RtlCopyMemory(fr
->filepart
.Buffer
, hl
->name
.Buffer
, hl
->name
.Length
);
3498 Status
= RtlUpcaseUnicodeString(&fr
->filepart_uc
, &fr
->filepart
, TRUE
);
3499 if (!NT_SUCCESS(Status
)) {
3500 ERR("RtlUpcaseUnicodeString returned %08x\n", Status
);
3507 insert_fileref_child(parfr
, fr
, TRUE
);
3511 return STATUS_SUCCESS
;
3515 static NTSTATUS STDCALL
fill_in_hard_link_information(FILE_LINKS_INFORMATION
* fli
, file_ref
* fileref
, PIRP Irp
, LONG
* length
) {
3519 FILE_LINK_ENTRY_INFORMATION
* feli
;
3520 BOOL overflow
= FALSE
;
3521 fcb
* fcb
= fileref
->fcb
;
3525 return STATUS_INVALID_PARAMETER
;
3527 if (*length
< offsetof(FILE_LINKS_INFORMATION
, Entry
))
3528 return STATUS_INVALID_PARAMETER
;
3530 RtlZeroMemory(fli
, *length
);
3532 bytes_needed
= offsetof(FILE_LINKS_INFORMATION
, Entry
);
3536 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, TRUE
);
3538 if (fcb
->inode
== SUBVOL_ROOT_INODE
) {
3541 if (fcb
== fcb
->Vcb
->root_fileref
->fcb
)
3542 namelen
= sizeof(WCHAR
);
3544 namelen
= fileref
->filepart
.Length
;
3546 bytes_needed
+= sizeof(FILE_LINK_ENTRY_INFORMATION
) - sizeof(WCHAR
) + namelen
;
3548 if (bytes_needed
> *length
)
3554 feli
->NextEntryOffset
= 0;
3555 feli
->ParentFileId
= 0; // we use an inode of 0 to mean the parent of a subvolume
3557 if (fcb
== fcb
->Vcb
->root_fileref
->fcb
) {
3558 feli
->FileNameLength
= 1;
3559 feli
->FileName
[0] = '.';
3561 feli
->FileNameLength
= fileref
->filepart
.Length
/ sizeof(WCHAR
);
3562 RtlCopyMemory(feli
->FileName
, fileref
->filepart
.Buffer
, fileref
->filepart
.Length
);
3565 fli
->EntriesReturned
++;
3570 ExAcquireResourceExclusiveLite(&fcb
->Vcb
->fcb_lock
, TRUE
);
3572 le
= fcb
->hardlinks
.Flink
;
3573 while (le
!= &fcb
->hardlinks
) {
3574 hardlink
* hl
= CONTAINING_RECORD(le
, hardlink
, list_entry
);
3577 TRACE("parent %llx, index %llx, name %.*S\n", hl
->parent
, hl
->index
, hl
->name
.Length
/ sizeof(WCHAR
), hl
->name
.Buffer
);
3579 Status
= open_fileref_by_inode(fcb
->Vcb
, fcb
->subvol
, hl
->parent
, &parfr
, Irp
);
3581 if (!NT_SUCCESS(Status
)) {
3582 ERR("open_fileref_by_inode returned %08x\n", Status
);
3583 } else if (!parfr
->deleted
) {
3585 BOOL found
= FALSE
, deleted
= FALSE
;
3588 le2
= parfr
->children
.Flink
;
3589 while (le2
!= &parfr
->children
) {
3590 file_ref
* fr2
= CONTAINING_RECORD(le2
, file_ref
, list_entry
);
3592 if (fr2
->index
== hl
->index
) {
3594 deleted
= fr2
->deleted
;
3597 fn
= &fr2
->filepart
;
3609 TRACE("fn = %.*S (found = %u)\n", fn
->Length
/ sizeof(WCHAR
), fn
->Buffer
, found
);
3612 bytes_needed
= sector_align(bytes_needed
, 8);
3614 bytes_needed
+= sizeof(FILE_LINK_ENTRY_INFORMATION
) + fn
->Length
- sizeof(WCHAR
);
3616 if (bytes_needed
> *length
)
3621 feli
->NextEntryOffset
= sector_align(sizeof(FILE_LINK_ENTRY_INFORMATION
) + ((feli
->FileNameLength
- 1) * sizeof(WCHAR
)), 8);
3622 feli
= (FILE_LINK_ENTRY_INFORMATION
*)((UINT8
*)feli
+ feli
->NextEntryOffset
);
3626 feli
->NextEntryOffset
= 0;
3627 feli
->ParentFileId
= parfr
->fcb
->inode
;
3628 feli
->FileNameLength
= fn
->Length
/ sizeof(WCHAR
);
3629 RtlCopyMemory(feli
->FileName
, fn
->Buffer
, fn
->Length
);
3631 fli
->EntriesReturned
++;
3637 free_fileref(parfr
);
3643 ExReleaseResourceLite(&fcb
->Vcb
->fcb_lock
);
3646 fli
->BytesNeeded
= bytes_needed
;
3650 Status
= overflow
? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
;
3652 ExReleaseResourceLite(fcb
->Header
.Resource
);
3656 #endif /* __REACTOS__ */
3658 #if (NTDDI_VERSION >= NTDDI_WIN10)
3660 typedef struct _FILE_ID_128
{
3661 UCHAR Identifier
[16];
3662 } FILE_ID_128
, *PFILE_ID_128
;
3664 typedef struct _FILE_ID_INFORMATION
{
3665 ULONGLONG VolumeSerialNumber
;
3667 } FILE_ID_INFORMATION
, *PFILE_ID_INFORMATION
;
3670 static NTSTATUS
fill_in_file_id_information(FILE_ID_INFORMATION
* fii
, fcb
* fcb
, LONG
* length
) {
3671 RtlCopyMemory(&fii
->VolumeSerialNumber
, &fcb
->Vcb
->superblock
.uuid
.uuid
[8], sizeof(UINT64
));
3672 RtlCopyMemory(&fii
->FileId
.Identifier
[0], &fcb
->inode
, sizeof(UINT64
));
3673 RtlCopyMemory(&fii
->FileId
.Identifier
[sizeof(UINT64
)], &fcb
->subvol
->id
, sizeof(UINT64
));
3675 *length
-= sizeof(FILE_ID_INFORMATION
);
3677 return STATUS_SUCCESS
;
3681 static NTSTATUS STDCALL
query_info(device_extension
* Vcb
, PFILE_OBJECT FileObject
, PIRP Irp
) {
3682 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
3683 LONG length
= IrpSp
->Parameters
.QueryFile
.Length
;
3684 fcb
* fcb
= FileObject
->FsContext
;
3685 ccb
* ccb
= FileObject
->FsContext2
;
3686 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
3689 TRACE("(%p, %p, %p)\n", Vcb
, FileObject
, Irp
);
3690 TRACE("fcb = %p\n", fcb
);
3692 if (fcb
== Vcb
->volume_fcb
)
3693 return STATUS_INVALID_PARAMETER
;
3696 ERR("ccb is NULL\n");
3697 return STATUS_INVALID_PARAMETER
;
3700 switch (IrpSp
->Parameters
.QueryFile
.FileInformationClass
) {
3701 case FileAllInformation
:
3703 FILE_ALL_INFORMATION
* fai
= Irp
->AssociatedIrp
.SystemBuffer
;
3706 TRACE("FileAllInformation\n");
3708 if (Irp
->RequestorMode
!= KernelMode
&& !(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3709 WARN("insufficient privileges\n");
3710 Status
= STATUS_ACCESS_DENIED
;
3715 if (!fileref
|| !fileref
->parent
) {
3716 ERR("no fileref for stream\n");
3717 Status
= STATUS_INTERNAL_ERROR
;
3721 ii
= &fileref
->parent
->fcb
->inode_item
;
3723 ii
= &fcb
->inode_item
;
3726 fill_in_file_basic_information(&fai
->BasicInformation
, ii
, &length
, fcb
, fileref
);
3729 fill_in_file_standard_information(&fai
->StandardInformation
, fcb
, fileref
, &length
);
3732 fill_in_file_internal_information(&fai
->InternalInformation
, fcb
, &length
);
3735 fill_in_file_ea_information(&fai
->EaInformation
, fcb
, &length
);
3738 fill_in_file_access_information(&fai
->AccessInformation
, &length
);
3741 fill_in_file_position_information(&fai
->PositionInformation
, FileObject
, &length
);
3744 fill_in_file_mode_information(&fai
->ModeInformation
, ccb
, &length
);
3747 fill_in_file_alignment_information(&fai
->AlignmentInformation
, Vcb
, &length
);
3750 fill_in_file_name_information(&fai
->NameInformation
, fcb
, fileref
, &length
);
3752 Status
= STATUS_SUCCESS
;
3757 case FileAttributeTagInformation
:
3759 FILE_ATTRIBUTE_TAG_INFORMATION
* ati
= Irp
->AssociatedIrp
.SystemBuffer
;
3761 TRACE("FileAttributeTagInformation\n");
3763 if (Irp
->RequestorMode
!= KernelMode
&& !(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3764 WARN("insufficient privileges\n");
3765 Status
= STATUS_ACCESS_DENIED
;
3769 Status
= fill_in_file_attribute_information(ati
, fcb
, fileref
, Irp
, &length
);
3774 case FileBasicInformation
:
3776 FILE_BASIC_INFORMATION
* fbi
= Irp
->AssociatedIrp
.SystemBuffer
;
3779 TRACE("FileBasicInformation\n");
3781 if (Irp
->RequestorMode
!= KernelMode
&& !(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3782 WARN("insufficient privileges\n");
3783 Status
= STATUS_ACCESS_DENIED
;
3787 if (IrpSp
->Parameters
.QueryFile
.Length
< sizeof(FILE_BASIC_INFORMATION
)) {
3789 Status
= STATUS_BUFFER_OVERFLOW
;
3794 if (!fileref
|| !fileref
->parent
) {
3795 ERR("no fileref for stream\n");
3796 Status
= STATUS_INTERNAL_ERROR
;
3800 ii
= &fileref
->parent
->fcb
->inode_item
;
3802 ii
= &fcb
->inode_item
;
3804 Status
= fill_in_file_basic_information(fbi
, ii
, &length
, fcb
, fileref
);
3808 case FileCompressionInformation
:
3809 FIXME("STUB: FileCompressionInformation\n");
3810 Status
= STATUS_INVALID_PARAMETER
;
3813 case FileEaInformation
:
3815 FILE_EA_INFORMATION
* eai
= Irp
->AssociatedIrp
.SystemBuffer
;
3817 TRACE("FileEaInformation\n");
3819 Status
= fill_in_file_ea_information(eai
, fcb
, &length
);
3824 case FileInternalInformation
:
3826 FILE_INTERNAL_INFORMATION
* fii
= Irp
->AssociatedIrp
.SystemBuffer
;
3828 TRACE("FileInternalInformation\n");
3830 Status
= fill_in_file_internal_information(fii
, fcb
, &length
);
3835 case FileNameInformation
:
3837 FILE_NAME_INFORMATION
* fni
= Irp
->AssociatedIrp
.SystemBuffer
;
3839 TRACE("FileNameInformation\n");
3841 Status
= fill_in_file_name_information(fni
, fcb
, fileref
, &length
);
3846 case FileNetworkOpenInformation
:
3848 FILE_NETWORK_OPEN_INFORMATION
* fnoi
= Irp
->AssociatedIrp
.SystemBuffer
;
3850 TRACE("FileNetworkOpenInformation\n");
3852 if (Irp
->RequestorMode
!= KernelMode
&& !(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
3853 WARN("insufficient privileges\n");
3854 Status
= STATUS_ACCESS_DENIED
;
3858 Status
= fill_in_file_network_open_information(fnoi
, fcb
, fileref
, &length
);
3863 case FilePositionInformation
:
3865 FILE_POSITION_INFORMATION
* fpi
= Irp
->AssociatedIrp
.SystemBuffer
;
3867 TRACE("FilePositionInformation\n");
3869 Status
= fill_in_file_position_information(fpi
, FileObject
, &length
);
3874 case FileStandardInformation
:
3876 FILE_STANDARD_INFORMATION
* fsi
= Irp
->AssociatedIrp
.SystemBuffer
;
3878 TRACE("FileStandardInformation\n");
3880 if (IrpSp
->Parameters
.QueryFile
.Length
< sizeof(FILE_STANDARD_INFORMATION
)) {
3882 Status
= STATUS_BUFFER_OVERFLOW
;
3886 Status
= fill_in_file_standard_information(fsi
, fcb
, ccb
->fileref
, &length
);
3891 case FileStreamInformation
:
3893 FILE_STREAM_INFORMATION
* fsi
= Irp
->AssociatedIrp
.SystemBuffer
;
3895 TRACE("FileStreamInformation\n");
3897 Status
= fill_in_file_stream_information(fsi
, fileref
, Irp
, &length
);
3902 #if (NTDDI_VERSION >= NTDDI_VISTA)
3903 case FileHardLinkInformation
:
3905 FILE_LINKS_INFORMATION
* fli
= Irp
->AssociatedIrp
.SystemBuffer
;
3907 TRACE("FileHardLinkInformation\n");
3909 Status
= fill_in_hard_link_information(fli
, fileref
, Irp
, &length
);
3914 case FileNormalizedNameInformation
:
3916 FILE_NAME_INFORMATION
* fni
= Irp
->AssociatedIrp
.SystemBuffer
;
3918 TRACE("FileNormalizedNameInformation\n");
3920 Status
= fill_in_file_name_information(fni
, fcb
, fileref
, &length
);
3926 #if (NTDDI_VERSION >= NTDDI_WIN7)
3927 case FileStandardLinkInformation
:
3929 FILE_STANDARD_LINK_INFORMATION
* fsli
= Irp
->AssociatedIrp
.SystemBuffer
;
3931 TRACE("FileStandardLinkInformation\n");
3933 Status
= fill_in_file_standard_link_information(fsli
, fcb
, ccb
->fileref
, &length
);
3938 case FileRemoteProtocolInformation
:
3939 TRACE("FileRemoteProtocolInformation\n");
3940 Status
= STATUS_INVALID_PARAMETER
;
3944 #if (NTDDI_VERSION >= NTDDI_WIN10)
3945 #pragma GCC diagnostic push
3946 #pragma GCC diagnostic ignored "-Wswitch"
3947 case FileIdInformation
:
3949 FILE_ID_INFORMATION
* fii
= Irp
->AssociatedIrp
.SystemBuffer
;
3951 if (IrpSp
->Parameters
.QueryFile
.Length
< sizeof(FILE_ID_INFORMATION
)) {
3953 Status
= STATUS_BUFFER_OVERFLOW
;
3957 TRACE("FileIdInformation\n");
3959 Status
= fill_in_file_id_information(fii
, fcb
, &length
);
3963 #pragma GCC diagnostic pop
3967 WARN("unknown FileInformationClass %u\n", IrpSp
->Parameters
.QueryFile
.FileInformationClass
);
3968 Status
= STATUS_INVALID_PARAMETER
;
3974 Status
= STATUS_BUFFER_OVERFLOW
;
3977 Irp
->IoStatus
.Information
= IrpSp
->Parameters
.QueryFile
.Length
- length
;
3980 TRACE("query_info returning %08x\n", Status
);
3985 NTSTATUS STDCALL
drv_query_information(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
3986 PIO_STACK_LOCATION IrpSp
;
3989 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
3992 FsRtlEnterFileSystem();
3994 top_level
= is_top_level(Irp
);
3996 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
3997 Status
= part0_passthrough(DeviceObject
, Irp
);
4001 Irp
->IoStatus
.Information
= 0;
4003 TRACE("query information\n");
4005 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
4007 ExAcquireResourceSharedLite(&Vcb
->tree_lock
, TRUE
);
4009 fcb
= IrpSp
->FileObject
->FsContext
;
4010 TRACE("fcb = %p\n", fcb
);
4011 TRACE("fcb->subvol = %p\n", fcb
->subvol
);
4013 Status
= query_info(fcb
->Vcb
, IrpSp
->FileObject
, Irp
);
4015 TRACE("returning %08x\n", Status
);
4017 Irp
->IoStatus
.Status
= Status
;
4019 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
4021 ExReleaseResourceLite(&Vcb
->tree_lock
);
4025 IoSetTopLevelIrp(NULL
);
4027 FsRtlExitFileSystem();
4032 NTSTATUS STDCALL
drv_query_ea(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
4035 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
4036 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
4037 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
4040 FILE_FULL_EA_INFORMATION
* ffei
;
4043 Status
= STATUS_INTERNAL_ERROR
;
4046 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
4048 FsRtlEnterFileSystem();
4050 top_level
= is_top_level(Irp
);
4052 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
4053 Status
= part0_passthrough(DeviceObject
, Irp
);
4057 ffei
= map_user_buffer(Irp
);
4059 ERR("could not get output buffer\n");
4060 Status
= STATUS_INVALID_PARAMETER
;
4065 ERR("no file object\n");
4066 Status
= STATUS_INVALID_PARAMETER
;
4070 fcb
= FileObject
->FsContext
;
4074 Status
= STATUS_INVALID_PARAMETER
;
4078 ccb
= FileObject
->FsContext2
;
4082 Status
= STATUS_INVALID_PARAMETER
;
4086 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& (FILE_READ_EA
| FILE_WRITE_EA
))) {
4087 WARN("insufficient privileges\n");
4088 Status
= STATUS_ACCESS_DENIED
;
4092 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, TRUE
);
4094 if (fcb
->ea_xattr
.Length
== 0)
4097 if (IrpSp
->Parameters
.QueryEa
.EaList
) {
4098 FILE_FULL_EA_INFORMATION
*ea
, *out
;
4099 FILE_GET_EA_INFORMATION
* in
;
4101 in
= IrpSp
->Parameters
.QueryEa
.EaList
;
4105 s
.Length
= s
.MaximumLength
= in
->EaNameLength
;
4106 s
.Buffer
= in
->EaName
;
4108 RtlUpperString(&s
, &s
);
4110 if (in
->NextEntryOffset
== 0)
4113 in
= (FILE_GET_EA_INFORMATION
*)(((UINT8
*)in
) + in
->NextEntryOffset
);
4116 ea
= (FILE_FULL_EA_INFORMATION
*)fcb
->ea_xattr
.Buffer
;
4122 in
= IrpSp
->Parameters
.QueryEa
.EaList
;
4124 if (in
->EaNameLength
== ea
->EaNameLength
&&
4125 RtlCompareMemory(in
->EaName
, ea
->EaName
, in
->EaNameLength
) == in
->EaNameLength
) {
4130 if (in
->NextEntryOffset
== 0)
4133 in
= (FILE_GET_EA_INFORMATION
*)(((UINT8
*)in
) + in
->NextEntryOffset
);
4137 UINT8 padding
= retlen
% 4 > 0 ? (4 - (retlen
% 4)) : 0;
4139 if (offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + ea
->EaNameLength
+ 1 + ea
->EaValueLength
> IrpSp
->Parameters
.QueryEa
.Length
- retlen
- padding
) {
4140 Status
= STATUS_BUFFER_OVERFLOW
;
4148 out
->NextEntryOffset
= offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + out
->EaNameLength
+ 1 + out
->EaValueLength
+ padding
;
4149 out
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)out
) + out
->NextEntryOffset
);
4153 out
->NextEntryOffset
= 0;
4154 out
->Flags
= ea
->Flags
;
4155 out
->EaNameLength
= ea
->EaNameLength
;
4156 out
->EaValueLength
= ea
->EaValueLength
;
4157 RtlCopyMemory(out
->EaName
, ea
->EaName
, ea
->EaNameLength
+ ea
->EaValueLength
+ 1);
4159 retlen
+= offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + ea
->EaNameLength
+ 1 + ea
->EaValueLength
;
4161 if (IrpSp
->Flags
& SL_RETURN_SINGLE_ENTRY
)
4165 if (ea
->NextEntryOffset
== 0)
4168 ea
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)ea
) + ea
->NextEntryOffset
);
4171 FILE_FULL_EA_INFORMATION
*ea
, *out
;
4174 if (IrpSp
->Flags
& SL_INDEX_SPECIFIED
) {
4175 // The index is 1-based
4176 if (IrpSp
->Parameters
.QueryEa
.EaIndex
== 0) {
4177 Status
= STATUS_NONEXISTENT_EA_ENTRY
;
4180 index
= IrpSp
->Parameters
.QueryEa
.EaIndex
- 1;
4181 } else if (IrpSp
->Flags
& SL_RESTART_SCAN
)
4182 index
= ccb
->ea_index
= 0;
4184 index
= ccb
->ea_index
;
4186 ea
= (FILE_FULL_EA_INFORMATION
*)fcb
->ea_xattr
.Buffer
;
4191 for (i
= 0; i
< index
; i
++) {
4192 if (ea
->NextEntryOffset
== 0) // last item
4195 ea
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)ea
) + ea
->NextEntryOffset
);
4202 UINT8 padding
= retlen
% 4 > 0 ? (4 - (retlen
% 4)) : 0;
4204 if (offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + ea
->EaNameLength
+ 1 + ea
->EaValueLength
> IrpSp
->Parameters
.QueryEa
.Length
- retlen
- padding
) {
4205 Status
= retlen
== 0 ? STATUS_BUFFER_TOO_SMALL
: STATUS_BUFFER_OVERFLOW
;
4212 out
->NextEntryOffset
= offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + out
->EaNameLength
+ 1 + out
->EaValueLength
+ padding
;
4213 out
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)out
) + out
->NextEntryOffset
);
4217 out
->NextEntryOffset
= 0;
4218 out
->Flags
= ea
->Flags
;
4219 out
->EaNameLength
= ea
->EaNameLength
;
4220 out
->EaValueLength
= ea
->EaValueLength
;
4221 RtlCopyMemory(out
->EaName
, ea
->EaName
, ea
->EaNameLength
+ ea
->EaValueLength
+ 1);
4223 retlen
+= offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + ea
->EaNameLength
+ 1 + ea
->EaValueLength
;
4225 if (!(IrpSp
->Flags
& SL_INDEX_SPECIFIED
))
4228 if (ea
->NextEntryOffset
== 0 || IrpSp
->Flags
& SL_RETURN_SINGLE_ENTRY
)
4231 ea
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)ea
) + ea
->NextEntryOffset
);
4235 Status
= STATUS_SUCCESS
;
4238 ExReleaseResourceLite(fcb
->Header
.Resource
);
4241 Irp
->IoStatus
.Status
= Status
;
4242 Irp
->IoStatus
.Information
= NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
? retlen
: 0;
4244 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
4248 IoSetTopLevelIrp(NULL
);
4250 FsRtlExitFileSystem();
4259 LIST_ENTRY list_entry
;
4262 NTSTATUS STDCALL
drv_set_ea(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
4263 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
4266 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
4267 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
4270 FILE_FULL_EA_INFORMATION
* ffei
;
4274 FILE_FULL_EA_INFORMATION
* ea
;
4279 TRACE("(%p, %p)\n", DeviceObject
, Irp
);
4281 FsRtlEnterFileSystem();
4283 top_level
= is_top_level(Irp
);
4285 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
4286 Status
= part0_passthrough(DeviceObject
, Irp
);
4290 if (Vcb
->readonly
) {
4291 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
4295 ffei
= map_user_buffer(Irp
);
4297 ERR("could not get output buffer\n");
4298 Status
= STATUS_INVALID_PARAMETER
;
4302 Status
= IoCheckEaBufferValidity(ffei
, IrpSp
->Parameters
.SetEa
.Length
, &offset
);
4303 if (!NT_SUCCESS(Status
)) {
4304 ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status
, offset
);
4309 ERR("no file object\n");
4310 Status
= STATUS_INVALID_PARAMETER
;
4314 fcb
= FileObject
->FsContext
;
4318 Status
= STATUS_INVALID_PARAMETER
;
4322 ccb
= FileObject
->FsContext2
;
4326 Status
= STATUS_INVALID_PARAMETER
;
4330 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& FILE_WRITE_EA
)) {
4331 WARN("insufficient privileges\n");
4332 Status
= STATUS_ACCESS_DENIED
;
4336 InitializeListHead(&ealist
);
4338 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
4340 if (fcb
->ea_xattr
.Length
> 0) {
4341 ea
= (FILE_FULL_EA_INFORMATION
*)fcb
->ea_xattr
.Buffer
;
4344 item
= ExAllocatePoolWithTag(PagedPool
, sizeof(ea_item
), ALLOC_TAG
);
4346 ERR("out of memory\n");
4347 Status
= STATUS_INSUFFICIENT_RESOURCES
;
4351 item
->name
.Length
= item
->name
.MaximumLength
= ea
->EaNameLength
;
4352 item
->name
.Buffer
= ea
->EaName
;
4354 item
->value
.Length
= item
->value
.MaximumLength
= ea
->EaValueLength
;
4355 item
->value
.Buffer
= &ea
->EaName
[ea
->EaNameLength
+ 1];
4357 item
->flags
= ea
->Flags
;
4359 InsertTailList(&ealist
, &item
->list_entry
);
4361 if (ea
->NextEntryOffset
== 0)
4364 ea
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)ea
) + ea
->NextEntryOffset
);
4374 s
.Length
= s
.MaximumLength
= ea
->EaNameLength
;
4375 s
.Buffer
= ea
->EaName
;
4377 RtlUpperString(&s
, &s
);
4380 while (le
!= &ealist
) {
4381 item
= CONTAINING_RECORD(le
, ea_item
, list_entry
);
4383 if (item
->name
.Length
== s
.Length
&&
4384 RtlCompareMemory(item
->name
.Buffer
, s
.Buffer
, s
.Length
) == s
.Length
) {
4385 item
->flags
= ea
->Flags
;
4386 item
->value
.Length
= item
->value
.MaximumLength
= ea
->EaValueLength
;
4387 item
->value
.Buffer
= &ea
->EaName
[ea
->EaNameLength
+ 1];
4396 item
= ExAllocatePoolWithTag(PagedPool
, sizeof(ea_item
), ALLOC_TAG
);
4398 ERR("out of memory\n");
4399 Status
= STATUS_INSUFFICIENT_RESOURCES
;
4403 item
->name
.Length
= item
->name
.MaximumLength
= ea
->EaNameLength
;
4404 item
->name
.Buffer
= ea
->EaName
;
4406 item
->value
.Length
= item
->value
.MaximumLength
= ea
->EaValueLength
;
4407 item
->value
.Buffer
= &ea
->EaName
[ea
->EaNameLength
+ 1];
4409 item
->flags
= ea
->Flags
;
4411 InsertTailList(&ealist
, &item
->list_entry
);
4414 if (ea
->NextEntryOffset
== 0)
4417 ea
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)ea
) + ea
->NextEntryOffset
);
4420 // remove entries with zero-length value
4422 while (le
!= &ealist
) {
4423 LIST_ENTRY
* le2
= le
->Flink
;
4425 item
= CONTAINING_RECORD(le
, ea_item
, list_entry
);
4427 if (item
->value
.Length
== 0) {
4428 RemoveEntryList(&item
->list_entry
);
4435 if (IsListEmpty(&ealist
)) {
4438 if (fcb
->ea_xattr
.Buffer
)
4439 ExFreePool(fcb
->ea_xattr
.Buffer
);
4441 fcb
->ea_xattr
.Length
= fcb
->ea_xattr
.MaximumLength
= 0;
4442 fcb
->ea_xattr
.Buffer
= NULL
;
4448 while (le
!= &ealist
) {
4449 item
= CONTAINING_RECORD(le
, ea_item
, list_entry
);
4452 size
+= 4 - (size
% 4);
4454 size
+= offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + item
->name
.Length
+ 1 + item
->value
.Length
;
4459 buf
= ExAllocatePoolWithTag(PagedPool
, size
, ALLOC_TAG
);
4461 ERR("out of memory\n");
4462 Status
= STATUS_INSUFFICIENT_RESOURCES
;
4466 oldbuf
= fcb
->ea_xattr
.Buffer
;
4468 fcb
->ea_xattr
.Length
= fcb
->ea_xattr
.MaximumLength
= size
;
4469 fcb
->ea_xattr
.Buffer
= buf
;
4475 while (le
!= &ealist
) {
4476 item
= CONTAINING_RECORD(le
, ea_item
, list_entry
);
4479 ea
->NextEntryOffset
= offsetof(FILE_FULL_EA_INFORMATION
, EaName
[0]) + ea
->EaNameLength
+ ea
->EaValueLength
;
4481 if (ea
->NextEntryOffset
% 4 > 0)
4482 ea
->NextEntryOffset
+= 4 - (ea
->NextEntryOffset
% 4);
4484 ea
= (FILE_FULL_EA_INFORMATION
*)(((UINT8
*)ea
) + ea
->NextEntryOffset
);
4486 ea
= (FILE_FULL_EA_INFORMATION
*)fcb
->ea_xattr
.Buffer
;
4488 ea
->NextEntryOffset
= 0;
4489 ea
->Flags
= item
->flags
;
4490 ea
->EaNameLength
= item
->name
.Length
;
4491 ea
->EaValueLength
= item
->value
.Length
;
4493 RtlCopyMemory(ea
->EaName
, item
->name
.Buffer
, item
->name
.Length
);
4494 ea
->EaName
[item
->name
.Length
] = 0;
4495 RtlCopyMemory(&ea
->EaName
[item
->name
.Length
+ 1], item
->value
.Buffer
, item
->value
.Length
);
4497 fcb
->ealen
+= 5 + item
->name
.Length
+ item
->value
.Length
;
4506 fcb
->ea_changed
= TRUE
;
4508 KeQuerySystemTime(&time
);
4509 win_time_to_unix(time
, &now
);
4511 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
4512 fcb
->inode_item
.sequence
++;
4514 if (!ccb
->user_set_change_time
)
4515 fcb
->inode_item
.st_ctime
= now
;
4517 fcb
->inode_item_changed
= TRUE
;
4518 mark_fcb_dirty(fcb
);
4520 send_notification_fileref(ccb
->fileref
, FILE_NOTIFY_CHANGE_EA
, FILE_ACTION_MODIFIED
);
4522 Status
= STATUS_SUCCESS
;
4525 ExReleaseResourceLite(fcb
->Header
.Resource
);
4527 while (!IsListEmpty(&ealist
)) {
4528 le
= RemoveHeadList(&ealist
);
4530 item
= CONTAINING_RECORD(le
, ea_item
, list_entry
);
4536 Irp
->IoStatus
.Status
= Status
;
4537 Irp
->IoStatus
.Information
= 0;
4539 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
4543 IoSetTopLevelIrp(NULL
);
4545 FsRtlExitFileSystem();