summaryrefslogtreecommitdiff
path: root/db-4.8.30/os_windows/os_unlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'db-4.8.30/os_windows/os_unlink.c')
-rw-r--r--db-4.8.30/os_windows/os_unlink.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/db-4.8.30/os_windows/os_unlink.c b/db-4.8.30/os_windows/os_unlink.c
new file mode 100644
index 0000000..7b5544c
--- /dev/null
+++ b/db-4.8.30/os_windows/os_unlink.c
@@ -0,0 +1,108 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "db_config.h"
+
+#include "db_int.h"
+
+/*
+ * __os_unlink --
+ * Remove a file.
+ */
+int
+__os_unlink(env, path, overwrite_test)
+ ENV *env;
+ const char *path;
+ int overwrite_test;
+{
+ DB_ENV *dbenv;
+ HANDLE h;
+ _TCHAR *tpath, *orig_tpath, buf[DB_MAXPATHLEN];
+ u_int32_t id;
+ int ret, t_ret;
+
+ dbenv = env == NULL ? NULL : env->dbenv;
+
+ if (dbenv != NULL &&
+ FLD_ISSET(dbenv->verbose, DB_VERB_FILEOPS | DB_VERB_FILEOPS_ALL))
+ __db_msg(env, "fileops: unlink %s", path);
+
+ /* Optionally overwrite the contents of the file to enhance security. */
+ if (dbenv != NULL && overwrite_test && F_ISSET(dbenv, DB_ENV_OVERWRITE))
+ (void)__db_file_multi_write(env, path);
+
+ TO_TSTRING(env, path, tpath, ret);
+ if (ret != 0)
+ return (ret);
+ orig_tpath = tpath;
+
+ LAST_PANIC_CHECK_BEFORE_IO(env);
+
+ /*
+ * Windows NT and its descendants allow removal of open files, but the
+ * DeleteFile Win32 system call isn't equivalent to a POSIX unlink.
+ * Firstly, it only succeeds if FILE_SHARE_DELETE is set when the file
+ * is opened. Secondly, it leaves the file in a "zombie" state, where
+ * it can't be opened again, but a new file with the same name can't be
+ * created either.
+ *
+ * Since we depend on being able to recreate files (during recovery,
+ * say), we have to first rename the file, and then delete it. It
+ * still hangs around, but with a name we don't care about. The rename
+ * will fail if the file doesn't exist, which isn't a problem, but if
+ * it fails for some other reason, we need to know about it or a
+ * subsequent open may fail for no apparent reason.
+ */
+ if (__os_is_winnt()) {
+ __os_unique_id(env, &id);
+ _sntprintf(buf, DB_MAXPATHLEN, _T("%s.del.%010u"), tpath, id);
+ if (MoveFile(tpath, buf))
+ tpath = buf;
+ else {
+ ret = __os_get_syserr();
+ if (__os_posix_err(ret) != ENOENT)
+ __db_err(env, ret,
+ "MoveFile: rename %s to temporary file",
+ path);
+ }
+
+ /*
+ * Try removing the file using the delete-on-close flag. This
+ * plays nicer with files that are still open than DeleteFile.
+ */
+ h = CreateFile(tpath, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
+ if (h != INVALID_HANDLE_VALUE) {
+ (void)CloseHandle (h);
+ if (GetFileAttributes(tpath) == INVALID_FILE_ATTRIBUTES)
+ goto skipdel;
+ }
+ }
+
+ RETRY_CHK((!DeleteFile(tpath)), ret);
+
+skipdel:
+ FREE_STRING(env, orig_tpath);
+
+ /*
+ * XXX
+ * We shouldn't be testing for an errno of ENOENT here, but ENOENT
+ * signals that a file is missing, and we attempt to unlink things
+ * (such as v. 2.x environment regions, in ENV->remove) that we
+ * are expecting not to be there. Reporting errors in these cases
+ * is annoying.
+ */
+ if (ret != 0) {
+ if ((t_ret = __os_posix_err(ret)) != ENOENT)
+ __db_syserr(env, ret, "DeleteFile: %s", path);
+ ret = t_ret;
+ }
+
+ return (ret);
+}