LCOV - code coverage report
Current view: top level - common/utils - mutils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 15 15 100.0 %
Date: 2021-10-27 03:06:47 Functions: 2 2 100.0 %

          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             : }

Generated by: LCOV version 1.14