1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1997,2008 Oracle. All rights reserved. 5 * 6 * $Id: os_unlink.c,v 12.26 2008/05/07 12:27:35 bschmeck Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12 13/* 14 * __os_unlink -- 15 * Remove a file. 16 */ 17int 18__os_unlink(env, path, overwrite_test) 19 ENV *env; 20 const char *path; 21 int overwrite_test; 22{ 23 DB_ENV *dbenv; 24 HANDLE h; 25 _TCHAR *tpath, *orig_tpath, buf[DB_MAXPATHLEN]; 26 u_int32_t id; 27 int ret, t_ret; 28 29 dbenv = env == NULL ? NULL : env->dbenv; 30 31 if (dbenv != NULL && 32 FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL)) 33 __db_msg(env, "fileops: unlink %s", path); 34 35 /* Optionally overwrite the contents of the file to enhance security. */ 36 if (dbenv != NULL && overwrite_test && F_ISSET(dbenv, DB_ENV_OVERWRITE)) 37 (void)__db_file_multi_write(env, path); 38 39 TO_TSTRING(env, path, tpath, ret); 40 if (ret != 0) 41 return (ret); 42 orig_tpath = tpath; 43 44 LAST_PANIC_CHECK_BEFORE_IO(env); 45 46 /* 47 * Windows NT and its descendants allow removal of open files, but the 48 * DeleteFile Win32 system call isn't equivalent to a POSIX unlink. 49 * Firstly, it only succeeds if FILE_SHARE_DELETE is set when the file 50 * is opened. Secondly, it leaves the file in a "zombie" state, where 51 * it can't be opened again, but a new file with the same name can't be 52 * created either. 53 * 54 * Since we depend on being able to recreate files (during recovery, 55 * say), we have to first rename the file, and then delete it. It 56 * still hangs around, but with a name we don't care about. The rename 57 * will fail if the file doesn't exist, which isn't a problem, but if 58 * it fails for some other reason, we need to know about it or a 59 * subsequent open may fail for no apparent reason. 60 */ 61 if (__os_is_winnt()) { 62 __os_unique_id(env, &id); 63 _sntprintf(buf, DB_MAXPATHLEN, _T("%s.del.%010u"), tpath, id); 64 if (MoveFile(tpath, buf)) 65 tpath = buf; 66 else { 67 ret = __os_get_syserr(); 68 if (__os_posix_err(ret) != ENOENT) 69 __db_err(env, ret, 70 "MoveFile: rename %s to temporary file", 71 path); 72 } 73 74 /* 75 * Try removing the file using the delete-on-close flag. This 76 * plays nicer with files that are still open than DeleteFile. 77 */ 78 h = CreateFile(tpath, 0, 79 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 80 NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0); 81 if (h != INVALID_HANDLE_VALUE) { 82 (void)CloseHandle (h); 83 if (GetFileAttributes(tpath) == INVALID_FILE_ATTRIBUTES) 84 goto skipdel; 85 } 86 } 87 88 RETRY_CHK((!DeleteFile(tpath)), ret); 89 90skipdel: 91 FREE_STRING(env, orig_tpath); 92 93 /* 94 * XXX 95 * We shouldn't be testing for an errno of ENOENT here, but ENOENT 96 * signals that a file is missing, and we attempt to unlink things 97 * (such as v. 2.x environment regions, in ENV->remove) that we 98 * are expecting not to be there. Reporting errors in these cases 99 * is annoying. 100 */ 101 if (ret != 0) { 102 if ((t_ret = __os_posix_err(ret)) != ENOENT) 103 __db_syserr(env, ret, "DeleteFile: %s", path); 104 ret = t_ret; 105 } 106 107 return (ret); 108} 109