nt-makefile-clean-targets-20010917
[openafs.git] / src / WINNT / afssvrcfg / salvage_results_dlg.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 "afscfg.h"             // Main header for this application
15 #include "resource.h"
16 #include "salvage_results_dlg.h"
17 extern "C" {
18 #include "afs_bosAdmin.h"
19 }
20
21
22 /*
23  * DEFINITIONS _________________________________________________________________
24  *
25  */
26 static const int     UPDATE_INTERVAL        = 5000;             // milleseconds
27 static const int     LOG_BUF_SIZE           = 25000;            // bytes
28 static const int     EDIT_CONTROL_MAX_CHARS = 64000;            // Max chars an edit control can hold
29 static const char   *SALVAGE_LOG_FILE_NAME  = "SalvageLog.txt";
30
31 static rwWindowData arwDialog[] = {
32         { IDC_LOG,                              raSizeX | raSizeY, MAKELONG(350, 150) },
33         { IDC_CLOSE,                    raMoveX | raMoveY },
34         { 9,                                    raMoveX | raMoveY },
35         { idENDLIST,                    0 }
36 };
37
38
39 /*
40  * Variables _________________________________________________________________
41  *
42  */
43 static HWND hDlg = 0;                                           // HWND for this page's dialog
44 static HWND hLogo;
45 static afs_status_t nStatus;
46 static void *hServer;
47 static int nResult; 
48 static BOOL bSalvageComplete;
49
50
51 /*
52  * PROTOTYPES _________________________________________________________________
53  *
54  */
55 static void OnInitDialog(HWND hwndDlg);
56 static void OnClose();
57 static void SetMessages(int nStatusMsgID, int nLogMsgID);
58 static DWORD WINAPI ShowResults(LPVOID param);
59 static void SaveLogToDisk(char *pszLogBuf, char *pszFileName);
60 static char *AddCarriageReturnsToLog(char *pszInBuf, char *&pszOutBuf);
61 static char *GetMaxPartOfLogWeCanShow(char *pszLogBuf);
62 static BOOL AllocMemory(char *&pszLogBuf, int nBufSize);
63
64 BOOL CALLBACK SalvageResultsDlgProc(HWND hRHS, UINT msg, WPARAM wp, LPARAM lp);
65
66
67 /*
68  * EXPORTED FUNCTIONS _________________________________________________________
69  *
70  */
71 BOOL ShowSalvageResults(HWND hParent)
72 {       
73         int nResult = ModalDialog(IDD_SALVAGE_RESULTS, hParent, (DLGPROC)SalvageResultsDlgProc);
74
75         return (nResult == IDOK);
76 }
77
78
79 /*
80  * Dialog Proc _________________________________________________________________
81  *
82  */
83 BOOL CALLBACK SalvageResultsDlgProc(HWND hwndDlg, UINT msg, WPARAM wp, LPARAM lp)
84 {
85         if (AfsAppLib_HandleHelp(IDD_SALVAGE_RESULTS, hwndDlg, msg, wp, lp))
86                 return TRUE;
87
88         switch (msg) {
89                 case WM_INITDIALOG:
90                         OnInitDialog(hwndDlg);
91                         break;
92
93                 case WM_COMMAND:
94                         switch (LOWORD(wp)) {
95                                 case IDC_CLOSE:
96                     OnClose();
97                                         break;
98
99                 case IDCANCEL:
100                     if (bSalvageComplete)
101                         OnClose();
102                         }
103                     break;
104
105                 case WM_SIZE:   
106                         if (lp != 0)
107                                 ResizeWindow(hwndDlg, arwDialog, rwaFixupGuts);
108                         break;
109         }
110
111     return FALSE;
112 }
113
114
115 /*
116  * STATIC FUNCTIONS _________________________________________________________________
117  *
118  */
119
120 /*
121  * Event Handler Functions __________________________________________________________
122  *
123  */
124 static void OnInitDialog(HWND hwndDlg)
125 {
126         hDlg = hwndDlg;
127
128     bSalvageComplete = FALSE;
129
130     ResizeWindow(hDlg, arwDialog, rwaFixupGuts);
131
132     hLogo = GetDlgItem(hDlg, IDC_LOGO);
133
134     AfsAppLib_StartAnimation(hLogo, 8);
135
136     SetMessages(IDS_SALVAGING, IDS_CURRENT_SALVAGE_LOG);
137
138         nResult = bos_ServerOpen(g_hCell, GetHostnameA(), &hServer, &nStatus);
139         if (!nResult) {
140                 ShowError(hDlg, nStatus, IDS_BOS_OPEN_FAILED);
141                 return;
142         }
143
144     // Remove the start menu - we do this so the user can't close
145     // the dialog while salvage is being performed.
146     DWORD dw;
147     dw = GetWindowLong(hDlg, GWL_STYLE);
148     dw &= ~WS_SYSMENU;
149     SetWindowLong(hDlg, GWL_STYLE, dw);
150
151         // Create a thread to keep the view of the log up to date
152         DWORD dwThreadID;
153         HANDLE hThread = CreateThread(0, 0, ShowResults, 0, 0, &dwThreadID);
154         CloseHandle(hThread);
155 }
156
157 static void OnClose()
158 {
159         bos_ServerClose(hServer, &nStatus);
160
161     EndDialog(hDlg, IDOK);
162 }
163
164
165 /*
166  * Utility Functions _________________________________________________________________
167  *
168  */
169 static void SetMessages(int nStatusMsgID, int nLogMsgID)
170 {
171     TCHAR szMsgBuf[cchRESOURCE];
172
173     SetDlgItemText(hDlg, IDC_SALVAGE_STATUS, GetResString(nStatusMsgID, szMsgBuf));
174     SetDlgItemText(hDlg, IDC_LOG_TITLE, GetResString(nLogMsgID, szMsgBuf));
175 }
176
177 static char *AddCarriageReturnsToLog(char *pszInBuf, char *& pszOutBuf)
178 {
179     ASSERT(pszInBuf);
180
181     char *pInBuf = pszInBuf;
182
183     // How man new lines are there?
184     int nNumNLs = 0;
185
186     while (*pInBuf) {
187         if (*pInBuf == '\n')
188             nNumNLs++;
189                 pInBuf++;
190     }
191
192     // Allocate enough memory for the log buffer plus CRs plus a NULL
193     if (!AllocMemory(pszOutBuf, strlen(pszInBuf) + nNumNLs + 1))
194         return 0;
195
196     // Copy over the whole buffer, adding \r's as we go.  The edit control
197     // seems to need \r before \n, so we set it up that way.
198     pInBuf = pszInBuf;
199     char *pOutBuf = pszOutBuf;
200
201     while (*pInBuf) {
202         if (*pInBuf == '\n') {
203             *pOutBuf++ = '\r';
204             *pOutBuf++ = '\n';
205         } else
206             *pOutBuf++ = *pInBuf;
207                 
208                 pInBuf++;
209     }
210
211     *pOutBuf = 0;
212
213     return pszOutBuf;
214 }
215
216 static char *GetMaxPartOfLogWeCanShow(char *pszLogBuf)
217 {
218     ASSERT(pszLogBuf);
219
220     // Find out how much of the log buffer is in use
221     int nLen = strlen(pszLogBuf);
222
223     if (nLen < EDIT_CONTROL_MAX_CHARS)
224         return pszLogBuf;
225
226     // Buffer is bigger than maximum, so find the last full line
227     // under the limit and return it.
228     char *psz = pszLogBuf + nLen - EDIT_CONTROL_MAX_CHARS;
229     
230     // Make sure we return the beginning of a line
231     while (*psz && (*psz != '\n'))
232         psz++;
233
234         if (*psz == '\n')
235                 psz++;
236
237     return psz;
238 }    
239
240 static BOOL AllocMemory(char *&pszLogBuf, int nBufSize)
241 {
242     if (pszLogBuf)
243         delete pszLogBuf;
244
245     pszLogBuf = new char[nBufSize];
246
247     if (!pszLogBuf) {
248         g_LogFile.Write("Failed to allocate memory (%d bytes) for the salvage log buffer.\r\n", nBufSize);
249         return FALSE;
250     }
251
252     return TRUE;
253 }
254
255 static void SaveLogToDisk(char *pszLogBuf, char *pszFileName)
256 {
257     // If no log file was specified by the user, then do nothing
258     if (!pszFileName[0])
259         return;
260
261         FILE *fp = fopen(pszFileName, "w");
262         if (!fp) {
263                 ShowError(hDlg, 0, IDS_ERROR_SAVING_SALVAGE_LOG_TO_DISK);
264                 return;
265         }
266
267         fprintf(fp, "%s", pszLogBuf);
268
269         fclose(fp);
270 }
271
272 static DWORD WINAPI ShowResults(LPVOID param)
273 {
274     ULONG nBufSize = LOG_BUF_SIZE;
275     char *pszLogBuf = 0;
276     char *pszLogBufWithCRs = 0;
277     DWORD dwWait = WAIT_TIMEOUT;
278     DWORD rc = 1;
279     ULONG nLogSize = LOG_BUF_SIZE;
280
281     if (!AllocMemory(pszLogBuf, nBufSize))
282         return 0;
283     
284     while (dwWait != WAIT_OBJECT_0) {
285         // Wait for either the salvage thread to terminate or our update
286         // interval to pass.
287         dwWait = WaitForSingleObject(g_CfgData.hSalvageThread, UPDATE_INTERVAL);
288
289         // In either case, update the log display for the user
290
291         // Get the salvage log as it currently exists
292 getlog: nResult = bos_LogGet(hServer, "SalvageLog", &nLogSize, pszLogBuf, &nStatus);
293         if (!nResult) {
294             if (nStatus == ADMMOREDATA) {
295                 // If salvage isn't done, then get a bigger buffer than we need to
296                 // prevent future ADMMOREDATA errors.
297                 nBufSize = nLogSize;
298                 if (dwWait != WAIT_OBJECT_0) {
299                     nBufSize += LOG_BUF_SIZE;
300                     nLogSize = nBufSize;
301                 }
302                 if (AllocMemory(pszLogBuf, nBufSize))
303                     goto getlog;
304             }
305
306             rc = 0;
307             break;            
308         }
309
310         // NULL-terminate the log
311         pszLogBuf[nLogSize] = 0;
312
313         // The edit control that we use to show the log to the user needs \r\n at the end
314         // of each line, but the salvage log only has \n.  We must replace the \n with
315         // \r\n before showing the log.
316         if (!AddCarriageReturnsToLog(pszLogBuf, pszLogBufWithCRs)) {
317             rc = 0;
318             break;
319         }
320         
321         // The edit control has a limit to the number of characters it can hold.  If the log
322         // is bigger than that limit, then we will show the maximum portion of the end of the
323         // log that we can fit in the edit control.
324         char *pszLogToShow = GetMaxPartOfLogWeCanShow(pszLogBufWithCRs);
325
326         // Put it into the edit control so the user can see it
327         SetDlgItemText(hDlg, IDC_LOG, A2S(pszLogToShow));
328     }
329
330     AfsAppLib_StopAnimation(hLogo);
331
332     if (rc) {
333         SetMessages(IDS_SALVAGE_COMPLETE, IDS_FINAL_SALVAGE_LOG);
334                 SaveLogToDisk(pszLogBufWithCRs, GetSalvageLogFileNameA());
335         MsgBox(hDlg, IDS_SALVAGE_COMPLETE, GetAppTitleID(), MB_OK);
336     } else {
337         SetMessages(IDS_SALVAGING, IDS_CANT_GET_SALVAGE_LOG);
338         ShowError(hDlg, nStatus, IDS_CANT_GET_SALVAGE_LOG);
339     }
340
341     CloseHandle(g_CfgData.hSalvageThread);
342
343     if (pszLogBuf)
344         delete pszLogBuf;
345
346     if (pszLogBufWithCRs)
347         delete pszLogBufWithCRs;
348
349     SetEnable(hDlg, IDC_CLOSE);
350
351     bSalvageComplete = TRUE;
352
353     return rc;
354 }
355