Line data Source code
1 : /*
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 : *
6 : * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
7 : */
8 :
9 : #include "monetdb_config.h"
10 : #include <sys/types.h>
11 : #include <sys/stat.h>
12 : #include <fcntl.h>
13 : #include <unistd.h>
14 : #include <string.h>
15 : #include "mutils.h"
16 : #include "mstring.h"
17 :
18 : #ifdef HAVE_MACH_O_DYLD_H
19 : # include <mach-o/dyld.h> /* _NSGetExecutablePath on OSX >=10.5 */
20 : #endif
21 :
22 : #include <limits.h> /* PATH_MAX on Solaris */
23 :
24 : #ifdef HAVE_SYS_PARAM_H
25 : # include <sys/param.h> /* realpath on OSX */
26 : #endif
27 :
28 : #ifdef BSD /* BSD macro is defined in sys/param.h */
29 : # include <sys/sysctl.h> /* KERN_PROC_PATHNAME on BSD */
30 : #endif
31 :
32 : #ifndef O_CLOEXEC
33 : #define O_CLOEXEC 0
34 : #endif
35 :
36 : #ifdef NATIVE_WIN32
37 :
38 : #include <windows.h>
39 : #include <wchar.h>
40 :
41 : /* Some definitions that we need to compile on Windows.
42 : * Note that Windows only runs on little endian architectures. */
43 : #define BIG_ENDIAN 4321
44 : #define LITTLE_ENDIAN 1234
45 : #define BYTE_ORDER LITTLE_ENDIAN
46 :
47 : wchar_t *
48 : utf8towchar(const char *src)
49 : {
50 : wchar_t *dest;
51 : size_t i = 0;
52 : size_t j = 0;
53 : uint32_t c;
54 :
55 : if (src == NULL)
56 : return NULL;
57 :
58 : /* count how many wchar_t's we need, while also checking for
59 : * correctness of the input */
60 : while (src[j]) {
61 : i++;
62 : if ((src[j+0] & 0x80) == 0) {
63 : j += 1;
64 : } else if ((src[j+0] & 0xE0) == 0xC0
65 : && (src[j+1] & 0xC0) == 0x80
66 : && (src[j+0] & 0x1E) != 0) {
67 : j += 2;
68 : } else if ((src[j+0] & 0xF0) == 0xE0
69 : && (src[j+1] & 0xC0) == 0x80
70 : && (src[j+2] & 0xC0) == 0x80
71 : && ((src[j+0] & 0x0F) != 0
72 : || (src[j+1] & 0x20) != 0)) {
73 : j += 3;
74 : } else if ((src[j+0] & 0xF8) == 0xF0
75 : && (src[j+1] & 0xC0) == 0x80
76 : && (src[j+2] & 0xC0) == 0x80
77 : && (src[j+3] & 0xC0) == 0x80) {
78 : c = (src[j+0] & 0x07) << 18
79 : | (src[j+1] & 0x3F) << 12
80 : | (src[j+2] & 0x3F) << 6
81 : | (src[j+3] & 0x3F);
82 : if (c < 0x10000
83 : || c > 0x10FFFF
84 : || (c & 0x1FF800) == 0x00D800) {
85 : return NULL;
86 : }
87 : #if SIZEOF_WCHAR_T == 2
88 : i++;
89 : #endif
90 : j += 4;
91 : } else {
92 : return NULL;
93 : }
94 : }
95 : dest = malloc((i + 1) * sizeof(wchar_t));
96 : if (dest == NULL)
97 : return NULL;
98 : /* go through the source string again, this time we can skip
99 : * the correctness tests */
100 : i = j = 0;
101 : while (src[j]) {
102 : if ((src[j+0] & 0x80) == 0) {
103 : dest[i++] = src[j+0];
104 : j += 1;
105 : } else if ((src[j+0] & 0xE0) == 0xC0) {
106 : dest[i++] = (src[j+0] & 0x1F) << 6
107 : | (src[j+1] & 0x3F);
108 : j += 2;
109 : } else if ((src[j+0] & 0xF0) == 0xE0) {
110 : dest[i++] = (src[j+0] & 0x0F) << 12
111 : | (src[j+1] & 0x3F) << 6
112 : | (src[j+2] & 0x3F);
113 : j += 3;
114 : } else if ((src[j+0] & 0xF8) == 0xF0) {
115 : c = (src[j+0] & 0x07) << 18
116 : | (src[j+1] & 0x3F) << 12
117 : | (src[j+2] & 0x3F) << 6
118 : | (src[j+3] & 0x3F);
119 : #if SIZEOF_WCHAR_T == 2
120 : dest[i++] = 0xD800 | ((c - 0x10000) >> 10);
121 : dest[i++] = 0xDE00 | (c & 0x3FF);
122 : #else
123 : dest[i++] = c;
124 : #endif
125 : j += 4;
126 : }
127 : }
128 : dest[i] = 0;
129 :
130 : /* dir manipulations fail in WIN32 if file name contains trailing
131 : * slashes; work around this */
132 : while (i > 2 && dest[i - 1] == L'\\' && dest[i - 2] != L':')
133 : dest[--i] = 0;
134 :
135 : return dest;
136 : }
137 :
138 : char *
139 : wchartoutf8(const wchar_t *ws)
140 : {
141 : size_t len = 1;
142 : for (size_t i = 0; ws[i]; i++) {
143 : if (ws[i] <= 0x7F)
144 : len += 1;
145 : else if (ws[i] <= 0x7FF)
146 : len += 2;
147 : else if (
148 : #if SIZEOF_WCHAR_T == 2
149 : (ws[i] & 0xF800) != 0xD800
150 : #else
151 : ws[i] <= 0xFFFF
152 : #endif
153 : ) {
154 : assert((ws[i] & 0xF800) != 0xD800);
155 : len += 3;
156 : } else {
157 : #if SIZEOF_WCHAR_T == 2
158 : assert((ws[i + 0] & 0xFC00) == 0xD800); /* high surrogate */
159 : assert((ws[i + 1] & 0xFC00) == 0xDC00); /* low surrogate */
160 : len += 4;
161 : i++;
162 : #else
163 : assert(ws[i] <= 0x10FFFF);
164 : len += 4;
165 : #endif
166 : }
167 : }
168 : unsigned char *us = malloc(len);
169 : if (us != NULL) {
170 : size_t j = 0;
171 : for (size_t i = 0; ws[i]; i++) {
172 : if (ws[i] <= 0x7F)
173 : us[j++] = (unsigned char) ws[i];
174 : else if (ws[i] <= 0x7FF) {
175 : us[j++] = (unsigned char) (ws[i] >> 6 | 0xC0);
176 : us[j++] = (unsigned char) ((ws[i] & 0x3F) | 0x80);
177 : } else if (
178 : #if SIZEOF_WCHAR_T == 2
179 : (ws[i] & 0xF800) != 0xD800
180 : #else
181 : ws[i] <= 0xFFFF
182 : #endif
183 : ) {
184 : us[j++] = (unsigned char) (ws[i] >> 12 | 0xE0);
185 : us[j++] = (unsigned char) (((ws[i] >> 6) & 0x3F) | 0x80);
186 : us[j++] = (unsigned char) ((ws[i] & 0x3F) | 0x80);
187 : } else {
188 : uint32_t wc;
189 : #if SIZEOF_WCHAR_T == 2
190 : wc = ((ws[i+0] & 0x03FF) + 0x40) << 10 | (ws[i+1] & 0x03FF);
191 : i++;
192 : #else
193 : wc = (uint32_t) ws[i];
194 : #endif
195 : us[j++] = (unsigned char) (wc >> 18 | 0xF0);
196 : us[j++] = (unsigned char) (((wc >> 12) & 0x3F) | 0x80);
197 : us[j++] = (unsigned char) (((wc >> 6) & 0x3F) | 0x80);
198 : us[j++] = (unsigned char) ((wc & 0x3F) | 0x80);
199 : }
200 : }
201 : us[j] = 0;
202 : }
203 : return (char *) us;
204 : }
205 :
206 : /* translate Windows error code (GetLastError()) to Unix-style error */
207 : int
208 : winerror(int e)
209 : {
210 : switch (e) {
211 : case ERROR_BAD_ENVIRONMENT:
212 : return E2BIG;
213 : case ERROR_ACCESS_DENIED:
214 : case ERROR_CANNOT_MAKE:
215 : case ERROR_CURRENT_DIRECTORY:
216 : case ERROR_DRIVE_LOCKED:
217 : case ERROR_FAIL_I24:
218 : case ERROR_LOCK_FAILED:
219 : case ERROR_LOCK_VIOLATION:
220 : case ERROR_NETWORK_ACCESS_DENIED:
221 : case ERROR_NOT_LOCKED:
222 : case ERROR_SEEK_ON_DEVICE:
223 : return EACCES;
224 : case ERROR_MAX_THRDS_REACHED:
225 : case ERROR_NESTING_NOT_ALLOWED:
226 : case ERROR_NO_PROC_SLOTS:
227 : return EAGAIN;
228 : case ERROR_DIRECT_ACCESS_HANDLE:
229 : case ERROR_INVALID_TARGET_HANDLE:
230 : return EBADF;
231 : case ERROR_CHILD_NOT_COMPLETE:
232 : case ERROR_WAIT_NO_CHILDREN:
233 : return ECHILD;
234 : case ERROR_ALREADY_EXISTS:
235 : case ERROR_FILE_EXISTS:
236 : return EEXIST;
237 : case ERROR_INVALID_ACCESS:
238 : case ERROR_INVALID_DATA:
239 : case ERROR_INVALID_FUNCTION:
240 : case ERROR_INVALID_HANDLE:
241 : case ERROR_INVALID_PARAMETER:
242 : case ERROR_NEGATIVE_SEEK:
243 : return EINVAL;
244 : case ERROR_TOO_MANY_OPEN_FILES:
245 : return EMFILE;
246 : case ERROR_BAD_NET_NAME:
247 : case ERROR_BAD_NETPATH:
248 : case ERROR_BAD_PATHNAME:
249 : case ERROR_FILE_NOT_FOUND:
250 : case ERROR_FILENAME_EXCED_RANGE:
251 : case ERROR_INVALID_DRIVE:
252 : case ERROR_NO_MORE_FILES:
253 : case ERROR_PATH_NOT_FOUND:
254 : return ENOENT;
255 : case ERROR_BAD_FORMAT:
256 : return ENOEXEC;
257 : case ERROR_ARENA_TRASHED:
258 : case ERROR_INVALID_BLOCK:
259 : case ERROR_NOT_ENOUGH_MEMORY:
260 : case ERROR_NOT_ENOUGH_QUOTA:
261 : return ENOMEM;
262 : case ERROR_DISK_FULL:
263 : return ENOSPC;
264 : case ERROR_DIR_NOT_EMPTY:
265 : return ENOTEMPTY;
266 : case ERROR_BROKEN_PIPE:
267 : return EPIPE;
268 : case ERROR_NOT_SAME_DEVICE:
269 : return EXDEV;
270 : default:
271 : return EINVAL;
272 : }
273 : }
274 :
275 : struct DIR {
276 : wchar_t *dir_name;
277 : int just_opened;
278 : HANDLE find_file_handle;
279 : void *find_file_data;
280 : struct dirent result;
281 : };
282 :
283 : DIR *
284 : opendir(const char *dirname)
285 : {
286 : DIR *result = NULL;
287 : wchar_t *mask;
288 : size_t k;
289 : DWORD e;
290 :
291 : if (dirname == NULL) {
292 : errno = EFAULT;
293 : return NULL;
294 : }
295 :
296 : result = (DIR *) malloc(sizeof(DIR));
297 : if (result == NULL) {
298 : errno = ENOMEM;
299 : return NULL;
300 : }
301 : result->find_file_data = malloc(sizeof(WIN32_FIND_DATAW));
302 : result->dir_name = utf8towchar(dirname);
303 : if (result->find_file_data == NULL || result->dir_name == NULL) {
304 : if (result->find_file_data)
305 : free(result->find_file_data);
306 : if (result->dir_name)
307 : free(result->dir_name);
308 : free(result);
309 : errno = ENOMEM;
310 : return NULL;
311 : }
312 :
313 : k = wcslen(result->dir_name);
314 : if (k && result->dir_name[k - 1] == L'\\') {
315 : result->dir_name[k - 1] = L'\0';
316 : k--;
317 : }
318 : size_t masklen = (wcslen(result->dir_name) + 3) * sizeof(wchar_t);
319 : mask = malloc(masklen);
320 : if (mask == NULL) {
321 : free(result->find_file_data);
322 : free(result->dir_name);
323 : free(result);
324 : errno = ENOMEM;
325 : return NULL;
326 : }
327 : swprintf(mask, masklen, L"%ls\\*", result->dir_name);
328 :
329 : result->find_file_handle = FindFirstFileW(mask, (LPWIN32_FIND_DATAW) result->find_file_data);
330 : if (result->find_file_handle == INVALID_HANDLE_VALUE) {
331 : e = GetLastError();
332 : free(mask);
333 : free(result->dir_name);
334 : free(result->find_file_data);
335 : free(result);
336 : SetLastError(e);
337 : errno = winerror(e);
338 : return NULL;
339 : }
340 : free(mask);
341 : result->just_opened = TRUE;
342 :
343 : return result;
344 : }
345 :
346 : static wchar_t *
347 : basename(const wchar_t *file_name)
348 : {
349 : const wchar_t *p;
350 : const wchar_t *base;
351 :
352 : if (file_name == NULL)
353 : return NULL;
354 :
355 : if (iswalpha(file_name[0]) && file_name[1] == L':')
356 : file_name += 2; /* skip over drive letter */
357 :
358 : base = NULL;
359 : for (p = file_name; *p; p++)
360 : if (*p == L'\\' || *p == L'/')
361 : base = p;
362 : if (base)
363 : return (wchar_t *) base + 1;
364 :
365 : return (wchar_t *) file_name;
366 : }
367 :
368 : struct dirent *
369 : readdir(DIR *dir)
370 : {
371 : char *base;
372 :
373 : if (dir == NULL) {
374 : errno = EFAULT;
375 : return NULL;
376 : }
377 :
378 : if (dir->just_opened)
379 : dir->just_opened = FALSE;
380 : else if (!FindNextFileW(dir->find_file_handle,
381 : (LPWIN32_FIND_DATAW) dir->find_file_data))
382 : return NULL;
383 : base = wchartoutf8(basename(((LPWIN32_FIND_DATAW) dir->find_file_data)->cFileName));
384 : if (base == NULL)
385 : return NULL;
386 : strcpy_len(dir->result.d_name, base, sizeof(dir->result.d_name));
387 : free(base);
388 : dir->result.d_namelen = (int) strlen(dir->result.d_name);
389 :
390 : return &dir->result;
391 : }
392 :
393 : void
394 : rewinddir(DIR *dir)
395 : {
396 : wchar_t *mask;
397 :
398 : if (dir == NULL) {
399 : errno = EFAULT;
400 : return;
401 : }
402 :
403 : if (!FindClose(dir->find_file_handle))
404 : fprintf(stderr, "#rewinddir(): FindClose() failed\n");
405 :
406 : size_t masklen = (wcslen(dir->dir_name) + 3) * sizeof(wchar_t);
407 : mask = malloc(masklen);
408 : if (mask == NULL) {
409 : errno = ENOMEM;
410 : dir->find_file_handle = INVALID_HANDLE_VALUE;
411 : return;
412 : }
413 : swprintf(mask, masklen, L"%ls\\*", dir->dir_name);
414 : dir->find_file_handle = FindFirstFileW(mask, (LPWIN32_FIND_DATAW) dir->find_file_data);
415 : free(mask);
416 : if (dir->find_file_handle == INVALID_HANDLE_VALUE)
417 : return;
418 : dir->just_opened = TRUE;
419 : }
420 :
421 : int
422 : closedir(DIR *dir)
423 : {
424 : if (dir == NULL) {
425 : errno = EFAULT;
426 : return -1;
427 : }
428 :
429 : if (!FindClose(dir->find_file_handle))
430 : return -1;
431 :
432 : free(dir->dir_name);
433 : free(dir->find_file_data);
434 : free(dir);
435 :
436 : return 0;
437 : }
438 :
439 : char *
440 : dirname(char *path)
441 : {
442 : char *p, *q;
443 :
444 : for (p = path, q = NULL; *p; p++)
445 : if (*p == '/' || *p == '\\')
446 : q = p;
447 : if (q == NULL)
448 : return ".";
449 : *q = '\0';
450 : return path;
451 : }
452 :
453 : /* see contract of unix MT_lockf */
454 : int
455 : MT_lockf(const char *filename, int mode)
456 : {
457 : int ret = 1, fd = -1;
458 : OVERLAPPED ov;
459 : HANDLE fh;
460 : static struct lockedfiles {
461 : struct lockedfiles *next;
462 : wchar_t *wfilename;
463 : int fildes;
464 : } *lockedfiles;
465 : struct lockedfiles **fpp, *fp;
466 : wchar_t *wfilename;
467 :
468 : if ((wfilename = utf8towchar(filename)) == NULL)
469 : return -2;
470 : ov = (OVERLAPPED) {0};
471 : #if defined(DUMMYSTRUCTNAME) && (defined(NONAMELESSUNION) || !defined(_MSC_EXTENSIONS)) /* Windows SDK v7.0 */
472 : ov.u.s.Offset = 4;
473 : ov.u.s.OffsetHigh = 0;
474 : #else
475 : ov.Offset = 4;
476 : ov.OffsetHigh = 0;
477 : #endif
478 :
479 : if (mode == F_ULOCK) {
480 : for (fpp = &lockedfiles; (fp = *fpp) != NULL; fpp = &fp->next) {
481 : if (wcscmp(fp->wfilename, wfilename) == 0) {
482 : free(fp->wfilename);
483 : fd = fp->fildes;
484 : fh = (HANDLE) _get_osfhandle(fd);
485 : fp = *fpp;
486 : *fpp = fp->next;
487 : free(fp);
488 : ret = UnlockFileEx(fh, 0, 1, 0, &ov);
489 : free(wfilename);
490 : return ret ? 0 : -1;
491 : }
492 : }
493 : /* didn't find the locked file, try opening the file
494 : * directly */
495 : fh = CreateFileW(wfilename,
496 : GENERIC_READ | GENERIC_WRITE, 0,
497 : NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
498 : free(wfilename);
499 : if (fh == INVALID_HANDLE_VALUE)
500 : return -2;
501 : ret = UnlockFileEx(fh, 0, 1, 0, &ov);
502 : CloseHandle(fh);
503 : return 0;
504 : }
505 :
506 : if (_wsopen_s(&fd, wfilename, _O_CREAT | _O_RDWR | _O_TEXT, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0) {
507 : free(wfilename);
508 : return -2;
509 : }
510 : fh = (HANDLE) _get_osfhandle(fd);
511 : if (fh == INVALID_HANDLE_VALUE) {
512 : close(fd);
513 : free(wfilename);
514 : return -2;
515 : }
516 :
517 : if (mode == F_TLOCK) {
518 : ret = LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ov);
519 : } else if (mode == F_LOCK) {
520 : ret = LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ov);
521 : } else if (mode == F_TEST) {
522 : ret = LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ov);
523 : if (ret != 0) {
524 : UnlockFileEx(fh, 0, 1, 0, &ov);
525 : close(fd);
526 : free(wfilename);
527 : return 0;
528 : }
529 : } else {
530 : close(fd);
531 : errno = EINVAL;
532 : free(wfilename);
533 : return -2;
534 : }
535 : if (ret != 0) {
536 : if ((fp = malloc(sizeof(*fp))) != NULL) {
537 : fp->wfilename = wfilename;
538 : fp->fildes = fd;
539 : fp->next = lockedfiles;
540 : lockedfiles = fp;
541 : } else {
542 : free(wfilename);
543 : }
544 : return fd;
545 : } else {
546 : close(fd);
547 : free(wfilename);
548 : return -1;
549 : }
550 : }
551 :
552 : FILE *
553 : MT_fopen(const char *filename, const char *mode)
554 : {
555 : wchar_t *wfilename, *wmode;
556 : wfilename = utf8towchar(filename);
557 : wmode = utf8towchar(mode);
558 : FILE *f = NULL;
559 : if (wfilename != NULL && wmode != NULL)
560 : f = _wfopen(wfilename, wmode);
561 : free(wfilename);
562 : free(wmode);
563 : return f;
564 : }
565 :
566 : int
567 : MT_open(const char *filename, int flags)
568 : {
569 : wchar_t *wfilename = utf8towchar(filename);
570 : if (wfilename == NULL)
571 : return -1;
572 : int fd;
573 : if (_wsopen_s(&fd, wfilename, flags, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0)
574 : fd = -1;
575 : free(wfilename);
576 : return fd;
577 : }
578 :
579 : int
580 : MT_stat(const char *pathname, struct _stat64 *st)
581 : {
582 : wchar_t *wpathname = utf8towchar(pathname);
583 : int ret;
584 : if (wpathname == NULL)
585 : return -1;
586 :
587 : ret = _wstat64(wpathname, st);
588 : free(wpathname);
589 : return ret;
590 : }
591 :
592 : int
593 : MT_rmdir(const char *pathname)
594 : {
595 : wchar_t *wpathname = utf8towchar(pathname);
596 : int ret;
597 : if (wpathname == NULL)
598 : return -1;
599 :
600 : ret = _wrmdir(wpathname);
601 : #if 0
602 : if (ret < 0 && errno != ENOENT) {
603 : /* it could be the <expletive deleted> indexing
604 : * service which prevents us from doing what we have a
605 : * right to do, so try again (once) */
606 : TRC_DEBUG(IO_, "Retry rmdir %s\n", pathname);
607 : MT_sleep_ms(100); /* wait a little */
608 : ret = _wrmdir(wpathname);
609 : }
610 : #endif
611 : free(wpathname);
612 : return ret;
613 : }
614 :
615 : int
616 : MT_remove(const char *pathname)
617 : {
618 : wchar_t *wpathname = utf8towchar(pathname);
619 : int ret;
620 : if (wpathname == NULL)
621 : return -1;
622 :
623 : SetFileAttributesW(wpathname, FILE_ATTRIBUTE_NORMAL);
624 : ret = _wunlink(wpathname);
625 : #if 0
626 : if (ret < 0 && errno != ENOENT) {
627 : /* it could be the <expletive deleted> indexing
628 : * service which prevents us from doing what we have a
629 : * right to do, so try again (once) */
630 : TRC_DEBUG(IO_, "Retry unlink %s\n", pathname);
631 : MT_sleep_ms(100); /* wait a little */
632 : ret = _wunlink(wpathname);
633 : }
634 : #endif
635 : free(wpathname);
636 : return ret;
637 : }
638 :
639 : int
640 : MT_rename(const char *old, const char *dst)
641 : {
642 : int ret = -1;
643 : wchar_t *wold, *wdst;
644 : wold = utf8towchar(old);
645 : wdst = utf8towchar(dst);
646 :
647 : if (wold && wdst) {
648 : ret = _wrename(wold, wdst);
649 : if (ret < 0 && errno == EEXIST) {
650 : (void) _wunlink(wdst);
651 : ret = _wrename(wold, wdst);
652 : }
653 : #if 0
654 : if (ret < 0 && errno != ENOENT) {
655 : /* it could be the <expletive deleted> indexing
656 : * service which prevents us from doing what we have a
657 : * right to do, so try again (once) */
658 : TRC_DEBUG(IO_, "Retry rename %s %s\n", old, dst);
659 : MT_sleep_ms(100); /* wait a little */
660 : ret = _wrename(wold, wdst);
661 : }
662 : #endif
663 : }
664 : free(wold);
665 : free(wdst);
666 : return ret;
667 : }
668 :
669 : int
670 : MT_mkdir(const char *pathname)
671 : {
672 : wchar_t *wpathname = utf8towchar(pathname);
673 : if (wpathname == NULL)
674 : return -1;
675 : int ret = _wmkdir(wpathname);
676 : free(wpathname);
677 : return ret;
678 : }
679 :
680 : char *
681 : MT_getcwd(char *buffer, size_t size)
682 : {
683 : wchar_t *wcwd = _wgetcwd(NULL, 0);
684 : if (wcwd == NULL)
685 : return NULL;
686 : char *cwd = wchartoutf8(wcwd);
687 : free(wcwd);
688 : if (cwd == NULL)
689 : return NULL;
690 : size_t len = strcpy_len(buffer, cwd, size);
691 : free(cwd);
692 : return len < size ? buffer : NULL;
693 : }
694 :
695 : int
696 : MT_access(const char *pathname, int mode)
697 : {
698 : wchar_t *wpathname = utf8towchar(pathname);
699 : if (wpathname == NULL)
700 : return -1;
701 : int ret = _waccess(wpathname, mode);
702 : free(wpathname);
703 : return ret;
704 : }
705 :
706 : #else
707 :
708 : #if defined(HAVE_LOCKF) && defined(__MACH__)
709 : /* lockf() seems to be there, but I didn't find any header file that
710 : declares the prototype ... */
711 : extern int lockf(int fd, int cmd, off_t len);
712 : #endif
713 :
714 : #ifndef HAVE_LOCKF
715 : /* Cygwin implementation: struct flock is there, but lockf() is
716 : missing.
717 : */
718 : static int
719 : lockf(int fd, int cmd, off_t len)
720 : {
721 : struct flock l;
722 :
723 : if (cmd == F_LOCK || cmd == F_TLOCK)
724 : l.l_type = F_WRLCK;
725 : else if (cmd == F_ULOCK)
726 : l.l_type = F_UNLCK;
727 : l.l_whence = SEEK_CUR;
728 : l.l_start = 0;
729 : l.l_len = len;
730 : return fcntl(fd, cmd == F_TLOCK ? F_SETLKW : F_SETLK, &l);
731 : }
732 : #endif
733 :
734 : #ifndef O_TEXT
735 : #define O_TEXT 0
736 : #endif
737 : /* returns -1 when locking failed,
738 : * returns -2 when the lock file could not be opened/created
739 : * returns 0 when mode is F_TEST and the lock file was not locked
740 : * returns the (open) file descriptor to the file when locking
741 : * returns 0 when unlocking */
742 : int
743 812 : MT_lockf(const char *filename, int mode)
744 : {
745 812 : int fd = open(filename, O_CREAT | O_RDWR | O_TEXT | O_CLOEXEC, MONETDB_MODE);
746 :
747 812 : if (fd < 0)
748 : return -2;
749 :
750 1624 : if (lseek(fd, 4, SEEK_SET) >= 0 &&
751 812 : lockf(fd, mode, 1) == 0) {
752 810 : if (mode == F_ULOCK || mode == F_TEST) {
753 404 : close(fd);
754 404 : return 0;
755 : }
756 : /* do not close else we lose the lock we want */
757 406 : (void) lseek(fd, 0, SEEK_SET); /* move seek pointer back */
758 406 : return fd;
759 : }
760 2 : close(fd);
761 2 : return -1;
762 : }
763 :
764 : #endif
765 :
766 : #ifndef PATH_MAX
767 : # define PATH_MAX 1024
768 : #endif
769 : static char _bin_path[PATH_MAX];
770 : char *
771 266 : get_bin_path(void)
772 : {
773 : /* getting the path to the executable's binary, isn't all that
774 : * simple, unfortunately */
775 : #ifdef NATIVE_WIN32
776 : static wchar_t wbin_path[PATH_MAX];
777 : if (GetModuleFileNameW(NULL, wbin_path, PATH_MAX) != 0) {
778 : char *path = wchartoutf8(wbin_path);
779 : size_t len = strcpy_len(_bin_path, path, PATH_MAX);
780 : free(path);
781 : if (len < PATH_MAX)
782 : return _bin_path;
783 : }
784 : #elif defined(HAVE__NSGETEXECUTABLEPATH) /* Darwin/OSX */
785 : char buf[PATH_MAX];
786 : uint32_t size = PATH_MAX;
787 : if (_NSGetExecutablePath(buf, &size) == 0 &&
788 : realpath(buf, _bin_path) != NULL)
789 : return _bin_path;
790 : #elif defined(BSD) && defined(KERN_PROC_PATHNAME) /* BSD */
791 : int mib[4];
792 : size_t cb = sizeof(_bin_path);
793 : mib[0] = CTL_KERN;
794 : mib[1] = KERN_PROC;
795 : mib[2] = KERN_PROC_PATHNAME;
796 : mib[3] = -1;
797 : if (sysctl(mib, 4, _bin_path, &cb, NULL, 0) == 0)
798 : return _bin_path;
799 : #elif defined(HAVE_GETEXECNAME) /* Solaris */
800 : char buf[PATH_MAX];
801 : const char *execn = getexecname();
802 : /* getexecname doesn't always return an absolute path, the only
803 : * thing it seems to do is strip leading ./ from the invocation
804 : * string. */
805 : if (*execn != '/') {
806 : if (getcwd(buf, PATH_MAX) != NULL) {
807 : snprintf(buf + strlen(buf), PATH_MAX - strlen(buf), "/%s", execn);
808 : if (realpath(buf, _bin_path) != NULL)
809 : return(_bin_path);
810 : }
811 : } else {
812 : if (realpath(execn, _bin_path) != NULL)
813 : return(_bin_path);
814 : }
815 : #else /* try Linux approach, also works on Cygwin */
816 266 : if (readlink("/proc/self/exe",
817 : _bin_path, sizeof(_bin_path)) != -1)
818 266 : return _bin_path;
819 : #endif
820 : /* could use argv[0] (passed) to deduce location based on PATH, but
821 : * that's a lot of work and unreliable */
822 : return NULL;
823 : }
|