LCOV - code coverage report
Current view: top level - common/utils - mutils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 43 90.7 %
Date: 2024-04-25 20:03:45 Functions: 2 2 100.0 %

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

Generated by: LCOV version 1.14