1 /*
2  * PROJECT:     shell32
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Shell change notification
5  * COPYRIGHT:   Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6  */
7 #include "shelldesktop.h"
8 #include "CDirectoryList.h"
9 #include <assert.h>      // for assert
10 
11 WINE_DEFAULT_DEBUG_CHANNEL(shcn);
12 
13 BOOL CDirectoryList::ContainsPath(LPCWSTR pszPath) const
14 {
15     assert(!PathIsRelativeW(pszPath));
16 
17     for (INT i = 0; i < m_items.GetSize(); ++i)
18     {
19         if (m_items[i].IsEmpty())
20             continue;
21 
22         if (m_items[i].EqualPath(pszPath))
23             return TRUE; // matched
24     }
25     return FALSE;
26 }
27 
28 BOOL CDirectoryList::AddPath(LPCWSTR pszPath)
29 {
30     assert(!PathIsRelativeW(pszPath));
31     if (ContainsPath(pszPath))
32         return FALSE;
33     for (INT i = 0; i < m_items.GetSize(); ++i)
34     {
35         if (m_items[i].IsEmpty())
36         {
37             m_items[i].SetPath(pszPath);
38             return TRUE;
39         }
40     }
41     return m_items.Add(pszPath);
42 }
43 
44 BOOL CDirectoryList::RenamePath(LPCWSTR pszPath1, LPCWSTR pszPath2)
45 {
46     assert(!PathIsRelativeW(pszPath1));
47     assert(!PathIsRelativeW(pszPath2));
48 
49     for (INT i = 0; i < m_items.GetSize(); ++i)
50     {
51         if (m_items[i].EqualPath(pszPath1))
52         {
53             // matched
54             m_items[i].SetPath(pszPath2);
55             return TRUE;
56         }
57     }
58     return FALSE;
59 }
60 
61 BOOL CDirectoryList::DeletePath(LPCWSTR pszPath)
62 {
63     assert(!PathIsRelativeW(pszPath));
64 
65     for (INT i = 0; i < m_items.GetSize(); ++i)
66     {
67         if (m_items[i].EqualPath(pszPath))
68         {
69             // matched
70             m_items[i].SetPath(NULL);
71             return TRUE;
72         }
73     }
74     return FALSE;
75 }
76 
77 BOOL CDirectoryList::AddPathsFromDirectory(LPCWSTR pszDirectoryPath)
78 {
79     // get the full path
80     WCHAR szPath[MAX_PATH];
81     lstrcpynW(szPath, pszDirectoryPath, _countof(szPath));
82     assert(!PathIsRelativeW(szPath));
83 
84     // is it a directory?
85     if (!PathIsDirectoryW(szPath))
86         return FALSE;
87 
88     // add the path
89     if (!AddPath(szPath))
90         return FALSE;
91 
92     // enumerate the file items to remember
93     PathAppendW(szPath, L"*");
94     WIN32_FIND_DATAW find;
95     HANDLE hFind = FindFirstFileW(szPath, &find);
96     if (hFind == INVALID_HANDLE_VALUE)
97     {
98         ERR("FindFirstFileW failed\n");
99         return FALSE;
100     }
101 
102     LPWSTR pch;
103     do
104     {
105         // ignore "." and ".."
106         pch = find.cFileName;
107         if (pch[0] == L'.' && (pch[1] == 0 || (pch[1] == L'.' && pch[2] == 0)))
108             continue;
109 
110         // build a path
111         PathRemoveFileSpecW(szPath);
112         if (lstrlenW(szPath) + lstrlenW(find.cFileName) + 1 > MAX_PATH)
113         {
114             ERR("szPath is too long\n");
115             continue;
116         }
117         PathAppendW(szPath, find.cFileName);
118 
119         // add the path and do recurse
120         if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
121         {
122             if (m_fRecursive)
123                 AddPathsFromDirectory(szPath);
124             else
125                 AddPath(szPath);
126         }
127     } while (FindNextFileW(hFind, &find));
128 
129     FindClose(hFind);
130 
131     return TRUE;
132 }
133