1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Test the result of enumerating over a folder with a zip in it
5  * COPYRIGHT:   Copyright 2020-2023 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 struct FileInfo
11 {
12     LPCWSTR Name;
13     SFGAOF Attributes;
14     bool Found;
15 };
16 
17 int zipfldr_loaded()
18 {
19     return GetModuleHandleA("zipfldr.dll") ? TRUE : FALSE;
20 }
21 
22 void FindExpectedFile(FileInfo* Array, size_t len, IShellFolder* pFolder, PCUITEMID_CHILD pidl, LPCWSTR& ExpectedName, SFGAOF& ExpectedAttributes)
23 {
24     ExpectedName = L"<WRONG FILE>";
25     ExpectedAttributes = (SFGAOF)~0;
26 
27     STRRET NameRet;
28     HRESULT hr;
29 
30     hr = pFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL, &NameRet);
31     ok_hr(hr, S_OK);
32     if (!SUCCEEDED(hr))
33         return;
34 
35     WCHAR DisplayName[MAX_PATH];
36     hr = StrRetToBufW(&NameRet, pidl, DisplayName, RTL_NUMBER_OF(DisplayName));
37     ok_hr(hr, S_OK);
38     if (!SUCCEEDED(hr))
39         return;
40 
41     for (size_t n = 0; n < len; ++n)
42     {
43         if (!_wcsicmp(Array[n].Name, DisplayName) && !Array[n].Found)
44         {
45             Array[n].Found = true;
46             ExpectedName = Array[n].Name;
47             ExpectedAttributes = Array[n].Attributes;
48             return;
49         }
50     }
51 }
52 
53 const SFGAOF BaseFileAttributes = SFGAO_FILESYSTEM;
54 const SFGAOF BaseFolderAttributes = SFGAO_FILESYSTEM | SFGAO_FOLDER;
55 FileInfo ExpectedFiles[] = {
56     { L"test.txt", BaseFileAttributes, false },
57     { L"TMP0.zip", BaseFileAttributes, false},  // 2k3 Shows this as a file, newer shows this as a folder
58     { L"ASUBFLD", BaseFolderAttributes | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR, false },
59 };
60 BOOL FoundZipfldr = FALSE;
61 
62 static void
63 test_EnumDirFiles(const WCHAR *TestFolder, BOOL EnumFolders)
64 {
65     CComPtr<IShellFolder> spFolder;
66     if (!InitializeShellFolder(TestFolder, spFolder))
67         return;
68 
69     CComPtr<IEnumIDList> spEnum;
70     ok_int(zipfldr_loaded(), FoundZipfldr);
71     HRESULT hr = spFolder->EnumObjects(NULL, EnumFolders ? SHCONTF_FOLDERS : SHCONTF_NONFOLDERS, &spEnum);
72     ok_hr(hr, S_OK);
73     if (!SUCCEEDED(hr))
74         return;
75     ok_int(zipfldr_loaded(), FoundZipfldr);
76 
77     do
78     {
79         CComHeapPtr<ITEMID_CHILD> child;
80         ULONG celtFetched = 0;
81         ok_int(zipfldr_loaded(), FoundZipfldr);
82         hr = spEnum->Next(1, &child, &celtFetched);
83         ok_int(zipfldr_loaded(), FoundZipfldr);
84         if (hr != S_OK)
85             break;
86         ok_int(celtFetched, 1);
87         if (celtFetched != 1)
88             break;
89 
90         LPCWSTR ExpectedName;
91         SFGAOF ExpectedAttributes;
92         FindExpectedFile(ExpectedFiles, RTL_NUMBER_OF(ExpectedFiles), spFolder, child, ExpectedName, ExpectedAttributes);
93 
94         ok_int(zipfldr_loaded(), FoundZipfldr);
95         ok_displayname(spFolder, child, SHGDN_NORMAL, ExpectedName);
96         ok_int(zipfldr_loaded(), FoundZipfldr);
97 
98         SFGAOF Attributes = SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
99         hr = spFolder->GetAttributesOf(1, &child, &Attributes);
100 
101         if (!_wcsicmp(ExpectedName, L"TMP0.zip"))
102         {
103             // We allow both .zip files being a 'file' (2k3) or a 'folder' (win10)
104             if (Attributes & SFGAO_FOLDER)
105                 ExpectedAttributes |= SFGAO_FOLDER;
106             // Only at this point (after calling GetAttributesOf) it will load zipfldr
107             FoundZipfldr = TRUE;
108             trace("Found zip (%S)\n", ExpectedName);
109         }
110         ok_int(zipfldr_loaded(), FoundZipfldr);
111 
112         /* Just keep the ones we are interested in */
113         Attributes &= (SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR);
114         ok_hr(hr, S_OK);
115         ok_hex(Attributes, ExpectedAttributes);
116     } while (true);
117 
118     ok_hr(hr, S_FALSE);
119     ok_int(zipfldr_loaded(), FoundZipfldr);
120 }
121 
122 
123 START_TEST(EnumParentDir)
124 {
125     HRESULT hr = CoInitialize(NULL);
126 
127     ok_hr(hr, S_OK);
128     if (!SUCCEEDED(hr))
129         return;
130 
131     ok_int(zipfldr_loaded(), FALSE);
132 
133     WCHAR TestFolder[MAX_PATH], TestFile[MAX_PATH], SubFolder[MAX_PATH];
134     GetTempPathW(_countof(TestFolder), TestFolder);
135     PathAppendW(TestFolder, L"ZipDir");
136     PathAddBackslashW(TestFolder);
137 
138     CreateDirectoryW(TestFolder, NULL);
139 
140     WCHAR ZipTestFile[MAX_PATH];
141     if (!extract_resource(ZipTestFile, MAKEINTRESOURCEW(IDR_ZIP_TEST_FILE), TestFolder))
142     {
143         RemoveDirectoryW(TestFolder);
144         return;
145     }
146 
147     StringCchPrintfW(TestFile, _countof(TestFile), L"%stest.txt", TestFolder);
148 
149     HANDLE hFile = CreateFileW(TestFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, NULL);
150 
151     ok(hFile != INVALID_HANDLE_VALUE, "Error creating %S\n", TestFile);
152     if (hFile != INVALID_HANDLE_VALUE)
153     {
154         StringCchPrintfW(SubFolder, _countof(SubFolder), L"%sASUBFLD", TestFolder);
155 
156         CreateDirectoryW(SubFolder, NULL);
157 
158         winetest_push_context("Files");
159         test_EnumDirFiles(TestFolder, FALSE);
160         winetest_pop_context();
161         winetest_push_context("Folders");
162         test_EnumDirFiles(TestFolder, TRUE);
163         winetest_pop_context();
164 
165         for (size_t n = 0; n < RTL_NUMBER_OF(ExpectedFiles); ++n)
166         {
167             ok(ExpectedFiles[n].Found, "Did not find %S\n", ExpectedFiles[n].Name);
168         }
169 
170         RemoveDirectoryW(SubFolder);
171 
172         CloseHandle(hFile);
173     }
174 
175     DeleteFileW(ZipTestFile);
176     RemoveDirectoryW(TestFolder);
177     CoUninitialize();
178 }
179