summaryrefslogtreecommitdiff
path: root/mysys/my_delete.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/my_delete.c')
-rw-r--r--mysys/my_delete.c166
1 files changed, 97 insertions, 69 deletions
diff --git a/mysys/my_delete.c b/mysys/my_delete.c
index 0655501aa16..c1a821e90c2 100644
--- a/mysys/my_delete.c
+++ b/mysys/my_delete.c
@@ -17,13 +17,23 @@
#include "mysys_err.h"
#include <my_sys.h>
+#ifdef _WIN32
+static int my_win_unlink(const char *name);
+#endif
+
int my_delete(const char *name, myf MyFlags)
{
int err;
DBUG_ENTER("my_delete");
DBUG_PRINT("my",("name %s MyFlags %lu", name, MyFlags));
- if ((err = unlink(name)) == -1)
+#ifdef _WIN32
+ err = my_win_unlink(name);
+#else
+ err = unlink(name);
+#endif
+
+ if(err)
{
my_errno=errno;
if (MyFlags & (MY_FAE+MY_WME))
@@ -36,90 +46,108 @@ int my_delete(const char *name, myf MyFlags)
DBUG_RETURN(err);
} /* my_delete */
-#if defined(__WIN__)
-/**
- Delete file which is possibly not closed.
- This function is intended to be used exclusively as a temporal solution
- for Win NT in case when it is needed to delete a not closed file (note
- that the file must be opened everywhere with FILE_SHARE_DELETE mode).
- Deleting not-closed files can not be supported on Win 98|ME (and because
- of that is considered harmful).
-
- The function deletes the file with its preliminary renaming. This is
- because when not-closed share-delete file is deleted it still lives on
- a disk until it will not be closed everwhere. This may conflict with an
- attempt to create a new file with the same name. The deleted file is
- renamed to <name>.<num>.deleted where <name> - the initial name of the
- file, <num> - a hexadecimal number chosen to make the temporal name to
- be unique.
+#if defined (_WIN32)
+/*
+ Delete file.
- @param the name of the being deleted file
- @param the flags instructing how to react on an error internally in
- the function
+ The function also makes best effort to minimize number of errors,
+ where another program (or thread in the current program) has the the same file
+ open.
- @note The per-thread @c my_errno holds additional info for a caller to
- decide how critical the error can be.
+ We're using 2 tricks to prevent the errors.
- @retval
- 0 ok
- @retval
- 1 error
+ 1. A usual Win32's DeleteFile() can with ERROR_SHARED_VIOLATION,
+ because the file is opened in another application (often, antivirus or backup)
+
+ We avoid the error by using CreateFile() with FILE_FLAG_DELETE_ON_CLOSE, instead
+ of DeleteFile()
+ 2. If file which is deleted (delete on close) but has not entirely gone,
+ because it is still opened by some app, an attempt to trcreate file with the
+ same name would result in yet another error. The workaround here is renaming
+ a file to unique name.
-*/
-int nt_share_delete(const char *name, myf MyFlags)
+ Symbolic link are deleted without renaming. Directories are not deleted.
+ */
+static int my_win_unlink(const char *name)
{
- char buf[MAX_PATH + 20];
- ulong cnt;
- DBUG_ENTER("nt_share_delete");
- DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
-
- for (cnt= GetTickCount(); cnt; cnt--)
+ HANDLE handle= INVALID_HANDLE_VALUE;
+ DWORD attributes;
+ DWORD last_error;
+ char unique_filename[MAX_PATH + 35];
+ unsigned long long tsc; /* time stamp counter, for unique filename*/
+
+ DBUG_ENTER("my_win_unlink");
+ attributes= GetFileAttributes(name);
+ if (attributes == INVALID_FILE_ATTRIBUTES)
{
- errno= 0;
- sprintf(buf, "%s.%08X.deleted", name, cnt);
- if (MoveFile(name, buf))
- break;
-
- if ((errno= GetLastError()) == ERROR_ALREADY_EXISTS)
- continue;
-
- /* This happened during tests with MERGE tables. */
- if (errno == ERROR_ACCESS_DENIED)
- continue;
-
- DBUG_PRINT("warning", ("Failed to rename %s to %s, errno: %d",
- name, buf, errno));
- break;
+ last_error= GetLastError();
+ DBUG_PRINT("error",("GetFileAttributes(%s) failed with %u\n", name, last_error));
+ goto error;
}
- if (errno == ERROR_FILE_NOT_FOUND)
+ if (attributes & FILE_ATTRIBUTE_DIRECTORY)
{
- my_errno= ENOENT; // marking, that `name' doesn't exist
+ DBUG_PRINT("error",("can't remove %s - it is a directory\n", name));
+ errno= EINVAL;
+ DBUG_RETURN(-1);
}
- else if (errno == 0)
+
+ if (attributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ {
+ /* Symbolic link. Delete link, the not target */
+ if (!DeleteFile(name))
+ {
+ last_error= GetLastError();
+ DBUG_PRINT("error",("DeleteFile(%s) failed with %u\n", name,last_error));
+ goto error;
+ }
+ DBUG_RETURN(0);
+ }
+
+ handle= CreateFile(name, DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ if (handle != INVALID_HANDLE_VALUE)
{
- if (DeleteFile(buf))
- DBUG_RETURN(0);
/*
- The below is more complicated than necessary. For some reason, the
- assignment to my_errno clears the error number, which is retrieved
- by GetLastError() (VC2005EE). Assigning to errno first, allows to
- retrieve the correct value.
+ We opened file without sharing flags (exclusive), noone else has this file
+ opened, thus it is save to close handle to remove it. No renaming is
+ necessary.
*/
- errno= GetLastError();
- if (errno == 0)
- my_errno= ENOENT; // marking, that `buf' doesn't exist
- else
- my_errno= errno;
+ CloseHandle(handle);
+ DBUG_RETURN(0);
+ }
+
+ /*
+ Can't open file exclusively, hence the file must be already opened by
+ someone else. Open it for delete (with all FILE_SHARE flags set),
+ rename to unique name, close.
+ */
+ handle= CreateFile(name, DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ last_error= GetLastError();
+ DBUG_PRINT("error",
+ ("CreateFile(%s) with FILE_FLAG_DELETE_ON_CLOSE failed with %u\n",
+ name,last_error));
+ goto error;
}
- else
- my_errno= errno;
- if (MyFlags & (MY_FAE+MY_WME))
- my_error(EE_DELETE, MYF(ME_BELL + ME_WAITTANG + (MyFlags & ME_NOINPUT)),
- name, my_errno);
+ tsc= __rdtsc();
+ my_snprintf(unique_filename,sizeof(unique_filename),"%s.%llx.deleted",
+ name, tsc);
+ if (!MoveFile(name, unique_filename))
+ {
+ DBUG_PRINT("warning", ("moving %s to unique filename failed, error %u\n",
+ name,GetLastError()));
+ }
+
+ CloseHandle(handle);
+ DBUG_RETURN(0);
+
+error:
+ my_osmaperr(last_error);
DBUG_RETURN(-1);
}
-#endif
+#endif \ No newline at end of file