1/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "mysys_priv.h"
17#include "mysys_err.h"
18#include <my_sys.h>
19
20#ifdef _WIN32
21static int my_win_unlink(const char *name);
22#endif
23
24CREATE_NOSYMLINK_FUNCTION(
25 unlink_nosymlinks(const char *pathname),
26 unlinkat(dfd, filename, 0),
27 unlink(pathname)
28);
29
30int my_delete(const char *name, myf MyFlags)
31{
32 int err;
33 DBUG_ENTER("my_delete");
34 DBUG_PRINT("my",("name %s MyFlags %lu", name, MyFlags));
35
36#ifdef _WIN32
37 err = my_win_unlink(name);
38#else
39 if (MyFlags & MY_NOSYMLINKS)
40 err= unlink_nosymlinks(name);
41 else
42 err= unlink(name);
43#endif
44
45 if(err)
46 {
47 my_errno=errno;
48 if (MyFlags & (MY_FAE+MY_WME))
49 my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
50 name,errno);
51 }
52 else if ((MyFlags & MY_SYNC_DIR) &&
53 my_sync_dir_by_file(name, MyFlags))
54 err= -1;
55 DBUG_RETURN(err);
56} /* my_delete */
57
58
59#if defined (_WIN32)
60/*
61 Delete file.
62
63 The function also makes best effort to minimize number of errors,
64 where another program (or thread in the current program) has the the same file
65 open.
66
67 We're using 2 tricks to prevent the errors.
68
69 1. A usual Win32's DeleteFile() can with ERROR_SHARED_VIOLATION,
70 because the file is opened in another application (often, antivirus or backup)
71
72 We avoid the error by using CreateFile() with FILE_FLAG_DELETE_ON_CLOSE, instead
73 of DeleteFile()
74
75 2. If file which is deleted (delete on close) but has not entirely gone,
76 because it is still opened by some app, an attempt to trcreate file with the
77 same name would result in yet another error. The workaround here is renaming
78 a file to unique name.
79
80 Symbolic link are deleted without renaming. Directories are not deleted.
81 */
82static int my_win_unlink(const char *name)
83{
84 HANDLE handle= INVALID_HANDLE_VALUE;
85 DWORD attributes;
86 uint last_error;
87 char unique_filename[MAX_PATH + 35];
88 unsigned long long tsc; /* time stamp counter, for unique filename*/
89
90 DBUG_ENTER("my_win_unlink");
91 attributes= GetFileAttributes(name);
92 if (attributes == INVALID_FILE_ATTRIBUTES)
93 {
94 last_error= GetLastError();
95 DBUG_PRINT("error",("GetFileAttributes(%s) failed with %u\n", name, last_error));
96 goto error;
97 }
98
99 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
100 {
101 DBUG_PRINT("error",("can't remove %s - it is a directory\n", name));
102 errno= EINVAL;
103 DBUG_RETURN(-1);
104 }
105
106 if (attributes & FILE_ATTRIBUTE_REPARSE_POINT)
107 {
108 /* Symbolic link. Delete link, the not target */
109 if (!DeleteFile(name))
110 {
111 last_error= GetLastError();
112 DBUG_PRINT("error",("DeleteFile(%s) failed with %u\n", name,last_error));
113 goto error;
114 }
115 DBUG_RETURN(0);
116 }
117
118 handle= CreateFile(name, DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
119 if (handle != INVALID_HANDLE_VALUE)
120 {
121 /*
122 We opened file without sharing flags (exclusive), no one else has this file
123 opened, thus it is save to close handle to remove it. No renaming is
124 necessary.
125 */
126 CloseHandle(handle);
127 DBUG_RETURN(0);
128 }
129
130 /*
131 Can't open file exclusively, hence the file must be already opened by
132 someone else. Open it for delete (with all FILE_SHARE flags set),
133 rename to unique name, close.
134 */
135 handle= CreateFile(name, DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
136 NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
137 if (handle == INVALID_HANDLE_VALUE)
138 {
139 last_error= GetLastError();
140 DBUG_PRINT("error",
141 ("CreateFile(%s) with FILE_FLAG_DELETE_ON_CLOSE failed with %u\n",
142 name,last_error));
143 goto error;
144 }
145
146 tsc= __rdtsc();
147 my_snprintf(unique_filename,sizeof(unique_filename),"%s.%llx.deleted",
148 name, tsc);
149 if (!MoveFile(name, unique_filename))
150 {
151 DBUG_PRINT("warning", ("moving %s to unique filename failed, error %lu\n",
152 name,GetLastError()));
153 }
154
155 CloseHandle(handle);
156 DBUG_RETURN(0);
157
158error:
159 my_osmaperr(last_error);
160 DBUG_RETURN(-1);
161}
162#endif
163