2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
20 #include <WINNT/afsreg.h>
22 #include "forceremove.h"
26 /* Functions to forcibly remove AFS software without using InstallShield. */
28 #define CLIENT34_FME_VALUE "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\File Manager\\AddOns\\AFS Client FME"
30 #define MS_UNINSTALL_KEY "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
34 ClientSoftwareGet(DWORD *version, char *dir, DWORD dirSize);
37 ClientServiceDelete(void);
40 FileForceRemove(const char *filePath);
43 DirectoryForceRemove(const char *dir);
46 FolderLocateInTree(const char *dir, const char *folderName, char *buf);
49 Client34ZapUninstallKeys(void);
53 /* ------------------ exported functions ---------------------- */
57 * Client34Eradicate() -- remove AFS 3.4a client, if extant.
59 * If keepConfig is TRUE then the following are not removed:
61 * a) file %WINDIR%\afsdcell.ini - CellServDB
62 * b) file %WINDIR%\afsdsbmt.ini - submount settings
63 * c) file %WINDIR%\afsd.ini - client parameter settings
65 DWORD Client34Eradicate(BOOL keepConfig)
67 DWORD rc = ERROR_SUCCESS;
68 DWORD status, version;
69 BOOL installPathValid = FALSE;
70 char installPath[MAX_PATH];
71 char winPath[MAX_PATH];
72 char sysPath[MAX_PATH];
73 char filePath[MAX_PATH];
75 /* check client version and fetch install directory */
77 status = ClientSoftwareGet(&version, installPath, MAX_PATH);
79 if (status == ERROR_SUCCESS) {
81 /* 3.4 client to eradicate */
82 installPathValid = TRUE;
84 /* 3.5 or later client installed */
89 /* If no client info found then assume partial unconfigure and keep
90 * trying. Save errors as proceed but keep going to maximize removal.
94 /* stop and delete client service */
96 status = ClientServiceDelete();
97 if (status != ERROR_SUCCESS) {
101 /* remove client files */
103 status = GetWindowsDirectory(winPath, MAX_PATH);
104 if (status == 0 || status > MAX_PATH) {
105 /* this should never happen */
109 status = GetSystemDirectory(sysPath, MAX_PATH);
110 if (status == 0 || status > MAX_PATH) {
111 /* this should never happen */
115 if (installPathValid) {
116 status = DirectoryForceRemove(installPath);
117 if (status != ERROR_SUCCESS && status != ERROR_PATH_NOT_FOUND) {
122 sprintf(filePath, "%s\\%s", winPath, "afsd.log");
123 status = FileForceRemove(filePath);
124 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
128 sprintf(filePath, "%s\\%s", winPath, "afsd_init.log");
129 status = FileForceRemove(filePath);
130 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
134 sprintf(filePath, "%s\\%s", sysPath, "afs_cpa.cpl");
135 status = FileForceRemove(filePath);
136 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
140 sprintf(filePath, "%s\\%s", sysPath, "afs_shl_ext.dll");
141 status = FileForceRemove(filePath);
142 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
147 sprintf(filePath, "%s\\%s", winPath, "afsdcell.ini");
148 status = FileForceRemove(filePath);
149 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
153 sprintf(filePath, "%s\\%s", winPath, "afsdsbmt.ini");
154 status = FileForceRemove(filePath);
155 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
159 sprintf(filePath, "%s\\%s", winPath, "afsd.ini");
160 status = FileForceRemove(filePath);
161 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
166 do { /* locate all start menu entries (common or for a user) */
167 status = FolderLocateInTree(winPath, "Transarc AFS Client", filePath);
168 if (status == ERROR_SUCCESS) {
169 status = DirectoryForceRemove(filePath);
171 } while (status == ERROR_SUCCESS);
172 if (status != ERROR_FILE_NOT_FOUND) {
176 /* update relevant Microsoft registry entries */
178 status = RegDeleteEntryAlt(CLIENT34_FME_VALUE, REGENTRY_VALUE);
179 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
183 status = Client34ZapUninstallKeys();
184 if (status != ERROR_SUCCESS) {
188 if (!RemoveFromProviderOrder(AFSREG_CLT_SVC_NAME)) {
189 /* function does not supply an error value; make one up */
190 rc = ERROR_FILE_NOT_FOUND;
193 if (installPathValid) {
194 status = GetShortPathName(installPath, filePath, MAX_PATH);
195 if (status == 0 || status > MAX_PATH) {
196 strcpy(filePath, installPath);
198 strcat(filePath, "\\Program");
199 if (!RemoveFromSystemPath(filePath)) {
200 /* function does not supply an error value; make one up */
201 rc = ERROR_FILE_NOT_FOUND;
205 /* remove client registry entries */
207 status = RegDeleteEntryAlt(AFSREG_CLT_SVC_KEY, REGENTRY_KEY);
208 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
212 status = RegDeleteEntryAlt(AFSREG_CLT_SW_KEY, REGENTRY_KEY);
213 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
221 /* ------------------ utility functions ---------------------- */
225 * ClientSoftwareGet() -- fetch client software installation information.
228 ClientSoftwareGet(DWORD *version, char *dir, DWORD dirSize)
231 DWORD rc = ERROR_SUCCESS;
233 /* get client version and install directory */
235 rc = RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_CLT_SW_VERSION_KEY,
236 KEY_READ, 0, &key, NULL);
237 if (rc == ERROR_SUCCESS) {
238 DWORD major, minor, dataSize;
240 dataSize = sizeof(DWORD);
241 rc = RegQueryValueEx(key, AFSREG_CLT_SW_VERSION_MAJOR_VALUE,
242 NULL, NULL, (void*)&major, &dataSize);
243 if (rc == ERROR_SUCCESS) {
244 dataSize = sizeof(DWORD);
245 rc = RegQueryValueEx(key, AFSREG_CLT_SW_VERSION_MINOR_VALUE,
246 NULL, NULL, (void*)&minor, &dataSize);
247 if (rc == ERROR_SUCCESS) {
249 rc = RegQueryValueEx(key, AFSREG_CLT_SW_VERSION_DIR_VALUE,
250 NULL, NULL, dir, &dataSize);
253 (void)RegCloseKey(key);
255 if (rc == ERROR_SUCCESS) {
256 *version = (major * 10) + minor;
264 * ClientServiceDelete() -- stop and delete the client service.
267 ClientServiceDelete(void)
269 SC_HANDLE scmHandle, svcHandle;
270 DWORD rc = ERROR_SUCCESS;
272 if ((scmHandle = OpenSCManager(NULL,
273 NULL, SC_MANAGER_ALL_ACCESS)) == NULL ||
274 (svcHandle = OpenService(scmHandle,
276 SERVICE_ALL_ACCESS)) == NULL) {
277 /* can't connect to SCM or can't open service */
278 DWORD status = GetLastError();
280 if (status != ERROR_SERVICE_DOES_NOT_EXIST) {
284 if (scmHandle != NULL) {
285 CloseServiceHandle(scmHandle);
289 SERVICE_STATUS svcStatus;
291 if (!ControlService(svcHandle, SERVICE_CONTROL_STOP, &svcStatus)) {
292 /* service stop failed */
293 DWORD status = GetLastError();
295 if (status != ERROR_SERVICE_NOT_ACTIVE) {
300 if (rc == ERROR_SUCCESS) {
301 if (!DeleteService(svcHandle)) {
302 /* service delete failed */
303 DWORD status = GetLastError();
305 if (status != ERROR_SERVICE_MARKED_FOR_DELETE) {
311 CloseServiceHandle(svcHandle);
312 CloseServiceHandle(scmHandle);
314 if (rc == ERROR_SUCCESS) {
315 /* let client state settle; not mandatory so don't do query */
324 * DirectoryForceRemove() -- forcibly, and recursively, remove a directory
325 * and its contents; this may require moving in-use files to a temp
326 * directory and marking them for delete on reboot.
329 DirectoryForceRemove(const char *dir)
331 DWORD rc = ERROR_SUCCESS;
333 WIN32_FIND_DATA enumResult;
334 char filePath[MAX_PATH];
336 /* enumerate directory and delete contents */
338 sprintf(filePath, "%s\\*.*", dir);
340 enumHandle = FindFirstFile(filePath, &enumResult);
342 if (enumHandle == INVALID_HANDLE_VALUE) {
343 DWORD status = GetLastError();
345 if (status != ERROR_NO_MORE_FILES) {
346 /* failure other than contents already deleted */
354 sprintf(filePath, "%s\\%s", dir, enumResult.cFileName);
356 if (enumResult.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
357 if (strcmp(enumResult.cFileName, ".") == 0 ||
358 strcmp(enumResult.cFileName, "..") == 0) {
359 /* ignore these special directories */
360 status = ERROR_SUCCESS;
362 status = DirectoryForceRemove(filePath);
365 status = FileForceRemove(filePath);
368 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
369 /* save error but keep on truckin' */
373 if (!FindNextFile(enumHandle, &enumResult)) {
374 status = GetLastError();
376 if (status != ERROR_NO_MORE_FILES) {
382 FindClose(enumHandle);
385 if (rc == ERROR_SUCCESS) {
386 if (!RemoveDirectory(dir)) {
395 * FileForceRemove() -- forcibly remove a file; if the file is in-use then
396 * move the file to a temp directory and mark it for delete on reboot.
399 FileForceRemove(const char *filePath)
401 DWORD rc = ERROR_SUCCESS;
403 if (!DeleteFile(filePath)) {
406 if (rc != ERROR_FILE_NOT_FOUND) {
407 /* couldn't just delete; probably in use; try to move */
408 char filePathFull[MAX_PATH];
414 status = GetFullPathName(filePath, MAX_PATH, filePathFull, &dummy);
415 if (status == 0 || status > MAX_PATH) {
419 rc = ERROR_INVALID_PARAMETER;
423 if (rc == ERROR_SUCCESS) {
424 char tempDir[MAX_PATH];
425 char tempPath[MAX_PATH];
427 status = GetTempPath(MAX_PATH, tempDir);
428 if ((status == 0 || status > MAX_PATH) ||
429 (_strnicmp(tempDir, filePathFull, 3))) {
430 /* failed getting temp dir, or temp dir is on different
431 * drive than file (so can't do a true move to there).
433 sprintf(tempDir, "%c:\\", filePathFull[0]);
436 if (!GetTempFileName(tempDir, "AFS", 0, tempPath)) {
439 if (MoveFileEx(filePathFull, tempPath,
440 MOVEFILE_REPLACE_EXISTING)) {
441 (void)SetFileAttributes(tempPath,
442 FILE_ATTRIBUTE_NORMAL);
443 (void)MoveFileEx(tempPath, NULL,
444 MOVEFILE_DELAY_UNTIL_REBOOT);
457 * FolderLocateInTree() -- find an instance of named directory in specified
458 * tree; folderName is presumed to be a directory name only (i.e., not
459 * a path); buf is presumed to be at least MAX_PATH characters.
462 FolderLocateInTree(const char *dir, const char *folderName, char *buf)
464 DWORD rc = ERROR_SUCCESS;
466 WIN32_FIND_DATA enumResult;
467 char filePath[MAX_PATH];
469 /* enumerate directory recursively looking for folder */
471 sprintf(filePath, "%s\\*.*", dir);
473 enumHandle = FindFirstFile(filePath, &enumResult);
475 if (enumHandle == INVALID_HANDLE_VALUE) {
476 DWORD status = GetLastError();
478 if (status == ERROR_NO_MORE_FILES) {
479 rc = ERROR_FILE_NOT_FOUND;
486 DWORD status = ERROR_FILE_NOT_FOUND;
488 if (enumResult.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
489 if (_stricmp(enumResult.cFileName, folderName) == 0) {
490 /* is folder that we're looking for */
491 sprintf(buf, "%s\\%s", dir, enumResult.cFileName);
492 status = ERROR_SUCCESS;
494 } else if (strcmp(enumResult.cFileName, ".") != 0 &&
495 strcmp(enumResult.cFileName, "..") != 0) {
496 /* is not folder that we're looking for; search it */
497 sprintf(filePath, "%s\\%s", dir, enumResult.cFileName);
498 status = FolderLocateInTree(filePath, folderName, buf);
502 if (status != ERROR_FILE_NOT_FOUND) {
503 /* found folder or encountered an error; quit */
507 /* folder not found; keep looking */
508 if (!FindNextFile(enumHandle, &enumResult)) {
509 status = GetLastError();
511 if (status == ERROR_NO_MORE_FILES) {
512 rc = ERROR_FILE_NOT_FOUND;
520 FindClose(enumHandle);
527 * Client34ZapUninstallKeys() -- delete all of the client uninstall keys
530 Client34ZapUninstallKeys(void)
532 DWORD rc = ERROR_SUCCESS;
535 /* enumerate all uninstall registry keys looking for client's */
537 rc = RegOpenKeyAlt(AFSREG_NULL_KEY,
538 MS_UNINSTALL_KEY, KEY_ALL_ACCESS, 0, &key, NULL);
539 if (rc == ERROR_SUCCESS) {
542 rc = RegEnumKeyAlt(key, &keyEnum);
543 if (rc == ERROR_SUCCESS && keyEnum != NULL) {
546 for (keyEnumName = keyEnum;
547 *keyEnumName != '\0';
548 keyEnumName += strlen(keyEnumName) + 1) {
549 if (_stricmp(keyEnumName, "AFSDeinstKey") == 0 ||
550 _strnicmp(keyEnumName, "AFSV34", 6) == 0) {
551 /* found an AFS uninstall key */
552 DWORD status = RegDeleteKeyAlt(key, keyEnumName);
553 if (status != ERROR_SUCCESS) {
560 (void) RegCloseKey(key);