ReactOS.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
December
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
April
March
February
January
2005
December
November
October
September
August
July
June
May
April
March
February
January
2004
December
November
October
September
August
July
June
May
April
March
February
List overview
Download
Ros-diffs
November 2019
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
ros-diffs@reactos.org
24 participants
322 discussions
Start a n
N
ew thread
[reactos] 01/01: [SHELLBTRFS] Replace emplace_back by something less efficient if not avaible
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5f779048d30bb7fc44e85…
commit 5f779048d30bb7fc44e855289c3680706687ad66 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Nov 12 23:29:08 2019 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Nov 12 23:29:08 2019 +0100 [SHELLBTRFS] Replace emplace_back by something less efficient if not avaible --- dll/shellext/shellbtrfs/mountmgr_local.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dll/shellext/shellbtrfs/mountmgr_local.cpp b/dll/shellext/shellbtrfs/mountmgr_local.cpp index 061962369ff..45a47e68e15 100644 --- a/dll/shellext/shellbtrfs/mountmgr_local.cpp +++ b/dll/shellext/shellbtrfs/mountmgr_local.cpp @@ -217,7 +217,11 @@ vector<mountmgr_point> mountmgr::query_points(const wstring_view& symlink, const if (mmps->MountPoints[i].DeviceNameLength) mpdn = wstring_view((WCHAR*)((uint8_t*)mmps + mmps->MountPoints[i].DeviceNameOffset), mmps->MountPoints[i].DeviceNameLength / sizeof(WCHAR)); +#ifndef __REACTOS__ v.emplace_back(mpsl, mpuid, mpdn); +#else + v.push_back(mountmgr_point(mpsl, mpuid, mpdn)); +#endif } return v;
5 years, 1 month
1
0
0
0
[reactos] 01/01: [SHELLBTRFS] Addendum to 1725ddf
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a3c13c624f4a115f99560…
commit a3c13c624f4a115f99560990f065dd94e4526304 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Nov 12 23:12:48 2019 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Nov 12 23:12:48 2019 +0100 [SHELLBTRFS] Addendum to 1725ddf --- dll/shellext/shellbtrfs/mountmgr_local.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dll/shellext/shellbtrfs/mountmgr_local.cpp b/dll/shellext/shellbtrfs/mountmgr_local.cpp index ee7901e1f2a..061962369ff 100644 --- a/dll/shellext/shellbtrfs/mountmgr_local.cpp +++ b/dll/shellext/shellbtrfs/mountmgr_local.cpp @@ -48,7 +48,11 @@ void mountmgr::create_point(const wstring_view& symlink, const wstring_view& dev memcpy((uint8_t*)mcpi + mcpi->DeviceNameOffset, device.data(), device.length() * sizeof(WCHAR)); Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_CREATE_POINT, +#ifndef __REACTOS__ buf.data(), (ULONG)buf.size(), nullptr, 0); +#else + &buf[0], (ULONG)buf.size(), nullptr, 0); +#endif if (!NT_SUCCESS(Status)) throw ntstatus_error(Status); @@ -103,13 +107,21 @@ void mountmgr::delete_points(const wstring_view& symlink, const wstring_view& un #endif Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS, +#ifndef __REACTOS__ buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); +#else + &buf[0], (ULONG)buf.size(), &buf2[0], (ULONG)buf2.size()); +#endif if (Status == STATUS_BUFFER_OVERFLOW) { buf2.resize(mmps->Size); Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS, +#ifndef __REACTOS__ buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); +#else + &buf[0], (ULONG)buf.size(), &buf2[0], (ULONG)buf2.size()); +#endif } if (!NT_SUCCESS(Status)) @@ -166,7 +178,11 @@ vector<mountmgr_point> mountmgr::query_points(const wstring_view& symlink, const #endif Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS, +#ifndef __REACTOS__ buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); +#else + &buf[0], (ULONG)buf.size(), &buf2[0], (ULONG)buf2.size()); +#endif if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) throw ntstatus_error(Status); @@ -179,7 +195,11 @@ vector<mountmgr_point> mountmgr::query_points(const wstring_view& symlink, const #endif Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS, +#ifndef __REACTOS__ buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size()); +#else + &buf[0], (ULONG)buf.size(), &buf2[0], (ULONG)buf2.size()); +#endif if (!NT_SUCCESS(Status)) throw ntstatus_error(Status);
5 years, 1 month
1
0
0
0
[reactos] 01/01: [SHELLBTRFS] Fix build? (Not sure why it works locally...)
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a837184300041ea328a18…
commit a837184300041ea328a187f44488f45252aa49f6 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Nov 12 21:52:16 2019 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Nov 12 21:52:16 2019 +0100 [SHELLBTRFS] Fix build? (Not sure why it works locally...) --- dll/shellext/shellbtrfs/shellext.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dll/shellext/shellbtrfs/shellext.h b/dll/shellext/shellbtrfs/shellext.h index af7776cb5a3..cfa09779213 100755 --- a/dll/shellext/shellbtrfs/shellext.h +++ b/dll/shellext/shellbtrfs/shellext.h @@ -42,6 +42,7 @@ #include <strsafe.h> #include <ndk/iofuncs.h> #include <ndk/obfuncs.h> +#include <ndk/rtlfuncs.h> #endif #include <string> #ifdef __REACTOS__
5 years, 1 month
1
0
0
0
[reactos] 01/01: [DOC] Addendum to aed50d7
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4eefc85c9020f923daead…
commit 4eefc85c9020f923daead4610ac33a03e76f9c48 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Nov 12 21:46:36 2019 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Nov 12 21:46:36 2019 +0100 [DOC] Addendum to aed50d7 --- media/doc/README.FSD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/doc/README.FSD b/media/doc/README.FSD index ed4c991c0c3..859b183edcc 100644 --- a/media/doc/README.FSD +++ b/media/doc/README.FSD @@ -4,7 +4,7 @@ The following FSD are shared with:
https://github.com/maharmstone/btrfs
. reactos/drivers/filesystems/btrfs # Synced to 1.5 -reactos/dll/shellext/shellbtrfs # Synced to 1.1 +reactos/dll/shellext/shellbtrfs # Synced to 1.5 reactos/sdk/lib/fslib/btrfslib # Synced to 1.5 The following FSD are shared with:
http://www.ext2fsd.com/
5 years, 1 month
1
0
0
0
[reactos] 02/02: [UBTRFS] Upgrade to 1.5
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=86ee9b0cc20186afe9e2f…
commit 86ee9b0cc20186afe9e2f1c27e24c0e8da206c66 Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Nov 12 19:34:14 2019 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Nov 12 19:35:43 2019 +0100 [UBTRFS] Upgrade to 1.5 CORE-16494 --- dll/win32/ubtrfs/ubtrfs.rc | 8 +-- media/doc/README.FSD | 2 +- sdk/lib/fslib/btrfslib/btrfslib.c | 108 ++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 27 deletions(-) diff --git a/dll/win32/ubtrfs/ubtrfs.rc b/dll/win32/ubtrfs/ubtrfs.rc index 1292452a5cd..1720597df5b 100644 --- a/dll/win32/ubtrfs/ubtrfs.rc +++ b/dll/win32/ubtrfs/ubtrfs.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,4,0,0 - PRODUCTVERSION 1,4,0,0 + FILEVERSION 1,5,0,0 + PRODUCTVERSION 1,5,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "Btrfs utility DLL" - VALUE "FileVersion", "1.4" + VALUE "FileVersion", "1.5" VALUE "InternalName", "ubtrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19" VALUE "OriginalFilename", "ubtrfs.dll" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.4" + VALUE "ProductVersion", "1.5" END END BLOCK "VarFileInfo" diff --git a/media/doc/README.FSD b/media/doc/README.FSD index 9ce6e3a7d29..ed4c991c0c3 100644 --- a/media/doc/README.FSD +++ b/media/doc/README.FSD @@ -5,7 +5,7 @@ The following FSD are shared with:
https://github.com/maharmstone/btrfs
. reactos/drivers/filesystems/btrfs # Synced to 1.5 reactos/dll/shellext/shellbtrfs # Synced to 1.1 -reactos/sdk/lib/fslib/btrfslib # Synced to 1.4 +reactos/sdk/lib/fslib/btrfslib # Synced to 1.5 The following FSD are shared with:
http://www.ext2fsd.com/
diff --git a/sdk/lib/fslib/btrfslib/btrfslib.c b/sdk/lib/fslib/btrfslib/btrfslib.c index ec9fe387037..254873089df 100644 --- a/sdk/lib/fslib/btrfslib/btrfslib.c +++ b/sdk/lib/fslib/btrfslib/btrfslib.c @@ -803,7 +803,7 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro sb->chunk_tree_addr = chunk_root->header.address; sb->total_bytes = dev->dev_item.num_bytes; sb->bytes_used = bytes_used; - sb->root_dir_objectid = 6; + sb->root_dir_objectid = BTRFS_ROOT_TREEDIR; sb->num_devices = 1; sb->sector_size = sector_size; sb->node_size = node_size; @@ -836,14 +836,14 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro } #ifndef __REACTOS__ - utf8len = WideCharToMultiByte(CP_UTF8, 0, label->Buffer, label->Length, NULL, 0, NULL, NULL); + utf8len = WideCharToMultiByte(CP_UTF8, 0, label->Buffer, label->Length / sizeof(WCHAR), NULL, 0, NULL, NULL); if (utf8len == 0 || utf8len > MAX_LABEL_SIZE) { free(sb); return STATUS_INVALID_VOLUME_LABEL; } - if (WideCharToMultiByte(CP_UTF8, 0, label->Buffer, label->Length, sb->label, utf8len, NULL, NULL) == 0) { + if (WideCharToMultiByte(CP_UTF8, 0, label->Buffer, label->Length / sizeof(WCHAR), sb->label, utf8len, NULL, NULL) == 0) { free(sb); return STATUS_INVALID_VOLUME_LABEL; } @@ -929,9 +929,29 @@ GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime) } #endif +static void add_inode_ref(btrfs_root* r, uint64_t inode, uint64_t parent, uint64_t index, const char* name) { + uint16_t name_len = (uint16_t)strlen(name); +#ifndef __REACTOS__ + INODE_REF* ir = malloc(offsetof(INODE_REF, name[0]) + name_len); +#else + INODE_REF* ir = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(INODE_REF, name[0]) + name_len); +#endif + + ir->index = 0; + ir->n = name_len; + memcpy(ir->name, name, name_len); + + add_item(r, inode, TYPE_INODE_REF, parent, ir, (uint16_t)offsetof(INODE_REF, name[0]) + ir->n); + +#ifndef __REACTOS__ + free(ir); +#else + RtlFreeHeap(RtlGetProcessHeap(), 0, ir); +#endif +} + static void init_fs_tree(btrfs_root* r, uint32_t node_size) { INODE_ITEM ii; - INODE_REF* ir; FILETIME filetime; LARGE_INTEGER time; @@ -951,24 +971,7 @@ static void init_fs_tree(btrfs_root* r, uint32_t node_size) { add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM)); -#ifndef __REACTOS__ - ir = malloc(sizeof(INODE_REF) - 1 + 2); -#else - ir = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(INODE_REF) - 1 + 2); -#endif - - ir->index = 0; - ir->n = 2; - ir->name[0] = '.'; - ir->name[1] = '.'; - - add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, sizeof(INODE_REF) - 1 + ir->n); - -#ifndef __REACTOS__ - free(ir); -#else - RtlFreeHeap(RtlGetProcessHeap(), 0, ir); -#endif + add_inode_ref(r, SUBVOL_ROOT_INODE, SUBVOL_ROOT_INODE, 0, ".."); } static void add_block_group_items(LIST_ENTRY* chunks, btrfs_root* extent_root) { @@ -1061,6 +1064,65 @@ static BOOL is_ssd(HANDLE h) { return FALSE; } +static void add_dir_item(btrfs_root* root, uint64_t inode, uint32_t hash, uint64_t key_objid, uint8_t key_type, + uint64_t key_offset, uint64_t transid, uint8_t type, const char* name) { + uint16_t name_len = (uint16_t)strlen(name); +#ifndef __REACTOS__ + DIR_ITEM* di = malloc(offsetof(DIR_ITEM, name[0]) + name_len); +#else + DIR_ITEM* di = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(DIR_ITEM, name[0]) + name_len); +#endif + + di->key.obj_id = key_objid; + di->key.obj_type = key_type; + di->key.offset = key_offset; + di->transid = transid; + di->m = 0; + di->n = name_len; + di->type = type; + memcpy(di->name, name, name_len); + + add_item(root, inode, TYPE_DIR_ITEM, hash, di, (uint16_t)(offsetof(DIR_ITEM, name[0]) + di->m + di->n)); + +#ifndef __REACTOS__ + free(di); +#else + RtlFreeHeap(RtlGetProcessHeap(), 0, di); +#endif +} + +static void set_default_subvol(btrfs_root* root_root, uint32_t node_size) { + INODE_ITEM ii; + FILETIME filetime; + LARGE_INTEGER time; + + static const char default_subvol[] = "default"; + static const uint32_t default_hash = 0x8dbfc2d2; + + add_inode_ref(root_root, BTRFS_ROOT_FSTREE, BTRFS_ROOT_TREEDIR, 0, default_subvol); + + memset(&ii, 0, sizeof(INODE_ITEM)); + + ii.generation = 1; + ii.st_blocks = node_size; + ii.st_nlink = 1; + ii.st_mode = 040755; + + GetSystemTimeAsFileTime(&filetime); + time.LowPart = filetime.dwLowDateTime; + time.HighPart = filetime.dwHighDateTime; + + win_time_to_unix(time, &ii.st_atime); + ii.st_ctime = ii.st_mtime = ii.otime = ii.st_atime; + + add_item(root_root, BTRFS_ROOT_TREEDIR, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM)); + + add_inode_ref(root_root, BTRFS_ROOT_TREEDIR, BTRFS_ROOT_TREEDIR, 0, ".."); + + add_dir_item(root_root, BTRFS_ROOT_TREEDIR, default_hash, BTRFS_ROOT_FSTREE, TYPE_ROOT_ITEM, + 0xffffffffffffffff, 0, BTRFS_TYPE_DIRECTORY, default_subvol); +} + static NTSTATUS write_btrfs(HANDLE h, uint64_t size, PUNICODE_STRING label, uint32_t sector_size, uint32_t node_size, uint64_t incompat_flags) { NTSTATUS Status; LIST_ENTRY roots, chunks; @@ -1121,6 +1183,8 @@ static NTSTATUS write_btrfs(HANDLE h, uint64_t size, PUNICODE_STRING label, uint add_item(chunk_root, 1, TYPE_DEV_ITEM, dev.dev_item.dev_id, &dev.dev_item, sizeof(DEV_ITEM)); + set_default_subvol(root_root, node_size); + init_fs_tree(fs_root, node_size); init_fs_tree(reloc_root, node_size);
5 years, 1 month
1
0
0
0
[reactos] 01/02: [BTRFS] Upgrade to 1.5
by Pierre Schweitzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=62e630de4c8c43542a04a…
commit 62e630de4c8c43542a04a848a0f2abf89e15f4ed Author: Pierre Schweitzer <pierre(a)reactos.org> AuthorDate: Tue Nov 12 19:32:46 2019 +0100 Commit: Pierre Schweitzer <pierre(a)reactos.org> CommitDate: Tue Nov 12 19:35:43 2019 +0100 [BTRFS] Upgrade to 1.5 CORE-16494 --- drivers/filesystems/btrfs/balance.c | 26 +- drivers/filesystems/btrfs/boot.c | 140 ++++- drivers/filesystems/btrfs/btrfs.c | 523 +++++++++------- drivers/filesystems/btrfs/btrfs.h | 1 + drivers/filesystems/btrfs/btrfs.rc | 8 +- drivers/filesystems/btrfs/btrfs_drv.h | 110 +++- drivers/filesystems/btrfs/btrfsioctl.h | 1 + drivers/filesystems/btrfs/cache.c | 24 +- drivers/filesystems/btrfs/create.c | 157 ++++- drivers/filesystems/btrfs/devctrl.c | 15 + drivers/filesystems/btrfs/dirctrl.c | 4 +- drivers/filesystems/btrfs/fastio.c | 28 +- drivers/filesystems/btrfs/fileinfo.c | 1033 ++++++++++++++++++++++++++++++- drivers/filesystems/btrfs/flushthread.c | 23 +- drivers/filesystems/btrfs/fsctl.c | 207 +++++-- drivers/filesystems/btrfs/fsrtl.c | 2 +- drivers/filesystems/btrfs/pnp.c | 56 +- drivers/filesystems/btrfs/read.c | 5 +- drivers/filesystems/btrfs/registry.c | 9 +- drivers/filesystems/btrfs/reparse.c | 8 +- drivers/filesystems/btrfs/scrub.c | 5 +- drivers/filesystems/btrfs/search.c | 22 + drivers/filesystems/btrfs/security.c | 12 +- drivers/filesystems/btrfs/send.c | 5 +- drivers/filesystems/btrfs/volume.c | 254 +++++--- drivers/filesystems/btrfs/write.c | 40 +- media/doc/README.FSD | 2 +- 27 files changed, 2185 insertions(+), 535 deletions(-) diff --git a/drivers/filesystems/btrfs/balance.c b/drivers/filesystems/btrfs/balance.c index b7794125deb..1a2c6a2dc6a 100644 --- a/drivers/filesystems/btrfs/balance.c +++ b/drivers/filesystems/btrfs/balance.c @@ -1037,6 +1037,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree tw->address = mr->new_address; tw->length = Vcb->superblock.node_size; tw->data = (uint8_t*)mr->data; + tw->allocated = false; if (IsListEmpty(&tree_writes)) InsertTailList(&tree_writes, &tw->list_entry); @@ -1089,6 +1090,10 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree end: while (!IsListEmpty(&tree_writes)) { tree_write* tw = CONTAINING_RECORD(RemoveHeadList(&tree_writes), tree_write, list_entry); + + if (tw->allocated) + ExFreePool(tw->data); + ExFreePool(tw); } @@ -1203,6 +1208,9 @@ end: ExFreePool(ref); } + if (mr->data) + ExFreePool(mr->data); + ExFreePool(mr); } @@ -2187,6 +2195,9 @@ end: ExFreePool(ref); } + if (mr->data) + ExFreePool(mr->data); + ExFreePool(mr); } @@ -3499,6 +3510,7 @@ end: NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE processor_mode) { NTSTATUS Status; btrfs_start_balance* bsb = (btrfs_start_balance*)data; + OBJECT_ATTRIBUTES oa; uint8_t i; if (length < sizeof(btrfs_start_balance) || !data) @@ -3599,7 +3611,9 @@ NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESS Vcb->balance.status = STATUS_SUCCESS; KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused); - Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); return Status; @@ -3613,6 +3627,7 @@ NTSTATUS look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_ex traverse_ptr tp; NTSTATUS Status; BALANCE_ITEM* bi; + OBJECT_ATTRIBUTES oa; int i; searchkey.obj_id = BALANCE_ITEM_ID; @@ -3679,7 +3694,9 @@ NTSTATUS look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_ex Vcb->balance.status = STATUS_SUCCESS; KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused); - Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); return Status; @@ -3783,6 +3800,7 @@ NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, KPROCESS NTSTATUS Status; int i; uint64_t num_rw_devices; + OBJECT_ATTRIBUTES oa; TRACE("(%p, %p, %x)\n", Vcb, data, length); @@ -3876,7 +3894,9 @@ NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, KPROCESS Vcb->balance.status = STATUS_SUCCESS; KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused); - Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); dev->reloc = false; diff --git a/drivers/filesystems/btrfs/boot.c b/drivers/filesystems/btrfs/boot.c index f73fc38b4e8..34fee170ec7 100755 --- a/drivers/filesystems/btrfs/boot.c +++ b/drivers/filesystems/btrfs/boot.c @@ -27,11 +27,26 @@ extern ERESOURCE pdo_list_lock; extern LIST_ENTRY pdo_list; +extern ERESOURCE boot_lock; +extern PDRIVER_OBJECT drvobj; #ifndef _MSC_VER NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR* pszFormat, ...); // not in mingw #endif +// Not in any headers? Windbg knows about it though. +#define DOE_START_PENDING 0x10 + +// Just as much as we need - the version in mingw is truncated still further +typedef struct { + CSHORT Type; + USHORT Size; + PDEVICE_OBJECT DeviceObject; + ULONG PowerFlags; + void* Dope; + ULONG ExtensionFlags; +} DEVOBJ_EXTENSION2; + static bool get_system_root_partition(uint32_t* disk_num, uint32_t* partition_num) { NTSTATUS Status; HANDLE h; @@ -191,6 +206,65 @@ static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID ERR("IoCreateSymbolicLink returned %08x\n", Status); } +static void mountmgr_notification(BTRFS_UUID* uuid) { + UNICODE_STRING mmdevpath; + NTSTATUS Status; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT mountmgr; + ULONG mmtnlen; + MOUNTMGR_TARGET_NAME* mmtn; + WCHAR* w; +#ifdef __REACTOS__ + unsigned int i; +#endif + + RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); + Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr); + if (!NT_SUCCESS(Status)) { + ERR("IoGetDeviceObjectPointer returned %08x\n", Status); + return; + } + + mmtnlen = offsetof(MOUNTMGR_TARGET_NAME, DeviceName[0]) + sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR)); + + mmtn = ExAllocatePoolWithTag(NonPagedPool, mmtnlen, ALLOC_TAG); + if (!mmtn) { + ERR("out of memory\n"); + return; + } + + mmtn->DeviceNameLength = sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR)); + + RtlCopyMemory(mmtn->DeviceName, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)); + + w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1]; + +#ifndef __REACTOS__ + for (unsigned int i = 0; i < 16; i++) { +#else + for (i = 0; i < 16; i++) { +#endif + *w = hex_digit(uuid->uuid[i] >> 4); w++; + *w = hex_digit(uuid->uuid[i] & 0xf); w++; + + if (i == 3 || i == 5 || i == 7 || i == 9) { + *w = L'-'; + w++; + } + } + + *w = L'}'; + + Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mmtn, mmtnlen, NULL, 0, false, NULL); + if (!NT_SUCCESS(Status)) { + ERR("IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION returned %08x\n", Status); + ExFreePool(mmtn); + return; + } + + ExFreePool(mmtn); +} + /* If booting from Btrfs, Windows will pass the device object for the raw partition to * mount_vol - which is no good to us, as we only use the \Device\Btrfs{} devices we * create so that RAID works correctly. @@ -205,9 +279,14 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULO uint32_t disk_num, partition_num; LIST_ENTRY* le; bool done = false; + PDEVICE_OBJECT pdo_to_add = NULL; TRACE("(%p, %p, %u)\n", DriverObject, Context, Count); + // wait for any PNP notifications in progress to finish + ExAcquireResourceExclusiveLite(&boot_lock, TRUE); + ExReleaseResourceLite(&boot_lock); + if (!get_system_root_partition(&disk_num, &partition_num)) return; @@ -230,19 +309,76 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULO if (vc->disk_num == disk_num && vc->part_num == partition_num) { change_symlink(disk_num, partition_num, &pdode->uuid); done = true; + + if (!pdode->vde) + pdo_to_add = pdode->pdo; + break; } le2 = le2->Flink; } - ExReleaseResourceLite(&pdode->child_lock); + if (done) { + le2 = pdode->children.Flink; + + while (le2 != &pdode->children) { + volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); + + /* On Windows 7 we need to clear the DO_SYSTEM_BOOT_PARTITION flag of + * all of our underlying partition objects - otherwise IopMountVolume + * will bugcheck with UNMOUNTABLE_BOOT_VOLUME when it tries and fails + * to mount one. */ + if (vc->devobj) { + PDEVICE_OBJECT dev = vc->devobj; + + ObReferenceObject(dev); + + while (dev) { + PDEVICE_OBJECT dev2 = IoGetLowerDeviceObject(dev); + + dev->Flags &= ~DO_SYSTEM_BOOT_PARTITION; + + ObDereferenceObject(dev); + + dev = dev2; + } + } + + le2 = le2->Flink; + } + + ExReleaseResourceLite(&pdode->child_lock); - if (done) break; + } + + ExReleaseResourceLite(&pdode->child_lock); le = le->Flink; } ExReleaseResourceLite(&pdo_list_lock); + + // If our FS depends on volumes that aren't there when we do our IoRegisterPlugPlayNotification calls + // in DriverEntry, bus_query_device_relations won't get called until it's too late. We need to do our + // own call to AddDevice here as a result. We need to clear the DOE_START_PENDING bits, or NtOpenFile + // will return STATUS_NO_SUCH_DEVICE. + if (pdo_to_add) { + pdo_device_extension* pdode = pdo_to_add->DeviceExtension; + + AddDevice(drvobj, pdo_to_add); + + // To stop Windows sneakily setting DOE_START_PENDING + pdode->dont_report = true; + + if (pdo_to_add->DeviceObjectExtension) { + ((DEVOBJ_EXTENSION2*)pdo_to_add->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING; + + if (pdode && pdode->vde && pdode->vde->device) + ((DEVOBJ_EXTENSION2*)pdode->vde->device->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING; + } + + mountmgr_notification(&pdode->uuid); + } } diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c index 2977667de9a..2080c5d70f7 100644 --- a/drivers/filesystems/btrfs/btrfs.c +++ b/drivers/filesystems/btrfs/btrfs.c @@ -86,6 +86,7 @@ uint32_t mount_no_trim = 0; uint32_t mount_clear_cache = 0; uint32_t mount_allow_degraded = 0; uint32_t mount_readonly = 0; +uint32_t mount_no_root_dir = 0; uint32_t no_pnp = 0; bool log_started = false; UNICODE_STRING log_device, log_file, registry_path; @@ -98,6 +99,8 @@ tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx; tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp; tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter; tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer; +tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest; +tFsRtlAreThereCurrentOrInProgressFileLocks fFsRtlAreThereCurrentOrInProgressFileLocks; bool diskacc = false; void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 = NULL; ERESOURCE pdo_list_lock, mapping_lock; @@ -107,6 +110,7 @@ HANDLE degraded_wait_handle = NULL, mountmgr_thread_handle = NULL; bool degraded_wait = true; KEVENT mountmgr_thread_event; bool shutting_down = false; +ERESOURCE boot_lock; #ifdef _DEBUG PFILE_OBJECT comfo = NULL; @@ -284,31 +288,6 @@ static void __stdcall DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { TRACE("(%p)\n", DriverObject); - free_cache(); - - IoUnregisterFileSystem(DriverObject->DeviceObject); - - if (notification_entry2) { - if (fIoUnregisterPlugPlayNotificationEx) - fIoUnregisterPlugPlayNotificationEx(notification_entry2); - else - IoUnregisterPlugPlayNotification(notification_entry2); - } - - if (notification_entry3) { - if (fIoUnregisterPlugPlayNotificationEx) - fIoUnregisterPlugPlayNotificationEx(notification_entry3); - else - IoUnregisterPlugPlayNotification(notification_entry3); - } - - if (notification_entry) { - if (fIoUnregisterPlugPlayNotificationEx) - fIoUnregisterPlugPlayNotificationEx(notification_entry); - else - IoUnregisterPlugPlayNotification(notification_entry); - } - dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name; dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR); @@ -504,7 +483,6 @@ static NTSTATUS __stdcall drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP IrpSp = IoGetCurrentIrpStackLocation(Irp); - // FIXME - unmount if called for volume // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting Status = close_file(IrpSp->FileObject, Irp); @@ -560,6 +538,8 @@ static NTSTATUS __stdcall drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _I goto end; } + FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); + Irp->IoStatus.Information = 0; fcb->Header.IsFastIoPossible = fast_io_possible(fcb); @@ -615,6 +595,8 @@ static void calculate_total_space(_In_ device_extension* Vcb, _Out_ uint64_t* to } #ifndef __REACTOS__ +#define INIT_UNICODE_STRING(var, val) UNICODE_STRING us##var; us##var.Buffer = (WCHAR*)val; us##var.Length = us##var.MaximumLength = sizeof(val) - sizeof(WCHAR); + // This function exists because we have to lie about our FS type in certain situations. // MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match, // it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working. @@ -631,17 +613,10 @@ static bool lie_about_fs_type() { ULONG_PTR wow64info; #endif - static const WCHAR mpr[] = L"MPR.DLL"; - static const WCHAR cmd[] = L"CMD.EXE"; - static const WCHAR fsutil[] = L"FSUTIL.EXE"; - UNICODE_STRING mprus, cmdus, fsutilus; - - mprus.Buffer = (WCHAR*)mpr; - mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR); - cmdus.Buffer = (WCHAR*)cmd; - cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR); - fsutilus.Buffer = (WCHAR*)fsutil; - fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR); + INIT_UNICODE_STRING(mpr, L"MPR.DLL"); + INIT_UNICODE_STRING(cmd, L"CMD.EXE"); + INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE"); + INIT_UNICODE_STRING(storsvc, L"STORSVC.DLL"); if (!PsGetCurrentProcess()) return false; @@ -673,31 +648,40 @@ static bool lie_about_fs_type() { LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(le, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); bool blacklist = false; - if (entry->FullDllName.Length >= mprus.Length) { + if (entry->FullDllName.Length >= usmpr.Length) { + UNICODE_STRING name; + + name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usmpr.Length) / sizeof(WCHAR)]; + name.Length = name.MaximumLength = usmpr.Length; + + blacklist = FsRtlAreNamesEqual(&name, &usmpr, true, NULL); + } + + if (!blacklist && entry->FullDllName.Length >= uscmd.Length) { UNICODE_STRING name; - name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - mprus.Length) / sizeof(WCHAR)]; - name.Length = name.MaximumLength = mprus.Length; + name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - uscmd.Length) / sizeof(WCHAR)]; + name.Length = name.MaximumLength = uscmd.Length; - blacklist = FsRtlAreNamesEqual(&name, &mprus, true, NULL); + blacklist = FsRtlAreNamesEqual(&name, &uscmd, true, NULL); } - if (!blacklist && entry->FullDllName.Length >= cmdus.Length) { + if (!blacklist && entry->FullDllName.Length >= usfsutil.Length) { UNICODE_STRING name; - name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - cmdus.Length) / sizeof(WCHAR)]; - name.Length = name.MaximumLength = cmdus.Length; + name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usfsutil.Length) / sizeof(WCHAR)]; + name.Length = name.MaximumLength = usfsutil.Length; - blacklist = FsRtlAreNamesEqual(&name, &cmdus, true, NULL); + blacklist = FsRtlAreNamesEqual(&name, &usfsutil, true, NULL); } - if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) { + if (!blacklist && entry->FullDllName.Length >= usstorsvc.Length) { UNICODE_STRING name; - name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - fsutilus.Length) / sizeof(WCHAR)]; - name.Length = name.MaximumLength = fsutilus.Length; + name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usstorsvc.Length) / sizeof(WCHAR)]; + name.Length = name.MaximumLength = usstorsvc.Length; - blacklist = FsRtlAreNamesEqual(&name, &fsutilus, true, NULL); + blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL); } if (blacklist) { @@ -1451,95 +1435,6 @@ end: return Status; } -static WCHAR* file_desc_fcb(_In_ fcb* fcb) { - char s[60]; - NTSTATUS Status; - UNICODE_STRING us; - ANSI_STRING as; - - if (fcb->debug_desc) - return fcb->debug_desc; - - if (fcb == fcb->Vcb->volume_fcb) - return L"volume FCB"; - - fcb->debug_desc = ExAllocatePoolWithTag(PagedPool, 60 * sizeof(WCHAR), ALLOC_TAG); - if (!fcb->debug_desc) - return L"(memory error)"; - - // I know this is pretty hackish... - // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf - // without the CRT, which breaks drivers. - - sprintf(s, "subvol %x, inode %x", (uint32_t)fcb->subvol->id, (uint32_t)fcb->inode); - - as.Buffer = s; - as.Length = as.MaximumLength = (USHORT)strlen(s); - - us.Buffer = fcb->debug_desc; - us.MaximumLength = 60 * sizeof(WCHAR); - us.Length = 0; - - Status = RtlAnsiStringToUnicodeString(&us, &as, false); - if (!NT_SUCCESS(Status)) - return L"(RtlAnsiStringToUnicodeString error)"; - - us.Buffer[us.Length / sizeof(WCHAR)] = 0; - - return fcb->debug_desc; -} - -WCHAR* file_desc_fileref(_In_ file_ref* fileref) { - NTSTATUS Status; - UNICODE_STRING fn; - ULONG reqlen; - - if (fileref->debug_desc) - return fileref->debug_desc; - - fn.Length = fn.MaximumLength = 0; - Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); - if (Status != STATUS_BUFFER_OVERFLOW) - return L"ERROR"; - - if (reqlen > 0xffff - sizeof(WCHAR)) - return L"(too long)"; - - fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG); - if (!fileref->debug_desc) - return L"(memory error)"; - - fn.Buffer = fileref->debug_desc; - fn.Length = 0; - fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR)); - - Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); - if (!NT_SUCCESS(Status)) { - ExFreePool(fileref->debug_desc); - fileref->debug_desc = NULL; - return L"ERROR"; - } - - fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0; - - return fileref->debug_desc; -} - -_Ret_z_ -WCHAR* file_desc(_In_ PFILE_OBJECT FileObject) { - fcb* fcb = FileObject->FsContext; - ccb* ccb = FileObject->FsContext2; - file_ref* fileref = ccb ? ccb->fileref : NULL; - - if (fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE) - return L"(paging file)"; - - if (fileref) - return file_desc_fileref(fileref); - else - return file_desc_fcb(fcb); -} - void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { UNICODE_STRING fn; NTSTATUS Status; @@ -1580,7 +1475,7 @@ void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, ExFreePool(fn.Buffer); } -void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { +static void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { fcb* fcb = fileref->fcb; LIST_ENTRY* le; NTSTATUS Status; @@ -1661,6 +1556,61 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ExReleaseResourceLite(&fcb->Vcb->fileref_lock); } +typedef struct { + file_ref* fileref; + ULONG filter_match; + ULONG action; + PUNICODE_STRING stream; + PIO_WORKITEM work_item; +} notification_fcb; + +_Function_class_(IO_WORKITEM_ROUTINE) +static void __stdcall notification_work_item(PDEVICE_OBJECT DeviceObject, PVOID con) { + notification_fcb* nf = con; + + UNUSED(DeviceObject); + + ExAcquireResourceSharedLite(&nf->fileref->fcb->Vcb->tree_lock, TRUE); // protect us from fileref being reaped + + send_notification_fcb(nf->fileref, nf->filter_match, nf->action, nf->stream); + + free_fileref(nf->fileref); + + ExReleaseResourceLite(&nf->fileref->fcb->Vcb->tree_lock); + + IoFreeWorkItem(nf->work_item); + + ExFreePool(nf); +} + +void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { + notification_fcb* nf; + PIO_WORKITEM work_item; + + nf = ExAllocatePoolWithTag(PagedPool, sizeof(notification_fcb), ALLOC_TAG); + if (!nf) { + ERR("out of memory\n"); + return; + } + + work_item = IoAllocateWorkItem(master_devobj); + if (!work_item) { + ERR("out of memory\n"); + ExFreePool(nf); + return; + } + + InterlockedIncrement(&fileref->refcount); + + nf->fileref = fileref; + nf->filter_match = filter_match; + nf->action = action; + nf->stream = stream; + nf->work_item = work_item; + + IoQueueWorkItem(work_item, notification_work_item, DelayedWorkQueue, nf); +} + void mark_fcb_dirty(_In_ fcb* fcb) { if (!fcb->dirty) { #ifdef DEBUG_FCB_REFCOUNTS @@ -1746,9 +1696,6 @@ void reap_fcb(fcb* fcb) { if (fcb->adsdata.Buffer) ExFreePool(fcb->adsdata.Buffer); - if (fcb->debug_desc) - ExFreePool(fcb->debug_desc); - while (!IsListEmpty(&fcb->extents)) { LIST_ENTRY* le = RemoveHeadList(&fcb->extents); extent* ext = CONTAINING_RECORD(le, extent, list_entry); @@ -1795,6 +1742,7 @@ void reap_fcb(fcb* fcb) { ExFreePool(fcb->hash_ptrs_uc); FsRtlUninitializeFileLock(&fcb->lock); + FsRtlUninitializeOplock(fcb_oplock(fcb)); if (fcb->pool_type == NonPagedPool) ExFreePool(fcb); @@ -1842,9 +1790,6 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) { // FIXME - do delete if needed - if (fr->debug_desc) - ExFreePool(fr->debug_desc); - ExDeleteResourceLite(&fr->nonpaged->fileref_lock); ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged); @@ -1869,6 +1814,9 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) { free_fcb(fr->fcb); + if (fr->oldutf8.Buffer) + ExFreePool(fr->oldutf8.Buffer); + ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr); } @@ -1911,7 +1859,7 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { ccb = FileObject->FsContext2; - TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb); + TRACE("close called for fcb %p)\n", fcb); // FIXME - make sure notification gets sent if file is being deleted @@ -1980,9 +1928,13 @@ void uninit(_In_ device_extension* Vcb) { ExReleaseResourceLite(&Vcb->tree_lock); } + if (Vcb->vde && Vcb->vde->mounted_device == Vcb->devobj) + Vcb->vde->mounted_device = NULL; + IoAcquireVpbSpinLock(&irql); Vcb->Vpb->Flags &= ~VPB_MOUNTED; Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; + Vcb->Vpb->DeviceObject = NULL; IoReleaseVpbSpinLock(irql); RemoveEntryList(&Vcb->list_entry); @@ -2071,6 +2023,21 @@ void uninit(_In_ device_extension* Vcb) { le = le->Flink; } + while (!IsListEmpty(&Vcb->all_fcbs)) { + fcb* fcb = CONTAINING_RECORD(Vcb->all_fcbs.Flink, struct _fcb, list_entry_all); + + reap_fcb(fcb); + } + + while (!IsListEmpty(&Vcb->sys_chunks)) { + sys_chunk* sc = CONTAINING_RECORD(RemoveHeadList(&Vcb->sys_chunks), sys_chunk, list_entry); + + if (sc->data) + ExFreePool(sc->data); + + ExFreePool(sc); + } + while (!IsListEmpty(&Vcb->roots)) { root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->roots), root, list_entry); @@ -2111,8 +2078,6 @@ void uninit(_In_ device_extension* Vcb) { ExFreePool(c); } - // FIXME - free any open fcbs? - while (!IsListEmpty(&Vcb->devices)) { device* dev = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry); @@ -2156,6 +2121,11 @@ void uninit(_In_ device_extension* Vcb) { ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); ZwClose(Vcb->flush_thread_handle); + + if (Vcb->devobj->AttachedDevice) + IoDetachDevice(Vcb->devobj); + + IoDeleteDevice(Vcb->devobj); } static NTSTATUS delete_fileref_fcb(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { @@ -2422,6 +2392,8 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR goto exit; } + FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); + // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup // messages belonging to other devices. @@ -2435,7 +2407,7 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR fileref = ccb ? ccb->fileref : NULL; TRACE("cleanup called for FileObject %p\n", FileObject); - TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0); + TRACE("fileref %p, refcount = %u, open_count = %u\n", fileref, fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0); ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true); @@ -2475,7 +2447,8 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR if (fileref && (oc == 0 || (fileref->delete_on_close && fileref->posix_delete))) { if (!fcb->Vcb->removing) { - if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0 && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { // last handle closed on POSIX-deleted file + if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0 && fileref != fcb->Vcb->root_fileref && + fcb != fcb->Vcb->volume_fcb && !fcb->ads) { // last handle closed on POSIX-deleted file LIST_ENTRY rollback; InitializeListHead(&rollback); @@ -2647,9 +2620,8 @@ ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_ex break; } - if (dotfile) { + if (dotfile || (r->id == BTRFS_ROOT_FSTREE && inode == SUBVOL_ROOT_INODE)) att |= FILE_ATTRIBUTE_HIDDEN; - } att |= FILE_ATTRIBUTE_ARCHIVE; @@ -3883,7 +3855,7 @@ static NTSTATUS load_sys_chunks(_In_ device_extension* Vcb) { } _Ret_maybenull_ -static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { +root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { LIST_ENTRY* le; static const char fn[] = "default"; @@ -3974,7 +3946,7 @@ end: void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs) { TRACE("(%p, %p)\n", FileObject, ccfs); - CcInitializeCacheMap(FileObject, ccfs, false, cache_callbacks, FileObject); + CcInitializeCacheMap(FileObject, ccfs, false, &cache_callbacks, FileObject); if (diskacc) fCcSetAdditionalCacheAttributesEx(FileObject, CC_ENABLE_DISK_IO_ACCOUNTING); @@ -3998,6 +3970,7 @@ uint32_t get_num_of_processors() { static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) { device_extension* Vcb = DeviceObject->DeviceExtension; + OBJECT_ATTRIBUTES oa; ULONG i; Vcb->calcthreads.num_threads = get_num_of_processors(); @@ -4014,13 +3987,15 @@ static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) { RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + for (i = 0; i < Vcb->calcthreads.num_threads; i++) { NTSTATUS Status; Vcb->calcthreads.threads[i].DeviceObject = DeviceObject; KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, false); - Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]); + Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, &oa, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]); if (!NT_SUCCESS(Status)) { ULONG j; @@ -4201,12 +4176,7 @@ static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT DeviceObject, _Out_ bool* pnp_name.Length = 0; } - if (pnp_name.Length == 0) - *pno_pnp = true; - else { - *pno_pnp = false; - volume_arrival(drvobj, &pnp_name); - } + *pno_pnp = pnp_name.Length == 0; if (pnp_name.Buffer) ExFreePool(pnp_name.Buffer); @@ -4223,7 +4193,6 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT f NTSTATUS Status; ULONG to_read; superblock* sb; - PDEVICE_OBJECT device2; if (!device) return false; @@ -4257,14 +4226,20 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT f } } - device2 = device; + ObReferenceObject(device); - do { - device2->Flags &= ~DO_VERIFY_VOLUME; - device2 = IoGetLowerDeviceObject(device2); - } while (device2); + while (device) { + PDEVICE_OBJECT device2 = IoGetLowerDeviceObject(device); + + device->Flags &= ~DO_VERIFY_VOLUME; + + ObDereferenceObject(device); + + device = device2; + } ExFreePool(sb); + return true; } @@ -4286,6 +4261,9 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { pdo_device_extension* pdode = NULL; volume_child* vc; uint64_t readobjsize; + OBJECT_ATTRIBUTES oa; + device_extension* real_devext; + KIRQL irql; TRACE("(%p, %p)\n", DeviceObject, Irp); @@ -4297,6 +4275,12 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { IrpSp = IoGetCurrentIrpStackLocation(Irp); DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject; + real_devext = IrpSp->Parameters.MountVolume.Vpb->RealDevice->DeviceExtension; + + // Make sure we're not trying to mount the PDO + if (IrpSp->Parameters.MountVolume.Vpb->RealDevice->DriverObject == drvobj && real_devext->type == VCB_TYPE_PDO) + return STATUS_UNRECOGNIZED_VOLUME; + if (!is_btrfs_volume(DeviceToMount)) { bool not_pnp = false; @@ -4313,8 +4297,17 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { pdo = DeviceToMount; - while (IoGetLowerDeviceObject(pdo)) { - pdo = IoGetLowerDeviceObject(pdo); + ObReferenceObject(pdo); + + while (true) { + PDEVICE_OBJECT pdo2 = IoGetLowerDeviceObject(pdo); + + ObDereferenceObject(pdo); + + if (!pdo2) + break; + else + pdo = pdo2; } ExAcquireResourceSharedLite(&pdo_list_lock, true); @@ -4797,7 +4790,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { Vcb->root_file->FsContext2 = root_ccb; _SEH2_TRY { - CcInitializeCacheMap(Vcb->root_file, (PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), false, cache_callbacks, Vcb->root_file); + CcInitializeCacheMap(Vcb->root_file, (PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), false, &cache_callbacks, Vcb->root_file); } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); goto exit; @@ -4816,17 +4809,23 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { le = le->Flink; } + IoAcquireVpbSpinLock(&irql); + NewDeviceObject->Vpb = IrpSp->Parameters.MountVolume.Vpb; IrpSp->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject; IrpSp->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED; NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME NewDeviceObject->Vpb->VolumeLabel[0] = '?'; NewDeviceObject->Vpb->VolumeLabel[1] = 0; - NewDeviceObject->Vpb->ReferenceCount++; // FIXME - should we deref this at any point? + NewDeviceObject->Vpb->ReferenceCount++; + + IoReleaseVpbSpinLock(irql); KeInitializeEvent(&Vcb->flush_thread_finished, NotificationEvent, false); - Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, NULL, NULL, NULL, flush_thread, NewDeviceObject); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, &oa, NULL, NULL, flush_thread, NewDeviceObject); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); goto exit; @@ -4851,6 +4850,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { if (vde) vde->mounted_device = NewDeviceObject; + Vcb->devobj = NewDeviceObject; + ExInitializeResourceLite(&Vcb->send_load_lock); exit: @@ -5166,7 +5167,7 @@ _Function_class_(DRIVER_DISPATCH) static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { NTSTATUS Status; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - fcb* fcb = IrpSp->FileObject->FsContext; + fcb* fcb = IrpSp->FileObject ? IrpSp->FileObject->FsContext : NULL; device_extension* Vcb = DeviceObject->DeviceExtension; bool top_level; @@ -5185,6 +5186,14 @@ static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In TRACE("lock control\n"); + if (!fcb) { + ERR("fcb was NULL\n"); + Status = STATUS_INVALID_PARAMETER; + goto exit; + } + + FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); + Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL); fcb->Header.IsFastIoPossible = fast_io_possible(fcb); @@ -5200,55 +5209,53 @@ exit: return Status; } -_Dispatch_type_(IRP_MJ_SHUTDOWN) -_Function_class_(DRIVER_DISPATCH) -static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { - NTSTATUS Status; - bool top_level; - device_extension* Vcb = DeviceObject->DeviceExtension; +void do_shutdown(PIRP Irp) { LIST_ENTRY* le; - - FsRtlEnterFileSystem(); - - TRACE("shutdown\n"); - - top_level = is_top_level(Irp); - - if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { - Status = vol_shutdown(DeviceObject, Irp); - goto end; - } - - Status = STATUS_SUCCESS; + bus_device_extension* bde; shutting_down = true; KeSetEvent(&mountmgr_thread_event, 0, false); le = VcbList.Flink; while (le != &VcbList) { - bool open_files; LIST_ENTRY* le2 = le->Flink; - Vcb = CONTAINING_RECORD(le, device_extension, list_entry); + device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry); + volume_device_extension* vde = Vcb->vde; TRACE("shutting down Vcb %p\n", Vcb); - ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); - Vcb->removing = true; - open_files = Vcb->open_files > 0; + if (vde) + InterlockedIncrement(&vde->open_count); - if (Vcb->need_write && !Vcb->readonly) { - Status = do_write(Vcb, Irp); + dismount_volume(Vcb, true, Irp); + + if (vde) { + NTSTATUS Status; + UNICODE_STRING mmdevpath; + PDEVICE_OBJECT mountmgr; + PFILE_OBJECT mountmgrfo; + KIRQL irql; + + RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); + Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); if (!NT_SUCCESS(Status)) - ERR("do_write returned %08x\n", Status); - } + ERR("IoGetDeviceObjectPointer returned %08x\n", Status); + else { + remove_drive_letter(mountmgr, &vde->name); + + ObDereferenceObject(mountmgrfo); + } - free_trees(Vcb); + vde->removing = true; - ExReleaseResourceLite(&Vcb->tree_lock); + IoAcquireVpbSpinLock(&irql); + vde->device->Vpb->DeviceObject = vde->device; + IoReleaseVpbSpinLock(irql); - if (!open_files) - uninit(Vcb); + if (InterlockedDecrement(&vde->open_count) == 0) + free_vol(vde); + } le = le2; } @@ -5261,6 +5268,66 @@ static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PI } #endif + IoUnregisterFileSystem(master_devobj); + + if (notification_entry2) { + if (fIoUnregisterPlugPlayNotificationEx) + fIoUnregisterPlugPlayNotificationEx(notification_entry2); + else + IoUnregisterPlugPlayNotification(notification_entry2); + + notification_entry2 = NULL; + } + + if (notification_entry3) { + if (fIoUnregisterPlugPlayNotificationEx) + fIoUnregisterPlugPlayNotificationEx(notification_entry3); + else + IoUnregisterPlugPlayNotification(notification_entry3); + + notification_entry3 = NULL; + } + + if (notification_entry) { + if (fIoUnregisterPlugPlayNotificationEx) + fIoUnregisterPlugPlayNotificationEx(notification_entry); + else + IoUnregisterPlugPlayNotification(notification_entry); + + notification_entry = NULL; + } + + bde = busobj->DeviceExtension; + + if (bde->attached_device) + IoDetachDevice(bde->attached_device); + + IoDeleteDevice(busobj); + IoDeleteDevice(master_devobj); +} + +_Dispatch_type_(IRP_MJ_SHUTDOWN) +_Function_class_(DRIVER_DISPATCH) +static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { + NTSTATUS Status; + bool top_level; + device_extension* Vcb = DeviceObject->DeviceExtension; + + FsRtlEnterFileSystem(); + + TRACE("shutdown\n"); + + top_level = is_top_level(Irp); + + if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { + Status = vol_shutdown(DeviceObject, Irp); + goto end; + } + + Status = STATUS_SUCCESS; + + do_shutdown(Irp); + end: Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; @@ -5380,7 +5447,7 @@ exit: return Status; } -bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix) { +bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream) { ULONG i; if (us->Length < sizeof(WCHAR)) @@ -5391,7 +5458,8 @@ bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix) { for (i = 0; i < us->Length / sizeof(WCHAR); i++) { if (us->Buffer[i] == '/' || us->Buffer[i] == 0 || - (!posix && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == ':' || us->Buffer[i] == '"' || + (!posix && (us->Buffer[i] == '/' || us->Buffer[i] == ':')) || + (!posix && !stream && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == '"' || us->Buffer[i] == '|' || us->Buffer[i] == '?' || us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i] <= 31)))) return false; } @@ -5518,7 +5586,11 @@ static void init_serial(bool first_time) { ERR("IoGetDeviceObjectPointer returned %08x\n", Status); if (first_time) { - Status = PsCreateSystemThread(&serial_thread_handle, 0, NULL, NULL, NULL, serial_thread, NULL); + OBJECT_ATTRIBUTES oa; + + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&serial_thread_handle, 0, &oa, NULL, NULL, serial_thread, NULL); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); return; @@ -5692,7 +5764,12 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Physica goto end; } - ExAcquireResourceSharedLite(&pdode->child_lock, true); + ExAcquireResourceExclusiveLite(&pdode->child_lock, true); + + if (pdode->vde) { // if already done, return success + Status = STATUS_SUCCESS; + goto end2; + } volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR)); volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG); // FIXME - when do we free this? @@ -5736,6 +5813,7 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Physica vde->pdo = PhysicalDeviceObject; vde->pdode = pdode; vde->removing = false; + vde->dead = false; vde->open_count = 0; Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name); @@ -5775,7 +5853,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S control_device_extension* cde; bus_device_extension* bde; HANDLE regh; - OBJECT_ATTRIBUTES oa; + OBJECT_ATTRIBUTES oa, system_thread_attributes; ULONG dispos; InitializeListHead(&uid_map_list); @@ -5844,12 +5922,16 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S RtlInitUnicodeString(&name, L"CcSetAdditionalCacheAttributesEx"); fCcSetAdditionalCacheAttributesEx = (tCcSetAdditionalCacheAttributesEx)MmGetSystemRoutineAddress(&name); + + RtlInitUnicodeString(&name, L"FsRtlCheckLockForOplockRequest"); + fFsRtlCheckLockForOplockRequest = (tFsRtlCheckLockForOplockRequest)MmGetSystemRoutineAddress(&name); } else { fPsUpdateDiskCounters = NULL; fCcCopyReadEx = NULL; fCcCopyWriteEx = NULL; fCcSetAdditionalCacheAttributesEx = NULL; fFsRtlUpdateDiskCounters = NULL; + fFsRtlCheckLockForOplockRequest = NULL; } if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN7)) { @@ -5857,8 +5939,13 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S RtlInitUnicodeString(&name, L"IoUnregisterPlugPlayNotificationEx"); fIoUnregisterPlugPlayNotificationEx = (tIoUnregisterPlugPlayNotificationEx)MmGetSystemRoutineAddress(&name); - } else + + RtlInitUnicodeString(&name, L"FsRtlAreThereCurrentOrInProgressFileLocks"); + fFsRtlAreThereCurrentOrInProgressFileLocks = (tFsRtlAreThereCurrentOrInProgressFileLocks)MmGetSystemRoutineAddress(&name); + } else { fIoUnregisterPlugPlayNotificationEx = NULL; + fFsRtlAreThereCurrentOrInProgressFileLocks = NULL; + } if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_VISTA)) { UNICODE_STRING name; @@ -5935,11 +6022,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S return Status; } - Status = init_cache(); - if (!NT_SUCCESS(Status)) { - ERR("init_cache returned %08x\n", Status); - return Status; - } + init_cache(); InitializeListHead(&VcbList); ExInitializeResourceLite(&global_loading_lock); @@ -5990,10 +6073,14 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S IoInvalidateDeviceRelations(bde->buspdo, BusRelations); - Status = PsCreateSystemThread(°raded_wait_handle, 0, NULL, NULL, NULL, degraded_wait_thread, NULL); + InitializeObjectAttributes(&system_thread_attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(°raded_wait_handle, 0, &system_thread_attributes, NULL, NULL, degraded_wait_thread, NULL); if (!NT_SUCCESS(Status)) WARN("PsCreateSystemThread returned %08x\n", Status); + ExInitializeResourceLite(&boot_lock); + Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, (PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry2); if (!NT_SUCCESS(Status)) @@ -6013,7 +6100,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S KeInitializeEvent(&mountmgr_thread_event, NotificationEvent, false); - Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, NULL, NULL, NULL, mountmgr_thread, NULL); + Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, &system_thread_attributes, NULL, NULL, mountmgr_thread, NULL); if (!NT_SUCCESS(Status)) WARN("PsCreateSystemThread returned %08x\n", Status); diff --git a/drivers/filesystems/btrfs/btrfs.h b/drivers/filesystems/btrfs/btrfs.h index f55ef82683e..780bb5d0bab 100644 --- a/drivers/filesystems/btrfs/btrfs.h +++ b/drivers/filesystems/btrfs/btrfs.h @@ -52,6 +52,7 @@ static const uint64_t superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0 #define BTRFS_ROOT_CHUNK 3 #define BTRFS_ROOT_DEVTREE 4 #define BTRFS_ROOT_FSTREE 5 +#define BTRFS_ROOT_TREEDIR 6 #define BTRFS_ROOT_CHECKSUM 7 #define BTRFS_ROOT_UUID 9 #define BTRFS_ROOT_FREE_SPACE 0xa diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc index c899d599b5d..a594c6014d1 100644 --- a/drivers/filesystems/btrfs/btrfs.rc +++ b/drivers/filesystems/btrfs/btrfs.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,4,0,0 - PRODUCTVERSION 1,4,0,0 + FILEVERSION 1,5,0,0 + PRODUCTVERSION 1,5,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "WinBtrfs" - VALUE "FileVersion", "1.4" + VALUE "FileVersion", "1.5" VALUE "InternalName", "btrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19" VALUE "OriginalFilename", "btrfs.sys" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.4" + VALUE "ProductVersion", "1.5" END END BLOCK "VarFileInfo" diff --git a/drivers/filesystems/btrfs/btrfs_drv.h b/drivers/filesystems/btrfs/btrfs_drv.h index 67cb24902c7..e24e4980244 100644 --- a/drivers/filesystems/btrfs/btrfs_drv.h +++ b/drivers/filesystems/btrfs/btrfs_drv.h @@ -136,6 +136,12 @@ C_ASSERT(sizeof(bool) == 1); #define finally if (1) #endif +#ifndef __REACTOS__ +#ifdef __GNUC__ +#define InterlockedIncrement64(a) __sync_add_and_fetch(a, 1) +#endif +#endif + #ifndef FILE_SUPPORTS_BLOCK_REFCOUNTING #define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 #endif @@ -248,6 +254,7 @@ typedef struct { UNICODE_STRING name_uc; ULONG size; struct _file_ref* fileref; + bool root_dir; LIST_ENTRY list_entry_index; LIST_ENTRY list_entry_hash; LIST_ENTRY list_entry_hash_uc; @@ -285,7 +292,6 @@ typedef struct _fcb { PKTHREAD lazy_writer_thread; ULONG atts; SHARE_ACCESS share_access; - WCHAR* debug_desc; bool csum_loaded; LIST_ENTRY extents; ANSI_STRING reparse_xattr; @@ -299,6 +305,7 @@ typedef struct _fcb { bool marked_as_orphan; bool case_sensitive; bool case_sensitive_set; + OPLOCK oplock; LIST_ENTRY dir_children_index; LIST_ENTRY dir_children_hash; @@ -344,7 +351,6 @@ typedef struct _file_ref { LONG refcount; LONG open_count; struct _file_ref* parent; - WCHAR* debug_desc; dir_child* dc; bool dirty; @@ -652,6 +658,7 @@ typedef struct { bool no_trim; bool clear_cache; bool allow_degraded; + bool no_root_dir; } mount_options; #define VCB_TYPE_FS 1 @@ -729,6 +736,7 @@ typedef struct _device_extension { uint32_t type; mount_options options; PVPB Vpb; + PDEVICE_OBJECT devobj; struct _volume_device_extension* vde; LIST_ENTRY devices; #ifdef DEBUG_CHUNK_LOCKS @@ -846,6 +854,7 @@ typedef struct _volume_device_extension { UNICODE_STRING bus_name; PDEVICE_OBJECT attached_device; bool removing; + bool dead; LONG open_count; } volume_device_extension; @@ -855,6 +864,7 @@ typedef struct pdo_device_extension { volume_device_extension* vde; PDEVICE_OBJECT pdo; bool removable; + bool dont_report; uint64_t num_children; uint64_t children_loaded; @@ -912,6 +922,7 @@ typedef struct { uint32_t length; uint8_t* data; chunk* c; + bool allocated; LIST_ENTRY list_entry; } tree_write; @@ -1082,9 +1093,9 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi void uninit(_In_ device_extension* Vcb); NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ IO_STATUS_BLOCK* iosb); -bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix); +bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream); void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); -void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); +void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); #ifdef DEBUG_CHUNK_LOCKS #define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock, true); InterlockedIncrement(&Vcb->chunk_locks_held); } @@ -1094,9 +1105,6 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ #define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock) #endif -_Ret_z_ -WCHAR* file_desc(_In_ PFILE_OBJECT FileObject); -WCHAR* file_desc_fileref(_In_ file_ref* fileref); void mark_fcb_dirty(_In_ fcb* fcb); void mark_fileref_dirty(_In_ file_ref* fileref); NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_ bool make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback); @@ -1122,6 +1130,11 @@ NTSTATUS utf8_to_utf16(WCHAR* dest, ULONG dest_max, ULONG* dest_len, char* src, NTSTATUS utf16_to_utf8(char* dest, ULONG dest_max, ULONG* dest_len, WCHAR* src, ULONG src_len); uint32_t get_num_of_processors(); +_Ret_maybenull_ +root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp); + +void do_shutdown(PIRP Irp); + #ifdef _MSC_VER #define funcname __FUNCTION__ #else @@ -1143,6 +1156,7 @@ extern uint32_t mount_no_trim; extern uint32_t mount_clear_cache; extern uint32_t mount_allow_degraded; extern uint32_t mount_readonly; +extern uint32_t mount_no_root_dir; extern uint32_t no_pnp; #ifdef _DEBUG @@ -1274,9 +1288,8 @@ void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lo _In_ volume_child* vc, _In_ bool skip_dev); // in cache.c -NTSTATUS init_cache(); -void free_cache(); -extern CACHE_MANAGER_CALLBACKS* cache_callbacks; +void init_cache(); +extern CACHE_MANAGER_CALLBACKS cache_callbacks; // in write.c NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write); @@ -1398,6 +1411,7 @@ void do_unlock_volume(device_extension* Vcb); void trim_whole_device(device* dev); void flush_subvol_fcbs(root* subvol); bool fcb_is_inline(fcb* fcb); +NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp); // in flushthread.c @@ -1552,6 +1566,8 @@ NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devp _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) NTSTATUS __stdcall pnp_removal(PVOID NotificationStructure, PVOID Context); +void free_vol(volume_device_extension* vde); + // in scrub.c NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS query_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode, void* data, ULONG length); @@ -1564,7 +1580,7 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG datalen, ULONG_PTR* retlen, KPROCESSOR_MODE processor_mode); // in fsrtl.c -NTSTATUS compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer); +NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer); // in boot.c void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG Count); @@ -1572,7 +1588,43 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULO // based on function in sys/sysmacros.h #define makedev(major, minor) (((minor) & 0xFF) | (((major) & 0xFFF) << 8) | (((uint64_t)((minor) & ~0xFF)) << 12) | (((uint64_t)((major) & ~0xFFF)) << 32)) -#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable) +// not in mingw yet +#ifndef _MSC_VER +typedef struct { + FSRTL_COMMON_FCB_HEADER DUMMYSTRUCTNAME; + PFAST_MUTEX FastMutex; + LIST_ENTRY FilterContexts; + EX_PUSH_LOCK PushLock; + PVOID* FileContextSupportPointer; + union { + OPLOCK Oplock; + PVOID ReservedForRemote; + }; + PVOID ReservedContext; +} FSRTL_ADVANCED_FCB_HEADER_NEW; + +#define FSRTL_FCB_HEADER_V2 2 + +#else +#define FSRTL_ADVANCED_FCB_HEADER_NEW FSRTL_ADVANCED_FCB_HEADER +#endif + +static __inline POPLOCK fcb_oplock(fcb* fcb) { + if (fcb->Header.Version >= FSRTL_FCB_HEADER_V2) + return &((FSRTL_ADVANCED_FCB_HEADER_NEW*)&fcb->Header)->Oplock; + else + return &fcb->oplock; +} + +static __inline FAST_IO_POSSIBLE fast_io_possible(fcb* fcb) { + if (!FsRtlOplockIsFastIoPossible(fcb_oplock(fcb))) + return FastIoIsNotPossible; + + if (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly) + return FastIoIsPossible; + + return FastIoIsQuestionable; +} static __inline void print_open_trees(device_extension* Vcb) { LIST_ENTRY* le = Vcb->trees.Flink; @@ -1738,16 +1790,16 @@ static __inline uint64_t fcb_alloc_size(fcb* fcb) { return sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size); } -typedef BOOLEAN (*tPsIsDiskCountersEnabled)(); +typedef BOOLEAN (__stdcall *tPsIsDiskCountersEnabled)(); -typedef VOID (*tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead, ULONG64 BytesWritten, - ULONG ReadOperationCount, ULONG WriteOperationCount, ULONG FlushOperationCount); +typedef VOID (__stdcall *tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead, ULONG64 BytesWritten, + ULONG ReadOperationCount, ULONG WriteOperationCount, ULONG FlushOperationCount); -typedef BOOLEAN (*tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, - PVOID Buffer, PETHREAD IoIssuerThread); +typedef BOOLEAN (__stdcall *tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, + PVOID Buffer, PETHREAD IoIssuerThread); -typedef BOOLEAN (*tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, - PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PETHREAD IoIssuerThread); +typedef BOOLEAN (__stdcall *tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, + PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PETHREAD IoIssuerThread); #ifndef CC_ENABLE_DISK_IO_ACCOUNTING #define CC_ENABLE_DISK_IO_ACCOUNTING 0x00000010 @@ -1758,22 +1810,26 @@ typedef struct _ECP_LIST ECP_LIST; typedef struct _ECP_LIST *PECP_LIST; #endif -typedef VOID (*tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags); +typedef VOID (__stdcall *tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags); + +typedef VOID (__stdcall *tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten); + +typedef NTSTATUS (__stdcall *tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry); -typedef VOID (*tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten); +typedef NTSTATUS (__stdcall *tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList); -typedef NTSTATUS (*tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry); +typedef NTSTATUS (__stdcall *tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType, + PVOID* NextEcpContext, ULONG* NextEcpContextSize); -typedef NTSTATUS (*tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList); +typedef NTSTATUS (__stdcall *tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer); -typedef NTSTATUS (*tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType, - PVOID* NextEcpContext, ULONG* NextEcpContextSize); +typedef BOOLEAN (__stdcall *tFsRtlCheckLockForOplockRequest)(PFILE_LOCK FileLock, PLARGE_INTEGER AllocationSize); -typedef NTSTATUS (*tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer); +typedef BOOLEAN (__stdcall *tFsRtlAreThereCurrentOrInProgressFileLocks)(PFILE_LOCK FileLock); #ifndef __REACTOS__ #ifndef _MSC_VER -PEPROCESS PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw +PEPROCESS __stdcall PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw #endif // not in DDK headers - taken from winternl.h diff --git a/drivers/filesystems/btrfs/btrfsioctl.h b/drivers/filesystems/btrfs/btrfsioctl.h index e08713119c6..0ba18cf837a 100644 --- a/drivers/filesystems/btrfs/btrfsioctl.h +++ b/drivers/filesystems/btrfs/btrfsioctl.h @@ -36,6 +36,7 @@ #define FSCTL_BTRFS_SEND_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x846, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_BTRFS_READ_SEND_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x847, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define FSCTL_BTRFS_RESIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x848, METHOD_IN_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_BTRFS_UNLOAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x849, METHOD_NEITHER, FILE_ANY_ACCESS) typedef struct { uint64_t subvol; diff --git a/drivers/filesystems/btrfs/cache.c b/drivers/filesystems/btrfs/cache.c index 42ce02c03da..90b0e2a3547 100644 --- a/drivers/filesystems/btrfs/cache.c +++ b/drivers/filesystems/btrfs/cache.c @@ -17,7 +17,7 @@ #include "btrfs_drv.h" -CACHE_MANAGER_CALLBACKS* cache_callbacks; +CACHE_MANAGER_CALLBACKS cache_callbacks; static BOOLEAN __stdcall acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) { PFILE_OBJECT FileObject = Context; @@ -82,21 +82,9 @@ static void __stdcall release_from_read_ahead(PVOID Context) { IoSetTopLevelIrp(NULL); } -NTSTATUS init_cache() { - cache_callbacks = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_MANAGER_CALLBACKS), ALLOC_TAG); - if (!cache_callbacks) { - ERR("out of memory\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - - cache_callbacks->AcquireForLazyWrite = acquire_for_lazy_write; - cache_callbacks->ReleaseFromLazyWrite = release_from_lazy_write; - cache_callbacks->AcquireForReadAhead = acquire_for_read_ahead; - cache_callbacks->ReleaseFromReadAhead = release_from_read_ahead; - - return STATUS_SUCCESS; -} - -void free_cache() { - ExFreePool(cache_callbacks); +void init_cache() { + cache_callbacks.AcquireForLazyWrite = acquire_for_lazy_write; + cache_callbacks.ReleaseFromLazyWrite = release_from_lazy_write; + cache_callbacks.AcquireForReadAhead = acquire_for_read_ahead; + cache_callbacks.ReleaseFromReadAhead = release_from_read_ahead; } diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c index 039fe287f13..4eebef939b1 100644 --- a/drivers/filesystems/btrfs/create.c +++ b/drivers/filesystems/btrfs/create.c @@ -28,6 +28,9 @@ extern tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer; static const WCHAR datastring[] = L"::$DATA"; +static const char root_dir[] = "$Root"; +static const WCHAR root_dir_utf16[] = L"$Root"; + // Windows 10 #define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002 #define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100 @@ -101,6 +104,7 @@ fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) { ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock); FsRtlInitializeFileLock(&fcb->lock, NULL, NULL); + FsRtlInitializeOplock(fcb_oplock(fcb)); InitializeListHead(&fcb->extents); InitializeListHead(&fcb->hardlinks); @@ -470,6 +474,7 @@ NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extens traverse_ptr tp, next_tp; NTSTATUS Status; ULONG num_children = 0; + uint64_t max_index = 2; fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); if (!fcb->hash_ptrs) { @@ -538,6 +543,9 @@ NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extens dc->index = tp.item->key.offset; dc->type = di->type; dc->fileref = NULL; + dc->root_dir = false; + + max_index = dc->index; dc->utf8.MaximumLength = dc->utf8.Length = di->n; dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG); @@ -592,6 +600,68 @@ cont: break; } + if (!Vcb->options.no_root_dir && fcb->inode == SUBVOL_ROOT_INODE) { + root* top_subvol; + + if (Vcb->root_fileref && Vcb->root_fileref->fcb) + top_subvol = Vcb->root_fileref->fcb->subvol; + else + top_subvol = find_default_subvol(Vcb, NULL); + + if (fcb->subvol == top_subvol && top_subvol->id != BTRFS_ROOT_FSTREE) { + dir_child* dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG); + if (!dc) { + ERR("out of memory\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + dc->key.obj_id = BTRFS_ROOT_FSTREE; + dc->key.obj_type = TYPE_ROOT_ITEM; + dc->key.offset = 0; + dc->index = max_index + 1; + dc->type = BTRFS_TYPE_DIRECTORY; + dc->fileref = NULL; + dc->root_dir = true; + + dc->utf8.MaximumLength = dc->utf8.Length = sizeof(root_dir) - sizeof(char); + dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir) - sizeof(char), ALLOC_TAG); + if (!dc->utf8.Buffer) { + ERR("out of memory\n"); + ExFreePool(dc); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(dc->utf8.Buffer, root_dir, sizeof(root_dir) - sizeof(char)); + + dc->name.MaximumLength = dc->name.Length = sizeof(root_dir_utf16) - sizeof(WCHAR); + dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir_utf16) - sizeof(WCHAR), ALLOC_TAG); + if (!dc->name.Buffer) { + ERR("out of memory\n"); + ExFreePool(dc->utf8.Buffer); + ExFreePool(dc); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(dc->name.Buffer, root_dir_utf16, sizeof(root_dir_utf16) - sizeof(WCHAR)); + + Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true); + if (!NT_SUCCESS(Status)) { + ERR("RtlUpcaseUnicodeString returned %08x\n", Status); + ExFreePool(dc->utf8.Buffer); + ExFreePool(dc->name.Buffer); + ExFreePool(dc); + goto cont; + } + + dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length); + dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length); + + InsertTailList(&fcb->dir_children_index, &dc->list_entry_index); + + insert_dir_child_into_hash_lists(fcb, dc); + } + } + return STATUS_SUCCESS; } @@ -1239,6 +1309,9 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo } } + if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE) + fcb->atts |= FILE_ATTRIBUTE_HIDDEN; + subvol->fcbs_version++; InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); @@ -1517,7 +1590,7 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex return STATUS_SUCCESS; } - if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id)) { + if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id && !dc->root_dir)) { fcb = Vcb->dummy_fcb; InterlockedIncrement(&fcb->refcount); } else { @@ -1639,8 +1712,8 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv } if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) { - WARN("passed related fileref which isn't a directory (%S) (fnus = %.*S)\n", - file_desc_fileref(related), fnus->Length / sizeof(WCHAR), fnus->Buffer); + WARN("passed related fileref which isn't a directory (fnus = %.*S)\n", + fnus->Length / sizeof(WCHAR), fnus->Buffer); return STATUS_OBJECT_PATH_NOT_FOUND; } @@ -1690,7 +1763,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv bool cs = case_sensitive; if (!cs) { - if (streampart) + if (streampart && sf->parent) cs = sf->parent->fcb->case_sensitive; else cs = sf->fcb->case_sensitive; @@ -2223,7 +2296,7 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr #ifdef DEBUG_FCB_REFCOUNTS rc = InterlockedIncrement(&parfileref->fcb->refcount); - WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref)); + WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc); #else InterlockedIncrement(&parfileref->fcb->refcount); #endif @@ -2441,9 +2514,9 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr } #ifndef __REACTOS__ - UINT32 dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length); + uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length); #else - dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length); + dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length); #endif if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) { @@ -2512,7 +2585,7 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr *pfr = fileref; - TRACE("created new file %S in subvol %I64x, inode %I64x\n", file_desc_fileref(fileref), fcb->subvol->id, fcb->inode); + TRACE("created new file in subvol %I64x, inode %I64x\n", fcb->subvol->id, fcb->inode); return STATUS_SUCCESS; } @@ -2557,7 +2630,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { UNICODE_STRING fpus2; - if (!is_file_name_valid(fpus, false)) + if (!is_file_name_valid(fpus, false, true)) return STATUS_OBJECT_NAME_INVALID; fpus2.Length = fpus2.MaximumLength = fpus->Length; @@ -2590,7 +2663,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ return Status; } else if (Status != STATUS_OBJECT_NAME_COLLISION) { send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); - send_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); } ExFreePool(fpus2.Buffer); @@ -2655,7 +2728,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ #ifdef DEBUG_FCB_REFCOUNTS rc = InterlockedIncrement(&parfileref->fcb->refcount); - WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref)); + WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc); #else InterlockedIncrement(&parfileref->fcb->refcount); #endif @@ -2920,9 +2993,17 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R Status = fFsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize); if (NT_SUCCESS(Status)) { - if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) { - acec = ctx; - break; + if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID)) { + if (ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) + acec = ctx; + else { + ERR("GUID_ECP_ATOMIC_CREATE context was too short: %u bytes, expected %u\n", ctxsize, + sizeof(ATOMIC_CREATE_ECP_CONTEXT)); + } + } else { + WARN("unhandled ECP {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", type.Data1, type.Data2, + type.Data3, type.Data4[0], type.Data4[1], type.Data4[2], type.Data4[3], type.Data4[4], type.Data4[5], + type.Data4[6], type.Data4[7]); } } } while (NT_SUCCESS(Status)); @@ -3015,7 +3096,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R } else { ACCESS_MASK granted_access; - if (!is_file_name_valid(&fpus, false)) { + if (!is_file_name_valid(&fpus, false, false)) { Status = STATUS_OBJECT_NAME_INVALID; goto end; } @@ -3056,7 +3137,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access); send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); - send_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); } FileObject->FsContext = fileref->fcb; @@ -3140,13 +3221,10 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R fileref->dc->type = fileref->fcb->type; - goto end2; - end: if (fpus.Buffer) ExFreePool(fpus.Buffer); -end2: if (parfileref && !loaded_related) free_fileref(parfileref); @@ -3414,7 +3492,7 @@ static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extens while (le != &fcb->extents) { extent* ext = CONTAINING_RECORD(le, extent, list_entry); - if (ext->extent_data.type == EXTENT_TYPE_REGULAR) { + if (!ext->ignore && ext->extent_data.type == EXTENT_TYPE_REGULAR) { EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0]; uint64_t len; @@ -3581,7 +3659,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO return STATUS_FILE_IS_A_DIRECTORY; } } else if (options & FILE_DIRECTORY_FILE) { - TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref)); + TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n", fileref->fcb->type); free_fileref(fileref); @@ -3617,6 +3695,15 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO } } + // FIXME - this can block waiting for network IO, while we're holding fileref_lock and tree_lock + Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, NULL, NULL, NULL); + if (!NT_SUCCESS(Status)) { + WARN("FsRtlCheckOplock returned %08x\n", Status); + free_fileref(fileref); + + return Status; + } + if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) { ULONG defda, oldatts, filter; LARGE_INTEGER time; @@ -3759,7 +3846,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO } if (dc->fileref) { - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name); + queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name); Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback); if (!NT_SUCCESS(Status)) { @@ -3787,7 +3874,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO fileref->parent->fcb->inode_item_changed = true; mark_fcb_dirty(fileref->parent->fcb); - send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name); + queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name); } else { mark_fcb_dirty(fileref->fcb); @@ -3813,7 +3900,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO fileref->fcb->inode_item.st_mtime = now; fileref->fcb->inode_item_changed = true; - send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); } } else { if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) { @@ -4222,9 +4309,21 @@ NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) hl_alloc = true; } } else { - ERR("couldn't find parent for subvol %I64x\n", subvol->id); - free_fcb(fcb); - return STATUS_INTERNAL_ERROR; + if (!Vcb->options.no_root_dir && subvol->id == BTRFS_ROOT_FSTREE && Vcb->root_fileref->fcb->subvol != subvol) { + Status = open_fileref_by_inode(Vcb, Vcb->root_fileref->fcb->subvol, SUBVOL_ROOT_INODE, &parfr, Irp); + if (!NT_SUCCESS(Status)) { + ERR("open_fileref_by_inode returned %08x\n", Status); + free_fcb(fcb); + return Status; + } + + name.Length = name.MaximumLength = sizeof(root_dir_utf16) - sizeof(WCHAR); + name.Buffer = (WCHAR*)root_dir_utf16; + } else { + ERR("couldn't find parent for subvol %I64x\n", subvol->id); + free_fcb(fcb); + return STATUS_INTERNAL_ERROR; + } } } else { Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp); @@ -4471,7 +4570,7 @@ loaded: if (NT_SUCCESS(Status)) { if (RequestedDisposition == FILE_CREATE) { - TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref)); + TRACE("file already exists, returning STATUS_OBJECT_NAME_COLLISION\n"); Status = STATUS_OBJECT_NAME_COLLISION; free_fileref(fileref); @@ -4788,7 +4887,7 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { TRACE("file name: %.*S\n", IrpSp->FileObject->FileName.Length / sizeof(WCHAR), IrpSp->FileObject->FileName.Buffer); if (IrpSp->FileObject->RelatedFileObject) - TRACE("related file = %S\n", file_desc(IrpSp->FileObject->RelatedFileObject)); + TRACE("related file = %p\n", IrpSp->FileObject->RelatedFileObject); // Don't lock again if we're being called from within CcCopyRead etc. skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock); diff --git a/drivers/filesystems/btrfs/devctrl.c b/drivers/filesystems/btrfs/devctrl.c index 99c2e542d5e..e3c69c97124 100644 --- a/drivers/filesystems/btrfs/devctrl.c +++ b/drivers/filesystems/btrfs/devctrl.c @@ -212,6 +212,17 @@ static NTSTATUS probe_volume(void* data, ULONG length, KPROCESSOR_MODE processor return STATUS_SUCCESS; } +static NTSTATUS ioctl_unload(PIRP Irp) { + if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_LOAD_DRIVER_PRIVILEGE), Irp->RequestorMode)) { + ERR("insufficient privileges\n"); + return STATUS_PRIVILEGE_NOT_HELD; + } + + do_shutdown(Irp); + + return STATUS_SUCCESS; +} + static NTSTATUS control_ioctl(PIRP Irp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS Status; @@ -225,6 +236,10 @@ static NTSTATUS control_ioctl(PIRP Irp) { Status = probe_volume(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.FileSystemControl.InputBufferLength, Irp->RequestorMode); break; + case IOCTL_BTRFS_UNLOAD: + Status = ioctl_unload(Irp); + break; + default: TRACE("unhandled ioctl %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode); Status = STATUS_NOT_IMPLEMENTED; diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c index 41a68268add..e6e96fe5fa0 100644 --- a/drivers/filesystems/btrfs/dirctrl.c +++ b/drivers/filesystems/btrfs/dirctrl.c @@ -209,7 +209,7 @@ static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len, PIRP Ir le = le->Flink; } - if (r && r->parent != fcb->subvol->id) + if (r && r->parent != fcb->subvol->id && (!de->dc || !de->dc->root_dir)) r = NULL; inode = SUBVOL_ROOT_INODE; @@ -1115,7 +1115,7 @@ static NTSTATUS notify_change_directory(device_extension* Vcb, PIRP Irp) { // FIXME - raise exception if FCB marked for deletion? - TRACE("%S\n", file_desc(FileObject)); + TRACE("FileObject %p\n", FileObject); if (ccb->filename.Length == 0) { ULONG reqlen; diff --git a/drivers/filesystems/btrfs/fastio.c b/drivers/filesystems/btrfs/fastio.c index 79604b469ad..5c2b8aaaf8b 100644 --- a/drivers/filesystems/btrfs/fastio.c +++ b/drivers/filesystems/btrfs/fastio.c @@ -336,15 +336,33 @@ static NTSTATUS __stdcall fast_io_release_for_ccflush(PFILE_OBJECT FileObject, P _Function_class_(FAST_IO_WRITE) static BOOLEAN __stdcall fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { - if (FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject)) { - fcb* fcb = FileObject->FsContext; + fcb* fcb = FileObject->FsContext; + bool ret; - fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart; + FsRtlEnterFileSystem(); - return true; + if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait)) { + FsRtlExitFileSystem(); + return false; } - return false; + if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, Wait)) { + ExReleaseResourceLite(&fcb->Vcb->tree_lock); + FsRtlExitFileSystem(); + return false; + } + + ret = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); + + if (ret) + fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart; + + ExReleaseResourceLite(fcb->Header.Resource); + ExReleaseResourceLite(&fcb->Vcb->tree_lock); + + FsRtlExitFileSystem(); + + return ret; } _Function_class_(FAST_IO_LOCK) diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c index 445f4948e59..206a5529deb 100644 --- a/drivers/filesystems/btrfs/fileinfo.c +++ b/drivers/filesystems/btrfs/fileinfo.c @@ -210,7 +210,7 @@ static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp, PFILE_OBJ return STATUS_INVALID_PARAMETER; } - TRACE("file = %S, attributes = %x\n", file_desc(FileObject), fbi->FileAttributes); + TRACE("file = %p, attributes = %x\n", FileObject, fbi->FileAttributes); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); @@ -344,7 +344,7 @@ static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp, PFILE_OBJ } if (filter != 0) - send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); Status = STATUS_SUCCESS; @@ -376,7 +376,7 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); - TRACE("changing delete_on_close to %s for %S (fcb %p)\n", flags & FILE_DISPOSITION_DELETE ? "true" : "false", file_desc(FileObject), fcb); + TRACE("changing delete_on_close to %s for fcb %p\n", flags & FILE_DISPOSITION_DELETE ? "true" : "false", fcb); if (fcb->ads) { if (fileref->parent) @@ -397,6 +397,12 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI goto end; } + if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE) { + WARN("not allowing \\$Root to be deleted\n"); + Status = STATUS_ACCESS_DENIED; + goto end; + } + // FIXME - can we skip this bit for subvols? if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && (!fileref || fileref->fcb != Vcb->dummy_fcb)) { TRACE("directory not empty\n"); @@ -1179,8 +1185,6 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry); ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock); - me->dummyfileref->debug_desc = me->fileref->debug_desc; - if (me->dummyfileref->fcb->type == BTRFS_TYPE_DIRECTORY) me->dummyfileref->fcb->fileref = me->dummyfileref; @@ -1498,9 +1502,958 @@ void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc) { } } +static NTSTATUS rename_stream_to_file(device_extension* Vcb, file_ref* fileref, ccb* ccb, ULONG flags, + PIRP Irp, LIST_ENTRY* rollback) { + NTSTATUS Status; + file_ref* ofr; + ANSI_STRING adsdata; + dir_child* dc; + fcb* dummyfcb; + + if (fileref->fcb->type != BTRFS_TYPE_FILE) + return STATUS_INVALID_PARAMETER; + + if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) { + WARN("trying to rename stream on readonly file\n"); + return STATUS_ACCESS_DENIED; + } + + if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) { + WARN("insufficient permissions\n"); + return STATUS_ACCESS_DENIED; + } + + if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) // file will always exist + return STATUS_OBJECT_NAME_COLLISION; + + // FIXME - POSIX overwrites of stream? + + ofr = fileref->parent; + + if (ofr->open_count > 0) { + WARN("trying to overwrite open file\n"); + return STATUS_ACCESS_DENIED; + } + + if (ofr->fcb->inode_item.st_size > 0) { + WARN("can only overwrite existing stream if it is zero-length\n"); + return STATUS_INVALID_PARAMETER; + } + + dummyfcb = create_fcb(Vcb, PagedPool); + if (!dummyfcb) { + ERR("out of memory\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // copy parent fcb onto this one + + fileref->fcb->subvol = ofr->fcb->subvol; + fileref->fcb->inode = ofr->fcb->inode; + fileref->fcb->hash = ofr->fcb->hash; + fileref->fcb->type = ofr->fcb->type; + fileref->fcb->inode_item = ofr->fcb->inode_item; + + fileref->fcb->sd = ofr->fcb->sd; + ofr->fcb->sd = NULL; + + fileref->fcb->deleted = ofr->fcb->deleted; + fileref->fcb->atts = ofr->fcb->atts; + + fileref->fcb->reparse_xattr = ofr->fcb->reparse_xattr; + ofr->fcb->reparse_xattr.Buffer = NULL; + ofr->fcb->reparse_xattr.Length = ofr->fcb->reparse_xattr.MaximumLength = 0; + + fileref->fcb->ea_xattr = ofr->fcb->ea_xattr; + ofr->fcb->ea_xattr.Buffer = NULL; + ofr->fcb->ea_xattr.Length = ofr->fcb->ea_xattr.MaximumLength = 0; + + fileref->fcb->ealen = ofr->fcb->ealen; + + while (!IsListEmpty(&ofr->fcb->hardlinks)) { + InsertTailList(&fileref->fcb->hardlinks, RemoveHeadList(&ofr->fcb->hardlinks)); + } + + fileref->fcb->inode_item_changed = true; + fileref->fcb->prop_compression = ofr->fcb->prop_compression; + + while (!IsListEmpty(&ofr->fcb->xattrs)) { + InsertTailList(&fileref->fcb->xattrs, RemoveHeadList(&ofr->fcb->xattrs)); + } + + fileref->fcb->marked_as_orphan = ofr->fcb->marked_as_orphan; + fileref->fcb->case_sensitive = ofr->fcb->case_sensitive; + fileref->fcb->case_sensitive_set = ofr->fcb->case_sensitive_set; + + while (!IsListEmpty(&ofr->fcb->dir_children_index)) { + InsertTailList(&fileref->fcb->dir_children_index, RemoveHeadList(&ofr->fcb->dir_children_index)); + } + + while (!IsListEmpty(&ofr->fcb->dir_children_hash)) { + InsertTailList(&fileref->fcb->dir_children_hash, RemoveHeadList(&ofr->fcb->dir_children_hash)); + } + + while (!IsListEmpty(&ofr->fcb->dir_children_hash_uc)) { + InsertTailList(&fileref->fcb->dir_children_hash_uc, RemoveHeadList(&ofr->fcb->dir_children_hash_uc)); + } + + fileref->fcb->hash_ptrs = ofr->fcb->hash_ptrs; + fileref->fcb->hash_ptrs_uc = ofr->fcb->hash_ptrs_uc; + + ofr->fcb->hash_ptrs = NULL; + ofr->fcb->hash_ptrs_uc = NULL; + + fileref->fcb->sd_dirty = ofr->fcb->sd_dirty; + fileref->fcb->sd_deleted = ofr->fcb->sd_deleted; + fileref->fcb->atts_changed = ofr->fcb->atts_changed; + fileref->fcb->atts_deleted = ofr->fcb->atts_deleted; + fileref->fcb->extents_changed = true; + fileref->fcb->reparse_xattr_changed = ofr->fcb->reparse_xattr_changed; + fileref->fcb->ea_changed = ofr->fcb->ea_changed; + fileref->fcb->prop_compression_changed = ofr->fcb->prop_compression_changed; + fileref->fcb->xattrs_changed = ofr->fcb->xattrs_changed; + fileref->fcb->created = ofr->fcb->created; + fileref->fcb->ads = false; + + if (fileref->fcb->adsxattr.Buffer) { + ExFreePool(fileref->fcb->adsxattr.Buffer); + fileref->fcb->adsxattr.Length = fileref->fcb->adsxattr.MaximumLength = 0; + fileref->fcb->adsxattr.Buffer = NULL; + } + + adsdata = fileref->fcb->adsdata; + + fileref->fcb->adsdata.Buffer = NULL; + fileref->fcb->adsdata.Length = fileref->fcb->adsdata.MaximumLength = 0; + + InsertHeadList(ofr->fcb->list_entry.Blink, &fileref->fcb->list_entry); + + if (fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] == &ofr->fcb->list_entry) + fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] = &fileref->fcb->list_entry; + + RemoveEntryList(&ofr->fcb->list_entry); + ofr->fcb->list_entry.Flink = ofr->fcb->list_entry.Blink = NULL; + + mark_fcb_dirty(fileref->fcb); + + // mark old parent fcb so it gets ignored by flush_fcb + ofr->fcb->created = true; + ofr->fcb->deleted = true; + + mark_fcb_dirty(ofr->fcb); + + // copy parent fileref onto this one + + fileref->oldutf8 = ofr->oldutf8; + ofr->oldutf8.Buffer = NULL; + ofr->oldutf8.Length = ofr->oldutf8.MaximumLength = 0; + + fileref->oldindex = ofr->oldindex; + fileref->delete_on_close = ofr->delete_on_close; + fileref->posix_delete = ofr->posix_delete; + fileref->deleted = ofr->deleted; + fileref->created = ofr->created; + + fileref->parent = ofr->parent; + + RemoveEntryList(&fileref->list_entry); + InsertHeadList(ofr->list_entry.Blink, &fileref->list_entry); + RemoveEntryList(&ofr->list_entry); + ofr->list_entry.Flink = ofr->list_entry.Blink = NULL; + + while (!IsListEmpty(&ofr->children)) { + file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&ofr->children), file_ref, list_entry); + + free_fileref(fr->parent); + + fr->parent = fileref; + InterlockedIncrement(&fileref->refcount); + + InsertTailList(&fileref->children, &fr->list_entry); + } + + dc = fileref->dc; + + fileref->dc = ofr->dc; + fileref->dc->fileref = fileref; + + mark_fileref_dirty(fileref); + + // mark old parent fileref so it gets ignored by flush_fileref + ofr->created = true; + ofr->deleted = true; + + // write file data + + fileref->fcb->inode_item.st_size = adsdata.Length; + + if (adsdata.Length > 0) { + bool make_inline = adsdata.Length <= Vcb->options.max_inline; + + if (make_inline) { + EXTENT_DATA* ed = ExAllocatePoolWithTag(PagedPool, (uint16_t)(offsetof(EXTENT_DATA, data[0]) + adsdata.Length), ALLOC_TAG); + if (!ed) { + ERR("out of memory\n"); + ExFreePool(adsdata.Buffer); + reap_fcb(dummyfcb); + return STATUS_INSUFFICIENT_RESOURCES; + } + + ed->generation = Vcb->superblock.generation; + ed->decoded_size = adsdata.Length; + ed->compression = BTRFS_COMPRESSION_NONE; + ed->encryption = BTRFS_ENCRYPTION_NONE; + ed->encoding = BTRFS_ENCODING_NONE; + ed->type = EXTENT_TYPE_INLINE; + + RtlCopyMemory(ed->data, adsdata.Buffer, adsdata.Length); + + ExFreePool(adsdata.Buffer); + + Status = add_extent_to_fcb(fileref->fcb, 0, ed, (uint16_t)(offsetof(EXTENT_DATA, data[0]) + adsdata.Length), false, NULL, rollback); + if (!NT_SUCCESS(Status)) { + ERR("add_extent_to_fcb returned %08x\n", Status); + ExFreePool(ed); + reap_fcb(dummyfcb); + return Status; + } + + ExFreePool(ed); + } else if (adsdata.Length % Vcb->superblock.sector_size) { + char* newbuf = ExAllocatePoolWithTag(PagedPool, (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size), ALLOC_TAG); + if (!newbuf) { + ERR("out of memory\n"); + ExFreePool(adsdata.Buffer); + reap_fcb(dummyfcb); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(newbuf, adsdata.Buffer, adsdata.Length); + RtlZeroMemory(newbuf + adsdata.Length, (uint16_t)(sector_align(adsdata.Length, Vcb->superblock.sector_size) - adsdata.Length)); + + ExFreePool(adsdata.Buffer); + + adsdata.Buffer = newbuf; + adsdata.Length = adsdata.MaximumLength = (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size); + } + + if (!make_inline) { + Status = do_write_file(fileref->fcb, 0, adsdata.Length, adsdata.Buffer, Irp, false, 0, rollback); + if (!NT_SUCCESS(Status)) { + ERR("do_write_file returned %08x\n", Status); + ExFreePool(adsdata.Buffer); + reap_fcb(dummyfcb); + return Status; + } + + ExFreePool(adsdata.Buffer); + } + + fileref->fcb->inode_item.st_blocks = adsdata.Length; + fileref->fcb->inode_item_changed = true; + } + + RemoveEntryList(&dc->list_entry_index); + + if (dc->utf8.Buffer) + ExFreePool(dc->utf8.Buffer); + + if (dc->name.Buffer) + ExFreePool(dc->name.Buffer); + + if (dc->name_uc.Buffer) + ExFreePool(dc->name_uc.Buffer); + + ExFreePool(dc); + + // FIXME - csums? + + // add dummy deleted xattr with old name + + dummyfcb->Vcb = Vcb; + dummyfcb->subvol = fileref->fcb->subvol; + dummyfcb->inode = fileref->fcb->inode; + dummyfcb->adsxattr = fileref->fcb->adsxattr; + dummyfcb->adshash = fileref->fcb->adshash; + dummyfcb->ads = true; + dummyfcb->deleted = true; + + // FIXME - dummyfileref as well? + + mark_fcb_dirty(dummyfcb); + + free_fcb(dummyfcb); + + return STATUS_SUCCESS; +} + +static NTSTATUS rename_stream(device_extension* Vcb, file_ref* fileref, ccb* ccb, FILE_RENAME_INFORMATION_EX* fri, + ULONG flags, PIRP Irp, LIST_ENTRY* rollback) { + NTSTATUS Status; + UNICODE_STRING fn; + file_ref* sf = NULL; + uint16_t newmaxlen; + ULONG utf8len; + ANSI_STRING utf8; + UNICODE_STRING utf16, utf16uc; + ANSI_STRING adsxattr; + uint32_t crc32; + fcb* dummyfcb; + + static const WCHAR datasuf[] = L":$DATA"; + static const char xapref[] = "user."; + + if (!fileref) { + ERR("fileref not set\n"); + return STATUS_INVALID_PARAMETER; + } + + if (!fileref->parent) { + ERR("fileref->parent not set\n"); + return STATUS_INVALID_PARAMETER; + } + + if (fri->FileNameLength < sizeof(WCHAR)) { + WARN("filename too short\n"); + return STATUS_OBJECT_NAME_INVALID; + } + + if (fri->FileName[0] != ':') { + WARN("destination filename must begin with a colon\n"); + return STATUS_INVALID_PARAMETER; + } + + if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) { + WARN("insufficient permissions\n"); + return STATUS_ACCESS_DENIED; + } + + fn.Buffer = &fri->FileName[1]; + fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR)); + + // remove :$DATA suffix + if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) && + RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) + sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) == sizeof(datasuf) - sizeof(WCHAR)) + fn.Length -= sizeof(datasuf) - sizeof(WCHAR); + + if (fn.Length == 0) + return rename_stream_to_file(Vcb, fileref, ccb, flags, Irp, rollback); + + if (!is_file_name_valid(&fn, false, true)) { + WARN("invalid stream name %.*S\n", fn.Length / sizeof(WCHAR), fn.Buffer); + return STATUS_OBJECT_NAME_INVALID; + } + + if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) { + WARN("trying to rename stream on readonly file\n"); + return STATUS_ACCESS_DENIED; + } + + Status = open_fileref_child(Vcb, fileref->parent, &fn, fileref->parent->fcb->case_sensitive, true, true, PagedPool, &sf, Irp); + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + if (Status == STATUS_SUCCESS) { + if (fileref == sf || sf->deleted) { + free_fileref(sf); + sf = NULL; + } else { + if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) { + Status = STATUS_OBJECT_NAME_COLLISION; + goto end; + } + + // FIXME - POSIX overwrites of stream? + + if (sf->open_count > 0) { + WARN("trying to overwrite open file\n"); + Status = STATUS_ACCESS_DENIED; + goto end; + } + + if (sf->fcb->adsdata.Length > 0) { + WARN("can only overwrite existing stream if it is zero-length\n"); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + Status = delete_fileref(sf, NULL, false, Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("delete_fileref returned %08x\n", Status); + goto end; + } + } + } else { + ERR("open_fileref_child returned %08x\n", Status); + goto end; + } + } + + Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length); + if (!NT_SUCCESS(Status)) + goto end; + + utf8.MaximumLength = utf8.Length = (uint16_t)utf8len; + utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8.MaximumLength, ALLOC_TAG); + if (!utf8.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length); + if (!NT_SUCCESS(Status)) { + ExFreePool(utf8.Buffer); + goto end; + } + + adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length; + adsxattr.Buffer = ExAllocatePoolWithTag(PagedPool, adsxattr.MaximumLength, ALLOC_TAG); + if (!adsxattr.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + goto end; + } + + RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1); + RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length); + + // don't allow if it's one of our reserved names + + if ((adsxattr.Length == sizeof(EA_DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_DOSATTRIB, adsxattr.Length) == adsxattr.Length) || + (adsxattr.Length == sizeof(EA_EA) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_EA, adsxattr.Length) == adsxattr.Length) || + (adsxattr.Length == sizeof(EA_REPARSE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_REPARSE, adsxattr.Length) == adsxattr.Length) || + (adsxattr.Length == sizeof(EA_CASE_SENSITIVE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_CASE_SENSITIVE, adsxattr.Length) == adsxattr.Length)) { + Status = STATUS_OBJECT_NAME_INVALID; + ExFreePool(utf8.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + utf16.Length = utf16.MaximumLength = fn.Length; + utf16.Buffer = ExAllocatePoolWithTag(PagedPool, utf16.MaximumLength, ALLOC_TAG); + if (!utf16.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length); + + newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - + offsetof(DIR_ITEM, name[0]); + + if (newmaxlen < adsxattr.Length) { + WARN("cannot rename as data too long\n"); + Status = STATUS_INVALID_PARAMETER; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + newmaxlen -= adsxattr.Length; + + if (newmaxlen < fileref->fcb->adsdata.Length) { + WARN("cannot rename as data too long\n"); + Status = STATUS_INVALID_PARAMETER; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true); + if (!NT_SUCCESS(Status)) { + ERR("RtlUpcaseUnicodeString returned %08x\n"); + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + // add dummy deleted xattr with old name + + dummyfcb = create_fcb(Vcb, PagedPool); + if (!dummyfcb) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + dummyfcb->Vcb = Vcb; + dummyfcb->subvol = fileref->fcb->subvol; + dummyfcb->inode = fileref->fcb->inode; + dummyfcb->adsxattr = fileref->fcb->adsxattr; + dummyfcb->adshash = fileref->fcb->adshash; + dummyfcb->ads = true; + dummyfcb->deleted = true; + + mark_fcb_dirty(dummyfcb); + + free_fcb(dummyfcb); + + // change fcb values + + fileref->dc->utf8 = utf8; + fileref->dc->name = utf16; + fileref->dc->name_uc = utf16uc; + + crc32 = calc_crc32c(0xfffffffe, (uint8_t*)adsxattr.Buffer, adsxattr.Length); + + fileref->fcb->adsxattr = adsxattr; + fileref->fcb->adshash = crc32; + fileref->fcb->adsmaxlen = newmaxlen; + + fileref->fcb->created = true; + + mark_fcb_dirty(fileref->fcb); + + Status = STATUS_SUCCESS; + +end: + if (sf) + free_fileref(sf); + + return Status; +} + +static NTSTATUS rename_file_to_stream(device_extension* Vcb, file_ref* fileref, ccb* ccb, FILE_RENAME_INFORMATION_EX* fri, + ULONG flags, PIRP Irp, LIST_ENTRY* rollback) { + NTSTATUS Status; + UNICODE_STRING fn; + file_ref* sf = NULL; + uint16_t newmaxlen; + ULONG utf8len; + ANSI_STRING utf8; + UNICODE_STRING utf16, utf16uc; + ANSI_STRING adsxattr, adsdata; + uint32_t crc32; + fcb* dummyfcb; + file_ref* dummyfileref; + dir_child* dc; + LIST_ENTRY* le; + + static const WCHAR datasuf[] = L":$DATA"; + static const char xapref[] = "user."; + + if (!fileref) { + ERR("fileref not set\n"); + return STATUS_INVALID_PARAMETER; + } + + if (fri->FileNameLength < sizeof(WCHAR)) { + WARN("filename too short\n"); + return STATUS_OBJECT_NAME_INVALID; + } + + if (fri->FileName[0] != ':') { + WARN("destination filename must begin with a colon\n"); + return STATUS_INVALID_PARAMETER; + } + + if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) { + WARN("insufficient permissions\n"); + return STATUS_ACCESS_DENIED; + } + + if (fileref->fcb->type != BTRFS_TYPE_FILE) + return STATUS_INVALID_PARAMETER; + + fn.Buffer = &fri->FileName[1]; + fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR)); + + // remove :$DATA suffix + if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) && + RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) + sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) == sizeof(datasuf) - sizeof(WCHAR)) + fn.Length -= sizeof(datasuf) - sizeof(WCHAR); + + if (fn.Length == 0) { + WARN("not allowing overwriting file with itself\n"); + return STATUS_INVALID_PARAMETER; + } + + if (!is_file_name_valid(&fn, false, true)) { + WARN("invalid stream name %.*S\n", fn.Length / sizeof(WCHAR), fn.Buffer); + return STATUS_OBJECT_NAME_INVALID; + } + + if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) { + WARN("trying to rename stream on readonly file\n"); + return STATUS_ACCESS_DENIED; + } + + Status = open_fileref_child(Vcb, fileref, &fn, fileref->fcb->case_sensitive, true, true, PagedPool, &sf, Irp); + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + if (Status == STATUS_SUCCESS) { + if (fileref == sf || sf->deleted) { + free_fileref(sf); + sf = NULL; + } else { + if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) { + Status = STATUS_OBJECT_NAME_COLLISION; + goto end; + } + + // FIXME - POSIX overwrites of stream? + + if (sf->open_count > 0) { + WARN("trying to overwrite open file\n"); + Status = STATUS_ACCESS_DENIED; + goto end; + } + + if (sf->fcb->adsdata.Length > 0) { + WARN("can only overwrite existing stream if it is zero-length\n"); + Status = STATUS_INVALID_PARAMETER; + goto end; + } + + Status = delete_fileref(sf, NULL, false, Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("delete_fileref returned %08x\n", Status); + goto end; + } + } + } else { + ERR("open_fileref_child returned %08x\n", Status); + goto end; + } + } + + Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length); + if (!NT_SUCCESS(Status)) + goto end; + + utf8.MaximumLength = utf8.Length = (uint16_t)utf8len; + utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8.MaximumLength, ALLOC_TAG); + if (!utf8.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length); + if (!NT_SUCCESS(Status)) { + ExFreePool(utf8.Buffer); + goto end; + } + + adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length; + adsxattr.Buffer = ExAllocatePoolWithTag(PagedPool, adsxattr.MaximumLength, ALLOC_TAG); + if (!adsxattr.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + goto end; + } + + RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1); + RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length); + + // don't allow if it's one of our reserved names + + if ((adsxattr.Length == sizeof(EA_DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_DOSATTRIB, adsxattr.Length) == adsxattr.Length) || + (adsxattr.Length == sizeof(EA_EA) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_EA, adsxattr.Length) == adsxattr.Length) || + (adsxattr.Length == sizeof(EA_REPARSE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_REPARSE, adsxattr.Length) == adsxattr.Length) || + (adsxattr.Length == sizeof(EA_CASE_SENSITIVE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_CASE_SENSITIVE, adsxattr.Length) == adsxattr.Length)) { + Status = STATUS_OBJECT_NAME_INVALID; + ExFreePool(utf8.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + utf16.Length = utf16.MaximumLength = fn.Length; + utf16.Buffer = ExAllocatePoolWithTag(PagedPool, utf16.MaximumLength, ALLOC_TAG); + if (!utf16.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length); + + newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - + offsetof(DIR_ITEM, name[0]); + + if (newmaxlen < adsxattr.Length) { + WARN("cannot rename as data too long\n"); + Status = STATUS_INVALID_PARAMETER; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + newmaxlen -= adsxattr.Length; + + if (newmaxlen < fileref->fcb->inode_item.st_size) { + WARN("cannot rename as data too long\n"); + Status = STATUS_INVALID_PARAMETER; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true); + if (!NT_SUCCESS(Status)) { + ERR("RtlUpcaseUnicodeString returned %08x\n"); + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + // read existing file data + + if (fileref->fcb->inode_item.st_size > 0) { + ULONG bytes_read; + + adsdata.Length = adsdata.MaximumLength = (uint16_t)fileref->fcb->inode_item.st_size; + + adsdata.Buffer = ExAllocatePoolWithTag(PagedPool, adsdata.MaximumLength, ALLOC_TAG); + if (!adsdata.Buffer) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + goto end; + } + + Status = read_file(fileref->fcb, (uint8_t*)adsdata.Buffer, 0, adsdata.Length, &bytes_read, Irp); + if (!NT_SUCCESS(Status)) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + ExFreePool(adsdata.Buffer); + goto end; + } + + if (bytes_read < fileref->fcb->inode_item.st_size) { + ERR("short read\n"); + Status = STATUS_INTERNAL_ERROR; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + ExFreePool(adsdata.Buffer); + goto end; + } + } else + adsdata.Buffer = NULL; + + dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG); + if (!dc) { + ERR("short read\n"); + Status = STATUS_INSUFFICIENT_RESOURCES;; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + + if (adsdata.Buffer) + ExFreePool(adsdata.Buffer); + + goto end; + } + + // add dummy deleted fcb with old name + + Status = duplicate_fcb(fileref->fcb, &dummyfcb); + if (!NT_SUCCESS(Status)) { + ERR("duplicate_fcb returned %08x\n", Status); + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + + if (adsdata.Buffer) + ExFreePool(adsdata.Buffer); + + ExFreePool(dc); + + goto end; + } + + dummyfileref = create_fileref(Vcb); + if (!dummyfileref) { + ERR("out of memory\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + + if (adsdata.Buffer) + ExFreePool(adsdata.Buffer); + + ExFreePool(dc); + + reap_fcb(dummyfcb); + + goto end; + } + + dummyfileref->fcb = dummyfcb; + + dummyfcb->Vcb = Vcb; + dummyfcb->subvol = fileref->fcb->subvol; + dummyfcb->inode = fileref->fcb->inode; + dummyfcb->hash = fileref->fcb->hash; + + if (fileref->fcb->inode_item.st_size > 0) { + Status = excise_extents(Vcb, dummyfcb, 0, sector_align(fileref->fcb->inode_item.st_size, Vcb->superblock.sector_size), + Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("excise_extents returned %08x\n", Status); + ExFreePool(utf8.Buffer); + ExFreePool(utf16.Buffer); + ExFreePool(utf16uc.Buffer); + ExFreePool(adsxattr.Buffer); + ExFreePool(adsdata.Buffer); + ExFreePool(dc); + + reap_fileref(Vcb, dummyfileref); + reap_fcb(dummyfcb); + + goto end; + } + + dummyfcb->inode_item.st_size = 0; + dummyfcb->Header.AllocationSize.QuadPart = 0; + dummyfcb->Header.FileSize.QuadPart = 0; + dummyfcb->Header.ValidDataLength.QuadPart = 0; + } + + dummyfcb->hash_ptrs = fileref->fcb->hash_ptrs; + dummyfcb->hash_ptrs_uc = fileref->fcb->hash_ptrs_uc; + dummyfcb->created = fileref->fcb->created; + + le = fileref->fcb->extents.Flink; + while (le != &fileref->fcb->extents) { + extent* ext = CONTAINING_RECORD(le, extent, list_entry); + + ext->ignore = true; + + le = le->Flink; + } + + while (!IsListEmpty(&fileref->fcb->dir_children_index)) { + InsertTailList(&dummyfcb->dir_children_index, RemoveHeadList(&fileref->fcb->dir_children_index)); + } + + while (!IsListEmpty(&fileref->fcb->dir_children_hash)) { + InsertTailList(&dummyfcb->dir_children_hash, RemoveHeadList(&fileref->fcb->dir_children_hash)); + } + + while (!IsListEmpty(&fileref->fcb->dir_children_hash_uc)) { + InsertTailList(&dummyfcb->dir_children_hash_uc, RemoveHeadList(&fileref->fcb->dir_children_hash_uc)); + } + + InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all); + + InsertHeadList(fileref->fcb->list_entry.Blink, &dummyfcb->list_entry); + + if (fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] == &fileref->fcb->list_entry) + fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] = &dummyfcb->list_entry; + + RemoveEntryList(&fileref->fcb->list_entry); + fileref->fcb->list_entry.Flink = fileref->fcb->list_entry.Blink = NULL; + + mark_fcb_dirty(dummyfcb); + + // create dummy fileref + + dummyfileref->oldutf8 = fileref->oldutf8; + dummyfileref->oldindex = fileref->oldindex; + dummyfileref->delete_on_close = fileref->delete_on_close; + dummyfileref->posix_delete = fileref->posix_delete; + dummyfileref->deleted = fileref->deleted; + dummyfileref->created = fileref->created; + dummyfileref->parent = fileref->parent; + + while (!IsListEmpty(&fileref->children)) { + file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&fileref->children), file_ref, list_entry); + + free_fileref(fr->parent); + + fr->parent = dummyfileref; + InterlockedIncrement(&dummyfileref->refcount); + + InsertTailList(&dummyfileref->children, &fr->list_entry); + } + + InsertTailList(fileref->list_entry.Blink, &dummyfileref->list_entry); + + RemoveEntryList(&fileref->list_entry); + InsertTailList(&dummyfileref->children, &fileref->list_entry); + + dummyfileref->dc = fileref->dc; + dummyfileref->dc->fileref = dummyfileref; + + mark_fileref_dirty(dummyfileref); + + free_fileref(dummyfileref); + + // change fcb values + + fileref->fcb->hash_ptrs = NULL; + fileref->fcb->hash_ptrs_uc = NULL; + + fileref->fcb->ads = true; + + fileref->oldutf8.Length = fileref->oldutf8.MaximumLength = 0; + fileref->oldutf8.Buffer = NULL; + + RtlZeroMemory(dc, sizeof(dir_child)); + + dc->utf8 = utf8; + dc->name = utf16; + dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length); + dc->name_uc = utf16uc; + dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length); + dc->fileref = fileref; + InsertTailList(&dummyfcb->dir_children_index, &dc->list_entry_index); + + fileref->dc = dc; + fileref->parent = dummyfileref; + + crc32 = calc_crc32c(0xfffffffe, (uint8_t*)adsxattr.Buffer, adsxattr.Length); + + fileref->fcb->adsxattr = adsxattr; + fileref->fcb->adshash = crc32; + fileref->fcb->adsmaxlen = newmaxlen; + fileref->fcb->adsdata = adsdata; + + fileref->fcb->created = true; + + mark_fcb_dirty(fileref->fcb); + + Status = STATUS_SUCCESS; + +end: + if (sf) + free_fileref(sf); + + return Status; +} + static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject, PFILE_OBJECT tfo, bool ex) { FILE_RENAME_INFORMATION_EX* fri = Irp->AssociatedIrp.SystemBuffer; - fcb *fcb = FileObject->FsContext; + fcb* fcb = FileObject->FsContext; ccb* ccb = FileObject->FsContext2; file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL; WCHAR* fn; @@ -1515,6 +2468,9 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB SECURITY_SUBJECT_CONTEXT subjcont; ACCESS_MASK access; ULONG flags; +#ifdef __REACTOS__ + unsigned int i; +#endif InitializeListHead(&rollback); @@ -1558,11 +2514,39 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); + if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE) { + WARN("not allowing \\$Root to be renamed\n"); + Status = STATUS_ACCESS_DENIED; + goto end; + } + if (fcb->ads) { - // MSDN says that NTFS data streams can be renamed (
https://msdn.microsoft.com/en-us/library/windows/hardware/ff540344.aspx
), - // but if you try it always seems to return STATUS_INVALID_PARAMETER. There is a function in ntfs.sys called NtfsStreamRename, - // but it never seems to get invoked... If you know what's going on here, I'd appreciate it if you let me know. - Status = STATUS_INVALID_PARAMETER; + if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) { + IO_STATUS_BLOCK iosb; + + CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb); + if (!NT_SUCCESS(iosb.Status)) { + ERR("CcFlushCache returned %08x\n", iosb.Status); + Status = iosb.Status; + goto end; + } + } + + Status = rename_stream(Vcb, fileref, ccb, fri, flags, Irp, &rollback); + goto end; + } else if (fnlen >= 1 && fn[0] == ':') { + if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) { + IO_STATUS_BLOCK iosb; + + CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb); + if (!NT_SUCCESS(iosb.Status)) { + ERR("CcFlushCache returned %08x\n", iosb.Status); + Status = iosb.Status; + goto end; + } + } + + Status = rename_file_to_stream(Vcb, fileref, ccb, fri, flags, Irp, &rollback); goto end; } @@ -1571,6 +2555,18 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB TRACE("fnus = %.*S\n", fnus.Length / sizeof(WCHAR), fnus.Buffer); +#ifndef __REACTOS__ + for (unsigned int i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) { +#else + for (i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) { +#endif + if (fnus.Buffer[i] == ':') { + TRACE("colon in filename\n"); + Status = STATUS_OBJECT_NAME_INVALID; + goto end; + } + } + origutf8len = fileref->dc->utf8.Length; Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR)); @@ -1602,7 +2598,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB Status = open_fileref(Vcb, &oldfileref, &fnus, related, false, NULL, NULL, PagedPool, ccb->case_sensitive, Irp); if (NT_SUCCESS(Status)) { - TRACE("destination file %S already exists\n", file_desc_fileref(oldfileref)); + TRACE("destination file already exists\n"); if (fileref != oldfileref && !oldfileref->deleted) { if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) { @@ -2237,12 +3233,12 @@ static NTSTATUS set_end_of_file_information(device_extension* Vcb, PIRP Irp, PFI mark_fcb_dirty(fileref->parent->fcb); } - send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED_STREAM, &fileref->dc->name); + queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED_STREAM, &fileref->dc->name); goto end; } - TRACE("file: %S\n", file_desc(FileObject)); + TRACE("file: %p\n", FileObject); TRACE("paging IO: %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false"); TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); @@ -2301,7 +3297,7 @@ static NTSTATUS set_end_of_file_information(device_extension* Vcb, PIRP Irp, PFI fcb->inode_item_changed = true; mark_fcb_dirty(fcb); - send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); Status = STATUS_SUCCESS; @@ -2332,7 +3328,7 @@ end: static NTSTATUS set_position_information(PFILE_OBJECT FileObject, PIRP Irp) { FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; - TRACE("setting the position on %S to %I64x\n", file_desc(FileObject), fpi->CurrentByteOffset.QuadPart); + TRACE("setting the position on %p to %I64x\n", FileObject, fpi->CurrentByteOffset.QuadPart); // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING @@ -2460,7 +3456,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE if (NT_SUCCESS(Status)) { if (!oldfileref->deleted) { - WARN("destination file %S already exists\n", file_desc_fileref(oldfileref)); + WARN("destination file already exists\n"); if (!(flags & FILE_LINK_REPLACE_IF_EXISTS)) { Status = STATUS_OBJECT_NAME_COLLISION; @@ -2755,7 +3751,7 @@ static NTSTATUS set_valid_data_length_information(device_extension* Vcb, PIRP Ir fcb->inode_item_changed = true; mark_fcb_dirty(fcb); - send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); Status = STATUS_SUCCESS; @@ -2879,6 +3875,8 @@ NTSTATUS __stdcall drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP I TRACE("set information\n"); + FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); + switch (IrpSp->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: { @@ -2951,7 +3949,6 @@ NTSTATUS __stdcall drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP I case FileRenameInformation: TRACE("FileRenameInformation\n"); - // FIXME - make this work with streams Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, false); break; diff --git a/drivers/filesystems/btrfs/flushthread.c b/drivers/filesystems/btrfs/flushthread.c index ef847a59cca..456c8541370 100644 --- a/drivers/filesystems/btrfs/flushthread.c +++ b/drivers/filesystems/btrfs/flushthread.c @@ -545,6 +545,9 @@ nextdev: for (num = 0; num < total_num; num++) { if (context.stripes[num].dmdsa) ExFreePool(context.stripes[num].dmdsa); + + if (context.stripes[num].Irp) + IoFreeIrp(context.stripes[num].Irp); } ExFreePool(context.stripes); @@ -1633,13 +1636,14 @@ NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY* tree_writes, bool no_ RtlCopyMemory(data, tw2->data, tw2->length); RtlCopyMemory(&data[tw2->length], tw->data, tw->length); - if (!no_free) + if (!no_free || tw2->allocated) ExFreePool(tw2->data); tw2->data = data; tw2->length += tw->length; + tw2->allocated = true; - if (!no_free) // FIXME - what if we allocated this just now? + if (!no_free || tw->allocated) ExFreePool(tw->data); RemoveEntryList(&tw->list_entry); @@ -2025,6 +2029,7 @@ static NTSTATUS write_trees(device_extension* Vcb, PIRP Irp) { tw->address = t->new_address; tw->length = Vcb->superblock.node_size; tw->data = data; + tw->allocated = false; if (IsListEmpty(&tree_writes)) InsertTailList(&tree_writes, &tw->list_entry); @@ -6482,8 +6487,6 @@ static NTSTATUS flush_fileref(file_ref* fileref, LIST_ENTRY* batchlist, PIRP Irp crc32 = calc_crc32c(0xfffffffe, (uint8_t*)name->Buffer, name->Length); - TRACE("deleting %.*S\n", file_desc_fileref(fileref)); - di = ExAllocatePoolWithTag(PagedPool, sizeof(DIR_ITEM) - 1 + name->Length, ALLOC_TAG); if (!di) { ERR("out of memory\n"); @@ -6750,6 +6753,9 @@ static void flush_disk_caches(device_extension* Vcb) { LIST_ENTRY* le; ioctl_context context; ULONG num; +#ifdef __REACTOS__ + unsigned int i; +#endif context.left = 0; @@ -6827,6 +6833,15 @@ nextdev: KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL); +#ifndef __REACTOS__ + for (unsigned int i = 0; i < num; i++) { +#else + for (i = 0; i < num; i++) { +#endif + if (context.stripes[i].Irp) + IoFreeIrp(context.stripes[i].Irp); + } + ExFreePool(context.stripes); } diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c index 039e828e962..52698383d3f 100644 --- a/drivers/filesystems/btrfs/fsctl.c +++ b/drivers/filesystems/btrfs/fsctl.c @@ -44,6 +44,8 @@ extern LIST_ENTRY VcbList; extern ERESOURCE global_loading_lock; extern PDRIVER_OBJECT drvobj; +extern tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest; +extern tFsRtlAreThereCurrentOrInProgressFileLocks fFsRtlAreThereCurrentOrInProgressFileLocks; static void mark_subvol_dirty(device_extension* Vcb, root* r); @@ -598,7 +600,7 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject, if (is_subvol_readonly(fcb->subvol, Irp)) return STATUS_ACCESS_DENIED; - if (!is_file_name_valid(&nameus, posix)) + if (!is_file_name_valid(&nameus, posix, false)) return STATUS_OBJECT_NAME_INVALID; utf8.Buffer = NULL; @@ -820,7 +822,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo nameus.Length = nameus.MaximumLength = bcs->namelen; nameus.Buffer = bcs->name; - if (!is_file_name_valid(&nameus, bcs->posix)) + if (!is_file_name_valid(&nameus, bcs->posix, false)) return STATUS_OBJECT_NAME_INVALID; utf8.Buffer = NULL; @@ -1789,7 +1791,7 @@ static NTSTATUS set_sparse(device_extension* Vcb, PFILE_OBJECT FileObject, void* } mark_fcb_dirty(fcb); - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); Status = STATUS_SUCCESS; @@ -2059,7 +2061,7 @@ static NTSTATUS set_zero_data(device_extension* Vcb, PFILE_OBJECT FileObject, vo fcb->inode_item_changed = true; mark_fcb_dirty(fcb); - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); fcb->subvol->root_item.ctransid = Vcb->superblock.generation; fcb->subvol->root_item.ctime = now; @@ -2568,22 +2570,25 @@ static void update_volumes(device_extension* Vcb) { ExReleaseResourceLite(&Vcb->tree_lock); } -static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) { +NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp) { NTSTATUS Status; + bool open_files; TRACE("FSCTL_DISMOUNT_VOLUME\n"); if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) return STATUS_SUCCESS; - if (Vcb->disallow_dismount || Vcb->page_file_count != 0) { - WARN("attempting to dismount boot volume or one containing a pagefile\n"); - return STATUS_ACCESS_DENIED; - } + if (!shutdown) { + if (Vcb->disallow_dismount || Vcb->page_file_count != 0) { + WARN("attempting to dismount boot volume or one containing a pagefile\n"); + return STATUS_ACCESS_DENIED; + } - Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT); - if (!NT_SUCCESS(Status)) { - WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status); + Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT); + if (!NT_SUCCESS(Status)) { + WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status); + } } ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); @@ -2603,6 +2608,8 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) { Vcb->removing = true; + open_files = Vcb->open_files > 0; + if (Vcb->vde) { update_volumes(Vcb); Vcb->vde->mounted_device = NULL; @@ -2610,6 +2617,9 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) { ExReleaseResourceLite(&Vcb->tree_lock); + if (!open_files) + uninit(Vcb); + return STATUS_SUCCESS; } @@ -3647,7 +3657,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject if (!ccb->user_set_write_time) { fcb->inode_item.st_mtime = now; - send_notification_fcb(ccb->fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(ccb->fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); } fcb->inode_item_changed = true; @@ -4040,7 +4050,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data send_notification_fileref(fileref, bmn->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); if (!parccb->user_set_write_time) - send_notification_fcb(parfileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(parfileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); Status = STATUS_SUCCESS; @@ -4727,6 +4737,7 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data, ULONG len, PIRP delta = dev->devitem.num_bytes - br->size; if (need_balance) { + OBJECT_ATTRIBUTES oa; int i; if (Vcb->balance.thread) { @@ -4751,7 +4762,9 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data, ULONG len, PIRP space_list_subtract2(&dev->space, NULL, br->size, delta, NULL, NULL); - Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); goto end; @@ -4835,57 +4848,145 @@ end: return Status; } -NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) { +static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) { + NTSTATUS Status; PIRP Irp = *Pirp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - NTSTATUS Status; + uint32_t fsctl = IrpSp->Parameters.FileSystemControl.FsControlCode; + PFILE_OBJECT FileObject = IrpSp->FileObject; + fcb* fcb = FileObject ? FileObject->FsContext : NULL; + ccb* ccb = FileObject ? FileObject->FsContext2 : NULL; + file_ref* fileref = ccb ? ccb->fileref : NULL; +#if (NTDDI_VERSION >= NTDDI_WIN7) + PREQUEST_OPLOCK_INPUT_BUFFER buf = NULL; + bool oplock_request = false, oplock_ack = false; +#else + bool oplock_request = false; +#endif + ULONG oplock_count = 0; +#ifdef __REACTOS__ + bool shared_request; +#endif + + if (!fcb) { + ERR("fcb was NULL\n"); + return STATUS_INVALID_PARAMETER; + } + + if (!fileref) { + ERR("fileref was NULL\n"); + return STATUS_INVALID_PARAMETER; + } + + if (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_DIRECTORY) + return STATUS_INVALID_PARAMETER; - switch (type) { #if (NTDDI_VERSION >= NTDDI_WIN7) - case FSCTL_REQUEST_OPLOCK: - WARN("STUB: FSCTL_REQUEST_OPLOCK\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; + if (fsctl == FSCTL_REQUEST_OPLOCK) { + if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(REQUEST_OPLOCK_INPUT_BUFFER)) + return STATUS_BUFFER_TOO_SMALL; + + if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER)) + return STATUS_BUFFER_TOO_SMALL; + + buf = Irp->AssociatedIrp.SystemBuffer; + + // flags are mutually exclusive + if (buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST && buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK) + return STATUS_INVALID_PARAMETER; + + oplock_request = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST; + oplock_ack = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK; + + if (!oplock_request && !oplock_ack) + return STATUS_INVALID_PARAMETER; + } #endif - case FSCTL_REQUEST_OPLOCK_LEVEL_1: - WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; +#if (NTDDI_VERSION >= NTDDI_WIN7) + bool shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2) || (fsctl == FSCTL_REQUEST_OPLOCK && !(buf->RequestedOplockLevel & OPLOCK_LEVEL_CACHE_WRITE)); +#else + shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2); +#endif - case FSCTL_REQUEST_OPLOCK_LEVEL_2: - WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; +#if (NTDDI_VERSION >= NTDDI_WIN7) + if (fcb->type == BTRFS_TYPE_DIRECTORY && (fsctl != FSCTL_REQUEST_OPLOCK || !shared_request)) { +#else + if (fcb->type == BTRFS_TYPE_DIRECTORY && !shared_request) { +#endif + WARN("oplock requests on directories can only be for read or read-handle oplocks\n"); + return STATUS_INVALID_PARAMETER; + } - case FSCTL_REQUEST_BATCH_OPLOCK: - WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; + ExAcquireResourceSharedLite(&Vcb->tree_lock, true); - case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: - WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; + if (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_1 || fsctl == FSCTL_REQUEST_BATCH_OPLOCK || fsctl == FSCTL_REQUEST_FILTER_OPLOCK || + fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) { + ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); - case FSCTL_OPLOCK_BREAK_ACK_NO_2: - WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; + if (shared_request) { + if (fcb->type == BTRFS_TYPE_FILE) { + if (fFsRtlCheckLockForOplockRequest) + oplock_count = !fFsRtlCheckLockForOplockRequest(&fcb->lock, &fcb->Header.AllocationSize); + else if (fFsRtlAreThereCurrentOrInProgressFileLocks) + oplock_count = fFsRtlAreThereCurrentOrInProgressFileLocks(&fcb->lock); + else + oplock_count = FsRtlAreThereCurrentFileLocks(&fcb->lock); + } + } else + oplock_count = fileref->open_count; + } else + ExAcquireResourceSharedLite(fcb->Header.Resource, true); - case FSCTL_OPBATCH_ACK_CLOSE_PENDING: - WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; +#if (NTDDI_VERSION >= NTDDI_WIN7) + if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK || + (fsctl == FSCTL_REQUEST_OPLOCK && buf->RequestedOplockLevel & OPLOCK_LEVEL_CACHE_HANDLE)) && +#else + if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK) && +#endif + fileref->delete_on_close) { + ExReleaseResourceLite(fcb->Header.Resource); + ExReleaseResourceLite(&Vcb->tree_lock); + return STATUS_DELETE_PENDING; + } - case FSCTL_OPLOCK_BREAK_NOTIFY: - WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; - break; + Status = FsRtlOplockFsctrl(fcb_oplock(fcb), Irp, oplock_count); + + *Pirp = NULL; + + fcb->Header.IsFastIoPossible = fast_io_possible(fcb); + ExReleaseResourceLite(fcb->Header.Resource); + ExReleaseResourceLite(&Vcb->tree_lock); + + return Status; +} + +NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) { + PIRP Irp = *Pirp; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + NTSTATUS Status; + + if (IrpSp->FileObject && IrpSp->FileObject->FsContext) { + device_extension* Vcb = DeviceObject->DeviceExtension; + + if (Vcb->type == VCB_TYPE_FS) + FsRtlCheckOplock(fcb_oplock(IrpSp->FileObject->FsContext), Irp, NULL, NULL, NULL); + } + + switch (type) { + case FSCTL_REQUEST_OPLOCK_LEVEL_1: + case FSCTL_REQUEST_OPLOCK_LEVEL_2: + case FSCTL_REQUEST_BATCH_OPLOCK: + case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: + case FSCTL_OPBATCH_ACK_CLOSE_PENDING: + case FSCTL_OPLOCK_BREAK_NOTIFY: + case FSCTL_OPLOCK_BREAK_ACK_NO_2: case FSCTL_REQUEST_FILTER_OPLOCK: - WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n"); - Status = STATUS_INVALID_DEVICE_REQUEST; +#if (NTDDI_VERSION >= NTDDI_WIN7) + case FSCTL_REQUEST_OPLOCK: +#endif + Status = fsctl_oplock(DeviceObject->DeviceExtension, Pirp); break; case FSCTL_LOCK_VOLUME: @@ -4897,7 +4998,7 @@ NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) { break; case FSCTL_DISMOUNT_VOLUME: - Status = dismount_volume(DeviceObject->DeviceExtension, Irp); + Status = dismount_volume(DeviceObject->DeviceExtension, false, Irp); break; case FSCTL_IS_VOLUME_MOUNTED: diff --git a/drivers/filesystems/btrfs/fsrtl.c b/drivers/filesystems/btrfs/fsrtl.c index 8654d84e5ae..fab85bc6572 100644 --- a/drivers/filesystems/btrfs/fsrtl.c +++ b/drivers/filesystems/btrfs/fsrtl.c @@ -29,7 +29,7 @@ IsEven(IN USHORT Digit) return ((Digit & 1) != 1); } -NTSTATUS compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer) +NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer) { USHORT DataLength; ULONG ReparseTag; diff --git a/drivers/filesystems/btrfs/pnp.c b/drivers/filesystems/btrfs/pnp.c index 2b012ed002c..3313d82831b 100644 --- a/drivers/filesystems/btrfs/pnp.c +++ b/drivers/filesystems/btrfs/pnp.c @@ -185,14 +185,15 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) { ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { - Status = STATUS_ACCESS_DENIED; - goto end; + ExReleaseResourceLite(&Vcb->tree_lock); + return STATUS_ACCESS_DENIED; } Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE); if (!NT_SUCCESS(Status)) { WARN("send_disks_pnp_message returned %08x\n", Status); - goto end; + ExReleaseResourceLite(&Vcb->tree_lock); + return Status; } Vcb->removing = true; @@ -204,16 +205,17 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) { if (!NT_SUCCESS(Status)) { ERR("do_write returned %08x\n", Status); - goto end; + ExReleaseResourceLite(&Vcb->tree_lock); + return Status; } } - - Status = STATUS_SUCCESS; -end: ExReleaseResourceLite(&Vcb->tree_lock); - return Status; + if (Vcb->open_files == 0) + uninit(Vcb); + + return STATUS_SUCCESS; } static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) { @@ -294,7 +296,10 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) { le = pdo_list.Flink; while (le != &pdo_list) { - num_children++; + pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); + + if (!pdode->dont_report) + num_children++; le = le->Flink; } @@ -315,9 +320,11 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) { while (le != &pdo_list) { pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); - ObReferenceObject(pdode->pdo); - dr->Objects[i] = pdode->pdo; - i++; + if (!pdode->dont_report) { + ObReferenceObject(pdode->pdo); + dr->Objects[i] = pdode->pdo; + i++; + } le = le->Flink; } @@ -539,6 +546,29 @@ static NTSTATUS pdo_device_usage_notification(pdo_device_extension* pdode, PIRP return STATUS_SUCCESS; } +static NTSTATUS pdo_query_device_relations(PDEVICE_OBJECT pdo, PIRP Irp) { + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PDEVICE_RELATIONS device_relations; + + if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + return Irp->IoStatus.Status; + + device_relations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), ALLOC_TAG); + if (!device_relations) { + ERR("out of memory\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + device_relations->Count = 1; + device_relations->Objects[0] = pdo; + + ObReferenceObject(pdo); + + Irp->IoStatus.Information = (ULONG_PTR)device_relations; + + return STATUS_SUCCESS; +} + static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); pdo_device_extension* pdode = pdo->DeviceExtension; @@ -559,6 +589,8 @@ static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) { case IRP_MN_DEVICE_USAGE_NOTIFICATION: return pdo_device_usage_notification(pdode, Irp); + case IRP_MN_QUERY_DEVICE_RELATIONS: + return pdo_query_device_relations(pdo, Irp); } return Irp->IoStatus.Status; diff --git a/drivers/filesystems/btrfs/read.c b/drivers/filesystems/btrfs/read.c index 5934821beb2..ae7a270bb18 100644 --- a/drivers/filesystems/btrfs/read.c +++ b/drivers/filesystems/btrfs/read.c @@ -3114,7 +3114,7 @@ NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) { if (!fcb || !fcb->Vcb || !fcb->subvol) return STATUS_INTERNAL_ERROR; - TRACE("file = %S (fcb = %p)\n", file_desc(FileObject), fcb); + TRACE("fcb = %p\n", fcb); TRACE("offset = %I64x, length = %x\n", start, length); TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false", Irp->Flags & IRP_NOCACHE ? "true" : "false"); @@ -3318,6 +3318,9 @@ NTSTATUS __stdcall drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) { goto exit2; } + if (!(Irp->Flags & IRP_PAGING_IO)) + FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); + wait = IoIsOperationSynchronous(Irp); // Don't offload jobs when doing paging IO - otherwise this can lead to diff --git a/drivers/filesystems/btrfs/registry.c b/drivers/filesystems/btrfs/registry.c index a13baf35aba..398d700b637 100644 --- a/drivers/filesystems/btrfs/registry.c +++ b/drivers/filesystems/btrfs/registry.c @@ -37,7 +37,8 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { BTRFS_UUID* uuid = &Vcb->superblock.uuid; mount_options* options = &Vcb->options; UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus, - maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus; + maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus, + norootdirus; OBJECT_ATTRIBUTES oa; NTSTATUS Status; ULONG i, j, kvfilen, index, retlen; @@ -121,6 +122,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { RtlInitUnicodeString(&clearcacheus, L"ClearCache"); RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded"); RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel"); + RtlInitUnicodeString(&norootdirus, L"NoRootDir"); do { Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen); @@ -193,6 +195,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) { DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset); options->zstd_level = *val; + } else if (FsRtlAreNamesEqual(&norootdirus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) { + DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset); + + options->no_root_dir = *val; } } else if (Status != STATUS_NO_MORE_ENTRIES) { ERR("ZwEnumerateValueKey returned %08x\n", Status); @@ -805,6 +811,7 @@ void read_registry(PUNICODE_STRING regpath, bool refresh) { get_registry_value(h, L"AllowDegraded", REG_DWORD, &mount_allow_degraded, sizeof(mount_allow_degraded)); get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly, sizeof(mount_readonly)); get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level, sizeof(mount_zstd_level)); + get_registry_value(h, L"NoRootDir", REG_DWORD, &mount_no_root_dir, sizeof(mount_no_root_dir)); if (!refresh) get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp)); diff --git a/drivers/filesystems/btrfs/reparse.c b/drivers/filesystems/btrfs/reparse.c index fb6a98808b8..a926bbd4a73 100644 --- a/drivers/filesystems/btrfs/reparse.c +++ b/drivers/filesystems/btrfs/reparse.c @@ -414,8 +414,6 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { fcb = fileref->fcb; } - TRACE("%S\n", file_desc(FileObject)); - ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); @@ -425,7 +423,7 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { goto end; } - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); end: if (NT_SUCCESS(Status)) @@ -488,8 +486,6 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); - TRACE("%S\n", file_desc(FileObject)); - if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) { ERR("buffer was too short\n"); Status = STATUS_INVALID_PARAMETER; @@ -619,7 +615,7 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) { Status = STATUS_SUCCESS; - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); end: if (NT_SUCCESS(Status)) diff --git a/drivers/filesystems/btrfs/scrub.c b/drivers/filesystems/btrfs/scrub.c index d1994b7fe63..e4d70d02e5e 100644 --- a/drivers/filesystems/btrfs/scrub.c +++ b/drivers/filesystems/btrfs/scrub.c @@ -3265,6 +3265,7 @@ end: NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode) { NTSTATUS Status; + OBJECT_ATTRIBUTES oa; if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode)) return STATUS_PRIVILEGE_NOT_HELD; @@ -3292,7 +3293,9 @@ NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode) { Vcb->scrub.error = STATUS_SUCCESS; KeInitializeEvent(&Vcb->scrub.event, NotificationEvent, !Vcb->scrub.paused); - Status = PsCreateSystemThread(&Vcb->scrub.thread, 0, NULL, NULL, NULL, scrub_thread, Vcb); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&Vcb->scrub.thread, 0, &oa, NULL, NULL, scrub_thread, Vcb); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); return Status; diff --git a/drivers/filesystems/btrfs/search.c b/drivers/filesystems/btrfs/search.c index a1a4217aec9..3d824d9f767 100644 --- a/drivers/filesystems/btrfs/search.c +++ b/drivers/filesystems/btrfs/search.c @@ -23,6 +23,7 @@ #include <windef.h> #include <ntddstor.h> #include <ntdddisk.h> +#include <ntddvol.h> #include <initguid.h> #include <wdmguid.h> @@ -35,6 +36,7 @@ extern HANDLE mountmgr_thread_handle; extern bool shutting_down; extern PDEVICE_OBJECT busobj; extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx; +extern ERESOURCE boot_lock; typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); @@ -270,8 +272,11 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { UNUSED(DriverObject); + ExAcquireResourceSharedLite(&boot_lock, TRUE); + Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj); if (!NT_SUCCESS(Status)) { + ExReleaseResourceLite(&boot_lock); ERR("IoGetDeviceObjectPointer returned %08x\n", Status); return; } @@ -323,6 +328,8 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { end: ObDereferenceObject(fileobj); + + ExReleaseResourceLite(&boot_lock); } void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock) _Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde, @@ -496,8 +503,11 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); + ExAcquireResourceSharedLite(&boot_lock, TRUE); + Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj); if (!NT_SUCCESS(Status)) { + ExReleaseResourceLite(&boot_lock); ERR("IoGetDeviceObjectPointer returned %08x\n", Status); return; } @@ -507,6 +517,10 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { if (devobj->DriverObject == DriverObject) goto end; + Status = dev_ioctl(devobj, IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, true, NULL); + if (!NT_SUCCESS(Status)) + TRACE("IOCTL_VOLUME_ONLINE returned %08x\n", Status); + Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), true, NULL); if (!NT_SUCCESS(Status)) { ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status); @@ -570,6 +584,8 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { end: ObDereferenceObject(fileobj); + + ExReleaseResourceLite(&boot_lock); } void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { @@ -648,6 +664,8 @@ static void __stdcall do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { ExFreePool(context->name.Buffer); IoFreeWorkItem(context->work_item); + + ExFreePool(context); } static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name, pnp_callback func) { @@ -655,6 +673,10 @@ static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING na pnp_callback_context* context; work_item = IoAllocateWorkItem(master_devobj); + if (!work_item) { + ERR("out of memory\n"); + return; + } context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG); diff --git a/drivers/filesystems/btrfs/security.c b/drivers/filesystems/btrfs/security.c index 42ff987723a..bf5cff0fdfc 100644 --- a/drivers/filesystems/btrfs/security.c +++ b/drivers/filesystems/btrfs/security.c @@ -432,7 +432,7 @@ static void get_top_level_sd(fcb* fcb) { goto end; } - RtlSetOwnerSecurityDescriptor(&sd, usersid, false); + Status = RtlSetOwnerSecurityDescriptor(&sd, usersid, false); if (!NT_SUCCESS(Status)) { ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status); @@ -442,11 +442,10 @@ static void get_top_level_sd(fcb* fcb) { gid_to_sid(fcb->inode_item.st_gid, &groupsid); if (!groupsid) { ERR("out of memory\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } - RtlSetGroupSecurityDescriptor(&sd, groupsid, false); + Status = RtlSetGroupSecurityDescriptor(&sd, groupsid, false); if (!NT_SUCCESS(Status)) { ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status); @@ -486,7 +485,6 @@ static void get_top_level_sd(fcb* fcb) { fcb->sd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG); if (!fcb->sd) { ERR("out of memory\n"); - Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } @@ -494,6 +492,8 @@ static void get_top_level_sd(fcb* fcb) { if (!NT_SUCCESS(Status)) { ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status); + ExFreePool(fcb->sd); + fcb->sd = NULL; goto end; } @@ -528,6 +528,7 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr, PIRP Irp) { &subjcont, IoGetFileObjectGenericMapping(), PagedPool); if (!NT_SUCCESS(Status)) { ERR("SeAssignSecurityEx returned %08x\n", Status); + return; } Status = uid_to_sid(fcb->inode_item.st_uid, &usersid); @@ -541,6 +542,7 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr, PIRP Irp) { gid_to_sid(fcb->inode_item.st_gid, &groupsid); if (!groupsid) { ERR("out of memory\n"); + ExFreePool(usersid); return; } @@ -733,7 +735,7 @@ static NTSTATUS set_file_security(device_extension* Vcb, PFILE_OBJECT FileObject mark_fcb_dirty(fcb); - send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, NULL); + queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, NULL); end: ExReleaseResourceLite(fcb->Header.Resource); diff --git a/drivers/filesystems/btrfs/send.c b/drivers/filesystems/btrfs/send.c index 4737be0a85a..2090131dc99 100644 --- a/drivers/filesystems/btrfs/send.c +++ b/drivers/filesystems/btrfs/send.c @@ -3598,6 +3598,7 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ send_info* send; ULONG num_clones = 0; root** clones = NULL; + OBJECT_ATTRIBUTES oa; if (!FileObject || !FileObject->FsContext || !FileObject->FsContext2 || FileObject->FsContext == Vcb->volume_fcb) return STATUS_INVALID_PARAMETER; @@ -3810,7 +3811,9 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ InterlockedIncrement(&Vcb->running_sends); - Status = PsCreateSystemThread(&send->thread, 0, NULL, NULL, NULL, send_thread, context); + InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + + Status = PsCreateSystemThread(&send->thread, 0, &oa, NULL, NULL, send_thread, context); if (!NT_SUCCESS(Status)) { ERR("PsCreateSystemThread returned %08x\n", Status); ccb->send = NULL; diff --git a/drivers/filesystems/btrfs/volume.c b/drivers/filesystems/btrfs/volume.c index d50852b5952..0718bb8d9de 100644 --- a/drivers/filesystems/btrfs/volume.c +++ b/drivers/filesystems/btrfs/volume.c @@ -31,6 +31,7 @@ extern PDEVICE_OBJECT busobj; extern ERESOURCE pdo_list_lock; extern LIST_ENTRY pdo_list; extern UNICODE_STRING registry_path; +extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx; NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { volume_device_extension* vde = DeviceObject->DeviceExtension; @@ -46,6 +47,51 @@ NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { return STATUS_SUCCESS; } +void free_vol(volume_device_extension* vde) { + PDEVICE_OBJECT pdo; + + vde->dead = true; + + if (vde->mounted_device) { + device_extension* Vcb = vde->mounted_device->DeviceExtension; + + Vcb->vde = NULL; + } + + if (vde->name.Buffer) + ExFreePool(vde->name.Buffer); + + ExDeleteResourceLite(&vde->pdode->child_lock); + + if (vde->pdo->AttachedDevice) + IoDetachDevice(vde->pdo); + + while (!IsListEmpty(&vde->pdode->children)) { + volume_child* vc = CONTAINING_RECORD(RemoveHeadList(&vde->pdode->children), volume_child, list_entry); + + if (vc->notification_entry) { + if (fIoUnregisterPlugPlayNotificationEx) + fIoUnregisterPlugPlayNotificationEx(vc->notification_entry); + else + IoUnregisterPlugPlayNotification(vc->notification_entry); + } + + if (vc->pnp_name.Buffer) + ExFreePool(vc->pnp_name.Buffer); + + ExFreePool(vc); + } + + if (no_pnp) + ExFreePool(vde->pdode); + + pdo = vde->pdo; + IoDeleteDevice(vde->device); + + if (!no_pnp) + IoDeleteDevice(pdo); +} + NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { volume_device_extension* vde = DeviceObject->DeviceExtension; pdo_device_extension* pdode = vde->pdode; @@ -54,47 +100,22 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { Irp->IoStatus.Information = 0; + if (vde->dead) + return STATUS_SUCCESS; + ExAcquireResourceExclusiveLite(&pdo_list_lock, true); + if (vde->dead) { + ExReleaseResourceLite(&pdo_list_lock); + return STATUS_SUCCESS; + } + ExAcquireResourceSharedLite(&pdode->child_lock, true); if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) { - NTSTATUS Status; - UNICODE_STRING mmdevpath; - PDEVICE_OBJECT mountmgr; - PFILE_OBJECT mountmgrfo; - PDEVICE_OBJECT pdo; - - RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); - Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); - if (!NT_SUCCESS(Status)) - ERR("IoGetDeviceObjectPointer returned %08x\n", Status); - else { - remove_drive_letter(mountmgr, &vde->name); - - ObDereferenceObject(mountmgrfo); - } - - if (vde->mounted_device) { - device_extension* Vcb = vde->mounted_device->DeviceExtension; - - Vcb->vde = NULL; - } - - if (vde->name.Buffer) - ExFreePool(vde->name.Buffer); - ExReleaseResourceLite(&pdode->child_lock); - ExDeleteResourceLite(&pdode->child_lock); - - if (vde->pdo->AttachedDevice) - IoDetachDevice(vde->pdo); - - pdo = vde->pdo; - IoDeleteDevice(vde->device); - if (!no_pnp) - IoDeleteDevice(pdo); + free_vol(vde); } else ExReleaseResourceLite(&pdode->child_lock); @@ -767,6 +788,8 @@ static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde, PIRP Irp) { ExReleaseResourceLite(&pdode->child_lock); + IoFreeIrp(Irp2); + return Status; } @@ -998,108 +1021,129 @@ end: } typedef struct { - PIO_WORKITEM work_item; - pdo_device_extension* pdode; -} drive_letter_callback_context; - -_Function_class_(IO_WORKITEM_ROUTINE) -static void __stdcall drive_letter_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { - drive_letter_callback_context* context = con; + LIST_ENTRY list_entry; + UNICODE_STRING name; NTSTATUS Status; - UNICODE_STRING mmdevpath; - PDEVICE_OBJECT mountmgr; - PFILE_OBJECT mountmgrfo; - LIST_ENTRY* le; - - UNUSED(DeviceObject); + BTRFS_UUID uuid; +} drive_letter_removal; - RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); - Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); - if (!NT_SUCCESS(Status)) { - ERR("IoGetDeviceObjectPointer returned %08x\n", Status); - return; - } - - ExAcquireResourceSharedLite(&pdo_list_lock, true); - - le = pdo_list.Flink; - while (le != &pdo_list) { - pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); +static void drive_letter_callback2(pdo_device_extension* pdode, PDEVICE_OBJECT mountmgr) { + LIST_ENTRY* le; + LIST_ENTRY dlrlist; - if (pdode == context->pdode) { - LIST_ENTRY* le2; + InitializeListHead(&dlrlist); - ExAcquireResourceExclusiveLite(&pdode->child_lock, true); + ExAcquireResourceExclusiveLite(&pdode->child_lock, true); - le2 = pdode->children.Flink; + le = pdode->children.Flink; - while (le2 != &pdode->children) { - UNICODE_STRING name; + while (le != &pdode->children) { + drive_letter_removal* dlr; - volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); + volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); - name.Length = name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR)); - name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG); + dlr = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_removal), ALLOC_TAG); + if (!dlr) { + ERR("out of memory\n"); - if (!name.Buffer) { - ERR("out of memory\n"); + while (!IsListEmpty(&dlrlist)) { + dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry); - ExReleaseResourceLite(&pdode->child_lock); - ExReleaseResourceLite(&pdo_list_lock); - ObDereferenceObject(mountmgrfo); - IoFreeWorkItem(context->work_item); - return; - } + ExFreePool(dlr->name.Buffer); + ExFreePool(dlr); + } - RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR)); - RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length); + ExReleaseResourceLite(&pdode->child_lock); + return; + } - Status = remove_drive_letter(mountmgr, &name); + dlr->name.Length = dlr->name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR)); + dlr->name.Buffer = ExAllocatePoolWithTag(PagedPool, dlr->name.Length, ALLOC_TAG); - if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) - WARN("remove_drive_letter returned %08x\n", Status); + if (!dlr->name.Buffer) { + ERR("out of memory\n"); - ExFreePool(name.Buffer); + ExFreePool(dlr); - vc->had_drive_letter = NT_SUCCESS(Status); + while (!IsListEmpty(&dlrlist)) { + dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry); - le2 = le2->Flink; + ExFreePool(dlr->name.Buffer); + ExFreePool(dlr); } ExReleaseResourceLite(&pdode->child_lock); - ExReleaseResourceLite(&pdo_list_lock); - ObDereferenceObject(mountmgrfo); - IoFreeWorkItem(context->work_item); return; } + RtlCopyMemory(dlr->name.Buffer, L"\\??", 3 * sizeof(WCHAR)); + RtlCopyMemory(&dlr->name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length); + + dlr->uuid = vc->uuid; + + InsertTailList(&dlrlist, &dlr->list_entry); + le = le->Flink; } - ExReleaseResourceLite(&pdo_list_lock); + ExReleaseResourceLite(&pdode->child_lock); - ObDereferenceObject(mountmgrfo); - IoFreeWorkItem(context->work_item); -} + le = dlrlist.Flink; + while (le != &dlrlist) { + drive_letter_removal* dlr = CONTAINING_RECORD(le, drive_letter_removal, list_entry); -static void add_drive_letter_work_item(pdo_device_extension* pdode) { - PIO_WORKITEM work_item; - drive_letter_callback_context* context; + dlr->Status = remove_drive_letter(mountmgr, &dlr->name); - work_item = IoAllocateWorkItem(master_devobj); + if (!NT_SUCCESS(dlr->Status) && dlr->Status != STATUS_NOT_FOUND) + WARN("remove_drive_letter returned %08x\n", dlr->Status); - context = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_callback_context), ALLOC_TAG); + le = le->Flink; + } - if (!context) { - ERR("out of memory\n"); - IoFreeWorkItem(work_item); + // set vc->had_drive_letter + + ExAcquireResourceExclusiveLite(&pdode->child_lock, true); + + while (!IsListEmpty(&dlrlist)) { + drive_letter_removal* dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry); + + le = pdode->children.Flink; + + while (le != &pdode->children) { + volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); + + if (RtlCompareMemory(&vc->uuid, &dlr->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { + vc->had_drive_letter = NT_SUCCESS(dlr->Status); + break; + } + + le = le->Flink; + } + + ExFreePool(dlr->name.Buffer); + ExFreePool(dlr); + } + + ExReleaseResourceLite(&pdode->child_lock); +} + +_Function_class_(IO_WORKITEM_ROUTINE) +static void __stdcall drive_letter_callback(pdo_device_extension* pdode) { + NTSTATUS Status; + UNICODE_STRING mmdevpath; + PDEVICE_OBJECT mountmgr; + PFILE_OBJECT mountmgrfo; + + RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); + Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); + if (!NT_SUCCESS(Status)) { + ERR("IoGetDeviceObjectPointer returned %08x\n", Status); return; } - context->work_item = work_item; - context->pdode = pdode; + drive_letter_callback2(pdode, mountmgr); - IoQueueWorkItem(work_item, drive_letter_callback, DelayedWorkQueue, context); + ObDereferenceObject(mountmgrfo); } void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, ULONG disk_num, ULONG part_num) { @@ -1112,6 +1156,7 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, bool inserted = false, new_pdo = false; pdo_device_extension* pdode = NULL; PDEVICE_OBJECT pdo = NULL; + bool process_drive_letters = false; if (devpath->Length == 0) return; @@ -1312,7 +1357,7 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, WARN("IoSetDeviceInterfaceState returned %08x\n", Status); } - add_drive_letter_work_item(pdode); + process_drive_letters = true; } ExReleaseResourceLite(&pdode->child_lock); @@ -1322,6 +1367,9 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, ExReleaseResourceLite(&pdo_list_lock); + if (process_drive_letters) + drive_letter_callback(pdode); + if (new_pdo) { if (no_pnp) AddDevice(drvobj, pdo); diff --git a/drivers/filesystems/btrfs/write.c b/drivers/filesystems/btrfs/write.c index c982e939b17..96ae287e02c 100644 --- a/drivers/filesystems/btrfs/write.c +++ b/drivers/filesystems/btrfs/write.c @@ -4164,7 +4164,7 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void TRACE("(%p, %p, %I64x, %p, %x, %u, %u)\n", Vcb, FileObject, offset.QuadPart, buf, *length, paging_io, no_cache); if (*length == 0) { - WARN("returning success for zero-length write\n"); + TRACE("returning success for zero-length write\n"); return STATUS_SUCCESS; } @@ -4231,20 +4231,18 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void acquired_tree_lock = true; } - if (no_cache) { - if (pagefile) { - if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { - Status = STATUS_PENDING; - goto end; - } else - acquired_fcb_lock = true; - } else if (!ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource)) { - if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, wait)) { - Status = STATUS_PENDING; - goto end; - } else - acquired_fcb_lock = true; - } + if (pagefile) { + if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { + Status = STATUS_PENDING; + goto end; + } else + acquired_fcb_lock = true; + } else if (!ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource)) { + if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, wait)) { + Status = STATUS_PENDING; + goto end; + } else + acquired_fcb_lock = true; } newlength = fcb->ads ? fcb->adsdata.Length : fcb->inode_item.st_size; @@ -4258,7 +4256,6 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void if (paging_io) { if (off64 >= newlength) { TRACE("paging IO tried to write beyond end of file (file size = %I64x, offset = %I64x, length = %x)\n", newlength, off64, *length); - TRACE("filename %S\n", file_desc(FileObject)); TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n", fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); Status = STATUS_SUCCESS; @@ -4354,8 +4351,8 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void } _SEH2_END; if (changed_length) { - send_notification_fcb(fcb->ads ? fileref->parent : fileref, fcb->ads ? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE, - fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name : NULL); + queue_notification_fcb(fcb->ads ? fileref->parent : fileref, fcb->ads ? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE, + fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name : NULL); } goto end; @@ -4609,8 +4606,8 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void Status = STATUS_SUCCESS; if (filter != 0) - send_notification_fcb(fcb->ads ? fileref->parent : fileref, filter, fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, - fcb->ads && fileref->dc ? &fileref->dc->name : NULL); + queue_notification_fcb(fcb->ads ? fileref->parent : fileref, filter, fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, + fcb->ads && fileref->dc ? &fileref->dc->name : NULL); end: if (NT_SUCCESS(Status) && FileObject->Flags & FO_SYNCHRONOUS_IO && !paging_io) { @@ -4779,6 +4776,9 @@ NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { Irp->MdlAddress = NULL; Status = STATUS_SUCCESS; } else { + if (!(Irp->Flags & IRP_PAGING_IO)) + FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL); + // Don't offload jobs when doing paging IO - otherwise this can lead to // deadlocks in CcCopyWrite. if (Irp->Flags & IRP_PAGING_IO) diff --git a/media/doc/README.FSD b/media/doc/README.FSD index 534e264b010..9ce6e3a7d29 100644 --- a/media/doc/README.FSD +++ b/media/doc/README.FSD @@ -3,7 +3,7 @@ The following FSD are shared with:
https://github.com/maharmstone/btrfs
. -reactos/drivers/filesystems/btrfs # Synced to 1.4 +reactos/drivers/filesystems/btrfs # Synced to 1.5 reactos/dll/shellext/shellbtrfs # Synced to 1.1 reactos/sdk/lib/fslib/btrfslib # Synced to 1.4
5 years, 1 month
1
0
0
0
[reactos] 01/01: [SHELLEXT][FONTEXT] An attempt to implement IDropTarget (#2019)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c214c0496477a9f3e7aa6…
commit c214c0496477a9f3e7aa65c063cbf0cdf66f175a Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Tue Nov 12 20:26:56 2019 +0900 Commit: GitHub <noreply(a)github.com> CommitDate: Tue Nov 12 20:26:56 2019 +0900 [SHELLEXT][FONTEXT] An attempt to implement IDropTarget (#2019) CORE-12861 --- dll/shellext/fontext/CFontCache.cpp | 4 - dll/shellext/fontext/CFontExt.cpp | 173 +++++++++++++++++++++++++++++++++++- dll/shellext/fontext/CFontExt.hpp | 13 ++- dll/shellext/fontext/CFontMenu.cpp | 12 +-- dll/shellext/fontext/CMakeLists.txt | 2 +- dll/shellext/fontext/precomp.h | 26 ++++++ 6 files changed, 211 insertions(+), 19 deletions(-) diff --git a/dll/shellext/fontext/CFontCache.cpp b/dll/shellext/fontext/CFontCache.cpp index 4d3ae5fcdf5..8bccf346582 100644 --- a/dll/shellext/fontext/CFontCache.cpp +++ b/dll/shellext/fontext/CFontCache.cpp @@ -9,10 +9,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(fontext); - -#define FONT_HIVE HKEY_LOCAL_MACHINE -#define FONT_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" - CFontCache* g_FontCache = NULL; CFontInfo::CFontInfo(LPCWSTR name) diff --git a/dll/shellext/fontext/CFontExt.cpp b/dll/shellext/fontext/CFontExt.cpp index de502a43fdb..1ce5325500a 100644 --- a/dll/shellext/fontext/CFontExt.cpp +++ b/dll/shellext/fontext/CFontExt.cpp @@ -3,6 +3,7 @@ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later
) * PURPOSE: CFontExt implementation * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org) + * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com) */ #include "precomp.h" @@ -196,9 +197,10 @@ STDMETHODIMP CFontExt::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppv if (IsEqualIID(riid, IID_IDropTarget)) { - // Needed to drop files into the fonts folder, we should probably install them? ERR("IDropTarget not implemented\n"); - hr = E_NOTIMPL; + *ppvOut = static_cast<IDropTarget *>(this); + AddRef(); + hr = S_OK; } else if (IsEqualIID(riid, IID_IContextMenu)) { @@ -363,3 +365,170 @@ STDMETHODIMP CFontExt::GetClassID(CLSID *lpClassId) return S_OK; } +// *** IDropTarget methods *** +STDMETHODIMP CFontExt::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) +{ + *pdwEffect = DROPEFFECT_NONE; + + CComHeapPtr<CIDA> cida; + HRESULT hr = _GetCidlFromDataObject(pDataObj, &cida); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + +#if 1 // Please implement DoGetFontTitle + return DRAGDROP_S_CANCEL; +#else + *pdwEffect = DROPEFFECT_COPY; + return S_OK; +#endif +} + +STDMETHODIMP CFontExt::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) +{ + return S_OK; +} + +STDMETHODIMP CFontExt::DragLeave() +{ + return S_OK; +} + +STDMETHODIMP CFontExt::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) +{ + *pdwEffect = DROPEFFECT_NONE; + + WCHAR szFontsDir[MAX_PATH]; + HRESULT hr = SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, szFontsDir); + if (FAILED_UNEXPECTEDLY(hr)) + return E_FAIL; + + CComHeapPtr<CIDA> cida; + hr = _GetCidlFromDataObject(pDataObj, &cida); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + PCUIDLIST_ABSOLUTE pidlParent = HIDA_GetPIDLFolder(cida); + if (!pidlParent) + { + ERR("pidlParent is NULL\n"); + return E_FAIL; + } + + BOOL bOK = TRUE; + CAtlArray<CStringW> FontPaths; + for (UINT n = 0; n < cida->cidl; ++n) + { + PCUIDLIST_RELATIVE pidlRelative = HIDA_GetPIDLItem(cida, n); + if (!pidlRelative) + continue; + + PIDLIST_ABSOLUTE pidl = ILCombine(pidlParent, pidlRelative); + if (!pidl) + { + ERR("ILCombine failed\n"); + bOK = FALSE; + break; + } + + WCHAR szPath[MAX_PATH]; + BOOL ret = SHGetPathFromIDListW(pidl, szPath); + ILFree(pidl); + + if (!ret) + { + ERR("SHGetPathFromIDListW failed\n"); + bOK = FALSE; + break; + } + + if (PathIsDirectoryW(szPath)) + { + ERR("PathIsDirectory\n"); + bOK = FALSE; + break; + } + + LPCWSTR pchDotExt = PathFindExtensionW(szPath); + if (!IsFontDotExt(pchDotExt)) + { + ERR("'%S' is not supported\n", pchDotExt); + bOK = FALSE; + break; + } + + FontPaths.Add(szPath); + } + + if (!bOK) + return E_FAIL; + + CRegKey keyFonts; + if (keyFonts.Open(FONT_HIVE, FONT_KEY, KEY_WRITE) != ERROR_SUCCESS) + { + ERR("keyFonts.Open failed\n"); + return E_FAIL; + } + + for (size_t iItem = 0; iItem < FontPaths.GetCount(); ++iItem) + { + HRESULT hr = DoInstallFontFile(FontPaths[iItem], szFontsDir, keyFonts.m_hKey); + if (FAILED_UNEXPECTEDLY(hr)) + { + bOK = FALSE; + break; + } + } + + // TODO: update g_FontCache + + SendMessageW(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); + + // TODO: Show message + + return bOK ? S_OK : E_FAIL; +} + +HRESULT CFontExt::DoInstallFontFile(LPCWSTR pszFontPath, LPCWSTR pszFontsDir, HKEY hkeyFonts) +{ + WCHAR szDestFile[MAX_PATH]; + LPCWSTR pszFileTitle = PathFindFileName(pszFontPath); + + WCHAR szFontName[512]; + if (!DoGetFontTitle(pszFontPath, szFontName)) + return E_FAIL; + + RemoveFontResourceW(pszFileTitle); + + StringCchCopyW(szDestFile, sizeof(szDestFile), pszFontsDir); + PathAppendW(szDestFile, pszFileTitle); + if (!CopyFileW(pszFontPath, szDestFile, FALSE)) + { + ERR("CopyFileW('%S', '%S') failed\n", pszFontPath, szDestFile); + return E_FAIL; + } + + if (!AddFontResourceW(pszFileTitle)) + { + ERR("AddFontResourceW('%S') failed\n", pszFileTitle); + DeleteFileW(szDestFile); + return E_FAIL; + } + + DWORD cbData = (wcslen(pszFileTitle) + 1) * sizeof(WCHAR); + LONG nError = RegSetValueExW(hkeyFonts, szFontName, 0, REG_SZ, (const BYTE *)szFontName, cbData); + if (nError) + { + ERR("RegSetValueExW failed with %ld\n", nError); + RemoveFontResourceW(pszFileTitle); + DeleteFileW(szDestFile); + return E_FAIL; + } + + return S_OK; +} + +HRESULT CFontExt::DoGetFontTitle(LPCWSTR pszFontPath, LPCWSTR pszFontName) +{ + // TODO: + return E_FAIL; +} diff --git a/dll/shellext/fontext/CFontExt.hpp b/dll/shellext/fontext/CFontExt.hpp index 0e7a04482d9..19d94f6fa1c 100644 --- a/dll/shellext/fontext/CFontExt.hpp +++ b/dll/shellext/fontext/CFontExt.hpp @@ -3,6 +3,7 @@ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later
) * PURPOSE: CFontExt definition * COPYRIGHT: Copyright 2019 Mark Jansen (mark.jansen(a)reactos.org) + * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com) */ #pragma once @@ -11,7 +12,8 @@ class CFontExt : public CComCoClass<CFontExt, &CLSID_CFontExt>, public CComObjectRootEx<CComMultiThreadModelNoCS>, public IShellFolder2, - public IPersistFolder2 + public IPersistFolder2, + public IDropTarget { CComHeapPtr<ITEMIDLIST> m_Folder; @@ -51,6 +53,11 @@ public: // *** IPersist methods *** virtual STDMETHODIMP GetClassID(CLSID *lpClassId); + // *** IDropTarget methods *** + virtual STDMETHODIMP DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect); + virtual STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect); + virtual STDMETHODIMP DragLeave(); + virtual STDMETHODIMP Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect); #if 0 static HRESULT WINAPI log_stuff(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw) @@ -79,6 +86,10 @@ public: COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) //COM_INTERFACE_ENTRY_FUNC_BLIND(0, log_stuff) END_COM_MAP() + + HRESULT DoInstallFontFile(LPCWSTR pszFontPath, LPCWSTR pszFontsDir, HKEY hkeyFonts); + HRESULT DoGetFontTitle(LPCWSTR pszFontPath, LPCWSTR pszFontName); }; diff --git a/dll/shellext/fontext/CFontMenu.cpp b/dll/shellext/fontext/CFontMenu.cpp index eab4427202d..0a2f0e55856 100644 --- a/dll/shellext/fontext/CFontMenu.cpp +++ b/dll/shellext/fontext/CFontMenu.cpp @@ -9,18 +9,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(fontext); - -static inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida) -{ - return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]); -} - -static inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i) -{ - return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]); -} - static CLIPFORMAT g_cfHIDA; + HRESULT _GetCidlFromDataObject(IDataObject *pDataObject, CIDA** ppcida) { if (g_cfHIDA == NULL) diff --git a/dll/shellext/fontext/CMakeLists.txt b/dll/shellext/fontext/CMakeLists.txt index a5ae38822cf..2f2586b2517 100644 --- a/dll/shellext/fontext/CMakeLists.txt +++ b/dll/shellext/fontext/CMakeLists.txt @@ -32,7 +32,7 @@ add_library(fontext MODULE set_module_type(fontext win32dll UNICODE) target_link_libraries(fontext uuid wine) -add_delay_importlibs(fontext ole32 oleaut32 shlwapi) +add_delay_importlibs(fontext ole32 oleaut32 shlwapi gdi32) add_importlibs(fontext shell32 advapi32 user32 msvcrt kernel32 ntdll) add_pch(fontext precomp.h SOURCE) add_cd_file(TARGET fontext DESTINATION reactos/system32 FOR all) diff --git a/dll/shellext/fontext/precomp.h b/dll/shellext/fontext/precomp.h index 28606824c1f..c17b4e53c71 100644 --- a/dll/shellext/fontext/precomp.h +++ b/dll/shellext/fontext/precomp.h @@ -27,6 +27,8 @@ extern LONG g_ModuleRefCnt; #include "CFontCache.hpp" #include "CFontExt.hpp" +#define FONT_HIVE HKEY_LOCAL_MACHINE +#define FONT_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" HRESULT _CEnumFonts_CreateInstance(CFontExt* zip, DWORD flags, REFIID riid, LPVOID* ppvOut); HRESULT _CFontMenu_CreateInstance(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, @@ -34,6 +36,30 @@ HRESULT _CFontMenu_CreateInstance(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY ap HRESULT _CDataObject_CreateInstance(PCIDLIST_ABSOLUTE folder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, LPVOID* ppvOut); +HRESULT _GetCidlFromDataObject(IDataObject *pDataObject, CIDA** ppcida); +inline PCUIDLIST_ABSOLUTE HIDA_GetPIDLFolder(CIDA const* pida) +{ + return (PCUIDLIST_ABSOLUTE)(((LPBYTE)pida) + (pida)->aoffset[0]); +} + +inline PCUIDLIST_RELATIVE HIDA_GetPIDLItem(CIDA const* pida, SIZE_T i) +{ + return (PCUIDLIST_RELATIVE)(((LPBYTE)pida) + (pida)->aoffset[i + 1]); +} + +inline BOOL IsFontDotExt(LPCWSTR pchDotExt) +{ + static const LPCWSTR array[] = + { + L".ttf", L".ttc", L".otf", L".otc", L".fon", L".fnt", NULL + }; + for (const LPCWSTR *pp = array; *pp; ++pp) + { + if (!_wcsicmp(*pp, pchDotExt)) + return TRUE; + } + return FALSE; +} #endif /* FONTEXT_PRECOMP_H */
5 years, 1 month
1
0
0
0
[reactos] 01/01: [SHELL32] Add SendTo My Documents (#2027)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d037003511fb832d3d952…
commit d037003511fb832d3d952b3696808723301a3224 Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Tue Nov 12 16:54:28 2019 +0900 Commit: GitHub <noreply(a)github.com> CommitDate: Tue Nov 12 16:54:28 2019 +0900 [SHELL32] Add SendTo My Documents (#2027) If SendTo folder is empty in SHGetFolderPathAndSubDirW function, then add a shortcut file linked to My Documents. CORE-16496 --- dll/win32/shell32/wine/shellpath.c | 76 +++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/dll/win32/shell32/wine/shellpath.c b/dll/win32/shell32/wine/shellpath.c index b247fd3bf3e..38e8dbebd96 100644 --- a/dll/win32/shell32/wine/shellpath.c +++ b/dll/win32/shell32/wine/shellpath.c @@ -3,7 +3,7 @@ * * Copyright 1998, 1999, 2000 Juergen Schmied * Copyright 2004 Juan Lang - * Copyright 2018 Katayama Hirofumi MZ + * Copyright 2018-2019 Katayama Hirofumi MZ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -42,6 +42,7 @@ #include <wine/unicode.h> #include <shlwapi_undoc.h> +#include <shellutils.h> #include <userenv.h> @@ -2144,6 +2145,74 @@ cleanup: return hr; } +static HRESULT +CreateShellLink( + LPCWSTR pszLinkPath, + LPCWSTR pszCmd, + LPCWSTR pszArg OPTIONAL, + LPCWSTR pszDir OPTIONAL, + LPCWSTR pszIconPath OPTIONAL, + INT iIconNr OPTIONAL, + LPCWSTR pszComment OPTIONAL) +{ + IShellLinkW *psl; + IPersistFile *ppf; + + HRESULT hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = IShellLinkW_SetPath(psl, pszCmd); + if (FAILED_UNEXPECTEDLY(hr)) + { + IShellLinkW_Release(psl); + return hr; + } + + if (pszArg) + hr = IShellLinkW_SetArguments(psl, pszArg); + + if (pszDir) + hr = IShellLinkW_SetWorkingDirectory(psl, pszDir); + + if (pszIconPath) + hr = IShellLinkW_SetIconLocation(psl, pszIconPath, iIconNr); + + if (pszComment) + hr = IShellLinkW_SetDescription(psl, pszComment); + + hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf); + + if (SUCCEEDED(hr)) + { + hr = IPersistFile_Save(ppf, pszLinkPath, TRUE); + IPersistFile_Release(ppf); + } + + IShellLinkW_Release(psl); + + return hr; +} + +HRESULT DoCreateSendToFiles(LPCWSTR pszSendTo) +{ + WCHAR szTarget[MAX_PATH]; + WCHAR szSendToFile[MAX_PATH]; + HRESULT hr; + + SHGetSpecialFolderPathW(NULL, szTarget, CSIDL_MYDOCUMENTS, TRUE); + + StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo); + PathAppendW(szSendToFile, PathFindFileNameW(szTarget)); + StringCbCatW(szSendToFile, sizeof(szSendToFile), L".lnk"); + + hr = CreateShellLink(szSendToFile, szTarget, NULL, NULL, NULL, -1, NULL); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return hr; +} + /************************************************************************* * SHGetFolderPathAndSubDirW [SHELL32.@] */ @@ -2314,6 +2383,11 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW( } end: + if (folder == CSIDL_SENDTO) + { + if (PathIsDirectoryEmptyW(szBuildPath)) + DoCreateSendToFiles(szBuildPath); + } TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath)); return hr; }
5 years, 1 month
1
0
0
0
[reactos] 01/01: [SHELL32_APITEST] Add DragDrop testcase (#2023)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6e42e63c4623bb929a968…
commit 6e42e63c4623bb929a968309b0ea4f9d82483c1f Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Tue Nov 12 16:49:52 2019 +0900 Commit: GitHub <noreply(a)github.com> CommitDate: Tue Nov 12 16:49:52 2019 +0900 [SHELL32_APITEST] Add DragDrop testcase (#2023) Add DragDrop testcase to shell32_apitest for testing Drag & Drop feature of the Shell. This PR tests IDropTarget::DragEnter and IDropTarget::Drop. CORE-11238 --- modules/rostests/apitests/shell32/CMakeLists.txt | 1 + modules/rostests/apitests/shell32/DragDrop.cpp | 381 +++++++++++++++++++++++ modules/rostests/apitests/shell32/testlist.c | 2 + 3 files changed, 384 insertions(+) diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt b/modules/rostests/apitests/shell32/CMakeLists.txt index 02b28625d63..f8d8c84e8d8 100644 --- a/modules/rostests/apitests/shell32/CMakeLists.txt +++ b/modules/rostests/apitests/shell32/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND SOURCE CShellLink.cpp CUserNotification.cpp Control_RunDLLW.cpp + DragDrop.cpp IShellFolderViewCB.cpp OpenAs_RunDLL.cpp PathResolve.cpp diff --git a/modules/rostests/apitests/shell32/DragDrop.cpp b/modules/rostests/apitests/shell32/DragDrop.cpp new file mode 100644 index 00000000000..43e06f5a0b2 --- /dev/null +++ b/modules/rostests/apitests/shell32/DragDrop.cpp @@ -0,0 +1,381 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory + * PURPOSE: Test for Drag & Drop + * PROGRAMMER: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> + */ + +#include "shelltest.h" +#include <shlwapi.h> + +#define NDEBUG +#include <debug.h> +#include <stdio.h> + +#define TESTFILENAME L"DragDropTest.txt" +#define DROPPED_ON_FILE L"DragDroppedOn.lnk" + +static CComPtr<IShellFolder> s_pDesktop; + +static WCHAR s_szSrcTestFile[MAX_PATH]; +static WCHAR s_szDestFolder[MAX_PATH]; +static WCHAR s_szDestTestFile[MAX_PATH]; +static WCHAR s_szDestLinkSpec[MAX_PATH]; +static WCHAR s_szDroppedToItem[MAX_PATH]; + +enum OP +{ + OP_NONE, + OP_COPY, + OP_MOVE, + OP_LINK, + OP_NONE_OR_COPY, + OP_NONE_OR_MOVE, + OP_NONE_OR_LINK +}; + +#define D_NONE DROPEFFECT_NONE +#define D_COPY DROPEFFECT_COPY +#define D_MOVE DROPEFFECT_MOVE +#define D_LINK DROPEFFECT_LINK +#define D_NONE_OR_COPY 0xAABBCCDD +#define D_NONE_OR_MOVE 0x11223344 +#define D_NONE_OR_LINK 0x55667788 + +struct TEST_ENTRY +{ + int line; + OP op; + HRESULT hr1; + HRESULT hr2; + DWORD dwKeyState; + DWORD dwEffects1; + DWORD dwEffects2; + DWORD dwEffects3; +}; + +static const TEST_ENTRY s_TestEntries[] = +{ + // MK_LBUTTON + { __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON, D_NONE, D_NONE, D_NONE }, + { __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON, D_COPY, D_COPY, D_COPY }, + { __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON, D_COPY | D_MOVE, D_MOVE, D_NONE }, + { __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON, D_MOVE, D_MOVE, D_NONE }, + { __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON, D_LINK, D_LINK, D_LINK }, + + // MK_LBUTTON | MK_SHIFT + { __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_NONE, D_NONE, D_NONE }, + { __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_COPY, D_NONE_OR_COPY, D_NONE_OR_COPY }, + { __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_COPY | D_MOVE, D_MOVE, D_NONE }, + { __LINE__, OP_MOVE, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_MOVE, D_MOVE, D_NONE }, + { __LINE__, OP_NONE_OR_LINK, S_OK, S_OK, MK_LBUTTON | MK_SHIFT, D_LINK, D_NONE_OR_LINK, D_NONE_OR_LINK }, + + // MK_LBUTTON | MK_SHIFT | MK_CONTROL +#define MK_LBUTTON_SHIFT_CTRL (MK_LBUTTON | MK_SHIFT | MK_CONTROL) + { __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_NONE, D_NONE, D_NONE }, + { __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_COPY, D_NONE_OR_COPY, D_NONE_OR_COPY }, + { __LINE__, OP_NONE_OR_COPY, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_COPY | D_MOVE, D_NONE_OR_COPY, D_NONE_OR_COPY }, + { __LINE__, OP_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_MOVE, D_NONE_OR_MOVE, D_NONE_OR_MOVE }, + { __LINE__, OP_LINK, S_OK, S_OK, MK_LBUTTON_SHIFT_CTRL, D_LINK, D_LINK, D_LINK }, +#undef MK_LBUTTON_SHIFT_CTRL + + // MK_LBUTTON | MK_CONTROL + { __LINE__, OP_NONE, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_NONE, D_NONE, D_NONE }, + { __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_COPY, D_COPY, D_COPY }, + { __LINE__, OP_COPY, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_COPY | D_MOVE, D_COPY, D_COPY }, + { __LINE__, OP_NONE_OR_MOVE, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_MOVE, D_NONE_OR_MOVE, D_NONE_OR_MOVE }, + { __LINE__, OP_NONE_OR_LINK, S_OK, S_OK, MK_LBUTTON | MK_CONTROL, D_LINK, D_NONE_OR_LINK, D_NONE_OR_LINK }, +}; + +static void DoCreateTestFile(LPCWSTR pszFileName) +{ + FILE *fp = _wfopen(pszFileName, L"wb"); + ok(fp != NULL, "fp is NULL for '%S'\n", pszFileName); + fclose(fp); +} + +HRESULT DoCreateShortcut( + LPCWSTR pszLnkFileName, + LPCWSTR pszTargetPathName) +{ + CComPtr<IPersistFile> ppf; + CComPtr<IShellLinkW> psl; + HRESULT hr; + + hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLinkW, (LPVOID *)&psl); + if (SUCCEEDED(hr)) + { + psl->SetPath(pszTargetPathName); + + hr = psl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf); + if (SUCCEEDED(hr)) + { + hr = ppf->Save(pszLnkFileName, TRUE); + } + } + + return hr; +} + +static HRESULT +GetUIObjectOfAbsPidl(PIDLIST_ABSOLUTE pidl, REFIID riid, LPVOID *ppvOut) +{ + *ppvOut = NULL; + + LPCITEMIDLIST pidlLast; + CComPtr<IShellFolder> psf; + HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID *)&psf, + &pidlLast); + if (FAILED(hr)) + return hr; + + hr = psf->GetUIObjectOf(NULL, 1, &pidlLast, riid, NULL, ppvOut); + return hr; +} + +static HRESULT +GetUIObjectOfPath(LPCWSTR pszPath, REFIID riid, LPVOID *ppvOut) +{ + *ppvOut = NULL; + + PIDLIST_ABSOLUTE pidl = ILCreateFromPathW(pszPath); + if (!pidl) + return E_FAIL; + + HRESULT hr = GetUIObjectOfAbsPidl(pidl, riid, ppvOut); + + CoTaskMemFree(pidl); + + return hr; +} + +BOOL DoSpecExistsW(LPCWSTR pszSpec) +{ + WIN32_FIND_DATAW find; + HANDLE hFind = FindFirstFileW(pszSpec, &find); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + return TRUE; + } + return FALSE; +} + +void DoDeleteSpecW(LPCWSTR pszSpec) +{ + WCHAR szPath[MAX_PATH], szFile[MAX_PATH]; + lstrcpyW(szPath, pszSpec); + PathRemoveFileSpecW(szPath); + + WIN32_FIND_DATAW find; + HANDLE hFind = FindFirstFileW(pszSpec, &find); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + lstrcpyW(szFile, szPath); + PathAppendW(szFile, find.cFileName); + DeleteFileW(szFile); + } while (FindNextFileW(hFind, &find)); + + FindClose(hFind); + } +} + +static void DoTestEntry(const TEST_ENTRY *pEntry) +{ + int line = pEntry->line; + HRESULT hr; + PIDLIST_ABSOLUTE pidlDesktop = NULL; + CComPtr<IDropTarget> pDropTarget; + CComPtr<IDataObject> pDataObject; + + // get the desktop PIDL + SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlDesktop); + ok(!!pidlDesktop, "pidlDesktop is NULL\n"); + + // build paths + // + SHGetPathFromIDListW(pidlDesktop, s_szDroppedToItem); + PathAppendW(s_szDroppedToItem, DROPPED_ON_FILE); + + GetModuleFileNameW(NULL, s_szSrcTestFile, _countof(s_szSrcTestFile)); + PathRemoveFileSpecW(s_szSrcTestFile); + PathAppendW(s_szSrcTestFile, TESTFILENAME); + + lstrcpyW(s_szDestTestFile, s_szDestFolder); + PathAppendW(s_szDestTestFile, TESTFILENAME); + + lstrcpyW(s_szDestLinkSpec, s_szDestFolder); + PathAppendW(s_szDestLinkSpec, L"*DragDropTest*.lnk"); + + //trace("s_szSrcTestFile: '%S'\n", s_szSrcTestFile); + //trace("s_szDestTestFile: '%S'\n", s_szDestTestFile); + //trace("s_szDestLinkSpec: '%S'\n", s_szDestLinkSpec); + //trace("s_szDroppedToItem: '%S'\n", s_szDroppedToItem); + + // create or delete files + // + DoCreateTestFile(s_szSrcTestFile); + DeleteFileW(s_szDestTestFile); + DoDeleteSpecW(s_szDestLinkSpec); + DeleteFileW(s_szDroppedToItem); + DoCreateShortcut(s_szDroppedToItem, s_szDestFolder); + + // check file existence + // + ok(PathIsDirectoryW(s_szDestFolder), "s_szDestFolder is not directory\n"); + ok(PathFileExistsW(s_szSrcTestFile), "s_szSrcTestFile doesn't exist\n"); + ok(!DoSpecExistsW(s_szDestLinkSpec), "s_szDestLinkSpec doesn't exist\n"); + ok(!PathFileExistsW(s_szDestTestFile), "s_szDestTestFile exists\n"); + + // get an IDataObject + pDataObject = NULL; + hr = GetUIObjectOfPath(s_szSrcTestFile, IID_IDataObject, (LPVOID *)&pDataObject); + ok_long(hr, S_OK); + + // get an IDropTarget + CComPtr<IEnumIDList> pEnumIDList; + PIDLIST_ABSOLUTE pidl = NULL; + hr = s_pDesktop->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, + &pEnumIDList); + ok_long(hr, S_OK); + while (pEnumIDList->Next(1, &pidl, NULL) == S_OK) + { + WCHAR szText[MAX_PATH]; + SHGetPathFromIDListW(pidl, szText); + if (wcsstr(szText, DROPPED_ON_FILE) != NULL) + { + break; + } + CoTaskMemFree(pidl); + pidl = NULL; + } + ok(pidl != NULL, "pidl is NULL\n"); + pDropTarget = NULL; + PITEMID_CHILD pidlLast = ILFindLastID(pidl); + hr = s_pDesktop->GetUIObjectOf(NULL, 1, &pidlLast, IID_IDropTarget, + NULL, (LPVOID *)&pDropTarget); + CoTaskMemFree(pidl); + ok_long(hr, S_OK); + + // DragEnter + POINTL ptl = { 0, 0 }; + DWORD dwKeyState = pEntry->dwKeyState; + DWORD dwEffects = pEntry->dwEffects1; + hr = pDropTarget->DragEnter(pDataObject, dwKeyState, ptl, &dwEffects); + + ok(hr == pEntry->hr1, "Line %d: hr1 was %08lX\n", line, hr); + + switch (pEntry->dwEffects2) + { + case D_NONE_OR_COPY: + ok((dwEffects == D_NONE || dwEffects == D_COPY), + "Line %d: dwEffects2 was %08lX\n", line, dwEffects); + break; + case D_NONE_OR_MOVE: + ok((dwEffects == D_NONE || dwEffects == D_MOVE), + "Line %d: dwEffects2 was %08lX\n", line, dwEffects); + break; + case D_NONE_OR_LINK: + ok((dwEffects == D_NONE || dwEffects == D_LINK), + "Line %d: dwEffects2 was %08lX\n", line, dwEffects); + break; + default: + ok(dwEffects == pEntry->dwEffects2, + "Line %d: dwEffects2 was %08lX\n", line, dwEffects); + break; + } + + // Drop + hr = pDropTarget->Drop(pDataObject, dwKeyState, ptl, &dwEffects); + ok(hr == pEntry->hr2, "Line %d: hr2 was %08lX\n", line, hr); + + switch (pEntry->dwEffects3) + { + case D_NONE_OR_COPY: + ok((dwEffects == D_NONE || dwEffects == D_COPY), + "Line %d: dwEffects3 was %08lX\n", line, dwEffects); + break; + case D_NONE_OR_MOVE: + ok((dwEffects == D_NONE || dwEffects == D_MOVE), + "Line %d: dwEffects3 was %08lX\n", line, dwEffects); + break; + case D_NONE_OR_LINK: + ok((dwEffects == D_NONE || dwEffects == D_LINK), + "Line %d: dwEffects3 was %08lX\n", line, dwEffects); + break; + default: + ok(dwEffects == pEntry->dwEffects3, + "Line %d: dwEffects3 was %08lX\n", line, dwEffects); + break; + } + + // check file existence by pEntry->op + switch (pEntry->op) + { + case OP_NONE: + ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line); + ok(!PathFileExistsW(s_szDestTestFile), "Line %d: dest exists\n", line); + ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line); + break; + case OP_COPY: + ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line); + ok(PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line); + ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line); + break; + case OP_MOVE: + ok(!PathFileExistsW(s_szSrcTestFile), "Line %d: src exists\n", line); + ok(PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line); + ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line); + break; + case OP_LINK: + ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line); + ok(!PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line); + ok(DoSpecExistsW(s_szDestLinkSpec), "Line %d: link not exists\n", line); + break; + case OP_NONE_OR_COPY: + ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line); + ok(!DoSpecExistsW(s_szDestLinkSpec), "Line %d: link exists\n", line); + break; + case OP_NONE_OR_MOVE: + ok(PathFileExistsW(s_szSrcTestFile) != PathFileExistsW(s_szDestTestFile), + "Line %d: It must be either None or Move\n", line); + break; + case OP_NONE_OR_LINK: + ok(PathFileExistsW(s_szSrcTestFile), "Line %d: src not exists\n", line); + ok(!PathFileExistsW(s_szDestTestFile), "Line %d: dest not exists\n", line); + break; + } + + // clean up + DeleteFileW(s_szSrcTestFile); + DeleteFileW(s_szDestTestFile); + DoDeleteSpecW(s_szDestLinkSpec); + ILFree(pidlDesktop); +} + +START_TEST(DragDrop) +{ + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok_int(SUCCEEDED(hr), TRUE); + + SHGetDesktopFolder(&s_pDesktop); + ok(!!s_pDesktop, "s_pDesktop is NULL\n"); + + BOOL ret = SHGetSpecialFolderPathW(NULL, s_szDestFolder, CSIDL_DESKTOP, FALSE); + ok_int(ret, TRUE); + + for (size_t i = 0; i < _countof(s_TestEntries); ++i) + { + DoTestEntry(&s_TestEntries[i]); + } + + DeleteFileW(s_szSrcTestFile); + DeleteFileW(s_szDestTestFile); + DoDeleteSpecW(s_szDestLinkSpec); + DeleteFileW(s_szDroppedToItem); + + CoUninitialize(); +} diff --git a/modules/rostests/apitests/shell32/testlist.c b/modules/rostests/apitests/shell32/testlist.c index 7b603dff147..b16ace6cc23 100644 --- a/modules/rostests/apitests/shell32/testlist.c +++ b/modules/rostests/apitests/shell32/testlist.c @@ -11,6 +11,7 @@ extern void func_CMyComputer(void); extern void func_CShellDesktop(void); extern void func_CShellLink(void); extern void func_CUserNotification(void); +extern void func_DragDrop(void); extern void func_IShellFolderViewCB(void); extern void func_menu(void); extern void func_OpenAs_RunDLL(void); @@ -32,6 +33,7 @@ const struct test winetest_testlist[] = { "CShellDesktop", func_CShellDesktop }, { "CShellLink", func_CShellLink }, { "CUserNotification", func_CUserNotification }, + { "DragDrop", func_DragDrop }, { "IShellFolderViewCB", func_IShellFolderViewCB }, { "menu", func_menu }, { "OpenAs_RunDLL", func_OpenAs_RunDLL },
5 years, 1 month
1
0
0
0
[reactos] 01/01: [SHELL32] Implement 'Open file location' of shortcut files (#2028)
by Katayama Hirofumi MZ
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c0f340bca567c5ae6ab49…
commit c0f340bca567c5ae6ab4906459b62e2ef26f226f Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com> AuthorDate: Tue Nov 12 16:47:36 2019 +0900 Commit: GitHub <noreply(a)github.com> CommitDate: Tue Nov 12 16:47:36 2019 +0900 [SHELL32] Implement 'Open file location' of shortcut files (#2028) "Open file location" is a feature to open the location of the target of a shortcut file. Ideally we should probably use SHOpenFolderAndSelectItems here, but that is not 100% implemented in ros yet... CORE-12770 --- dll/win32/shell32/CShellLink.cpp | 67 +++++++++++++++++++++++++++++++++------- dll/win32/shell32/CShellLink.h | 13 ++++++-- dll/win32/shell32/lang/bg-BG.rc | 1 + dll/win32/shell32/lang/ca-ES.rc | 1 + dll/win32/shell32/lang/cs-CZ.rc | 1 + dll/win32/shell32/lang/da-DK.rc | 1 + dll/win32/shell32/lang/de-DE.rc | 1 + dll/win32/shell32/lang/el-GR.rc | 1 + dll/win32/shell32/lang/en-GB.rc | 1 + dll/win32/shell32/lang/en-US.rc | 1 + dll/win32/shell32/lang/es-ES.rc | 1 + dll/win32/shell32/lang/et-EE.rc | 1 + dll/win32/shell32/lang/fi-FI.rc | 1 + dll/win32/shell32/lang/fr-FR.rc | 1 + dll/win32/shell32/lang/he-IL.rc | 1 + dll/win32/shell32/lang/hi-IN.rc | 1 + dll/win32/shell32/lang/hu-HU.rc | 1 + dll/win32/shell32/lang/id-ID.rc | 1 + dll/win32/shell32/lang/it-IT.rc | 1 + dll/win32/shell32/lang/ja-JP.rc | 1 + dll/win32/shell32/lang/ko-KR.rc | 1 + dll/win32/shell32/lang/nl-NL.rc | 1 + dll/win32/shell32/lang/no-NO.rc | 1 + dll/win32/shell32/lang/pl-PL.rc | 1 + dll/win32/shell32/lang/pt-BR.rc | 1 + dll/win32/shell32/lang/pt-PT.rc | 1 + dll/win32/shell32/lang/ro-RO.rc | 1 + dll/win32/shell32/lang/ru-RU.rc | 1 + dll/win32/shell32/lang/sk-SK.rc | 1 + dll/win32/shell32/lang/sl-SI.rc | 1 + dll/win32/shell32/lang/sq-AL.rc | 1 + dll/win32/shell32/lang/sv-SE.rc | 1 + dll/win32/shell32/lang/tr-TR.rc | 1 + dll/win32/shell32/lang/uk-UA.rc | 1 + dll/win32/shell32/lang/zh-CN.rc | 1 + dll/win32/shell32/lang/zh-TW.rc | 1 + dll/win32/shell32/shresdef.h | 2 ++ 37 files changed, 101 insertions(+), 15 deletions(-) diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp index 3d7051d9699..8883e801c69 100644 --- a/dll/win32/shell32/CShellLink.cpp +++ b/dll/win32/shell32/CShellLink.cpp @@ -278,9 +278,9 @@ CShellLink::CShellLink() m_pDBList = NULL; m_bInInit = FALSE; m_hIcon = NULL; + m_idCmdFirst = 0; m_sLinkPath = NULL; - m_iIdOpen = -1; /**/sProduct = sComponent = NULL;/**/ } @@ -2578,7 +2578,9 @@ HRESULT STDMETHODCALLTYPE CShellLink::Initialize(PCIDLIST_ABSOLUTE pidlFolder, I HRESULT STDMETHODCALLTYPE CShellLink::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { - int id = 1; + INT id = 0; + + m_idCmdFirst = idCmdFirst; TRACE("%p %p %u %u %u %u\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); @@ -2586,31 +2588,54 @@ HRESULT STDMETHODCALLTYPE CShellLink::QueryContextMenu(HMENU hMenu, UINT indexMe if (!hMenu) return E_INVALIDARG; - WCHAR wszOpen[20]; - if (!LoadStringW(shell32_hInstance, IDS_OPEN_VERB, wszOpen, _countof(wszOpen))) - *wszOpen = L'\0'; + CStringW strOpen(MAKEINTRESOURCEW(IDS_OPEN_VERB)); + CStringW strOpenFileLoc(MAKEINTRESOURCEW(IDS_OPENFILELOCATION)); MENUITEMINFOW mii; ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; - mii.dwTypeData = wszOpen; + mii.dwTypeData = strOpen.GetBuffer(); mii.cch = wcslen(mii.dwTypeData); mii.wID = idCmdFirst + id++; mii.fState = MFS_DEFAULT | MFS_ENABLED; mii.fType = MFT_STRING; - if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii)) + if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii)) + return E_FAIL; + + mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; + mii.dwTypeData = strOpenFileLoc.GetBuffer(); + mii.cch = wcslen(mii.dwTypeData); + mii.wID = idCmdFirst + id++; + mii.fState = MFS_ENABLED; + mii.fType = MFT_STRING; + if (!InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii)) return E_FAIL; - m_iIdOpen = 1; + + UNREFERENCED_PARAMETER(indexMenu); return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id); } -HRESULT STDMETHODCALLTYPE CShellLink::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) +HRESULT CShellLink::DoOpenFileLocation() { - LPWSTR args = NULL; - LPWSTR path = NULL; + WCHAR szParams[MAX_PATH + 64]; + StringCbPrintfW(szParams, sizeof(szParams), L"/select,%s", m_sPath); + + INT_PTR ret; + ret = reinterpret_cast<INT_PTR>(ShellExecuteW(NULL, NULL, L"explorer.exe", szParams, + NULL, m_Header.nShowCommand)); + if (ret <= 32) + { + ERR("ret: %08lX\n", ret); + return E_FAIL; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CShellLink::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) +{ TRACE("%p %p\n", this, lpici); if (lpici->cbSize < sizeof(CMINVOKECOMMANDINFO)) @@ -2627,7 +2652,25 @@ HRESULT STDMETHODCALLTYPE CShellLink::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) return hr; } - path = strdupW(m_sPath); + UINT idCmd = LOWORD(lpici->lpVerb); + TRACE("idCmd: %d\n", idCmd); + + switch (idCmd) + { + case IDCMD_OPEN: + return DoOpen(lpici); + case IDCMD_OPENFILELOCATION: + return DoOpenFileLocation(); + default: + return E_NOTIMPL; + } +} + +HRESULT CShellLink::DoOpen(LPCMINVOKECOMMANDINFO lpici) +{ + HRESULT hr; + LPWSTR args = NULL; + LPWSTR path = strdupW(m_sPath); if ( lpici->cbSize == sizeof(CMINVOKECOMMANDINFOEX) && (lpici->fMask & CMIC_MASK_UNICODE) ) diff --git a/dll/win32/shell32/CShellLink.h b/dll/win32/shell32/CShellLink.h index dac5369fedf..7ad131c0284 100644 --- a/dll/win32/shell32/CShellLink.h +++ b/dll/win32/shell32/CShellLink.h @@ -51,16 +51,20 @@ public: /* Link file formats */ #include "pshpack1.h" - struct volume_info { DWORD type; DWORD serial; WCHAR label[12]; /* assume 8.3 */ }; - #include "poppack.h" + enum IDCMD + { + IDCMD_OPEN = 0, + IDCMD_OPENFILELOCATION + }; + private: /* Cached link header */ SHELL_LINK_HEADER m_Header; @@ -83,13 +87,13 @@ private: LPDBLIST m_pDBList; /* Optional data block list (in the extra data section) */ BOOL m_bInInit; // in initialization or not HICON m_hIcon; + UINT m_idCmdFirst; /* Pointers to strings inside Logo3/Darwin info blocks, cached for debug info purposes only */ LPWSTR sProduct; LPWSTR sComponent; LPWSTR m_sLinkPath; - INT m_iIdOpen; /* ID of the "Open" entry in the context menu */ CComPtr<IUnknown> m_site; CComPtr<IDropTarget> m_DropTarget; @@ -102,6 +106,9 @@ private: HRESULT SetTargetFromPIDLOrPath(LPCITEMIDLIST pidl, LPCWSTR pszFile); HICON CreateShortcutIcon(LPCWSTR wszIconPath, INT IconIndex); + HRESULT DoOpen(LPCMINVOKECOMMANDINFO lpici); + HRESULT DoOpenFileLocation(); + public: CShellLink(); ~CShellLink(); diff --git a/dll/win32/shell32/lang/bg-BG.rc b/dll/win32/shell32/lang/bg-BG.rc index ac083431deb..e61b6c675fb 100644 --- a/dll/win32/shell32/lang/bg-BG.rc +++ b/dll/win32/shell32/lang/bg-BG.rc @@ -770,6 +770,7 @@ BEGIN IDS_PASTE "Вмъкване" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/ca-ES.rc b/dll/win32/shell32/lang/ca-ES.rc index 1a4ba5be874..b2e25f93076 100644 --- a/dll/win32/shell32/lang/ca-ES.rc +++ b/dll/win32/shell32/lang/ca-ES.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/cs-CZ.rc b/dll/win32/shell32/lang/cs-CZ.rc index eb4da556af9..b5f4c2c2616 100644 --- a/dll/win32/shell32/lang/cs-CZ.rc +++ b/dll/win32/shell32/lang/cs-CZ.rc @@ -775,6 +775,7 @@ BEGIN IDS_PASTE "Vložit" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Složku '%1' nebylo možné vytvořit" IDS_CREATEFOLDER_CAPTION "Složku nebylo možné vytvořit" diff --git a/dll/win32/shell32/lang/da-DK.rc b/dll/win32/shell32/lang/da-DK.rc index 445c85a043e..7a063778cab 100644 --- a/dll/win32/shell32/lang/da-DK.rc +++ b/dll/win32/shell32/lang/da-DK.rc @@ -775,6 +775,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/de-DE.rc b/dll/win32/shell32/lang/de-DE.rc index 0061ff76d81..f0145f348be 100644 --- a/dll/win32/shell32/lang/de-DE.rc +++ b/dll/win32/shell32/lang/de-DE.rc @@ -770,6 +770,7 @@ BEGIN IDS_PASTE "Einfügen" IDS_EJECT "Auswerfen" IDS_DISCONNECT "Trennen" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED " Der Ordner kann nicht erstellt werden '%1'" IDS_CREATEFOLDER_CAPTION " Der Ordner kann nicht erstellt werden." diff --git a/dll/win32/shell32/lang/el-GR.rc b/dll/win32/shell32/lang/el-GR.rc index 0240442978f..aaf9db3c3b7 100644 --- a/dll/win32/shell32/lang/el-GR.rc +++ b/dll/win32/shell32/lang/el-GR.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/en-GB.rc b/dll/win32/shell32/lang/en-GB.rc index 80ae4fdfb72..7eb8229884e 100644 --- a/dll/win32/shell32/lang/en-GB.rc +++ b/dll/win32/shell32/lang/en-GB.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/en-US.rc b/dll/win32/shell32/lang/en-US.rc index 3e049ea5877..bce8bc31278 100644 --- a/dll/win32/shell32/lang/en-US.rc +++ b/dll/win32/shell32/lang/en-US.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/es-ES.rc b/dll/win32/shell32/lang/es-ES.rc index 95c57999784..1464b4d14f0 100644 --- a/dll/win32/shell32/lang/es-ES.rc +++ b/dll/win32/shell32/lang/es-ES.rc @@ -777,6 +777,7 @@ BEGIN IDS_PASTE "Insertar" IDS_EJECT "Extraer" IDS_DISCONNECT "Desconectar" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "No se pudo crear la carpeta '%1'" IDS_CREATEFOLDER_CAPTION "No se pudo crear la carpeta" diff --git a/dll/win32/shell32/lang/et-EE.rc b/dll/win32/shell32/lang/et-EE.rc index 295b6f3a4a8..e2e8cf41e28 100644 --- a/dll/win32/shell32/lang/et-EE.rc +++ b/dll/win32/shell32/lang/et-EE.rc @@ -776,6 +776,7 @@ BEGIN IDS_PASTE "Kleebi" IDS_EJECT "Väljuta" IDS_DISCONNECT "Katkesta ühendus" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Ei saa luua kausta '%1'" IDS_CREATEFOLDER_CAPTION "Ei saa kausta luua" diff --git a/dll/win32/shell32/lang/fi-FI.rc b/dll/win32/shell32/lang/fi-FI.rc index c3d16d96d90..f6cd13e6878 100644 --- a/dll/win32/shell32/lang/fi-FI.rc +++ b/dll/win32/shell32/lang/fi-FI.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/fr-FR.rc b/dll/win32/shell32/lang/fr-FR.rc index b28d8770a58..58464c856ff 100644 --- a/dll/win32/shell32/lang/fr-FR.rc +++ b/dll/win32/shell32/lang/fr-FR.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Insérer" IDS_EJECT "Éjecter" IDS_DISCONNECT "Déconnecter" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Impossible de créer le dossier '%1'" IDS_CREATEFOLDER_CAPTION "Impossible de créer un dossier" diff --git a/dll/win32/shell32/lang/he-IL.rc b/dll/win32/shell32/lang/he-IL.rc index ff7da470c61..9e63d54b428 100644 --- a/dll/win32/shell32/lang/he-IL.rc +++ b/dll/win32/shell32/lang/he-IL.rc @@ -771,6 +771,7 @@ BEGIN IDS_PASTE "הכנס" IDS_EJECT "הוצא" IDS_DISCONNECT "נתק" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/hi-IN.rc b/dll/win32/shell32/lang/hi-IN.rc index 76e7cc2a6d0..6903fe2372e 100644 --- a/dll/win32/shell32/lang/hi-IN.rc +++ b/dll/win32/shell32/lang/hi-IN.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "पैस्ट" IDS_EJECT "इजेक्ट" IDS_DISCONNECT "डिस्कनेक्ट" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "फ़ोल्डर '%1' बनाने में असमर्थ" IDS_CREATEFOLDER_CAPTION "फ़ोल्डर बनाने में असमर्थ" diff --git a/dll/win32/shell32/lang/hu-HU.rc b/dll/win32/shell32/lang/hu-HU.rc index d840240b990..037d7f8e4c9 100644 --- a/dll/win32/shell32/lang/hu-HU.rc +++ b/dll/win32/shell32/lang/hu-HU.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/id-ID.rc b/dll/win32/shell32/lang/id-ID.rc index 4e9a7c654e2..4d5abb5d14e 100644 --- a/dll/win32/shell32/lang/id-ID.rc +++ b/dll/win32/shell32/lang/id-ID.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Tempel" IDS_EJECT "Keluarkan" IDS_DISCONNECT "Putuskan" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Tidak bisa membuat folder folder '%1'" IDS_CREATEFOLDER_CAPTION "Tidak bisa membuat folder" diff --git a/dll/win32/shell32/lang/it-IT.rc b/dll/win32/shell32/lang/it-IT.rc index a109c0d74fc..fa5cd0d287e 100644 --- a/dll/win32/shell32/lang/it-IT.rc +++ b/dll/win32/shell32/lang/it-IT.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Inserisci" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/ja-JP.rc b/dll/win32/shell32/lang/ja-JP.rc index ac55db842ff..56a7ca99a3d 100644 --- a/dll/win32/shell32/lang/ja-JP.rc +++ b/dll/win32/shell32/lang/ja-JP.rc @@ -766,6 +766,7 @@ BEGIN IDS_PASTE "挿入" IDS_EJECT "取り出し" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "フォルダ '%1' を作成できません" IDS_CREATEFOLDER_CAPTION "フォルダを作成できません" diff --git a/dll/win32/shell32/lang/ko-KR.rc b/dll/win32/shell32/lang/ko-KR.rc index 3647553a1f0..4239b7e3da5 100644 --- a/dll/win32/shell32/lang/ko-KR.rc +++ b/dll/win32/shell32/lang/ko-KR.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/nl-NL.rc b/dll/win32/shell32/lang/nl-NL.rc index db458b1b9e1..cb9ec3ef3e9 100644 --- a/dll/win32/shell32/lang/nl-NL.rc +++ b/dll/win32/shell32/lang/nl-NL.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/no-NO.rc b/dll/win32/shell32/lang/no-NO.rc index 8dfeb901bba..16c0a4333ea 100644 --- a/dll/win32/shell32/lang/no-NO.rc +++ b/dll/win32/shell32/lang/no-NO.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Sett inn" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/pl-PL.rc b/dll/win32/shell32/lang/pl-PL.rc index 66461af8b7b..38724ea0bbd 100644 --- a/dll/win32/shell32/lang/pl-PL.rc +++ b/dll/win32/shell32/lang/pl-PL.rc @@ -774,6 +774,7 @@ BEGIN IDS_PASTE "Włóż" IDS_EJECT "Wysuń" IDS_DISCONNECT "Odłącz" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Nie można utworzyć folderu '%1'" IDS_CREATEFOLDER_CAPTION "Nie można utworzyć folderu" diff --git a/dll/win32/shell32/lang/pt-BR.rc b/dll/win32/shell32/lang/pt-BR.rc index 2e9abdc3702..035a4ae514a 100644 --- a/dll/win32/shell32/lang/pt-BR.rc +++ b/dll/win32/shell32/lang/pt-BR.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Inserir" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/pt-PT.rc b/dll/win32/shell32/lang/pt-PT.rc index 26e26d915cf..685f86cf1bc 100644 --- a/dll/win32/shell32/lang/pt-PT.rc +++ b/dll/win32/shell32/lang/pt-PT.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Inserir" IDS_EJECT "Eject" IDS_DISCONNECT "Desligar" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Impossivel de criar pasta '%1'" IDS_CREATEFOLDER_CAPTION "Impossivel de criar pasta" diff --git a/dll/win32/shell32/lang/ro-RO.rc b/dll/win32/shell32/lang/ro-RO.rc index a53281668b8..5d6c56c8a7c 100644 --- a/dll/win32/shell32/lang/ro-RO.rc +++ b/dll/win32/shell32/lang/ro-RO.rc @@ -771,6 +771,7 @@ BEGIN IDS_PASTE "&Lipește" IDS_EJECT "S&coate" IDS_DISCONNECT "Deconectea&ză" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Nu poate fi creat un dosar cu numele „%1”" IDS_CREATEFOLDER_CAPTION "Nu poate fi creat dosar" diff --git a/dll/win32/shell32/lang/ru-RU.rc b/dll/win32/shell32/lang/ru-RU.rc index 2072afb9558..36002d87d62 100644 --- a/dll/win32/shell32/lang/ru-RU.rc +++ b/dll/win32/shell32/lang/ru-RU.rc @@ -776,6 +776,7 @@ BEGIN IDS_PASTE "Вставить" IDS_EJECT "Извлечь" IDS_DISCONNECT "Отсоединить" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Невозможно создать папку '%1'" IDS_CREATEFOLDER_CAPTION "Невозможно создать папку" diff --git a/dll/win32/shell32/lang/sk-SK.rc b/dll/win32/shell32/lang/sk-SK.rc index 96f9637d067..165f210a79d 100644 --- a/dll/win32/shell32/lang/sk-SK.rc +++ b/dll/win32/shell32/lang/sk-SK.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Vložiť" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/sl-SI.rc b/dll/win32/shell32/lang/sl-SI.rc index 01c5658256d..678c5f5f7be 100644 --- a/dll/win32/shell32/lang/sl-SI.rc +++ b/dll/win32/shell32/lang/sl-SI.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Paste" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/sq-AL.rc b/dll/win32/shell32/lang/sq-AL.rc index a7718e6dab9..f65bf86b3f2 100644 --- a/dll/win32/shell32/lang/sq-AL.rc +++ b/dll/win32/shell32/lang/sq-AL.rc @@ -773,6 +773,7 @@ BEGIN IDS_PASTE "Fut" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Unable to create the folder '%1'" IDS_CREATEFOLDER_CAPTION "Unable to create folder" diff --git a/dll/win32/shell32/lang/sv-SE.rc b/dll/win32/shell32/lang/sv-SE.rc index 029468c5ea6..e17328ecc79 100644 --- a/dll/win32/shell32/lang/sv-SE.rc +++ b/dll/win32/shell32/lang/sv-SE.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Klistra in" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Kunde inte skapa mappen '%1'" IDS_CREATEFOLDER_CAPTION "Kunde inte skapa mapp" diff --git a/dll/win32/shell32/lang/tr-TR.rc b/dll/win32/shell32/lang/tr-TR.rc index 6b491372bf9..bc6addfed2b 100644 --- a/dll/win32/shell32/lang/tr-TR.rc +++ b/dll/win32/shell32/lang/tr-TR.rc @@ -771,6 +771,7 @@ BEGIN IDS_PASTE "Yapıştır" IDS_EJECT "Eject" IDS_DISCONNECT "Disconnect" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED """%1"" dizini oluşturulamıyor." IDS_CREATEFOLDER_CAPTION "Dizin Oluşturulamıyor" diff --git a/dll/win32/shell32/lang/uk-UA.rc b/dll/win32/shell32/lang/uk-UA.rc index 96b20ade200..97ec05510e7 100644 --- a/dll/win32/shell32/lang/uk-UA.rc +++ b/dll/win32/shell32/lang/uk-UA.rc @@ -769,6 +769,7 @@ BEGIN IDS_PASTE "Вставити" IDS_EJECT "Витягнути" IDS_DISCONNECT "Відключити" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "Не вдалося створити папку '%1'" IDS_CREATEFOLDER_CAPTION "Не вдалося створити папку" diff --git a/dll/win32/shell32/lang/zh-CN.rc b/dll/win32/shell32/lang/zh-CN.rc index b8881df8db0..f3debf50826 100644 --- a/dll/win32/shell32/lang/zh-CN.rc +++ b/dll/win32/shell32/lang/zh-CN.rc @@ -777,6 +777,7 @@ BEGIN IDS_PASTE "贴上" IDS_EJECT "弹出" IDS_DISCONNECT "断开" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "无法创建文件夹 '%1'" IDS_CREATEFOLDER_CAPTION "无法创建文件夹" diff --git a/dll/win32/shell32/lang/zh-TW.rc b/dll/win32/shell32/lang/zh-TW.rc index f3d35038a32..31faf69e845 100644 --- a/dll/win32/shell32/lang/zh-TW.rc +++ b/dll/win32/shell32/lang/zh-TW.rc @@ -778,6 +778,7 @@ BEGIN IDS_PASTE "插入" IDS_EJECT "退出" IDS_DISCONNECT "中斷" + IDS_OPENFILELOCATION "Open f&ile location" IDS_CREATEFOLDER_DENIED "無法建立資料夾 '%1'" IDS_CREATEFOLDER_CAPTION "無法建立資料夾" diff --git a/dll/win32/shell32/shresdef.h b/dll/win32/shell32/shresdef.h index 766f32f07dc..2b729d6a2ea 100644 --- a/dll/win32/shell32/shresdef.h +++ b/dll/win32/shell32/shresdef.h @@ -227,6 +227,8 @@ #define IDS_EJECT 339 #define IDS_DISCONNECT 340 +#define IDS_OPENFILELOCATION 341 + #define IDS_MENU_EMPTY 34561 /* Note: those strings are referenced from the registry */
5 years, 1 month
1
0
0
0
← Newer
1
...
18
19
20
21
22
23
24
...
33
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Results per page:
10
25
50
100
200