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

Generated by: LCOV version 1.14