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