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-11-15 19:37: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             : #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             : 
     462             :         if (mode == F_ULOCK) {
     463             :                 EnterCriticalSection(&cs);
     464             :                 for (fpp = &lockedfiles; (fp = *fpp) != NULL; fpp = &fp->next) {
     465             :                         if (wcscmp(fp->wfilename, wfilename) == 0) {
     466             :                                 *fpp = fp->next;
     467             :                                 LeaveCriticalSection(&cs);
     468             :                                 free(fp->wfilename);
     469             :                                 fd = fp->fildes;
     470             :                                 fh = (HANDLE) _get_osfhandle(fd);
     471             :                                 free(fp);
     472             :                                 ret = UnlockFileEx(fh, 0, 10, 0, &ov);
     473             :                                 free(wfilename);
     474             :                                 return ret ? 0 : -1;
     475             :                         }
     476             :                 }
     477             :                 LeaveCriticalSection(&cs);
     478             :                 /* didn't find the locked file, try opening the file
     479             :                  * directly */
     480             :                 fh = CreateFileW(wfilename,
     481             :                                 GENERIC_READ | GENERIC_WRITE, 0,
     482             :                                 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, NULL);
     483             :                 free(wfilename);
     484             :                 if (fh == INVALID_HANDLE_VALUE)
     485             :                         return -2;
     486             :                 ret = UnlockFileEx(fh, 0, 10, 0, &ov);
     487             :                 CloseHandle(fh);
     488             :                 return 0;
     489             :         }
     490             : 
     491             :         if (_wsopen_s(&fd, wfilename, _O_CREAT | _O_RDWR | _O_TEXT, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0) {
     492             :                 free(wfilename);
     493             :                 return -2;
     494             :         }
     495             :         fh = (HANDLE) _get_osfhandle(fd);
     496             :         if (fh == INVALID_HANDLE_VALUE) {
     497             :                 close(fd);
     498             :                 free(wfilename);
     499             :                 return -2;
     500             :         }
     501             : 
     502             :         if (mode == F_TLOCK) {
     503             :                 ret = LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 10, 0, &ov);
     504             :         } else if (mode == F_LOCK) {
     505             :                 ret = LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, 10, 0, &ov);
     506             :         } else if (mode == F_TEST) {
     507             :                 ret = LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 10, 0, &ov);
     508             :                 if (ret != 0) {
     509             :                         UnlockFileEx(fh, 0, 10, 0, &ov);
     510             :                         close(fd);
     511             :                         free(wfilename);
     512             :                         return 0;
     513             :                 }
     514             :         } else {
     515             :                 close(fd);
     516             :                 errno = EINVAL;
     517             :                 free(wfilename);
     518             :                 return -2;
     519             :         }
     520             :         if (ret != 0) {
     521             :                 if ((fp = malloc(sizeof(*fp))) != NULL) {
     522             :                         fp->wfilename = wfilename;
     523             :                         fp->fildes = fd;
     524             :                         EnterCriticalSection(&cs);
     525             :                         fp->next = lockedfiles;
     526             :                         lockedfiles = fp;
     527             :                         LeaveCriticalSection(&cs);
     528             :                 } else {
     529             :                         free(wfilename);
     530             :                 }
     531             :                 return fd;
     532             :         } else {
     533             :                 close(fd);
     534             :                 free(wfilename);
     535             :                 return -1;
     536             :         }
     537             : }
     538             : 
     539             : FILE *
     540             : MT_fopen(const char *filename, const char *mode)
     541             : {
     542             :         wchar_t *wfilename, *wmode;
     543             :         wfilename = utf8towchar(filename);
     544             :         wmode = utf8towchar(mode);
     545             :         FILE *f = NULL;
     546             :         if (wfilename != NULL && wmode != NULL && (f = _wfopen(wfilename, wmode)) != NULL && strchr(mode, 'w') != NULL)
     547             :                 SetFileAttributesW(wfilename, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
     548             :         free(wfilename);
     549             :         free(wmode);
     550             :         return f;
     551             : }
     552             : 
     553             : int
     554             : MT_open(const char *filename, int flags)
     555             : {
     556             :         wchar_t *wfilename = utf8towchar(filename);
     557             :         if (wfilename == NULL)
     558             :                 return -1;
     559             :         int fd;
     560             :         if (_wsopen_s(&fd, wfilename, flags, _SH_DENYNO, _S_IREAD | _S_IWRITE) != 0)
     561             :                 fd = -1;
     562             :         else if (flags & O_CREAT)
     563             :                 SetFileAttributesW(wfilename, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
     564             :         free(wfilename);
     565             :         return fd;
     566             : }
     567             : 
     568             : int
     569             : MT_stat(const char *pathname, struct _stat64 *st)
     570             : {
     571             :         wchar_t *wpathname = utf8towchar(pathname);
     572             :         int ret;
     573             :         if (wpathname == NULL)
     574             :                 return -1;
     575             : 
     576             :         ret = _wstat64(wpathname, st);
     577             :         free(wpathname);
     578             :         return ret;
     579             : }
     580             : 
     581             : #define RETRIES 10
     582             : #define SLEEPTIME 20
     583             : 
     584             : int
     585             : MT_rmdir(const char *pathname)
     586             : {
     587             :         wchar_t *wpathname = utf8towchar(pathname);
     588             :         int ret;
     589             :         if (wpathname == NULL)
     590             :                 return -1;
     591             : 
     592             :         for (int i = 0; i < RETRIES; i++) {
     593             :                 ret = _wrmdir(wpathname);
     594             :                 if (ret == 0 || errno == ENOENT)
     595             :                         break;
     596             :                 /* it could be the <expletive deleted> indexing
     597             :                  * service which prevents us from doing what we have a
     598             :                  * right to do, so try again (once) */
     599             : //              fprintf(stderr, "#Retry rmdir %s\n", pathname);
     600             :                 Sleep(SLEEPTIME);       /* wait a little */
     601             :         }
     602             :         free(wpathname);
     603             :         return ret;
     604             : }
     605             : 
     606             : static inline int
     607             : WMT_remove(const wchar_t *wpathname)
     608             : {
     609             :         int ret;
     610             : 
     611             :         SetFileAttributesW(wpathname, FILE_ATTRIBUTE_NORMAL);
     612             :         for (int i = 0; i < RETRIES; i++) {
     613             :                 ret = _wunlink(wpathname);
     614             :                 if (ret == 0 || errno == ENOENT)
     615             :                         break;
     616             :                 /* it could be the <expletive deleted> indexing
     617             :                  * service which prevents us from doing what we have a
     618             :                  * right to do, so try again (once) */
     619             : //              fprintf(stderr, "#Retry unlink %ls\n", wpathname);
     620             :                 Sleep(SLEEPTIME);       /* wait a little */
     621             :         }
     622             :         return ret;
     623             : }
     624             : 
     625             : int
     626             : MT_remove(const char *pathname)
     627             : {
     628             :         wchar_t *wpathname = utf8towchar(pathname);
     629             :         int ret;
     630             :         if (wpathname == NULL)
     631             :                 return -1;
     632             : 
     633             :         ret = WMT_remove(wpathname);
     634             :         free(wpathname);
     635             :         return ret;
     636             : }
     637             : 
     638             : int
     639             : MT_rename(const char *old, const char *dst)
     640             : {
     641             :         int ret = -1;
     642             :         wchar_t *wold, *wdst;
     643             :         wold = utf8towchar(old);
     644             :         wdst = utf8towchar(dst);
     645             : 
     646             :         if (wold && wdst) {
     647             :                 for (int i = 0; i < RETRIES; i++) {
     648             :                         ret = _wrename(wold, wdst);
     649             :                         if (ret < 0 && errno == EEXIST) {
     650             :                                 if ((ret = WMT_remove(wdst)) < 0 &&
     651             :                                     errno != ENOENT)
     652             :                                         break;
     653             :                                 ret = _wrename(wold, wdst);
     654             :                         }
     655             :                         if (ret == 0 || errno == ENOENT)
     656             :                                 break;
     657             :                         /* it could be the <expletive deleted> indexing
     658             :                          * service which prevents us from doing what we have a
     659             :                          * right to do, so try again (once) */
     660             : //                      fprintf(stderr, "#Retry rename %s %s\n", old, dst);
     661             :                         Sleep(SLEEPTIME);       /* wait a little */
     662             :                 }
     663             :         }
     664             :         free(wold);
     665             :         free(wdst);
     666             :         return ret;
     667             : }
     668             : 
     669             : int
     670             : MT_mkdir(const char *pathname)
     671             : {
     672             :         wchar_t *wpathname = utf8towchar(pathname);
     673             :         if (wpathname == NULL)
     674             :                 return -1;
     675             :         int ret = _wmkdir(wpathname);
     676             :         if (ret == 0)
     677             :                 SetFileAttributesW(wpathname, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
     678             :         free(wpathname);
     679             :         return ret;
     680             : }
     681             : 
     682             : char *
     683             : MT_getcwd(char *buffer, size_t size)
     684             : {
     685             :         wchar_t *wcwd = _wgetcwd(NULL, 0);
     686             :         if (wcwd == NULL)
     687             :                 return NULL;
     688             :         char *cwd = wchartoutf8(wcwd);
     689             :         free(wcwd);
     690             :         if (cwd == NULL)
     691             :                 return NULL;
     692             :         size_t len = strcpy_len(buffer, cwd, size);
     693             :         free(cwd);
     694             :         return len < size ? buffer : NULL;
     695             : }
     696             : 
     697             : int
     698             : MT_access(const char *pathname, int mode)
     699             : {
     700             :         wchar_t *wpathname = utf8towchar(pathname);
     701             :         if (wpathname == NULL)
     702             :                 return -1;
     703             :         int ret = _waccess(wpathname, mode);
     704             :         free(wpathname);
     705             :         return ret;
     706             : }
     707             : 
     708             : #else
     709             : 
     710             : #if defined(HAVE_LOCKF) && defined(__MACH__)
     711             : /* lockf() seems to be there, but I didn't find any header file that
     712             :    declares the prototype ... */
     713             : extern int lockf(int fd, int cmd, off_t len);
     714             : #endif
     715             : 
     716             : #ifndef HAVE_LOCKF
     717             : /* Cygwin implementation: struct flock is there, but lockf() is
     718             :    missing.
     719             :  */
     720             : static int
     721             : lockf(int fd, int cmd, off_t len)
     722             : {
     723             :         struct flock l;
     724             : 
     725             :         if (cmd == F_LOCK || cmd == F_TLOCK)
     726             :                 l.l_type = F_WRLCK;
     727             :         else if (cmd == F_ULOCK)
     728             :                 l.l_type = F_UNLCK;
     729             :         l.l_whence = SEEK_CUR;
     730             :         l.l_start = 0;
     731             :         l.l_len = len;
     732             :         return fcntl(fd, cmd == F_TLOCK ? F_SETLKW : F_SETLK, &l);
     733             : }
     734             : #endif
     735             : 
     736             : #include <pthread.h>
     737             : 
     738             : #ifndef O_TEXT
     739             : #define O_TEXT 0
     740             : #endif
     741             : /* returns -1 when locking failed,
     742             :  * returns -2 when the lock file could not be opened/created
     743             :  * returns 0 when mode is F_TEST and the lock file was not locked
     744             :  * returns the (open) file descriptor to the file when locking
     745             :  * returns 0 when unlocking */
     746             : int
     747      111566 : MT_lockf(const char *filename, int mode)
     748             : {
     749      111566 :         static struct lockfile {
     750             :                 char *filename;
     751             :                 int fd;
     752             :                 struct lockfile *next;
     753             :         } *lockfiles = NULL;
     754      111566 :         static pthread_mutex_t cs = PTHREAD_MUTEX_INITIALIZER;
     755      111566 :         struct lockfile *fp;
     756      111566 :         int fd;
     757      111566 :         off_t seek;
     758             : 
     759      111566 :         if (mode == F_ULOCK) {
     760       55773 :                 pthread_mutex_lock(&cs);
     761       55922 :                 for (struct lockfile **fpp = &lockfiles; (fp = *fpp) != NULL; fpp = &fp->next) {
     762       55922 :                         if (strcmp(fp->filename, filename) == 0) {
     763       55773 :                                 *fpp = fp->next;
     764       55773 :                                 pthread_mutex_unlock(&cs);
     765       55773 :                                 free(fp->filename);
     766       55773 :                                 fd = fp->fd;
     767       55773 :                                 free(fp);
     768       55773 :                                 seek = lseek(fd, 0, SEEK_SET);
     769       55773 :                                 if (seek < 0)
     770             :                                         seek = 0;       /* should never happen, just for coverity */
     771       55773 :                                 int ret = lockf(fd, mode, 0);
     772       55773 :                                 (void) lseek(fd, seek, 0); /* move seek pointer back */
     773             :                                 /* do not close fd, it is closed by caller */
     774       55773 :                                 return ret;             /* 0 if unlock successful, -1 if not */
     775             :                         }
     776             :                 }
     777           0 :                 pthread_mutex_unlock(&cs);
     778             :         }
     779       55793 :         fd = open(filename, O_CREAT | O_RDWR | O_TEXT | O_CLOEXEC, MONETDB_MODE);
     780             : 
     781       55793 :         if (fd < 0)
     782             :                 return -2;
     783             : 
     784      111586 :         if ((seek = lseek(fd, 0, SEEK_SET)) >= 0 &&
     785       55793 :             lockf(fd, mode, 0) == 0) {
     786       55791 :                 if (mode == F_ULOCK || mode == F_TEST) {
     787           0 :                         close(fd);
     788           0 :                         return 0;
     789             :                 }
     790       55791 :                 if ((fp = malloc(sizeof(*fp))) != NULL) {
     791       55791 :                         if ((fp->filename = strdup(filename)) != NULL) {
     792       55791 :                                 fp->fd = fd;
     793       55791 :                                 pthread_mutex_lock(&cs);
     794       55791 :                                 fp->next = lockfiles;
     795       55791 :                                 lockfiles = fp;
     796       55791 :                                 pthread_mutex_unlock(&cs);
     797             :                         } else {
     798           0 :                                 free(fp);
     799             :                         }
     800             :                 }
     801             :                 /* do not close else we lose the lock we want */
     802       55791 :                 (void) lseek(fd, seek, SEEK_SET); /* move seek pointer back */
     803       55791 :                 return fd;
     804             :         }
     805           2 :         close(fd);
     806           2 :         return -1;
     807             : }
     808             : 
     809             : #endif
     810             : 
     811             : #ifndef PATH_MAX
     812             : # define PATH_MAX 1024
     813             : #endif
     814             : static char _bin_path[PATH_MAX];
     815             : char *
     816        1503 : get_bin_path(void)
     817             : {
     818             :         /* getting the path to the executable's binary, isn't all that
     819             :          * simple, unfortunately */
     820             : #ifdef NATIVE_WIN32
     821             :         static wchar_t wbin_path[PATH_MAX];
     822             :         if (GetModuleFileNameW(NULL, wbin_path, PATH_MAX) != 0) {
     823             :                 char *path = wchartoutf8(wbin_path);
     824             :                 size_t len = strcpy_len(_bin_path, path, PATH_MAX);
     825             :                 free(path);
     826             :                 if (len < PATH_MAX)
     827             :                         return _bin_path;
     828             :         }
     829             : #elif defined(HAVE__NSGETEXECUTABLEPATH)  /* Darwin/OSX */
     830             :         char buf[PATH_MAX];
     831             :         uint32_t size = PATH_MAX;
     832             :         if (_NSGetExecutablePath(buf, &size) == 0 &&
     833             :                         realpath(buf, _bin_path) != NULL)
     834             :                 return _bin_path;
     835             : #elif defined(BSD) && defined(KERN_PROC_PATHNAME)  /* BSD */
     836             :         int mib[4];
     837             :         size_t cb = sizeof(_bin_path);
     838             :         mib[0] = CTL_KERN;
     839             :         mib[1] = KERN_PROC;
     840             :         mib[2] = KERN_PROC_PATHNAME;
     841             :         mib[3] = -1;
     842             :         if (sysctl(mib, 4, _bin_path, &cb, NULL, 0) == 0)
     843             :                 return _bin_path;
     844             : #elif defined(HAVE_GETEXECNAME)  /* Solaris */
     845             :         char buf[PATH_MAX];
     846             :         const char *execn = getexecname();
     847             :         /* getexecname doesn't always return an absolute path, the only
     848             :          * thing it seems to do is strip leading ./ from the invocation
     849             :          * string. */
     850             :         if (*execn != '/') {
     851             :                 if (getcwd(buf, PATH_MAX) != NULL) {
     852             :                         snprintf(buf + strlen(buf), PATH_MAX - strlen(buf), "/%s", execn);
     853             :                         if (realpath(buf, _bin_path) != NULL)
     854             :                                 return(_bin_path);
     855             :                 }
     856             :         } else {
     857             :                 if (realpath(execn, _bin_path) != NULL)
     858             :                         return(_bin_path);
     859             :         }
     860             : #else  /* try Linux approach, also works on Cygwin */
     861        1503 :         ssize_t n;
     862        1503 :         if ((n = readlink("/proc/self/exe", _bin_path, sizeof(_bin_path))) != -1
     863        1503 :                 && (size_t) n < sizeof(_bin_path)) {
     864        1503 :                 _bin_path[n] = 0;
     865        1503 :                 return _bin_path;
     866             :         }
     867             : #endif
     868             :         /* could use argv[0] (passed) to deduce location based on PATH, but
     869             :          * that's a lot of work and unreliable */
     870             :         return NULL;
     871             : }

Generated by: LCOV version 1.14