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

Generated by: LCOV version 1.14