1 /* Copyright (C) 1999 Transarc Corporation - All rights reserved.
15 #include <WINNT/afsreg.h>
17 #include "forceremove.h"
21 /* Functions to forcibly remove AFS software without using InstallShield. */
23 #define CLIENT34_FME_VALUE "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\File Manager\\AddOns\\AFS Client FME"
25 #define MS_UNINSTALL_KEY "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
29 ClientSoftwareGet(DWORD *version, char *dir, DWORD dirSize);
32 ClientServiceDelete(void);
35 FileForceRemove(const char *filePath);
38 DirectoryForceRemove(const char *dir);
41 FolderLocateInTree(const char *dir, const char *folderName, char *buf);
44 Client34ZapUninstallKeys(void);
48 /* ------------------ exported functions ---------------------- */
52 * Client34Eradicate() -- remove AFS 3.4a client, if extant.
54 * If keepConfig is TRUE then the following are not removed:
56 * a) file %WINDIR%\afsdcell.ini - CellServDB
57 * b) file %WINDIR%\afsdsbmt.ini - submount settings
58 * c) file %WINDIR%\afsd.ini - client parameter settings
60 DWORD Client34Eradicate(BOOL keepConfig)
62 DWORD rc = ERROR_SUCCESS;
63 DWORD status, version;
64 BOOL installPathValid = FALSE;
65 char installPath[MAX_PATH];
66 char winPath[MAX_PATH];
67 char sysPath[MAX_PATH];
68 char filePath[MAX_PATH];
70 /* check client version and fetch install directory */
72 status = ClientSoftwareGet(&version, installPath, MAX_PATH);
74 if (status == ERROR_SUCCESS) {
76 /* 3.4 client to eradicate */
77 installPathValid = TRUE;
79 /* 3.5 or later client installed */
84 /* If no client info found then assume partial unconfigure and keep
85 * trying. Save errors as proceed but keep going to maximize removal.
89 /* stop and delete client service */
91 status = ClientServiceDelete();
92 if (status != ERROR_SUCCESS) {
96 /* remove client files */
98 status = GetWindowsDirectory(winPath, MAX_PATH);
99 if (status == 0 || status > MAX_PATH) {
100 /* this should never happen */
104 status = GetSystemDirectory(sysPath, MAX_PATH);
105 if (status == 0 || status > MAX_PATH) {
106 /* this should never happen */
110 if (installPathValid) {
111 status = DirectoryForceRemove(installPath);
112 if (status != ERROR_SUCCESS && status != ERROR_PATH_NOT_FOUND) {
117 sprintf(filePath, "%s\\%s", winPath, "afsd.log");
118 status = FileForceRemove(filePath);
119 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
123 sprintf(filePath, "%s\\%s", winPath, "afsd_init.log");
124 status = FileForceRemove(filePath);
125 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
129 sprintf(filePath, "%s\\%s", sysPath, "afs_cpa.cpl");
130 status = FileForceRemove(filePath);
131 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
135 sprintf(filePath, "%s\\%s", sysPath, "afs_shl_ext.dll");
136 status = FileForceRemove(filePath);
137 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
142 sprintf(filePath, "%s\\%s", winPath, "afsdcell.ini");
143 status = FileForceRemove(filePath);
144 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
148 sprintf(filePath, "%s\\%s", winPath, "afsdsbmt.ini");
149 status = FileForceRemove(filePath);
150 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
154 sprintf(filePath, "%s\\%s", winPath, "afsd.ini");
155 status = FileForceRemove(filePath);
156 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
161 do { /* locate all start menu entries (common or for a user) */
162 status = FolderLocateInTree(winPath, "Transarc AFS Client", filePath);
163 if (status == ERROR_SUCCESS) {
164 status = DirectoryForceRemove(filePath);
166 } while (status == ERROR_SUCCESS);
167 if (status != ERROR_FILE_NOT_FOUND) {
171 /* update relevant Microsoft registry entries */
173 status = RegDeleteEntryAlt(CLIENT34_FME_VALUE, REGENTRY_VALUE);
174 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
178 status = Client34ZapUninstallKeys();
179 if (status != ERROR_SUCCESS) {
183 if (!RemoveFromProviderOrder(AFSREG_CLT_SVC_NAME)) {
184 /* function does not supply an error value; make one up */
185 rc = ERROR_FILE_NOT_FOUND;
188 if (installPathValid) {
189 status = GetShortPathName(installPath, filePath, MAX_PATH);
190 if (status == 0 || status > MAX_PATH) {
191 strcpy(filePath, installPath);
193 strcat(filePath, "\\Program");
194 if (!RemoveFromSystemPath(filePath)) {
195 /* function does not supply an error value; make one up */
196 rc = ERROR_FILE_NOT_FOUND;
200 /* remove client registry entries */
202 status = RegDeleteEntryAlt(AFSREG_CLT_SVC_KEY, REGENTRY_KEY);
203 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
207 status = RegDeleteEntryAlt(AFSREG_CLT_SW_KEY, REGENTRY_KEY);
208 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
216 /* ------------------ utility functions ---------------------- */
220 * ClientSoftwareGet() -- fetch client software installation information.
223 ClientSoftwareGet(DWORD *version, char *dir, DWORD dirSize)
226 DWORD rc = ERROR_SUCCESS;
228 /* get client version and install directory */
230 rc = RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_CLT_SW_VERSION_KEY,
231 KEY_READ, 0, &key, NULL);
232 if (rc == ERROR_SUCCESS) {
233 DWORD major, minor, dataSize;
235 dataSize = sizeof(DWORD);
236 rc = RegQueryValueEx(key, AFSREG_CLT_SW_VERSION_MAJOR_VALUE,
237 NULL, NULL, (void*)&major, &dataSize);
238 if (rc == ERROR_SUCCESS) {
239 dataSize = sizeof(DWORD);
240 rc = RegQueryValueEx(key, AFSREG_CLT_SW_VERSION_MINOR_VALUE,
241 NULL, NULL, (void*)&minor, &dataSize);
242 if (rc == ERROR_SUCCESS) {
244 rc = RegQueryValueEx(key, AFSREG_CLT_SW_VERSION_DIR_VALUE,
245 NULL, NULL, dir, &dataSize);
248 (void)RegCloseKey(key);
250 if (rc == ERROR_SUCCESS) {
251 *version = (major * 10) + minor;
259 * ClientServiceDelete() -- stop and delete the client service.
262 ClientServiceDelete(void)
264 SC_HANDLE scmHandle, svcHandle;
265 DWORD rc = ERROR_SUCCESS;
267 if ((scmHandle = OpenSCManager(NULL,
268 NULL, SC_MANAGER_ALL_ACCESS)) == NULL ||
269 (svcHandle = OpenService(scmHandle,
271 SERVICE_ALL_ACCESS)) == NULL) {
272 /* can't connect to SCM or can't open service */
273 DWORD status = GetLastError();
275 if (status != ERROR_SERVICE_DOES_NOT_EXIST) {
279 if (scmHandle != NULL) {
280 CloseServiceHandle(scmHandle);
284 SERVICE_STATUS svcStatus;
286 if (!ControlService(svcHandle, SERVICE_CONTROL_STOP, &svcStatus)) {
287 /* service stop failed */
288 DWORD status = GetLastError();
290 if (status != ERROR_SERVICE_NOT_ACTIVE) {
295 if (rc == ERROR_SUCCESS) {
296 if (!DeleteService(svcHandle)) {
297 /* service delete failed */
298 DWORD status = GetLastError();
300 if (status != ERROR_SERVICE_MARKED_FOR_DELETE) {
306 CloseServiceHandle(svcHandle);
307 CloseServiceHandle(scmHandle);
309 if (rc == ERROR_SUCCESS) {
310 /* let client state settle; not mandatory so don't do query */
319 * DirectoryForceRemove() -- forcibly, and recursively, remove a directory
320 * and its contents; this may require moving in-use files to a temp
321 * directory and marking them for delete on reboot.
324 DirectoryForceRemove(const char *dir)
326 DWORD rc = ERROR_SUCCESS;
328 WIN32_FIND_DATA enumResult;
329 char filePath[MAX_PATH];
331 /* enumerate directory and delete contents */
333 sprintf(filePath, "%s\\*.*", dir);
335 enumHandle = FindFirstFile(filePath, &enumResult);
337 if (enumHandle == INVALID_HANDLE_VALUE) {
338 DWORD status = GetLastError();
340 if (status != ERROR_NO_MORE_FILES) {
341 /* failure other than contents already deleted */
349 sprintf(filePath, "%s\\%s", dir, enumResult.cFileName);
351 if (enumResult.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
352 if (strcmp(enumResult.cFileName, ".") == 0 ||
353 strcmp(enumResult.cFileName, "..") == 0) {
354 /* ignore these special directories */
355 status = ERROR_SUCCESS;
357 status = DirectoryForceRemove(filePath);
360 status = FileForceRemove(filePath);
363 if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
364 /* save error but keep on truckin' */
368 if (!FindNextFile(enumHandle, &enumResult)) {
369 status = GetLastError();
371 if (status != ERROR_NO_MORE_FILES) {
377 FindClose(enumHandle);
380 if (rc == ERROR_SUCCESS) {
381 if (!RemoveDirectory(dir)) {
390 * FileForceRemove() -- forcibly remove a file; if the file is in-use then
391 * move the file to a temp directory and mark it for delete on reboot.
394 FileForceRemove(const char *filePath)
396 DWORD rc = ERROR_SUCCESS;
398 if (!DeleteFile(filePath)) {
401 if (rc != ERROR_FILE_NOT_FOUND) {
402 /* couldn't just delete; probably in use; try to move */
403 char filePathFull[MAX_PATH];
409 status = GetFullPathName(filePath, MAX_PATH, filePathFull, &dummy);
410 if (status == 0 || status > MAX_PATH) {
414 rc = ERROR_INVALID_PARAMETER;
418 if (rc == ERROR_SUCCESS) {
419 char tempDir[MAX_PATH];
420 char tempPath[MAX_PATH];
422 status = GetTempPath(MAX_PATH, tempDir);
423 if ((status == 0 || status > MAX_PATH) ||
424 (_strnicmp(tempDir, filePathFull, 3))) {
425 /* failed getting temp dir, or temp dir is on different
426 * drive than file (so can't do a true move to there).
428 sprintf(tempDir, "%c:\\", filePathFull[0]);
431 if (!GetTempFileName(tempDir, "AFS", 0, tempPath)) {
434 if (MoveFileEx(filePathFull, tempPath,
435 MOVEFILE_REPLACE_EXISTING)) {
436 (void)SetFileAttributes(tempPath,
437 FILE_ATTRIBUTE_NORMAL);
438 (void)MoveFileEx(tempPath, NULL,
439 MOVEFILE_DELAY_UNTIL_REBOOT);
452 * FolderLocateInTree() -- find an instance of named directory in specified
453 * tree; folderName is presumed to be a directory name only (i.e., not
454 * a path); buf is presumed to be at least MAX_PATH characters.
457 FolderLocateInTree(const char *dir, const char *folderName, char *buf)
459 DWORD rc = ERROR_SUCCESS;
461 WIN32_FIND_DATA enumResult;
462 char filePath[MAX_PATH];
464 /* enumerate directory recursively looking for folder */
466 sprintf(filePath, "%s\\*.*", dir);
468 enumHandle = FindFirstFile(filePath, &enumResult);
470 if (enumHandle == INVALID_HANDLE_VALUE) {
471 DWORD status = GetLastError();
473 if (status == ERROR_NO_MORE_FILES) {
474 rc = ERROR_FILE_NOT_FOUND;
481 DWORD status = ERROR_FILE_NOT_FOUND;
483 if (enumResult.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
484 if (_stricmp(enumResult.cFileName, folderName) == 0) {
485 /* is folder that we're looking for */
486 sprintf(buf, "%s\\%s", dir, enumResult.cFileName);
487 status = ERROR_SUCCESS;
489 } else if (strcmp(enumResult.cFileName, ".") != 0 &&
490 strcmp(enumResult.cFileName, "..") != 0) {
491 /* is not folder that we're looking for; search it */
492 sprintf(filePath, "%s\\%s", dir, enumResult.cFileName);
493 status = FolderLocateInTree(filePath, folderName, buf);
497 if (status != ERROR_FILE_NOT_FOUND) {
498 /* found folder or encountered an error; quit */
502 /* folder not found; keep looking */
503 if (!FindNextFile(enumHandle, &enumResult)) {
504 status = GetLastError();
506 if (status == ERROR_NO_MORE_FILES) {
507 rc = ERROR_FILE_NOT_FOUND;
515 FindClose(enumHandle);
522 * Client34ZapUninstallKeys() -- delete all of the client uninstall keys
525 Client34ZapUninstallKeys(void)
527 DWORD rc = ERROR_SUCCESS;
530 /* enumerate all uninstall registry keys looking for client's */
532 rc = RegOpenKeyAlt(AFSREG_NULL_KEY,
533 MS_UNINSTALL_KEY, KEY_ALL_ACCESS, 0, &key, NULL);
534 if (rc == ERROR_SUCCESS) {
537 rc = RegEnumKeyAlt(key, &keyEnum);
538 if (rc == ERROR_SUCCESS && keyEnum != NULL) {
541 for (keyEnumName = keyEnum;
542 *keyEnumName != '\0';
543 keyEnumName += strlen(keyEnumName) + 1) {
544 if (_stricmp(keyEnumName, "AFSDeinstKey") == 0 ||
545 _strnicmp(keyEnumName, "AFSV34", 6) == 0) {
546 /* found an AFS uninstall key */
547 DWORD status = RegDeleteKeyAlt(key, keyEnumName);
548 if (status != ERROR_SUCCESS) {
555 (void) RegCloseKey(key);