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