/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*------------------------------------------------------------------------- * * Created: H5system.c * Aug 21 2006 * Quincey Koziol * * Purpose: System call wrapper implementations. * *------------------------------------------------------------------------- */ /****************/ /* Module Setup */ /****************/ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* File access */ #include "H5MMprivate.h" /* Memory management */ /****************/ /* Local Macros */ /****************/ /******************/ /* Local Typedefs */ /******************/ /********************/ /* Package Typedefs */ /********************/ /********************/ /* Local Prototypes */ /********************/ /*********************/ /* Package Variables */ /*********************/ /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* Local Variables */ /*******************/ /* Track whether tzset routine was called */ static hbool_t H5_ntzset = FALSE; /*------------------------------------------------------------------------- * Function: HDfprintf * * Purpose: Prints the optional arguments under the control of the format * string FMT to the stream STREAM. This function takes the * same format as fprintf(3c) with a few added features: * * The conversion modifier `H' refers to the size of an * `hsize_t' or `hssize_t' type. For instance, "0x%018Hx" * prints an `hsize_t' value as a hex number right justified and * zero filled in an 18-character field. * * The conversion 'a' refers to an haddr_t type. * * The conversion 't' refers to an htri_t type. * * Return: Success: Number of characters printed * * Failure: -1 * * Programmer: Robb Matzke * Thursday, April 9, 1998 * *------------------------------------------------------------------------- */ /* Disable warning for "format not a string literal" here -QAK */ /* * This pragma only needs to surround the fprintf() calls with * format_templ in the code below, but early (4.4.7, at least) gcc only * allows diagnostic pragmas to be toggled outside of functions. */ H5_GCC_DIAG_OFF("format-nonliteral") int HDfprintf(FILE *stream, const char *fmt, ...) { int n = 0, nout = 0; int fwidth, prec; int zerofill; int leftjust; int plussign; int ldspace; int prefix; char modifier[8]; int conv; char * rest, format_templ[128]; int len; const char *s; va_list ap; HDassert(stream); HDassert(fmt); HDva_start(ap, fmt); while (*fmt) { fwidth = prec = 0; zerofill = 0; leftjust = 0; plussign = 0; prefix = 0; ldspace = 0; modifier[0] = '\0'; if ('%' == fmt[0] && '%' == fmt[1]) { HDputc('%', stream); fmt += 2; nout++; } else if ('%' == fmt[0]) { s = fmt + 1; /* Flags */ while (HDstrchr("-+ #", *s)) { switch (*s) { case '-': leftjust = 1; break; case '+': plussign = 1; break; case ' ': ldspace = 1; break; case '#': prefix = 1; break; default: HDassert(0 && "Unknown format flag"); } /* end switch */ /*lint !e744 Switch statement doesn't _need_ default */ s++; } /* end while */ /* Field width */ if (HDisdigit(*s)) { zerofill = ('0' == *s); fwidth = (int)HDstrtol(s, &rest, 10); s = rest; } /* end if */ else if ('*' == *s) { fwidth = HDva_arg(ap, int); if (fwidth < 0) { leftjust = 1; fwidth = -fwidth; } s++; } /* Precision */ if ('.' == *s) { s++; if (HDisdigit(*s)) { prec = (int)HDstrtol(s, &rest, 10); s = rest; } else if ('*' == *s) { prec = HDva_arg(ap, int); s++; } if (prec < 1) prec = 1; } /* Extra type modifiers */ if (HDstrchr("zZHhlqLI", *s)) { switch (*s) { /*lint --e{506} Don't issue warnings about constant value booleans */ /*lint --e{774} Don't issue warnings boolean within 'if' always evaluates false/true */ case 'H': if (sizeof(hsize_t) < sizeof(long)) modifier[0] = '\0'; else if (sizeof(hsize_t) == sizeof(long)) { HDstrncpy(modifier, "l", sizeof(modifier)); modifier[sizeof(modifier) - 1] = '\0'; } /* end if */ else { HDstrncpy(modifier, H5_PRINTF_LL_WIDTH, sizeof(modifier)); modifier[sizeof(modifier) - 1] = '\0'; } /* end else */ break; case 'Z': case 'z': if (sizeof(size_t) < sizeof(long)) modifier[0] = '\0'; else if (sizeof(size_t) == sizeof(long)) { HDstrncpy(modifier, "l", sizeof(modifier)); modifier[sizeof(modifier) - 1] = '\0'; } /* end if */ else { HDstrncpy(modifier, H5_PRINTF_LL_WIDTH, sizeof(modifier)); modifier[sizeof(modifier) - 1] = '\0'; } /* end else */ break; default: /* Handle 'I64' modifier for Microsoft's "__int64" type */ if (*s == 'I' && *(s + 1) == '6' && *(s + 2) == '4') { modifier[0] = *s; modifier[1] = *(s + 1); modifier[2] = *(s + 2); modifier[3] = '\0'; s += 2; /* Increment over 'I6', the '4' is taken care of below */ } /* end if */ else { /* Handle 'll' for long long types */ if (*s == 'l' && *(s + 1) == 'l') { modifier[0] = *s; modifier[1] = *s; modifier[2] = '\0'; s++; /* Increment over first 'l', second is taken care of below */ } /* end if */ else { modifier[0] = *s; modifier[1] = '\0'; } /* end else */ } /* end else */ break; } s++; } /* Conversion */ conv = *s++; /* Create the format template */ len = 0; len += HDsnprintf(format_templ, (sizeof(format_templ) - (size_t)(len + 1)), "%%%s%s%s%s%s", (leftjust ? "-" : ""), (plussign ? "+" : ""), (ldspace ? " " : ""), (prefix ? "#" : ""), (zerofill ? "0" : "")); if (fwidth > 0) len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth); if (prec > 0) len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), ".%d", prec); if (*modifier) len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%s", modifier); HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%c", conv); /* Conversion */ switch (conv) { case 'd': case 'i': if (!HDstrcmp(modifier, "h")) { short x = (short)HDva_arg(ap, int); n = fprintf(stream, format_templ, x); } else if (!*modifier) { int x = HDva_arg(ap, int); n = fprintf(stream, format_templ, x); } else if (!HDstrcmp(modifier, "l")) { long x = HDva_arg(ap, long); n = fprintf(stream, format_templ, x); } else { int64_t x = HDva_arg(ap, int64_t); n = fprintf(stream, format_templ, x); } break; case 'o': case 'u': case 'x': case 'X': if (!HDstrcmp(modifier, "h")) { unsigned short x = (unsigned short)HDva_arg(ap, unsigned int); n = fprintf(stream, format_templ, x); } else if (!*modifier) { unsigned int x = HDva_arg(ap, unsigned int); n = fprintf(stream, format_templ, x); } else if (!HDstrcmp(modifier, "l")) { unsigned long x = HDva_arg(ap, unsigned long); n = fprintf(stream, format_templ, x); } else { uint64_t x = HDva_arg(ap, uint64_t); n = fprintf(stream, format_templ, x); } break; case 'f': case 'e': case 'E': case 'g': case 'G': if (!HDstrcmp(modifier, "h")) { float x = (float)HDva_arg(ap, double); n = fprintf(stream, format_templ, (double)x); } else if (!*modifier || !HDstrcmp(modifier, "l")) { double x = HDva_arg(ap, double); n = fprintf(stream, format_templ, x); } else { /* * Some compilers complain when `long double' and * `double' are the same thing. */ #if H5_SIZEOF_LONG_DOUBLE != H5_SIZEOF_DOUBLE long double x = HDva_arg(ap, long double); n = fprintf(stream, format_templ, x); #else double x = HDva_arg(ap, double); n = fprintf(stream, format_templ, x); #endif } break; case 'a': { haddr_t x = HDva_arg(ap, haddr_t); if (H5F_addr_defined(x)) { len = 0; len += HDsnprintf(format_templ, (sizeof(format_templ) - (size_t)(len + 1)), "%%%s%s%s%s%s", (leftjust ? "-" : ""), (plussign ? "+" : ""), (ldspace ? " " : ""), (prefix ? "#" : ""), (zerofill ? "0" : "")); if (fwidth > 0) len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth); /*lint --e{506} Don't issue warnings about constant value booleans */ /*lint --e{774} Don't issue warnings boolean within 'if' always evaluates false/true */ if (sizeof(x) == H5_SIZEOF_INT) { HDstrncat(format_templ, "u", (sizeof(format_templ) - (size_t)(len + 1))); len++; } /* end if */ else if (sizeof(x) == H5_SIZEOF_LONG) { HDstrncat(format_templ, "lu", (sizeof(format_templ) - (size_t)(len + 1))); len++; } /* end if */ else if (sizeof(x) == H5_SIZEOF_LONG_LONG) { HDstrncat(format_templ, H5_PRINTF_LL_WIDTH, (sizeof(format_templ) - (size_t)(len + 1))); len += (int)sizeof(H5_PRINTF_LL_WIDTH); HDstrncat(format_templ, "u", (sizeof(format_templ) - (size_t)(len + 1))); len++; } n = fprintf(stream, format_templ, x); } else { len = 0; HDstrncpy(format_templ, "%", (sizeof(format_templ) - (size_t)(len + 1))); len++; if (leftjust) { HDstrncat(format_templ, "-", (sizeof(format_templ) - (size_t)(len + 1))); len++; } /* end if */ if (fwidth) len += HDsnprintf(format_templ + len, (sizeof(format_templ) - (size_t)(len + 1)), "%d", fwidth); HDstrncat(format_templ, "s", (sizeof(format_templ) - (size_t)(len + 1))); n = fprintf(stream, format_templ, "UNDEF"); } } break; case 'c': { char x = (char)HDva_arg(ap, int); n = fprintf(stream, format_templ, x); } break; case 's': case 'p': { char *x = HDva_arg(ap, char *); n = fprintf(stream, format_templ, x); } break; case 'n': format_templ[HDstrlen(format_templ) - 1] = 'u'; n = fprintf(stream, format_templ, nout); break; case 't': { htri_t tri_var = HDva_arg(ap, htri_t); if (tri_var > 0) n = fprintf(stream, "TRUE"); else if (!tri_var) n = fprintf(stream, "FALSE"); else n = fprintf(stream, "FAIL(%d)", (int)tri_var); } break; case 'T': /* Elapsed time, in seconds */ { double seconds = HDva_arg(ap, double); char * time_string = H5_timer_get_time_string(seconds); if (time_string) { n = fprintf(stream, format_templ, time_string); HDfree(time_string); } /* end if */ else n = fprintf(stream, format_templ, "(error)"); } break; default: HDfputs(format_templ, stream); n = (int)HDstrlen(format_templ); break; } nout += n; fmt = s; } else { HDputc(*fmt, stream); fmt++; nout++; } } HDva_end(ap); return nout; } /* end HDfprintf() */ H5_GCC_DIAG_ON("format-nonliteral") /*------------------------------------------------------------------------- * Function: HDstrtoll * * Purpose: Converts the string S to an int64_t value according to the * given BASE, which must be between 2 and 36 inclusive, or be * the special value zero. * * The string must begin with an arbitrary amount of white space * (as determined by isspace(3c)) followed by a single optional * `+' or `-' sign. If BASE is zero or 16 the string may then * include a `0x' or `0X' prefix, and the number will be read in * base 16; otherwise a zero BASE is taken as 10 (decimal) * unless the next character is a `0', in which case it is taken * as 8 (octal). * * The remainder of the string is converted to an int64_t in the * obvious manner, stopping at the first character which is not * a valid digit in the given base. (In bases above 10, the * letter `A' in either upper or lower case represetns 10, `B' * represents 11, and so forth, with `Z' representing 35.) * * If REST is not null, the address of the first invalid * character in S is stored in *REST. If there were no digits * at all, the original value of S is stored in *REST. Thus, if * *S is not `\0' but **REST is `\0' on return the entire string * was valid. * * Return: Success: The result. * * Failure: If the input string does not contain any * digits then zero is returned and REST points * to the original value of S. If an overflow * or underflow occurs then the maximum or * minimum possible value is returned and the * global `errno' is set to ERANGE. If BASE is * incorrect then zero is returned. * * Programmer: Robb Matzke * Thursday, April 9, 1998 * *------------------------------------------------------------------------- */ #ifndef HDstrtoll int64_t HDstrtoll(const char *s, const char **rest, int base) { int64_t sign = 1, acc = 0; hbool_t overflow = FALSE; errno = 0; if (!s || (base && (base < 2 || base > 36))) { if (rest) *rest = s; return 0; } /* Skip white space */ while (HDisspace(*s)) s++; /* Optional minus or plus sign */ if ('+' == *s) { s++; } else if ('-' == *s) { sign = -1; s++; } /* Zero base prefix */ if (0 == base && '0' == *s && ('x' == s[1] || 'X' == s[1])) { base = 16; s += 2; } else if (0 == base && '0' == *s) { base = 8; s++; } else if (0 == base) { base = 10; } /* Digits */ while ((base <= 10 && *s >= '0' && *s < '0' + base) || (base > 10 && ((*s >= '0' && *s <= '9') || (*s >= 'a' && *s < 'a' + base - 10) || (*s >= 'A' && *s < 'A' + base - 10)))) { if (!overflow) { int64_t digit = 0; if (*s >= '0' && *s <= '9') digit = *s - '0'; else if (*s >= 'a' && *s <= 'z') digit = (*s - 'a') + 10; else digit = (*s - 'A') + 10; if (acc * base + digit < acc) { overflow = TRUE; } else { acc = acc * base + digit; } } s++; } /* Overflow */ if (overflow) { if (sign > 0) { acc = ((uint64_t)1 << (8 * sizeof(int64_t) - 1)) - 1; } else { acc = (int64_t)((uint64_t)1 << (8 * sizeof(int64_t) - 1)); } errno = ERANGE; } /* Return values */ acc *= sign; if (rest) *rest = s; return acc; } /* end HDstrtoll() */ #endif /*------------------------------------------------------------------------- * Function: HDrand/HDsrand * * Purpose: Wrapper function for rand. If rand_r exists on this system, * use it. * * Wrapper function for srand. If rand_r is available, it will keep * track of the seed locally instead of using srand() which modifies * global state and can break other programs. * * Return: Success: Random number from 0 to RAND_MAX * * Failure: Cannot fail. * * Programmer: Leon Arber * March 6, 2006. * *------------------------------------------------------------------------- */ #ifdef H5_HAVE_RAND_R static unsigned int g_seed = 42; int HDrand(void) { return rand_r(&g_seed); } void HDsrand(unsigned int seed) { g_seed = seed; } #endif /* H5_HAVE_RAND_R */ /*------------------------------------------------------------------------- * Function: Pflock * * Purpose: Wrapper function for POSIX systems where flock(2) is not * available. * * Return: Success: 0 * Failure: -1 * *------------------------------------------------------------------------- */ /* NOTE: Compile this all the time on POSIX systems, even when flock(2) is * present so that it's less likely to become dead code. */ #ifdef H5_HAVE_FCNTL int Pflock(int fd, int operation) { struct flock flk; /* Set the lock type */ if (operation & LOCK_UN) flk.l_type = F_UNLCK; else if (operation & LOCK_SH) flk.l_type = F_RDLCK; else flk.l_type = F_WRLCK; /* Set the other flock struct values */ flk.l_whence = SEEK_SET; flk.l_start = 0; flk.l_len = 0; /* to EOF */ flk.l_pid = 0; /* not used with set */ /* Lock or unlock */ if (HDfcntl(fd, F_SETLK, &flk) < 0) return -1; return 0; } /* end Pflock() */ #endif /* H5_HAVE_FCNTL */ /*------------------------------------------------------------------------- * Function: Nflock * * Purpose: Wrapper function for systems where no file locking is * available. * * Return: 0 (success) * *------------------------------------------------------------------------- */ int H5_ATTR_CONST Nflock(int H5_ATTR_UNUSED fd, int H5_ATTR_UNUSED operation) { /* just succeed */ return 0; } /* end Nflock() */ /*------------------------------------------------------------------------- * Function: H5_make_time * * Purpose: Portability routine to abstract converting a 'tm' struct into * a time_t value. * * Note: This is a little problematic because mktime() operates on * local times. We convert to local time and then figure out the * adjustment based on the local time zone and daylight savings * setting. * * Return: Success: The value of timezone * Failure: -1 * * Programmer: Quincey Koziol * November 18, 2015 * *------------------------------------------------------------------------- */ time_t H5_make_time(struct tm *tm) { time_t the_time; /* The converted time */ #if defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) /* VS 2015 */ /* In gcc and in Visual Studio prior to VS 2015 'timezone' is a global * variable declared in time.h. That variable was deprecated and in * VS 2015 is removed, with _get_timezone replacing it. */ long timezone = 0; #endif /* defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) */ time_t ret_value = 0; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Sanity check */ HDassert(tm); /* Initialize timezone information */ if (!H5_ntzset) { HDtzset(); H5_ntzset = TRUE; } /* end if */ /* Perform base conversion */ if ((time_t)-1 == (the_time = HDmktime(tm))) HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCONVERT, FAIL, "badly formatted modification time message") /* Adjust for timezones */ #if defined(H5_HAVE_TM_GMTOFF) /* BSD-like systems */ the_time += tm->tm_gmtoff; #elif defined(H5_HAVE_TIMEZONE) #if defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) /* VS 2015 */ /* In gcc and in Visual Studio prior to VS 2015 'timezone' is a global * variable declared in time.h. That variable was deprecated and in * VS 2015 is removed, with _get_timezone replacing it. */ _get_timezone(&timezone); #endif /* defined(H5_HAVE_VISUAL_STUDIO) && (_MSC_VER >= 1900) */ the_time -= timezone - (tm->tm_isdst ? 3600 : 0); #else /* * The catch-all. If we can't convert a character string universal * coordinated time to a time_t value reliably then we can't decode the * modification time message. This really isn't as bad as it sounds -- the * only way a user can get the modification time is from our internal * query routines, which can gracefully recover. */ HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "unable to obtain local timezone information") #endif /* Set return value */ ret_value = the_time; done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5_make_time() */ #ifdef H5_HAVE_WIN32_API /* Offset between 1/1/1601 and 1/1/1970 in 100 nanosecond units */ #define _W32_FT_OFFSET (116444736000000000ULL) /*------------------------------------------------------------------------- * Function: Wgettimeofday * * Purpose: Wrapper function for gettimeofday on Windows systems * * This function can get the time as well as a timezone * * Return: 0 * * This implementation is taken from the Cygwin source distribution at * src/winsup/mingw/mingwex/gettimeofday.c * * The original source code was contributed by * Danny Smith * and released in the public domain. * * Programmer: Scott Wegner * May 19, 2009 * *------------------------------------------------------------------------- */ int Wgettimeofday(struct timeval *tv, struct timezone *tz) { union { unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ FILETIME ft; } _now; static int tzsetflag; if (tv) { GetSystemTimeAsFileTime(&_now.ft); tv->tv_usec = (long)((_now.ns100 / 10ULL) % 1000000ULL); tv->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); } if (tz) { if (!tzsetflag) { _tzset(); tzsetflag = 1; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } /* Always return 0 as per Open Group Base Specifications Issue 6. Do not set errno on error. */ return 0; } /* end Wgettimeofday() */ /*------------------------------------------------------------------------- * Function: Wsetenv * * Purpose: Wrapper function for setenv on Windows systems. * Interestingly, getenv *is* available in the Windows * POSIX layer, just not setenv. * * Return: Success: 0 * Failure: non-zero error code * * Programmer: Dana Robinson * February 2016 * *------------------------------------------------------------------------- */ int Wsetenv(const char *name, const char *value, int overwrite) { size_t bufsize; errno_t err; /* If we're not overwriting, check if the environment variable exists. * If it does (i.e.: the required buffer size to store the variable's * value is non-zero), then return an error code. */ if (!overwrite) { err = getenv_s(&bufsize, NULL, 0, name); if (err || bufsize) return (int)err; } /* end if */ return (int)_putenv_s(name, value); } /* end Wsetenv() */ #ifdef H5_HAVE_WINSOCK2_H #pragma comment(lib, "advapi32.lib") #endif /*------------------------------------------------------------------------- * Function: H5_get_win32_times * * Purpose: Gets the elapsed, system and user times on Windows platforms. * All time values are in seconds. * * Return: Success: 0 * Failure: -1 * * Programmer: Dana Robinson * May 2011 * *------------------------------------------------------------------------- */ #ifdef H5_HAVE_WIN32_API int H5_get_win32_times(H5_timevals_t *tvs /*in,out*/) { static HANDLE process_handle; ULARGE_INTEGER kernel_start; ULARGE_INTEGER user_start; FILETIME KernelTime; FILETIME UserTime; FILETIME CreationTime; FILETIME ExitTime; LARGE_INTEGER counts_start; static LARGE_INTEGER counts_freq; static hbool_t is_initialized = FALSE; BOOL err; HDassert(tvs); if (!is_initialized) { /* NOTE: This is just a pseudo handle and does not need to be closed. */ process_handle = GetCurrentProcess(); err = QueryPerformanceFrequency(&counts_freq); if (0 == err) return -1; is_initialized = TRUE; } /* end if */ /************************* * System and user times * *************************/ err = GetProcessTimes(process_handle, &CreationTime, &ExitTime, &KernelTime, &UserTime); if (0 == err) return -1; /* The 1.0E7 factor seems strange but it's due to the clock * ticking in 100 ns increments. */ kernel_start.HighPart = KernelTime.dwHighDateTime; kernel_start.LowPart = KernelTime.dwLowDateTime; tvs->system = (double)(kernel_start.QuadPart / 1.0E7F); user_start.HighPart = UserTime.dwHighDateTime; user_start.LowPart = UserTime.dwLowDateTime; tvs->user = (double)(user_start.QuadPart / 1.0E7F); /**************** * Elapsed time * ****************/ err = QueryPerformanceCounter(&counts_start); if (0 == err) return -1; tvs->elapsed = (double)(counts_start.QuadPart) / (double)counts_freq.QuadPart; return 0; } /* end H5_get_win32_times() */ #endif #define WloginBuffer_count 256 static char Wlogin_buffer[WloginBuffer_count]; char * Wgetlogin(void) { #ifdef H5_HAVE_WINSOCK2_H long bufferCount = WloginBuffer_count; if (GetUserName(Wlogin_buffer, &bufferCount) == 0) return (Wlogin_buffer); else #endif /* H5_HAVE_WINSOCK2_H */ return NULL; } int c99_snprintf(char *str, size_t size, const char *format, ...) { int count; va_list ap; HDva_start(ap, format); count = c99_vsnprintf(str, size, format, ap); HDva_end(ap); return count; } int c99_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int count = -1; if (size != 0) count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); if (count == -1) count = _vscprintf(format, ap); return count; } /*------------------------------------------------------------------------- * Function: Wflock * * Purpose: Wrapper function for flock on Windows systems * * Return: Success: 0 * Failure: -1 * *------------------------------------------------------------------------- */ int Wflock(int H5_ATTR_UNUSED fd, int H5_ATTR_UNUSED operation) { /* This is a no-op while we implement a Win32 VFD */ #if 0 int Wflock(int fd, int operation) { HANDLE hFile; DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; DWORD dwReserved = 0; /* MAXDWORD for entire file */ DWORD nNumberOfBytesToLockLow = MAXDWORD; DWORD nNumberOfBytesToLockHigh = MAXDWORD; /* Must initialize OVERLAPPED struct */ OVERLAPPED overlapped = {0}; /* Get Windows HANDLE */ hFile = _get_osfhandle(fd); /* Convert to Windows flags */ if(operation & LOCK_EX) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; /* Lock or unlock */ if(operation & LOCK_UN) if(0 == UnlockFileEx(hFile, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, &overlapped)) return -1; else if(0 == LockFileEx(hFile, dwFlags, dwReserved, nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh, &overlapped)) return -1; #endif /* 0 */ return 0; } /* end Wflock() */ /*-------------------------------------------------------------------------- * Function: Wnanosleep * * Purpose: Sleep for a given # of nanoseconds (Windows version) * * Return: SUCCEED/FAIL * * Programmer: Dana Robinson * Fall 2016 *-------------------------------------------------------------------------- */ int Wnanosleep(const struct timespec *req, struct timespec *rem) { /* XXX: Currently just a placeholder */ return 0; } /* end Wnanosleep() */ /*------------------------------------------------------------------------- * Function: Wllround, Wllroundf, Wlround, Wlroundf, Wround, Wroundf * * Purpose: Wrapper function for round functions for use with VS2012 * and earlier. * * Return: The rounded value that was passed in. * * Programmer: Dana Robinson * December 2016 * *------------------------------------------------------------------------- */ long long Wllround(double arg) { return (long long)(arg < 0.0 ? HDceil(arg - 0.5) : HDfloor(arg + 0.5)); } long long Wllroundf(float arg) { return (long long)(arg < 0.0F ? HDceil(arg - 0.5F) : HDfloor(arg + 0.5F)); } long Wlround(double arg) { return (long)(arg < 0.0 ? HDceil(arg - 0.5) : HDfloor(arg + 0.5)); } long Wlroundf(float arg) { return (long)(arg < 0.0F ? HDceil(arg - 0.5F) : HDfloor(arg + 0.5F)); } double Wround(double arg) { return arg < 0.0 ? HDceil(arg - 0.5) : HDfloor(arg + 0.5); } float Wroundf(float arg) { return (float)(arg < 0.0F ? HDceil(arg - 0.5F) : HDfloor(arg + 0.5F)); } /*------------------------------------------------------------------------- * Function: H5_get_utf16_str * * Purpose: Gets a UTF-16 string from an UTF-8 (or ASCII) string. * * Return: Success: A pointer to a UTF-16 string * This must be freed by the caller using H5MM_xfree() * Failure: NULL * * Programmer: Dana Robinson * Spring 2019 * *------------------------------------------------------------------------- */ const wchar_t * H5_get_utf16_str(const char *s) { int nwchars = -1; /* Length of the UTF-16 buffer */ wchar_t *ret_s = NULL; /* UTF-16 version of the string */ /* Get the number of UTF-16 characters needed */ if (0 == (nwchars = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0))) goto error; /* Allocate a buffer for the UTF-16 string */ if (NULL == (ret_s = (wchar_t *)H5MM_calloc(sizeof(wchar_t) * (size_t)nwchars))) goto error; /* Convert the input UTF-8 string to UTF-16 */ if (0 == MultiByteToWideChar(CP_UTF8, 0, s, -1, ret_s, nwchars)) goto error; return ret_s; error: if (ret_s) H5MM_xfree((void *)ret_s); return NULL; } /* end H5_get_utf16_str() */ /*------------------------------------------------------------------------- * Function: Wopen_utf8 * * Purpose: UTF-8 equivalent of open(2) for use on Windows. * Converts a UTF-8 input path to UTF-16 and then opens the * file via _wopen() under the hood * * Return: Success: A POSIX file descriptor * Failure: -1 * * Programmer: Dana Robinson * Spring 2019 * *------------------------------------------------------------------------- */ int Wopen_utf8(const char *path, int oflag, ...) { int fd = -1; /* POSIX file descriptor to be returned */ wchar_t *wpath = NULL; /* UTF-16 version of the path */ int pmode = 0; /* mode (optionally set via variable args) */ /* Convert the input UTF-8 path to UTF-16 */ if (NULL == (wpath = H5_get_utf16_str(path))) goto done; /* _O_BINARY must be set in Windows to avoid CR-LF <-> LF EOL * transformations when performing I/O. Note that this will * produce Unix-style text files, though. */ oflag |= _O_BINARY; /* Get the mode, if O_CREAT was specified */ if (oflag & O_CREAT) { va_list vl; HDva_start(vl, oflag); pmode = HDva_arg(vl, int); HDva_end(vl); } /* Open the file */ fd = _wopen(wpath, oflag, pmode); done: if (wpath) H5MM_xfree((void *)wpath); return fd; } /* end Wopen_utf8() */ /*------------------------------------------------------------------------- * Function: Wremove_utf8 * * Purpose: UTF-8 equivalent of remove(3) for use on Windows. * Converts a UTF-8 input path to UTF-16 and then opens the * file via _wremove() under the hood * * Return: Success: 0 * Failure: -1 * * Programmer: Dana Robinson * Spring 2019 * *------------------------------------------------------------------------- */ int Wremove_utf8(const char *path) { wchar_t *wpath = NULL; /* UTF-16 version of the path */ int ret; /* Convert the input UTF-8 path to UTF-16 */ if (NULL == (wpath = H5_get_utf16_str(path))) goto done; /* Open the file */ ret = _wremove(wpath); done: if (wpath) H5MM_xfree((void *)wpath); return ret; } /* end Wremove_utf8() */ #endif /* H5_HAVE_WIN32_API */ /*------------------------------------------------------------------------- * Function: H5_build_extpath * * Purpose: To build the path for later searching of target file for external * links and external files. This path can be either: * 1. The absolute path of NAME * or * 2. The current working directory + relative path of NAME * * Return: SUCCEED/FAIL * * Programmer: Vailin Choi * April 2, 2008 * *------------------------------------------------------------------------- */ #define MAX_PATH_LEN 1024 herr_t H5_build_extpath(const char *name, char **extpath /*out*/) { char * full_path = NULL; /* Pointer to the full path, as built or passed in */ char * cwdpath = NULL; /* Pointer to the current working directory path */ char * new_name = NULL; /* Pointer to the name of the file */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Sanity check */ HDassert(name); HDassert(extpath); /* Clear external path pointer to begin with */ *extpath = NULL; /* * Unix: name[0] is a "/" * Windows: name[0-2] is ":\" or ":/" */ if (H5_CHECK_ABSOLUTE(name)) { if (NULL == (full_path = (char *)H5MM_strdup(name))) HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed") } /* end if */ else { /* relative pathname */ char * retcwd; size_t name_len; int drive; if (NULL == (cwdpath = (char *)H5MM_malloc(MAX_PATH_LEN))) HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed") name_len = HDstrlen(name) + 1; if (NULL == (new_name = (char *)H5MM_malloc(name_len))) HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed") /* * Windows: name[0-1] is ":" * Get current working directory on the drive specified in NAME * Unix: does not apply */ if (H5_CHECK_ABS_DRIVE(name)) { drive = HDtoupper(name[0]) - 'A' + 1; retcwd = HDgetdcwd(drive, cwdpath, MAX_PATH_LEN); HDstrncpy(new_name, &name[2], name_len); } /* end if */ /* * Windows: name[0] is a '/' or '\' * Get current drive * Unix: does not apply */ else if (H5_CHECK_ABS_PATH(name) && (0 != (drive = HDgetdrive()))) { HDsnprintf(cwdpath, MAX_PATH_LEN, "%c:%c", (drive + 'A' - 1), name[0]); retcwd = cwdpath; HDstrncpy(new_name, &name[1], name_len); } /* totally relative for Unix and Windows: get current working directory */ else { retcwd = HDgetcwd(cwdpath, MAX_PATH_LEN); HDstrncpy(new_name, name, name_len); } /* end if */ if (retcwd != NULL) { size_t cwdlen; size_t path_len; HDassert(cwdpath); cwdlen = HDstrlen(cwdpath); HDassert(cwdlen); HDassert(new_name); path_len = cwdlen + HDstrlen(new_name) + 2; if (NULL == (full_path = (char *)H5MM_malloc(path_len))) HGOTO_ERROR(H5E_INTERNAL, H5E_NOSPACE, FAIL, "memory allocation failed") HDstrncpy(full_path, cwdpath, cwdlen + 1); if (!H5_CHECK_DELIMITER(cwdpath[cwdlen - 1])) HDstrncat(full_path, H5_DIR_SEPS, HDstrlen(H5_DIR_SEPS)); HDstrncat(full_path, new_name, HDstrlen(new_name)); } /* end if */ } /* end else */ /* strip out the last component (the file name itself) from the path */ if (full_path) { char *ptr = NULL; H5_GET_LAST_DELIMITER(full_path, ptr) HDassert(ptr); *++ptr = '\0'; *extpath = full_path; } /* end if */ done: /* Release resources */ if (cwdpath) H5MM_xfree(cwdpath); if (new_name) H5MM_xfree(new_name); FUNC_LEAVE_NOAPI(ret_value) } /* end H5_build_extpath() */ /*-------------------------------------------------------------------------- * Function: H5_combine_path * * Purpose: If path2 is relative, interpret path2 as relative to path1 * and store the result in full_name. Otherwise store path2 * in full_name. * * Return: SUCCEED/FAIL * * Programmer: Steffen Kiess * June 22, 2015 *-------------------------------------------------------------------------- */ herr_t H5_combine_path(const char *path1, const char *path2, char **full_name /*out*/) { size_t path1_len = 0; /* length of path1 */ size_t path2_len; /* length of path2 */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT HDassert(path2); if (path1) path1_len = HDstrlen(path1); path2_len = HDstrlen(path2); if (path1 == NULL || *path1 == '\0' || H5_CHECK_ABSOLUTE(path2)) { /* If path1 is empty or path2 is absolute, simply use path2 */ if (NULL == (*full_name = (char *)H5MM_strdup(path2))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") } /* end if */ else if (H5_CHECK_ABS_PATH(path2)) { /* On windows path2 is a path absolute name */ if (H5_CHECK_ABSOLUTE(path1) || H5_CHECK_ABS_DRIVE(path1)) { /* path1 is absolute or drive absolute and path2 is path absolute. * Use the drive letter of path1 + path2 */ if (NULL == (*full_name = (char *)H5MM_malloc(path2_len + 3))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate path2 buffer") HDsnprintf(*full_name, (path2_len + 3), "%c:%s", path1[0], path2); } /* end if */ else { /* On windows path2 is path absolute name ("\foo\bar"), * path1 does not have a drive letter (i.e. is "a\b" or "\a\b"). * Use path2. */ if (NULL == (*full_name = (char *)H5MM_strdup(path2))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") } /* end else */ } /* end else if */ else { /* Relative path2: * Allocate a buffer to hold path1 + path2 + possibly the delimiter * + terminating null byte */ if (NULL == (*full_name = (char *)H5MM_malloc(path1_len + path2_len + 2 + 2))) /* Extra "+2" to quiet GCC warning - 2019/07/05, QAK */ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate filename buffer") /* Compose the full file name */ HDsnprintf(*full_name, (path1_len + path2_len + 2 + 2), "%s%s%s", path1, /* Extra "+2" to quiet GCC warning - 2019/07/05, QAK */ (H5_CHECK_DELIMITER(path1[path1_len - 1]) ? "" : H5_DIR_SEPS), path2); } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5_combine_path() */ /*-------------------------------------------------------------------------- * Function: H5_nanosleep * * Purpose: Sleep for a given # of nanoseconds * * Return: SUCCEED/FAIL * * Programmer: Quincey Koziol * October 01, 2016 *-------------------------------------------------------------------------- */ void H5_nanosleep(uint64_t nanosec) { struct timespec sleeptime; /* Struct to hold time to sleep */ FUNC_ENTER_NOAPI_NOINIT_NOERR /* Set up time to sleep */ sleeptime.tv_sec = 0; sleeptime.tv_nsec = (long)nanosec; HDnanosleep(&sleeptime, NULL); FUNC_LEAVE_NOAPI_VOID } /* end H5_nanosleep() */ #ifdef H5_HAVE_WIN32_API #define H5_WIN32_ENV_VAR_BUFFER_SIZE 32767 /*------------------------------------------------------------------------- * Function: H5_expand_windows_env_vars() * * Purpose: Replaces windows environment variables of the form %foo% * with user-specific values. * * Return: SUCCEED/FAIL * *------------------------------------------------------------------------- */ herr_t H5_expand_windows_env_vars(char **env_var) { long n_chars = 0; char * temp_buf = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI_NOINIT /* Allocate buffer for expanded environment variable string */ if (NULL == (temp_buf = (char *)H5MM_calloc((size_t)H5_WIN32_ENV_VAR_BUFFER_SIZE))) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTALLOC, FAIL, "can't allocate memory for expanded path") /* Expand the environment variable string */ if ((n_chars = ExpandEnvironmentStringsA(*env_var, temp_buf, H5_WIN32_ENV_VAR_BUFFER_SIZE)) > H5_WIN32_ENV_VAR_BUFFER_SIZE) HGOTO_ERROR(H5E_PLUGIN, H5E_NOSPACE, FAIL, "expanded path is too long") if (0 == n_chars) HGOTO_ERROR(H5E_PLUGIN, H5E_CANTGET, FAIL, "failed to expand path") *env_var = (char *)H5MM_xfree(*env_var); *env_var = temp_buf; done: if (FAIL == ret_value && temp_buf) temp_buf = (char *)H5MM_xfree(temp_buf); FUNC_LEAVE_NOAPI(ret_value) } /* end H5_expand_windows_env_vars() */ #endif /* H5_HAVE_WIN32_API */