Windows: remove trailing whitespace
[openafs.git] / src / WINNT / afssvrcfg / volume_utils.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Includes _________________________________________________________________
12  *
13  */
14 #include <winsock2.h>
15 #include <ws2tcpip.h>
16
17 extern "C" {
18 #include <afsconfig.h>
19 #include <afs/param.h>
20 #include <afs/stds.h>
21 #include <roken.h>
22 }
23
24 #include "afscfg.h"
25 #include <stdio.h>
26 #include "volume_utils.h"
27 #include "resource.h"
28 #include "partition_utils.h"
29
30
31 /*
32  * Definitions _________________________________________________________________
33  *
34  */
35 static HWND m_hDriveList = 0;
36
37 //static const UINT MAX_DRIVES = 26;
38 static const UINT DISK_DRIVE_IMAGE = 0;
39 static const UINT DISABLED_DISK_DRIVE_IMAGE = 1;
40 static const UINT DISK_DRIVE_WITH_WARNING_IMAGE = 2;
41 static const UINT AFS_DISK_DRIVE_IMAGE = 3;
42
43
44 struct DRIVE_INFO
45 {
46     TCHAR szRootDir[4];         // Drive letter plus colon plus slash, ex: "c:\"
47     TCHAR szVolName[256];
48     TCHAR szSize[32];           // Drive size in megabytes
49     DWORD dwFlags;
50     BOOL bDisabled;             // Disabled is TRUE if partition not suitable for AFS
51     UINT nImage;                // Image to show in the FastList
52 };
53
54
55 /*
56  * Prototypes ____________________________________________________________________
57  *
58  */
59
60
61 /*
62  * Static Functions _________________________________________________________________
63  *
64  */
65 LPTSTR GetString(UINT nStrID)
66 {
67     static TCHAR szText[cchRESOURCE];
68
69     GetString(szText, nStrID);
70
71     return szText;
72 }
73
74 static BOOL SetupImageLists()
75 {
76     HIMAGELIST hiList = ImageList_Create(16, 16, TRUE, 1, 1);
77
78     AfsAppLib_AddToImageList(hiList, IDI_DISK_DRIVE, FALSE);
79     AfsAppLib_AddToImageList(hiList, IDI_DISABLED_DISK_DRIVE, FALSE);
80     AfsAppLib_AddToImageList(hiList, IDI_DISK_DRIVE_WITH_WARNING, FALSE);
81     AfsAppLib_AddToImageList(hiList, IDI_AGGREGATE, FALSE);
82
83     FastList_SetImageLists(m_hDriveList, hiList, 0);
84
85     return TRUE;
86 }
87
88 static void AddColumn(int nWidth, LPCTSTR pszTitle)
89 {
90     static int nCol = 1;
91     FASTLISTCOLUMN col;
92
93     col.dwFlags = FLCF_JUSTIFY_LEFT;
94     col.cxWidth = nWidth;
95     lstrcpy(col.szText, pszTitle);
96
97     FastList_SetColumn(m_hDriveList, nCol++, &col);
98 }
99
100 static void SetupDriveListCols()
101 {
102     // Set width of cols based on width of the list
103     RECT rect;
104     GetClientRect(m_hDriveList, &rect);
105
106     int nWidth = rect.right - rect.left;
107
108     // If the width of the list is too small to show all
109     // three cols in a reasonable size that will fit without
110     // scrolling, then set the width to the ideal size and
111     // make the user scroll.
112     if (nWidth < 150)   // Minimum we will accept
113         nWidth = 370;   // The ideal size
114
115     AddColumn(50, GetString(IDS_DRIVE));
116     AddColumn(nWidth - 100, GetString(IDS_NAME_OR_ERROR));
117     AddColumn(50, GetString(IDS_SIZE));
118 }
119
120 static LPCTSTR GetDriveSizeAsString(LPCTSTR pszRootDir)
121 {
122     _ASSERTE(pszRootDir != 0);
123
124     ULARGE_INTEGER liDummy;
125     ULARGE_INTEGER liSize;
126     static TCHAR szSize[64];
127
128     *szSize = 0;
129
130     // Get partition size in bytes
131     if (GetDiskFreeSpaceEx(pszRootDir, &liDummy, &liSize, &liDummy)) {
132         // Covert to megabytes
133         ULONG nSize = (ULONG)(liSize.QuadPart / (1024 * 1024));
134         // Convert to a string
135         _ultot(nSize, szSize, 10);
136         lstrcat(szSize, TEXT(" MB"));
137     }
138
139     return szSize;
140 }
141
142 static BOOL DoesDriveContainData(LPCTSTR pszDriveRootDir)
143 {
144     TCHAR szSearchSpec[16];
145     WIN32_FIND_DATA findData;
146
147     _stprintf(szSearchSpec, TEXT("%s*.*"), pszDriveRootDir);
148
149     HANDLE hFind = FindFirstFile(szSearchSpec, &findData);
150     if (hFind == INVALID_HANDLE_VALUE)
151         return FALSE;
152
153     FindClose(hFind);
154
155     return TRUE;
156 }
157
158 static BOOL OnlyHasFolder(LPCTSTR pszRootDir, LPCTSTR pszFolder)
159 {
160     TCHAR szSearchSpec[MAX_PATH];
161     WIN32_FIND_DATA findData;
162     BOOL bFound = FALSE;
163
164     _stprintf(szSearchSpec, TEXT("%s*.*"), pszRootDir);
165
166     // If there is nothing in the root dir, then return FALSE
167     HANDLE hFind = FindFirstFile(szSearchSpec, &findData);
168     if (hFind == INVALID_HANDLE_VALUE)
169         return bFound;
170
171     // Is the first thing on the disk the recycle bin?  If not
172     // the the recycle bin is not the only thing on the disk.
173     if (_tcsicmp(findData.cFileName, pszFolder) == 0) {
174         // Is anything else on the disk?
175         if (!FindNextFile(hFind, &findData))
176             bFound = TRUE;
177     }
178
179     FindClose(hFind);
180
181     return bFound;
182 }
183
184 static BOOL DriveHasRecycleBin(LPCTSTR pszDriveRootDir)
185 {
186     if (OnlyHasFolder(pszDriveRootDir, TEXT("Recycled")))
187         return TRUE;
188
189     if (OnlyHasFolder(pszDriveRootDir, TEXT("Recycle Bin")))
190         return TRUE;
191
192     if (OnlyHasFolder(pszDriveRootDir, TEXT("Recycler")))
193         return TRUE;
194
195     return FALSE;
196 }
197
198 static BOOL DoesDriveContainNT(LPCTSTR pszDriveRootDir)
199 {
200     UINT nBufSize = MAX_PATH;
201     LPTSTR pszWinDir = 0;
202
203     while (!pszWinDir) {
204         pszWinDir = new TCHAR[nBufSize];
205
206         UINT nWinDirLen = GetWindowsDirectory(pszWinDir, nBufSize);
207
208         if (nWinDirLen > nBufSize) {
209             nBufSize = nWinDirLen;
210             delete [] pszWinDir;
211             pszWinDir = 0;
212         }
213     }
214
215     BOOL bNT = (_tcsncmp(pszDriveRootDir, pszWinDir, 3) == 0);
216
217     delete [] pszWinDir;
218
219     return bNT;
220 }
221
222 static BOOL ValidateDrive(BOOL bInvalid, UINT uiErrorMsgID, LPTSTR pszErrorStr)
223 {
224     if (!bInvalid)
225         return FALSE;
226
227     if (*pszErrorStr)
228         lstrcat(pszErrorStr, GetString(IDS_ERROR_SEP));
229     lstrcat(pszErrorStr, GetString(uiErrorMsgID));
230
231     return TRUE;
232 }
233
234 static BOOL GetDriveInfo(TCHAR chDrive, DRIVE_INFO& di)
235 {
236     DWORD dwDummy;
237     TCHAR szFileSys[64];
238     DWORD dwDriveFlags;
239
240     _stprintf(di.szRootDir, TEXT("%c:\\"), chDrive);
241
242     if (GetDriveType(di.szRootDir) != DRIVE_FIXED)
243         return FALSE;
244
245     if (!GetVolumeInformation(di.szRootDir, di.szVolName, sizeof(di.szVolName), 0, &dwDummy, &dwDriveFlags, szFileSys, sizeof(szFileSys)))
246         return FALSE;
247
248     TCHAR szError[256] = TEXT("");
249
250     BOOL bInvalid = FALSE, bHasData = FALSE;
251     BOOL bIsAfs = ValidateDrive(IsAnAfsPartition(di.szRootDir), IDS_ERROR_DRIVE_ALREADY_HAS_AFS, szError);
252     if (!bIsAfs) {
253         bInvalid |= ValidateDrive(dwDriveFlags & FS_VOL_IS_COMPRESSED, IDS_ERROR_DRIVE_COMPRESSED, szError);
254         bInvalid |= ValidateDrive(lstrcmp(szFileSys, TEXT("NTFS")) != 0, IDS_ERROR_FS_IS_NOT_NTFS, szError);
255
256         /*
257          *  We are no longer going to require that afs drives be empty; we will give a warning instead.
258          *
259          *      bInvalid |= ValidateDrive(DoesDriveContainNT(di.szRootDir), IDS_ERROR_DRIVE_CONTAINS_NT, szError);
260          *      bRecycle = ValidateDrive(DriveHasRecycleBin(di.szRootDir), IDS_WARNING_DRIVE_HAS_RECYCLE_BIN, szError);
261          */
262         if (!bInvalid)
263             bHasData = ValidateDrive(DoesDriveContainData(di.szRootDir), IDS_ERROR_DRIVE_HAS_DATA, szError);
264     }
265
266     if (*szError) {
267         lstrcpy(di.szVolName, szError);
268
269         if (bIsAfs)
270             di.nImage = AFS_DISK_DRIVE_IMAGE;
271         else if (bHasData)
272             di.nImage = DISK_DRIVE_WITH_WARNING_IMAGE;      // Treat this as a warning
273         else
274             di.nImage = DISABLED_DISK_DRIVE_IMAGE;
275
276         if (bIsAfs || bInvalid) {
277             di.bDisabled = TRUE;
278             di.dwFlags |= FLIF_DISALLOW_SELECT;
279         }
280     } else {
281         di.nImage = DISK_DRIVE_IMAGE;
282
283         if (lstrlen(di.szVolName) == 0)
284             GetString(di.szVolName, IDS_VOLUME_HAS_NO_NAME);
285     }
286
287     lstrncpy(di.szSize, GetDriveSizeAsString(di.szRootDir), sizeof(di.szSize));
288
289     return TRUE;
290 }
291
292 static BOOL FillDriveList()
293 {
294     DRIVE_INFO di;
295
296     TCHAR chDrive = TEXT('A');
297     DWORD dwDrives = GetLogicalDrives();
298
299     // This failing is not fatal to this function
300     // Make sure the partition table is up to date
301     afs_status_t nStatus;
302     int nResult = ReadPartitionTable(&nStatus);
303     ASSERT(nResult);
304
305     while (dwDrives) {
306         if (dwDrives & 1) {
307             memset(&di, 0, sizeof(di));
308
309             if (GetDriveInfo(chDrive, di)) {
310                 FASTLISTADDITEM ai = { 0, di.nImage, IMAGE_NOIMAGE, di.szRootDir, di.bDisabled, di.dwFlags };
311                 HLISTITEM hItem = FastList_AddItem(m_hDriveList, &ai);
312                 FastList_SetItemText(m_hDriveList, hItem, 1, di.szVolName);
313                 FastList_SetItemText(m_hDriveList, hItem, 2, di.szSize);
314             }
315         }
316
317         chDrive++;
318         dwDrives >>= 1;
319     }
320
321     return TRUE;
322 }
323
324 static int CALLBACK DriveListSortFunc(HWND hList, HLISTITEM hItem1, LPARAM lpItem1, HLISTITEM hItem2, LPARAM lpItem2)
325 {
326     _ASSERTE(hList == m_hDriveList);
327
328     // Ignore the first call which is only used to initialize static data
329     if (!hItem1 && !hItem2)
330         return 0;
331
332     // The lpItem vars contain 1 if the item is disabled, 0 if not
333     // Show enabled items before disabled items
334     if (lpItem1 != lpItem2)
335         return lpItem1 - lpItem2;
336
337     LPCTSTR pszItem1 = FastList_GetItemText(m_hDriveList, hItem1, 0);
338     LPCTSTR pszItem2 = FastList_GetItemText(m_hDriveList, hItem2, 0);
339
340     return lstrcmp(pszItem1, pszItem2);
341 }
342
343
344 /*
345  * Exported Functions _________________________________________________________________
346  *
347  */
348 void SetupDriveList(HWND driveList)
349 {
350     m_hDriveList = driveList;
351
352     SetupImageLists();
353
354     SetupDriveListCols();
355
356     FastList_SetSortFunction(m_hDriveList, DriveListSortFunc);
357 }
358
359 BOOL UpdateDriveList()
360 {
361     FastList_RemoveAll(m_hDriveList);
362
363     return FillDriveList();
364 }
365