xapian-core  2.0.0
posixy_wrapper.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2007 Lemur Consulting Ltd
5  * Copyright (C) 2007,2012,2018,2023,2025 Olly Betts
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include <cerrno>
25 
26 #ifdef __CYGWIN__
27 # include "posixy_wrapper.h"
28 
29 # include "filetests.h"
30 
31 int
32 posixy_unlink(const char * filename)
33 {
34  // On Cygwin we seem to inexplicably get ECHILD from unlink() sometimes.
35  // The path doesn't actually exists after the call when we get ECHILD, but
36  // the correct return value depends on whether it existed before so we
37  // need to check here as well.
38  if (!path_exists(filename)) {
39  errno = ENOENT;
40  return -1;
41  }
42 
43  int r = unlink(filename);
44  if (r < 0) {
45  int unlink_errno = errno;
46  if (unlink_errno == ECHILD && !path_exists(filename)) {
47  errno = 0;
48  return 0;
49  }
50 
51  errno = unlink_errno;
52  }
53  return r;
54 }
55 
56 #elif defined __WIN32__
57 
58 #include "posixy_wrapper.h"
59 
60 #include <io.h>
61 
62 #include "safefcntl.h"
63 #include "safewindows.h"
64 
65 int
66 posixy_set_errno_from_getlasterror()
67 {
68  int e;
69  unsigned long winerr = GetLastError();
70  switch (winerr) {
71  case ERROR_FILENAME_EXCED_RANGE:
72  case ERROR_FILE_NOT_FOUND:
73  case ERROR_PATH_NOT_FOUND:
74  case ERROR_INVALID_DRIVE:
75  case ERROR_NO_MORE_FILES:
76  case ERROR_BAD_NETPATH:
77  case ERROR_BAD_NET_NAME:
78  case ERROR_BAD_PATHNAME:
79  e = ENOENT;
80  break;
81  case ERROR_ARENA_TRASHED:
82  case ERROR_NOT_ENOUGH_MEMORY:
83  case ERROR_INVALID_BLOCK:
84  case ERROR_NOT_ENOUGH_QUOTA:
85  e = ENOMEM;
86  break;
87  case ERROR_LOCK_VIOLATION:
88  case ERROR_LOCK_FAILED:
89  case ERROR_SEEK_ON_DEVICE:
90  case ERROR_NETWORK_ACCESS_DENIED:
91  case ERROR_NOT_LOCKED:
92  case ERROR_ACCESS_DENIED:
93  case ERROR_CANNOT_MAKE:
94  case ERROR_FAIL_I24:
95  case ERROR_DRIVE_LOCKED:
96  case ERROR_CURRENT_DIRECTORY:
97  e = EACCES;
98  break;
99  case ERROR_INVALID_FUNCTION:
100  case ERROR_INVALID_ACCESS:
101  case ERROR_NEGATIVE_SEEK:
102  case ERROR_INVALID_DATA:
103  case ERROR_INVALID_PARAMETER:
104  e = EINVAL;
105  break;
106  case ERROR_NO_PROC_SLOTS:
107  case ERROR_NESTING_NOT_ALLOWED:
108  case ERROR_MAX_THRDS_REACHED:
109  e = EAGAIN;
110  break;
111  case ERROR_INVALID_HANDLE:
112  case ERROR_INVALID_TARGET_HANDLE:
113  case ERROR_DIRECT_ACCESS_HANDLE:
114  e = EBADF;
115  break;
116  case ERROR_ALREADY_EXISTS:
117  case ERROR_FILE_EXISTS:
118  e = EEXIST;
119  break;
120  case ERROR_BROKEN_PIPE:
121  e = EPIPE;
122  break;
123  case ERROR_DISK_FULL:
124  e = ENOSPC;
125  break;
126  case ERROR_TOO_MANY_OPEN_FILES:
127  e = EMFILE;
128  break;
129  case ERROR_WAIT_NO_CHILDREN:
130  case ERROR_CHILD_NOT_COMPLETE:
131  e = ECHILD;
132  break;
133  case ERROR_DIR_NOT_EMPTY:
134  e = ENOTEMPTY;
135  break;
136  case ERROR_BAD_ENVIRONMENT:
137  e = E2BIG;
138  break;
139  case ERROR_BAD_FORMAT:
140  e = ENOEXEC;
141  break;
142  case ERROR_NOT_SAME_DEVICE:
143  e = EXDEV;
144  break;
145  default:
146  if (winerr >= ERROR_WRITE_PROTECT && winerr <= ERROR_SHARING_BUFFER_EXCEEDED)
147  e = EACCES;
148  else if (winerr >= ERROR_INVALID_STARTING_CODESEG && winerr <= ERROR_INFLOOP_IN_RELOC_CHAIN)
149  e = ENOEXEC;
150  else
151  e = EINVAL;
152  break;
153  }
154  errno = e;
155  return -1;
156 }
157 
158 int
159 posixy_unlink(const char * filename)
160 {
161  /* We must use DeleteFile as this can delete files that are open. */
162  if (DeleteFile(filename) != 0) {
163  return 0;
164  }
165 
166  return posixy_set_errno_from_getlasterror();
167 }
168 
169 int
170 posixy_open(const char *filename, int flags)
171 {
172  /* Translate POSIX read mode to Windows access mode */
173  DWORD dwDesiredAccess = GENERIC_READ;
174  switch (flags & (O_RDONLY | O_RDWR | O_WRONLY)) {
175  case O_RDONLY:
176  dwDesiredAccess = GENERIC_READ;
177  break;
178  case O_RDWR:
179  dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
180  break;
181  case O_WRONLY:
182  dwDesiredAccess = GENERIC_WRITE;
183  break;
184  }
185  /* Subsequent operations may open this file to read, write or delete it */
186  DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
187 
188  /* Translate POSIX creation mode to Windows creation mode */
189  DWORD dwCreationDisposition = OPEN_EXISTING;
190  switch (flags & (O_CREAT | O_TRUNC | O_EXCL)) {
191  case O_EXCL:
192  dwCreationDisposition = OPEN_EXISTING;
193  break;
194 
195  case O_CREAT:
196  dwCreationDisposition = OPEN_ALWAYS;
197  break;
198 
199  case O_CREAT | O_TRUNC:
200  dwCreationDisposition = CREATE_ALWAYS;
201  break;
202 
203  case O_CREAT | O_EXCL:
204  case O_CREAT | O_TRUNC | O_EXCL:
205  dwCreationDisposition = CREATE_NEW;
206  break;
207 
208  case O_TRUNC:
209  case O_TRUNC | O_EXCL:
210  dwCreationDisposition = TRUNCATE_EXISTING;
211  break;
212  }
213 
214  HANDLE handleWin =
215  CreateFile(filename,
216  dwDesiredAccess,
217  dwShareMode,
218  NULL,
219  dwCreationDisposition,
220  FILE_ATTRIBUTE_NORMAL,
221  NULL);
222  if (handleWin == INVALID_HANDLE_VALUE) {
223  return posixy_set_errno_from_getlasterror();
224  }
225 
226  /* Return a standard file descriptor. */
227  return _open_osfhandle(intptr_t(handleWin), flags|O_BINARY);
228 }
229 
230 int
231 posixy_rename(const char *from, const char *to)
232 {
233  if (MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) != 0) {
234  return 0;
235  }
236 
237  return posixy_set_errno_from_getlasterror();
238 }
239 
240 #endif // __WIN32__
Utility functions for testing files.
bool path_exists(const char *path)
Test if a path exists.
Definition: filetests.h:167
Provides wrappers with POSIXy semantics.
#define posixy_open
#define posixy_rename(F, T)
#define posixy_unlink(F)
include <fcntl.h>, but working around broken platforms.
#define O_BINARY
Definition: safefcntl.h:80
include <windows.h> without all the bloat and damage.