e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
1b10db2002-10-08Martin Nilsson 
cc26c32018-04-24Henrik Grubbström (Grubba) /* * This file contains wrappers for NT system calls that * implement the corresponding POSIX system calls. * One major difference compared to the native wrappers * in crt.lib is that filenames are assumed to be UTF-8- * encoded, with a fallback to Latin-1. * * The UTF-8 filenames are recoded to UTF16 and used * with the wide versions of the NT system calls. */
24ddc71998-03-28Henrik Grubbström (Grubba) #include "global.h"
5740881998-01-01Fredrik Hübinette (Hubbe) #include "fdlib.h"
1f16da2018-09-18Henrik Grubbström (Grubba) #include "backend.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
e42eaf1998-01-02Fredrik Hübinette (Hubbe) #include <math.h>
e0f5672016-11-11Henrik Grubbström (Grubba) #include "port.h"
8304062018-04-26Henrik Grubbström (Grubba) #include <assert.h>
5740881998-01-01Fredrik Hübinette (Hubbe) 
bd9a902006-07-02Martin Nilsson #ifdef HAVE_DIRECT_H #include <direct.h> #endif
a712de2006-07-05Martin Stjernholm #if defined(HAVE_WINSOCK_H)
0557002018-05-11Henrik Grubbström (Grubba) #include <shlobj.h> #include <objbase.h>
7aafba2018-05-11Henrik Grubbström (Grubba) #include <wchar.h> #include <io.h>
5a8cdd2006-06-20Martin Stjernholm #include <time.h>
f09acd2003-03-28Martin Stjernholm /* Old versions of the headerfiles don't have this constant... */ #ifndef INVALID_SET_FILE_POINTER #define INVALID_SET_FILE_POINTER ((DWORD)-1) #endif
9f48b52018-04-25Henrik Grubbström (Grubba) #ifndef ENOTSOCK #define ENOTSOCK WSAENOTSOCK #endif
5a7ab61998-01-31Fredrik Hübinette (Hubbe) #include "threads.h"
ddeb2a2018-04-26Henrik Grubbström (Grubba) /* Mutex protecting da_handle, fd_type, fd_busy and first_free_handle. */
74ea782016-01-29Martin Nilsson static PIKE_MUTEX_T fd_mutex;
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
ddeb2a2018-04-26Henrik Grubbström (Grubba) /* Condition indicating that some field of fd_busy has been cleared. */ static COND_T fd_cond;
2400262018-04-25Henrik Grubbström (Grubba) /* HANDLEs corresponding to the fd of the same index. */
e16e512014-10-02Per Hedbor HANDLE da_handle[FD_SETSIZE];
2400262018-04-25Henrik Grubbström (Grubba)  /* Next free fd when >= 0. * * When < 0: * FD_NO_MORE_FREE (-1) * End marker for the free list. * * FD_FILE (-2) * Handle from CreateFileW(). * * FD_CONSOLE (-3) * Handle from GetStdHandle(). * * FD_SOCKET (-4) * socket_fd from socket(). * * FD_PIPE (-5) * Handle from CreatePipe(). */
e16e512014-10-02Per Hedbor int fd_type[FD_SETSIZE];
2400262018-04-25Henrik Grubbström (Grubba) 
ddeb2a2018-04-26Henrik Grubbström (Grubba) /* Indication whether the corresponding fd is in use. */ int fd_busy[FD_SETSIZE];
2400262018-04-25Henrik Grubbström (Grubba) /* Next free fd. FD_NO_MORE_FREE (-1) if all fds allocated. */
5740881998-01-01Fredrik Hübinette (Hubbe) int first_free_handle;
0557002018-05-11Henrik Grubbström (Grubba) /* The root desktop folder. */ static LPSHELLFOLDER isf = NULL;
9f57892000-09-01Henrik Grubbström (Grubba) /* #define FD_DEBUG */
c0bd392012-07-02Martin Stjernholm /* #define FD_STAT_DEBUG */
6f1a2c2000-09-01Henrik Grubbström (Grubba) 
98524e1999-08-06Fredrik Hübinette (Hubbe) #ifdef FD_DEBUG #define FDDEBUG(X) X #else
bcf9461998-01-27Fredrik Hübinette (Hubbe) #define FDDEBUG(X)
98524e1999-08-06Fredrik Hübinette (Hubbe) #endif
e42eaf1998-01-02Fredrik Hübinette (Hubbe) 
c0bd392012-07-02Martin Stjernholm #ifdef FD_STAT_DEBUG #define STATDEBUG(X) X #else #define STATDEBUG(X) do {} while (0) #endif
4cd5602018-04-20Henrik Grubbström (Grubba)  #ifdef USE_DL_MALLOC /* NB: We use some calls that allocate memory with the libc malloc(). */ static inline void libc_free(void *ptr); #else #define libc_free(PTR) free(PTR) #endif
54517f2018-05-09Henrik Grubbström (Grubba) /* Provide and use our own implementation of _dosmaperr(), * as it isn't provided by all CRT runtimes; eg both MinGW * and msvcr100.dll seem to not implement _dosmaperr()... */
0502ff2018-05-08Henrik Grubbström (Grubba) #undef _dosmaperr #define _dosmaperr pike_dosmaperr
54517f2018-05-09Henrik Grubbström (Grubba) /* Mapping of Windows error codes to POSIX error codes. * * This table was generated by correlating the behavior of * _dosmaperr() with the <WinError.h> and <errno.h> header files. * * Entries not in the table map to EINVAL. */
0502ff2018-05-08Henrik Grubbström (Grubba) static const unsigned long pike_doserrtab[][2] = { { ERROR_INVALID_FUNCTION, EINVAL, }, /* 1 */ { ERROR_FILE_NOT_FOUND, ENOENT, }, /* 2 */ { ERROR_PATH_NOT_FOUND, ENOENT, }, /* 3 */ { ERROR_TOO_MANY_OPEN_FILES, EMFILE, }, /* 4 */ { ERROR_ACCESS_DENIED, EACCES, }, /* 5 */ { ERROR_INVALID_HANDLE, EBADF, }, /* 6 */ { ERROR_ARENA_TRASHED, ENOMEM, }, /* 7 */ { ERROR_NOT_ENOUGH_MEMORY, ENOMEM, }, /* 8 */ { ERROR_INVALID_BLOCK, ENOMEM, }, /* 9 */ { ERROR_BAD_ENVIRONMENT, E2BIG, }, /* 10 */ { ERROR_BAD_FORMAT, ENOEXEC, }, /* 11 */ { ERROR_INVALID_ACCESS, EINVAL, }, /* 12 */ { ERROR_INVALID_DATA, EINVAL, }, /* 13 */ { ERROR_INVALID_DRIVE, ENOENT, }, /* 15 */ { ERROR_CURRENT_DIRECTORY, EACCES, }, /* 16 */ { ERROR_NOT_SAME_DEVICE, EXDEV, }, /* 17 */ { ERROR_NO_MORE_FILES, ENOENT, }, /* 18 */
54517f2018-05-09Henrik Grubbström (Grubba)  { ERROR_WRITE_PROTECT, EACCES, }, /* 19 */ { ERROR_BAD_UNIT, EACCES, }, /* 20 */ { ERROR_NOT_READY, EACCES, }, /* 21 */ { ERROR_BAD_COMMAND, EACCES }, /* 22 */ { ERROR_CRC, EACCES }, /* 23 */ { ERROR_BAD_LENGTH, EACCES }, /* 24 */ { ERROR_NOT_DOS_DISK, EACCES }, /* 26 */ { ERROR_SECTOR_NOT_FOUND, EACCES }, /* 27 */ { ERROR_OUT_OF_PAPER, EACCES }, /* 28 */ { ERROR_WRITE_FAULT, EACCES }, /* 29 */ { ERROR_READ_FAULT, EACCES }, /* 30 */ { ERROR_GEN_FAILURE, EACCES }, /* 31 */ { ERROR_SHARING_VIOLATION, EACCES }, /* 32 */
0502ff2018-05-08Henrik Grubbström (Grubba)  { ERROR_LOCK_VIOLATION, EACCES, }, /* 33 */
54517f2018-05-09Henrik Grubbström (Grubba)  { ERROR_WRONG_DISK, EACCES }, /* 34 */ { ERROR_SHARING_BUFFER_EXCEEDED, EACCES }, /* 36 */
0502ff2018-05-08Henrik Grubbström (Grubba)  { ERROR_BAD_NETPATH, ENOENT, }, /* 53 */ { ERROR_NETWORK_ACCESS_DENIED, EACCES, }, /* 65 */ { ERROR_BAD_NET_NAME, ENOENT, }, /* 67 */ { ERROR_FILE_EXISTS, EEXIST, }, /* 80 */ { ERROR_CANNOT_MAKE, EACCES, }, /* 82 */ { ERROR_FAIL_I24, EACCES, }, /* 83 */ { ERROR_INVALID_PARAMETER, EINVAL, }, /* 87 */ { ERROR_NO_PROC_SLOTS, EAGAIN, }, /* 89 */ { ERROR_DRIVE_LOCKED, EACCES, }, /* 108 */ { ERROR_BROKEN_PIPE, EPIPE, }, /* 109 */ { ERROR_DISK_FULL, ENOSPC, }, /* 112 */ { ERROR_INVALID_TARGET_HANDLE, EBADF, }, /* 114 */ { ERROR_INVALID_HANDLE, EINVAL, }, /* 124 */ { ERROR_WAIT_NO_CHILDREN, ECHILD, }, /* 128 */ { ERROR_CHILD_NOT_COMPLETE, ECHILD, }, /* 129 */ { ERROR_DIRECT_ACCESS_HANDLE, EBADF, }, /* 130 */ { ERROR_NEGATIVE_SEEK, EINVAL, }, /* 131 */ { ERROR_SEEK_ON_DEVICE, EACCES, }, /* 132 */ { ERROR_DIR_NOT_EMPTY, ENOTEMPTY, }, /* 145 */ { ERROR_NOT_LOCKED, EACCES, }, /* 158 */ { ERROR_BAD_PATHNAME, ENOENT, }, /* 161 */ { ERROR_MAX_THRDS_REACHED, EAGAIN, }, /* 164 */ { ERROR_LOCK_FAILED, EACCES, }, /* 167 */ { ERROR_ALREADY_EXISTS, EEXIST, }, /* 183 */
54517f2018-05-09Henrik Grubbström (Grubba)  { ERROR_INVALID_STARTING_CODESEG, ENOEXEC }, /* 188 */ { ERROR_INVALID_STACKSEG, ENOEXEC }, /* 189 */ { ERROR_INVALID_MODULETYPE, ENOEXEC }, /* 190 */ { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC }, /* 191 */ { ERROR_EXE_MARKED_INVALID, ENOEXEC }, /* 192 */ { ERROR_BAD_EXE_FORMAT, ENOEXEC }, /* 193 */ { ERROR_ITERATED_DATA_EXCEEDS_64k, ENOEXEC }, /* 194 */ { ERROR_INVALID_MINALLOCSIZE, ENOEXEC }, /* 195 */ { ERROR_DYNLINK_FROM_INVALID_RING, ENOEXEC }, /* 196 */ { ERROR_IOPL_NOT_ENABLED, ENOEXEC }, /* 197 */ { ERROR_INVALID_SEGDPL, ENOEXEC }, /* 198 */ { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC }, /* 199 */ { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC }, /* 200 */ { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC }, /* 201 */ { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC }, /* 202 */
0502ff2018-05-08Henrik Grubbström (Grubba)  { ERROR_FILENAME_EXCED_RANGE, ENOENT, }, /* 206 */ { ERROR_NESTING_NOT_ALLOWED, EAGAIN, }, /* 215 */ { ERROR_NOT_ENOUGH_QUOTA, ENOMEM, }, /* 1816 */ }; static inline void _dosmaperr(unsigned long err) {
7aafba2018-05-11Henrik Grubbström (Grubba)  unsigned int l = 0, h = NELEM(pike_doserrtab);
0502ff2018-05-08Henrik Grubbström (Grubba)  while (l < h) {
7aafba2018-05-11Henrik Grubbström (Grubba)  unsigned int m = (l+h)>>1; unsigned long e = pike_doserrtab[m][0];
0502ff2018-05-08Henrik Grubbström (Grubba)  if (e == err) { errno = pike_doserrtab[m][1]; return; } if (e < err) { l = m+1; } else { h = m; } } errno = EINVAL; }
a56e682008-10-17Martin Stjernholm  PMOD_EXPORT void set_errno_from_win32_error (unsigned long err) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Win32Error: %ld\n", err));
a56e682008-10-17Martin Stjernholm  /* _dosmaperr handles the common I/O errors from GetLastError, but * not the winsock codes. */ _dosmaperr (err); /* Let through any error that _dosmaperr didn't map, and which * doesn't conflict with the errno range in msvcrt. */ if (errno == EINVAL && err > STRUNCATE /* 80 */) { switch (err) { /* Special cases for the error codes above STRUNCATE that * _dosmaperr actively map to EINVAL. */ case ERROR_INVALID_PARAMETER: /* 87 */ case ERROR_INVALID_HANDLE: /* 124 */ case ERROR_NEGATIVE_SEEK: /* 131 */ return;
f1444c2014-09-15Martin Karlgren  case ERROR_DIRECTORY: /* 267 */ errno = ENOTDIR; /* [Bug 7271] */ return;
a56e682008-10-17Martin Stjernholm  } /* FIXME: This lets most winsock codes through as-is, e.g. * WSAEWOULDBLOCK (10035) instead of EAGAIN. There are symbolic * constants for all of them in the System module, but the * duplicate values still complicates code on the Windows * platform, so they ought to be mapped to the basic codes where * possible, I think. That wouldn't be compatible, though. * /mast */ errno = err; } }
87549a2018-04-19Henrik Grubbström (Grubba) /* Dynamic load of functions that don't exist in all Windows versions. */ #undef NTLIB #define NTLIB(LIB) \ static HINSTANCE PIKE_CONCAT3(Pike_NT_, LIB, _lib); #undef NTLIBFUNC #define NTLIBFUNC(LIB, RET, NAME, ARGLIST) \ typedef RET (WINAPI * PIKE_CONCAT3(Pike_NT_, NAME, _type)) ARGLIST; \ static PIKE_CONCAT3(Pike_NT_, NAME, _type) PIKE_CONCAT(Pike_NT_, NAME) #include "ntlibfuncs.h"
4b2ca02004-11-18Martin Stjernholm #define ISSEPARATOR(a) ((a) == '\\' || (a) == '/')
56f4f42001-09-18Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG static int IsValidHandle(HANDLE h) {
e5d8a82005-01-06Henrik Grubbström (Grubba) #ifndef __GNUC__
56f4f42001-09-18Fredrik Hübinette (Hubbe)  __try { HANDLE ret; if(DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), &ret, 0, 0, DUPLICATE_SAME_ACCESS)) { CloseHandle(ret); } } __except (1) { return 0; }
e5d8a82005-01-06Henrik Grubbström (Grubba) #endif /* !__GNUC__ */
56f4f42001-09-18Fredrik Hübinette (Hubbe)  return 1; } PMOD_EXPORT HANDLE CheckValidHandle(HANDLE h) { if(!IsValidHandle(h))
5aad932002-08-15Marcus Comstedt  Pike_fatal("Invalid handle!\n");
56f4f42001-09-18Fredrik Hübinette (Hubbe)  return h; } #endif
65c26d2018-04-26Henrik Grubbström (Grubba) /* Used by signal_handler.c:get_inheritable_handle(). */ int fd_to_handle(int fd, int *type, HANDLE *handle)
9f48b52018-04-25Henrik Grubbström (Grubba) { int ret = -1;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_to_handle(%d, %p, %p)...\n", fd, type, handle));
9f48b52018-04-25Henrik Grubbström (Grubba)  if (fd >= FD_NO_MORE_FREE) { mt_lock(&fd_mutex);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  while (fd_busy[fd]) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is busy; waiting...\n", fd));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  co_wait(&fd_cond, &fd_mutex); }
9f48b52018-04-25Henrik Grubbström (Grubba)  if (fd_type[fd] < 0) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is valid.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  if (type) *type = fd_type[fd]; if (handle) *handle = da_handle[fd];
ddeb2a2018-04-26Henrik Grubbström (Grubba)  fd_busy[fd] = 1;
9f48b52018-04-25Henrik Grubbström (Grubba)  ret = 0;
7c8ed62018-05-09Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d ==> handle: %ld (%d)\n", fd, (long)da_handle[fd], fd_type[fd]));
9f48b52018-04-25Henrik Grubbström (Grubba)  } else {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is invalid.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = EBADF; } mt_unlock(&fd_mutex); } else {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is invalid (range).\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = EBADF; } return ret; } static int fd_to_socket(int fd, SOCKET *socket) { int ret = -1;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_to_socket(%d, %p)...\n", fd, socket));
9f48b52018-04-25Henrik Grubbström (Grubba)  if (fd >= FD_NO_MORE_FREE) { mt_lock(&fd_mutex);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  while (fd_busy[fd]) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is busy; waiting...\n", fd));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  co_wait(&fd_cond, &fd_mutex); }
9f48b52018-04-25Henrik Grubbström (Grubba)  if (fd_type[fd] == FD_SOCKET) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is a valid socket.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  if (socket) *socket = (SOCKET)da_handle[fd];
ddeb2a2018-04-26Henrik Grubbström (Grubba)  fd_busy[fd] = 1;
9f48b52018-04-25Henrik Grubbström (Grubba)  ret = 0; } else if (fd_type[fd] < 0) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is not a socket.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = ENOTSOCK; } else {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is invalid.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = EBADF; } mt_unlock(&fd_mutex); } else {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is invalid (range).\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = EBADF; } return ret; } static int allocate_fd(int type, HANDLE handle) { int fd; if (type >= FD_NO_MORE_FREE) { errno = EINVAL; return -1; } mt_lock(&fd_mutex); fd = first_free_handle; if (fd >= 0) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "allocating fd %d (busy: %d)\n", fd, fd_busy[fd]));
8304062018-04-26Henrik Grubbström (Grubba)  assert(!fd_busy[fd]); assert(fd_type[fd] >= -1);
9f48b52018-04-25Henrik Grubbström (Grubba)  first_free_handle = fd_type[fd]; fd_type[fd] = type; da_handle[fd] = handle;
ddeb2a2018-04-26Henrik Grubbström (Grubba)  fd_busy[fd] = 1;
9f48b52018-04-25Henrik Grubbström (Grubba)  } else {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "All fds are allocated.\n"));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = EMFILE; } mt_unlock(&fd_mutex); return fd; } static int reallocate_fd(int fd, int type, HANDLE handle) { int prev_fd; if ((fd < 0) || (fd >= FD_SETSIZE) || (type >= FD_NO_MORE_FREE)) { errno = EINVAL; return -1; }
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "reallocate_fd(%d, %d, %p)...\n", fd, type, (void *)handle));
9f48b52018-04-25Henrik Grubbström (Grubba)  mt_lock(&fd_mutex);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  while (fd_busy[fd]) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d is busy; waiting...\n", fd));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  co_wait(&fd_cond, &fd_mutex); }
9f48b52018-04-25Henrik Grubbström (Grubba)  if (fd_type[fd] < FD_NO_MORE_FREE) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d was in use; reallocating.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  goto reallocate; }
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d was not i use. Allocating.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  prev_fd = first_free_handle; if (prev_fd == fd) {
8304062018-04-26Henrik Grubbström (Grubba)  assert(!fd_busy[fd]); assert(fd_type[fd] >= -1);
9f48b52018-04-25Henrik Grubbström (Grubba)  first_free_handle = fd_type[fd]; goto found; } while (prev_fd != FD_NO_MORE_FREE) { if (fd_type[prev_fd] == fd) { /* Found. */
8304062018-04-26Henrik Grubbström (Grubba)  assert(!fd_busy[fd]); assert(fd_type[fd] >= -1);
9f48b52018-04-25Henrik Grubbström (Grubba)  fd_type[prev_fd] = fd_type[fd]; goto found; } prev_fd = fd_type[prev_fd]; }
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd %d was not on the free list!\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  errno = EMFILE; mt_unlock(&fd_mutex); return -1; reallocate: if (fd_type[fd] == FD_SOCKET) {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Closing socket that was fd %d.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  closesocket((SOCKET)da_handle[fd]); } else {
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Closing handle that was fd %d.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  CloseHandle(da_handle[fd]); } /* FALLTHRU */ found:
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Allocating fd %d.\n", fd));
9f48b52018-04-25Henrik Grubbström (Grubba)  fd_type[fd] = type; da_handle[fd] = handle;
ddeb2a2018-04-26Henrik Grubbström (Grubba)  fd_busy[fd] = 1;
9f48b52018-04-25Henrik Grubbström (Grubba)  mt_unlock(&fd_mutex); return fd; }
65c26d2018-04-26Henrik Grubbström (Grubba) /* Used by signal_handler.c:get_inheritable_handle(). */ void release_fd(int fd)
ddeb2a2018-04-26Henrik Grubbström (Grubba) { if ((fd < 0) || (fd >= FD_SETSIZE)) { return; } mt_lock(&fd_mutex);
8304062018-04-26Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Releasing fd %d. Busy: %d\n", fd, fd_busy[fd]));
8304062018-04-26Henrik Grubbström (Grubba)  assert(fd_busy[fd]);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  fd_busy[fd] = 0;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Broadcasting now that fd %d is no longer busy.\n", fd));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  co_broadcast(&fd_cond); mt_unlock(&fd_mutex); }
9f48b52018-04-25Henrik Grubbström (Grubba) static void free_fd(int fd) { if ((fd < 0) || (fd >= FD_SETSIZE)) { return; } mt_lock(&fd_mutex);
8304062018-04-26Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Freeing fd %d. Busy: %d\n", fd, fd_busy[fd]));
9f48b52018-04-25Henrik Grubbström (Grubba)  if (fd_type[fd] < FD_NO_MORE_FREE) {
8304062018-04-26Henrik Grubbström (Grubba)  assert(fd_busy[fd]);
9f48b52018-04-25Henrik Grubbström (Grubba)  fd_type[fd] = first_free_handle; first_free_handle = fd;
ddeb2a2018-04-26Henrik Grubbström (Grubba)  fd_busy[fd] = 0;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Broadcasting now that fd %d is free.\n", fd));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  co_broadcast(&fd_cond);
1287a72018-04-27Henrik Grubbström (Grubba)  } else { FDDEBUG(fprintf(stderr, "Fd %d is already free!\n", fd)); FDDEBUG(fprintf(stderr, "fd_type[%d]: %d\n", fd, fd_type[fd])); FDDEBUG(fprintf(stderr, "fd_busy[%d]: %d\n", fd, fd_busy[fd]));
9f48b52018-04-25Henrik Grubbström (Grubba)  } mt_unlock(&fd_mutex); } static void set_fd_handle(int fd, HANDLE handle) { if (fd < 0) { return; }
8304062018-04-26Henrik Grubbström (Grubba) 
9f48b52018-04-25Henrik Grubbström (Grubba)  mt_lock(&fd_mutex);
8304062018-04-26Henrik Grubbström (Grubba)  assert(fd_busy[fd]);
9f48b52018-04-25Henrik Grubbström (Grubba)  da_handle[fd] = handle; mt_unlock(&fd_mutex); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT char *debug_fd_info(int fd)
b3eeab1998-01-21Fredrik Hübinette (Hubbe) { if(fd<0) return "BAD";
e16e512014-10-02Per Hedbor  if(fd > FD_SETSIZE)
b3eeab1998-01-21Fredrik Hübinette (Hubbe)  return "OUT OF RANGE"; switch(fd_type[fd]) { case FD_SOCKET: return "IS SOCKET"; case FD_CONSOLE: return "IS CONSOLE"; case FD_FILE: return "IS FILE";
bcf9461998-01-27Fredrik Hübinette (Hubbe)  case FD_PIPE: return "IS PIPE";
b3eeab1998-01-21Fredrik Hübinette (Hubbe)  default: return "NOT OPEN"; } }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_query_properties(int fd, int guess)
bcf9461998-01-27Fredrik Hübinette (Hubbe) {
7bfa602018-04-25Henrik Grubbström (Grubba)  int type;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_query_properties(%d, %d)...\n", fd, guess));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, NULL) < 0) return 0;
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
7bfa602018-04-25Henrik Grubbström (Grubba)  switch(type)
bcf9461998-01-27Fredrik Hübinette (Hubbe)  { case FD_SOCKET: return fd_BUFFERED | fd_CAN_NONBLOCK | fd_CAN_SHUTDOWN;
b04c242007-04-20Martin Stjernholm 
bcf9461998-01-27Fredrik Hübinette (Hubbe)  case FD_FILE: return fd_INTERPROCESSABLE;
b04c242007-04-20Martin Stjernholm  case FD_CONSOLE: return fd_CAN_NONBLOCK | fd_INTERPROCESSABLE;
bcf9461998-01-27Fredrik Hübinette (Hubbe)  case FD_PIPE: return fd_INTERPROCESSABLE | fd_BUFFERED; default: return 0; } }
3b54e52014-08-21Martin Nilsson void fd_init(void)
5740881998-01-01Fredrik Hübinette (Hubbe) { int e; WSADATA wsadata;
87549a2018-04-19Henrik Grubbström (Grubba)  OSVERSIONINFO osversion;
13670c2015-05-25Martin Nilsson 
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  mt_init(&fd_mutex);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  co_init(&fd_cond);
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  mt_lock(&fd_mutex);
ddeb2a2018-04-26Henrik Grubbström (Grubba) 
2043ba1998-02-10Fredrik Hübinette (Hubbe)  if(WSAStartup(MAKEWORD(1,1), &wsadata) != 0)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
5aad932002-08-15Marcus Comstedt  Pike_fatal("No winsock available.\n");
5740881998-01-01Fredrik Hübinette (Hubbe)  }
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"Using %s\n",wsadata.szDescription));
13670c2015-05-25Martin Nilsson 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "FD_SETSIZE: %ld\n", (long)FD_SETSIZE)); FDDEBUG(fprintf(stderr, "fd_busy: %ld bytes.\n", (long)sizeof(fd_busy)));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  memset(fd_busy, 0, sizeof(fd_busy));
948d282000-08-17Henrik Grubbström (Grubba)  fd_type[0] = FD_CONSOLE; da_handle[0] = GetStdHandle(STD_INPUT_HANDLE); fd_type[1] = FD_CONSOLE; da_handle[1] = GetStdHandle(STD_OUTPUT_HANDLE); fd_type[2] = FD_CONSOLE; da_handle[2] = GetStdHandle(STD_ERROR_HANDLE);
5740881998-01-01Fredrik Hübinette (Hubbe)  first_free_handle=3;
e16e512014-10-02Per Hedbor  for(e=3;e<FD_SETSIZE-1;e++)
5740881998-01-01Fredrik Hübinette (Hubbe)  fd_type[e]=e+1; fd_type[e]=FD_NO_MORE_FREE;
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  mt_unlock(&fd_mutex);
87549a2018-04-19Henrik Grubbström (Grubba)  /* MoveFileEx doesn't exist in W98 and earlier. */ /* Correction, it exists but does not work -Hubbe */ osversion.dwOSVersionInfoSize = sizeof(osversion); if (GetVersionEx(&osversion) && (osversion.dwPlatformId != VER_PLATFORM_WIN32s) && /* !win32s */ (osversion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)) /* !win9x */ { #undef NTLIB #define NTLIB(LIBNAME) \ PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib) = \ LoadLibrary(TOSTR(LIBNAME)) #undef NTLIBFUNC #define NTLIBFUNC(LIBNAME, RETTYPE, SYMBOL, ARGLIST) do { \ if (PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib)) { \ PIKE_CONCAT(Pike_NT_, SYMBOL) = \ (PIKE_CONCAT3(Pike_NT_, SYMBOL, _type)) \ GetProcAddress(PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib), \ TOSTR(SYMBOL)); \ } \ } while(0) #include "ntlibfuncs.h" }
0557002018-05-11Henrik Grubbström (Grubba)  if (SHGetDesktopFolder(&isf) != S_OK) { Pike_fatal("fdlib: No desktop folder!\n"); }
5740881998-01-01Fredrik Hübinette (Hubbe) }
3b54e52014-08-21Martin Nilsson void fd_exit(void)
5740881998-01-01Fredrik Hübinette (Hubbe) {
87549a2018-04-19Henrik Grubbström (Grubba) #undef NTLIB #define NTLIB(LIBNAME) do { \ if (PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib)) { \ if (FreeLibrary(PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib))) { \ PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib) = NULL; \ } \ } \ } while(0) #undef NTLIBFUNC #define NTLIBFUNC(LIBNAME, RETTYPE, SYMBOL, ARGLIST) do { \ if (!PIKE_CONCAT3(Pike_NT_, LIBNAME, _lib)) { \ PIKE_CONCAT(Pike_NT_, SYMBOL) = NULL; \ } \ } while(0) #include "ntlibfuncs.h"
5740881998-01-01Fredrik Hübinette (Hubbe)  WSACleanup();
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  mt_destroy(&fd_mutex);
5740881998-01-01Fredrik Hübinette (Hubbe) }
01b9212016-01-12Per Hedbor static inline time_t convert_filetime_to_time_t(FILETIME *tmp)
4b2ca02004-11-18Martin Stjernholm {
5a8cdd2006-06-20Martin Stjernholm  /* FILETIME is in 100ns since Jan 01, 1601 00:00 UTC. * * Offset to Jan 01, 1970 is thus 0x019db1ded53e8000 * 100ns. */
b657482004-11-20Martin Nilsson  return (((INT64) tmp->dwHighDateTime << 32) + tmp->dwLowDateTime
5a8cdd2006-06-20Martin Stjernholm  - 0x019db1ded53e8000) / 10000000;
4b2ca02004-11-18Martin Stjernholm } /* The following replaces _stat in MS CRT since it's buggy on ntfs. * Axel Siebert explains: * * On NTFS volumes, the time is stored as UTC, so it's easy to * calculate the difference to January 1, 1601 00:00 UTC directly. * * On FAT volumes, the time is stored as local time, as a heritage * from MS-DOS days. This means that this local time must be * converted to UTC first before calculating the FILETIME. During * this conversion, all Windows versions exhibit the same bug, using * the *current* DST status instead of the DST status at that time. * So the FILETIME value can be off by one hour for FAT volumes. * * Now the CRT _stat implementation uses FileTimeToLocalFileTime to * convert this value back to local time - which suffers from the * same DST bug. Then the undocumented function __loctotime_t is * used to convert this local time to a time_t, and this function
5a8cdd2006-06-20Martin Stjernholm  * correctly accounts for DST at that time(*).
4b2ca02004-11-18Martin Stjernholm  * * On FAT volumes, the conversion error while retrieving the * FILETIME, and the conversion error of FileTimeToLocalFileTime * exactly cancel each other out, so the final result of the _stat * implementation is always correct. * * On NTFS volumes however, there is no conversion error while * retrieving the FILETIME because the file system already stores it * as UTC, so the conversion error of FileTimeToLocalFileTime can * cause the final result to be 1 hour off. * * The following implementation tries to do the correct thing based in * the filesystem type.
5a8cdd2006-06-20Martin Stjernholm  * * Note also that the UTC timestamps are cached by the OS. In the case * of FAT volumes that means that the current DST setting might be * different when FileTimeToLocalFileTime runs than it was when the * FILETIME was calculated, so the calculation errors might not cancel * each other out shortly after DST changes. A reboot is necessary * after a DST change to ensure that no cached timestamps remain. * There is nothing we can do to correct this error. :( * * See also http://msdn.microsoft.com/library/en-us/sysinfo/base/file_times.asp * * *) Actually it doesn't in all cases: The overlapping hour(s) when * going from DST to normal time are ambiguous and since there's no * DST flag it has to make an arbitrary choice. */ static time_t local_time_to_utc (time_t t) /* Converts a time_t containing local time to a real time_t (i.e. UTC). * * Note that there's an ambiguity in the autumn transition from DST to * normal time: The returned timestamp can be one hour off in the hour * where the clock is "turned back". This function always consider * that hour to be in normal time. * * Might return -1 if the time is outside the valid range.
4b2ca02004-11-18Martin Stjernholm  */
5a8cdd2006-06-20Martin Stjernholm { int tz_secs, dl_secs;
e765152002-10-15Martin Stjernholm 
5a8cdd2006-06-20Martin Stjernholm  /* First adjust for the time zone. */ #ifdef HAVE__GET_TIMEZONE _get_timezone (&tz_secs); #else tz_secs = _timezone; #endif t += tz_secs; /* Then DST. */ #ifdef HAVE__GET_DAYLIGHT _get_daylight (&dl_secs); #else dl_secs = _daylight; #endif if (dl_secs) { /* See if localtime thinks this is in DST. */ int isdst;
83b2872006-07-02Martin Stjernholm #ifdef HAVE_LOCALTIME_S
5a8cdd2006-06-20Martin Stjernholm  struct tm ts;
83b2872006-07-02Martin Stjernholm  if (localtime_s (&ts, &t)) return -1;
5a8cdd2006-06-20Martin Stjernholm  isdst = ts.tm_isdst; #else struct tm *ts; /* FIXME: A mutex is necessary to avoid a race here, but we * can't protect all calls to localtime anyway. */ if (!(ts = localtime (&t))) return -1; isdst = ts->tm_isdst;
7d504e2006-05-26Martin Stjernholm #endif
5a8cdd2006-06-20Martin Stjernholm  if (isdst) t += dl_secs; } return t; }
7d504e2006-05-26Martin Stjernholm 
5a8cdd2006-06-20Martin Stjernholm static time_t fat_filetime_to_time_t (FILETIME *in)
4b2ca02004-11-18Martin Stjernholm { FILETIME local_ft;
5a8cdd2006-06-20Martin Stjernholm  if (!FileTimeToLocalFileTime (in, &local_ft)) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
5a8cdd2006-06-20Martin Stjernholm  return -1;
4b2ca02004-11-18Martin Stjernholm  } else {
5a8cdd2006-06-20Martin Stjernholm  time_t t = convert_filetime_to_time_t (&local_ft); /* Now we have a strange creature, namely a time_t that contains * local time. */ return local_time_to_utc (t);
4b2ca02004-11-18Martin Stjernholm  } } static int fat_filetimes_to_stattimes (FILETIME *creation, FILETIME *last_access, FILETIME *last_write, PIKE_STAT_T *stat) {
5a8cdd2006-06-20Martin Stjernholm  time_t t; if ((t = fat_filetime_to_time_t (last_write)) < 0)
4b2ca02004-11-18Martin Stjernholm  return -1;
5a8cdd2006-06-20Martin Stjernholm  stat->st_mtime = t;
4b2ca02004-11-18Martin Stjernholm  if (last_access->dwLowDateTime || last_access->dwHighDateTime) {
5a8cdd2006-06-20Martin Stjernholm  if ((t = fat_filetime_to_time_t (last_access)) < 0)
4b2ca02004-11-18Martin Stjernholm  return -1;
5a8cdd2006-06-20Martin Stjernholm  stat->st_atime = t;
4b2ca02004-11-18Martin Stjernholm  } else stat->st_atime = stat->st_mtime; /* Putting the creation time in the last status change field.. :\ */ if (creation->dwLowDateTime || creation->dwHighDateTime) {
5a8cdd2006-06-20Martin Stjernholm  if ((t = fat_filetime_to_time_t (creation)) < 0)
4b2ca02004-11-18Martin Stjernholm  return -1;
5a8cdd2006-06-20Martin Stjernholm  stat->st_ctime = t;
4b2ca02004-11-18Martin Stjernholm  } else stat->st_ctime = stat->st_mtime;
091bed2006-06-20Martin Stjernholm  return 0;
4b2ca02004-11-18Martin Stjernholm } static void nonfat_filetimes_to_stattimes (FILETIME *creation, FILETIME *last_access, FILETIME *last_write, PIKE_STAT_T *stat) {
b657482004-11-20Martin Nilsson  stat->st_mtime = convert_filetime_to_time_t (last_write);
4b2ca02004-11-18Martin Stjernholm 
b657482004-11-20Martin Nilsson  if (last_access->dwLowDateTime || last_access->dwHighDateTime) stat->st_atime = convert_filetime_to_time_t(last_access);
4b2ca02004-11-18Martin Stjernholm  else
b657482004-11-20Martin Nilsson  stat->st_atime = stat->st_mtime;
4b2ca02004-11-18Martin Stjernholm  /* Putting the creation time in the last status change field.. :\ */
b657482004-11-20Martin Nilsson  if (creation->dwLowDateTime || creation->dwHighDateTime) stat->st_ctime = convert_filetime_to_time_t (creation);
4b2ca02004-11-18Martin Stjernholm  else
b657482004-11-20Martin Nilsson  stat->st_ctime = stat->st_mtime;
4b2ca02004-11-18Martin Stjernholm }
e765152002-10-15Martin Stjernholm  /* * IsUncRoot - returns TRUE if the argument is a UNC name specifying a * root share. That is, if it is of the form * \\server\share\. This routine will also return true if * the argument is of the form \\server\share (no trailing * slash). * * Forward slashes ('/') may be used instead of * backslashes ('\'). */
b9616b2018-04-19Henrik Grubbström (Grubba) static int IsUncRoot(const p_wchar1 *path)
e765152002-10-15Martin Stjernholm { /* root UNC names start with 2 slashes */
b9616b2018-04-19Henrik Grubbström (Grubba)  if ( wcslen(path) >= 5 && /* minimum string is "//x/y" */
e765152002-10-15Martin Stjernholm  ISSEPARATOR(path[0]) && ISSEPARATOR(path[1]) ) {
b9616b2018-04-19Henrik Grubbström (Grubba)  const p_wchar1 *p = path + 2 ;
13670c2015-05-25Martin Nilsson 
e765152002-10-15Martin Stjernholm  /* find the slash between the server name and share name */ while ( *++p ) if ( ISSEPARATOR(*p) ) break ;
13670c2015-05-25Martin Nilsson 
e765152002-10-15Martin Stjernholm  if ( *p && p[1] ) { /* is there a further slash? */ while ( *++p ) if ( ISSEPARATOR(*p) ) break ;
13670c2015-05-25Martin Nilsson 
e765152002-10-15Martin Stjernholm  /* final slash (if any) */ if ( !*p || !p[1]) return 1; } }
13670c2015-05-25Martin Nilsson 
e765152002-10-15Martin Stjernholm  return 0 ; }
ed01672018-04-19Henrik Grubbström (Grubba) PMOD_EXPORT p_wchar1 *pike_dwim_utf8_to_utf16(const p_wchar0 *str) { /* NB: Maximum expansion factor is 2. * * UTF8 UTF16 Range Expansion * 1 byte 2 bytes U000000 - U00007f 2 * 2 bytes 2 bytes U000080 - U0007ff 1 * 3 bytes 2 bytes U000800 - U00ffff 0.67 * 4 bytes 4 bytes U010000 - U10ffff 1 * * NB: Some extra padding at the end for NUL and adding * of terminating slashes, etc. */ size_t len = strlen(str); p_wchar1 *res = malloc((len + 4) * sizeof(p_wchar1)); size_t i = 0, j = 0; if (!res) { return NULL; } while (i < len) { p_wchar0 c = str[i++]; p_wchar2 ch, mask = 0x3f; if (!(c & 0x80)) { /* US-ASCII */ res[j++] = c; continue; } if (!(c & 0x40)) { /* Continuation character. Invalid. Retry as Latin-1. */ goto latin1_to_utf16; } ch = c; while (c & 0x40) { p_wchar0 cc = str[i++]; if ((cc & 0xc0) != 0x80) { /* Expected continuation character. */ goto latin1_to_utf16; } ch = ch<<6 | (cc & 0x3f); mask |= mask << 5; c <<= 1; } ch &= mask; if (ch < 0) { goto latin1_to_utf16; } if (ch < 0x10000) { res[j++] = ch; continue; } ch -= 0x10000; if (ch >= 0x100000) { goto latin1_to_utf16; } /* Encode with surrogates. */ res[j++] = 0xd800 | ch >> 10; res[j++] = 0xdc00 | (ch & 0x3ff); } goto done; latin1_to_utf16: /* DWIM: Assume Latin-1. Just widen the string. */ for (j = 0; j < len; j++) { res[j] = str[j]; } done: res[j++] = 0; /* NUL-termination. */ return res; } PMOD_EXPORT p_wchar0 *pike_utf16_to_utf8(const p_wchar1 *str) { /* NB: Maximum expansion factor is 1.5. * * UTF16 UTF8 Range Expansion * 2 bytes 1 byte U000000 - U00007f 0.5 * 2 bytes 2 bytes U000080 - U0007ff 1 * 2 bytes 3 bytes U000800 - U00d7ff 1.5 * 2 bytes 2 bytes U00d800 - U00dfff 1 * 2 bytes 3 bytes U00e000 - U00ffff 1.5 * 4 bytes 4 bytes U010000 - U10ffff 1 * * NB: Some extra padding at the end for NUL and adding * of terminating slashes, etc.
67c6ed2018-05-05Henrik Grubbström (Grubba)  * * NB: According to Wikipedia, win32 doesn't enforce correct * pairing of surrogates. Encode such code units as-is.
ed01672018-04-19Henrik Grubbström (Grubba)  */ size_t i = 0, j = 0; size_t sz = 0; p_wchar1 c; p_wchar0 *ret; while ((c = str[i++])) { sz++; if (c < 0x80) continue; sz++; if (c < 0x0800) continue;
67c6ed2018-05-05Henrik Grubbström (Grubba) #if 0 /* NB: The following is only correct if all surrogates are paired correctly. */
ed01672018-04-19Henrik Grubbström (Grubba)  if ((c & 0xf800) == 0xd800) { /* One half of a surrogate pair. */ continue; }
67c6ed2018-05-05Henrik Grubbström (Grubba) #endif /* 0 */
ed01672018-04-19Henrik Grubbström (Grubba)  sz++; } sz++; /* NUL termination. */ ret = malloc(sz); if (!ret) return NULL; for (i = 0; (c = str[i]); i++) { if (c < 0x80) {
faacc82018-05-09Henrik Grubbström (Grubba)  ret[j++] = c & 0x7f;
ed01672018-04-19Henrik Grubbström (Grubba)  continue; } if (c < 0x800) { ret[j++] = 0xc0 | (c>>6); ret[j++] = 0x80 | (c & 0x3f); continue; } if ((c & 0xf800) == 0xd800) { /* Surrogate */ if ((c & 0xfc00) == 0xd800) { p_wchar2 ch = str[++i];
67c6ed2018-05-05Henrik Grubbström (Grubba)  if ((ch & 0xfc00) == 0xdc00) { ch = 0x100000 | (ch & 0x3ff) | ((c & 0x3ff)<<10); ret[j++] = 0xf0 | (ch >> 18); ret[j++] = 0x80 | ((ch >> 12) & 0x3f); ret[j++] = 0x80 | ((ch >> 6) & 0x3f); ret[j++] = 0x80 | (ch & 0x3f); continue;
ed01672018-04-19Henrik Grubbström (Grubba)  }
67c6ed2018-05-05Henrik Grubbström (Grubba)  /* Invalid surrogate pair. * Unget the second code unit. */ i--;
ed01672018-04-19Henrik Grubbström (Grubba)  }
67c6ed2018-05-05Henrik Grubbström (Grubba)  /* Invalid or lone surrogate. * Encode as-is. */
ed01672018-04-19Henrik Grubbström (Grubba)  } ret[j++] = 0xe0 | (c >> 12); ret[j++] = 0x80 | ((c >> 6) & 0x3f); ret[j++] = 0x80 | (c & 0x3f); } ret[j++] = 0; return ret; }
5a8cdd2006-06-20Martin Stjernholm /* Note 1: s->st_mtime is the creation time for non-root directories. * * Note 2: Root directories (e.g. C:\) and network share roots (e.g. * \\server\foo\) have no time information at all. All timestamps are
99f1722006-06-20Martin Stjernholm  * set to one year past the start of the epoch for these.
5a8cdd2006-06-20Martin Stjernholm  * * Note 3: s->st_ctime is set to the file creation time. It should
4b2ca02004-11-18Martin Stjernholm  * probably be the last access time to be closer to the unix * counterpart, but the creation time is admittedly more useful. */
b9616b2018-04-19Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_stat(const char *file, PIKE_STAT_T *buf)
e765152002-10-15Martin Stjernholm {
b9616b2018-04-19Henrik Grubbström (Grubba)  ptrdiff_t l; p_wchar1 *fname;
4b2ca02004-11-18Martin Stjernholm  int drive; /* current = -1, A: = 0, B: = 1, ... */ HANDLE hFind;
b9616b2018-04-19Henrik Grubbström (Grubba)  WIN32_FIND_DATAW findbuf; int exec_bits = 0;
4b2ca02004-11-18Martin Stjernholm 
b9616b2018-04-19Henrik Grubbström (Grubba)  /* Note: On NT the following characters are illegal in filenames: * \ / : * ? " < > | * * The first three are valid in paths, so check for the remaining 6. */ if (strpbrk(file, "*?\"<>|"))
e765152002-10-15Martin Stjernholm  { errno = ENOENT; return(-1); }
13670c2015-05-25Martin Nilsson 
b9616b2018-04-19Henrik Grubbström (Grubba)  fname = pike_dwim_utf8_to_utf16(file); if (!fname) { errno = ENOMEM; return -1; } l = wcslen(fname); /* Get rid of terminating slashes. */ while (l && ISSEPARATOR(fname[l-1])) { fname[--l] = 0; }
205b602018-05-15Martin Nilsson  if( l==0 ) { errno = ENOENT; return -1; }
b9616b2018-04-19Henrik Grubbström (Grubba) 
e765152002-10-15Martin Stjernholm  /* get disk from file */
b9616b2018-04-19Henrik Grubbström (Grubba)  if (fname[1] == ':') drive = toupper(*fname) - 'A';
e765152002-10-15Martin Stjernholm  else
4b2ca02004-11-18Martin Stjernholm  drive = -1;
8c1a2b2012-07-02Martin Stjernholm 
b9616b2018-04-19Henrik Grubbström (Grubba)  /* Look at the extension to see if a file appears to be executable. */ if ((l >= 4) && (fname[l-4] == '.')) { char ext[4]; int i; for (i = 0; i < 3; i++) { p_wchar1 c = fname[l + i - 4]; ext[i] = (c > 128)?0:tolower(c); } ext[3] = 0; if (!strcmp (ext, "exe") || !strcmp (ext, "cmd") || !strcmp (ext, "bat") || !strcmp (ext, "com")) exec_bits = 0111; /* Execute perm for all. */ }
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "fd_stat %s drive %d\n", file, drive));
8c1a2b2012-07-02Martin Stjernholm 
e765152002-10-15Martin Stjernholm  /* get info for file */
b9616b2018-04-19Henrik Grubbström (Grubba)  hFind = FindFirstFileW(fname, &findbuf);
4b2ca02004-11-18Martin Stjernholm 
e765152002-10-15Martin Stjernholm  if ( hFind == INVALID_HANDLE_VALUE ) {
2a75a02006-06-20Martin Stjernholm  UINT drive_type;
b9616b2018-04-19Henrik Grubbström (Grubba)  p_wchar1 *abspath;
2a75a02006-06-20Martin Stjernholm 
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "check root dir\n"));
8c1a2b2012-07-02Martin Stjernholm 
a825be2012-07-02Martin Stjernholm  if (!strpbrk(file, ":./\\")) {
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "no path separators\n"));
b9616b2018-04-19Henrik Grubbström (Grubba)  free(fname);
a825be2012-07-02Martin Stjernholm  errno = ENOENT; return -1; }
b9616b2018-04-19Henrik Grubbström (Grubba)  /* NB: One extra byte for the terminating separator. */ abspath = malloc((l + _MAX_PATH + 1 + 1) * sizeof(p_wchar1)); if (!abspath) { free(fname); errno = ENOMEM; return -1; } if (!_wfullpath( abspath, fname, l + _MAX_PATH ) ||
a825be2012-07-02Martin Stjernholm  /* Neither root dir ('C:\') nor UNC root dir ('\\server\share\'). */
b9616b2018-04-19Henrik Grubbström (Grubba)  (wcslen(abspath) > 3 && !IsUncRoot (abspath))) { STATDEBUG (fprintf (stderr, "not a root %S\n", abspath)); free(abspath); free(fname);
e765152002-10-15Martin Stjernholm  errno = ENOENT;
2a75a02006-06-20Martin Stjernholm  return -1;
e765152002-10-15Martin Stjernholm  }
2a75a02006-06-20Martin Stjernholm 
b9616b2018-04-19Henrik Grubbström (Grubba)  free(fname); fname = NULL;
c0bd392012-07-02Martin Stjernholm 
b9616b2018-04-19Henrik Grubbström (Grubba)  STATDEBUG (fprintf (stderr, "abspath: %S\n", abspath)); l = wcslen(abspath);
2a75a02006-06-20Martin Stjernholm  if (!ISSEPARATOR (abspath[l - 1])) { /* Ensure there's a slash at the end or else GetDriveType * won't like it. */ abspath[l] = '\\'; abspath[l + 1] = 0; }
b9616b2018-04-19Henrik Grubbström (Grubba)  drive_type = GetDriveTypeW (abspath);
2a75a02006-06-20Martin Stjernholm  if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) {
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "invalid drive type: %u\n", drive_type));
b9616b2018-04-19Henrik Grubbström (Grubba)  free(abspath);
2a75a02006-06-20Martin Stjernholm  errno = ENOENT; return -1; }
b9616b2018-04-19Henrik Grubbström (Grubba)  free(abspath); abspath = NULL;
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "faking root stat\n"));
5a8cdd2006-06-20Martin Stjernholm  /* Root directories (e.g. C:\ and \\server\share\) are faked */
e765152002-10-15Martin Stjernholm  findbuf.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; findbuf.nFileSizeHigh = 0; findbuf.nFileSizeLow = 0; findbuf.cFileName[0] = '\0';
5a8cdd2006-06-20Martin Stjernholm  /* Don't have any timestamp info, so set it to some date. The * following is ridiculously complex, but it's compatible with the * stat function in MS CRT. */ { struct tm t; t.tm_year = 1980 - 1900; t.tm_mon = 0; t.tm_mday = 1; t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; t.tm_isdst = -1; buf->st_mtime = mktime (&t); buf->st_atime = buf->st_mtime; buf->st_ctime = buf->st_mtime; }
e765152002-10-15Martin Stjernholm  }
4b2ca02004-11-18Martin Stjernholm  else {
b9616b2018-04-19Henrik Grubbström (Grubba)  p_wchar1 fstype[50];
8c1a2b2012-07-02Martin Stjernholm  /* Really only need room in this buffer for "FAT" and anything * longer that begins with "FAT", but since GetVolumeInformation * has shown to trig unreliable error codes for a too short buffer * (see below), we allocate ample space. */
4b2ca02004-11-18Martin Stjernholm  BOOL res;
b9616b2018-04-19Henrik Grubbström (Grubba)  fstype[0] = '-'; fstype[1] = 0;
205b602018-05-15Martin Nilsson  if (l>=3 && fname[1] == ':') {
b9616b2018-04-19Henrik Grubbström (Grubba)  /* Construct a string "X:\" in fname. */ fname[0] = toupper(fname[0]); fname[2] = '\\'; fname[3] = 0; } else { free(fname); fname = NULL;
4b2ca02004-11-18Martin Stjernholm  }
8c1a2b2012-07-02Martin Stjernholm 
b9616b2018-04-19Henrik Grubbström (Grubba)  res = GetVolumeInformationW (fname, NULL, 0, NULL, NULL,NULL, fstype, sizeof(fstype)/sizeof(fstype[0])); if (fname) { free(fname); fname = NULL; } STATDEBUG (fprintf (stderr, "found, vol info: %d, %S\n", res, fstype));
8c1a2b2012-07-02Martin Stjernholm  if (!res) { unsigned long w32_err = GetLastError(); /* Get ERROR_MORE_DATA if the fstype buffer wasn't long enough, * so let's ignore it. That error is also known to be reported * as ERROR_BAD_LENGTH in Vista and 7. */ if (w32_err != ERROR_MORE_DATA && w32_err != ERROR_BAD_LENGTH) {
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "GetVolumeInformation failure: %d\n", w32_err));
8c1a2b2012-07-02Martin Stjernholm  set_errno_from_win32_error (w32_err); FindClose (hFind); return -1; }
e765152002-10-15Martin Stjernholm  }
b9616b2018-04-19Henrik Grubbström (Grubba)  if (res && (fstype[0] == 'F') && (fstype[1] == 'A') && (fstype[2] == 'T')) {
4b2ca02004-11-18Martin Stjernholm  if (!fat_filetimes_to_stattimes (&findbuf.ftCreationTime, &findbuf.ftLastAccessTime, &findbuf.ftLastWriteTime, buf)) {
c0bd392012-07-02Martin Stjernholm  STATDEBUG (fprintf (stderr, "fat_filetimes_to_stattimes failed.\n"));
4b2ca02004-11-18Martin Stjernholm  FindClose (hFind); return -1;
e765152002-10-15Martin Stjernholm  }
4b2ca02004-11-18Martin Stjernholm  } else /* Any non-fat filesystem is assumed to have sane timestamps. */ nonfat_filetimes_to_stattimes (&findbuf.ftCreationTime, &findbuf.ftLastAccessTime, &findbuf.ftLastWriteTime, buf);
e765152002-10-15Martin Stjernholm  FindClose(hFind); }
5a8cdd2006-06-20Martin Stjernholm  if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) /* Always label a directory as executable. Note that this also * catches special locations like root dirs and network share * roots. */ buf->st_mode = S_IFDIR | 0111; else {
b9616b2018-04-19Henrik Grubbström (Grubba)  buf->st_mode = S_IFREG | exec_bits;
5a8cdd2006-06-20Martin Stjernholm  } /* The file is read/write unless the read only flag is set. */ if (findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) buf->st_mode |= 0444; /* Read perm for all. */ else buf->st_mode |= 0666; /* Read and write perm for all. */
e765152002-10-15Martin Stjernholm  buf->st_nlink = 1;
0239412003-03-28Martin Stjernholm  buf->st_size = ((INT64) findbuf.nFileSizeHigh << 32) + findbuf.nFileSizeLow;
13670c2015-05-25Martin Nilsson 
e765152002-10-15Martin Stjernholm  buf->st_uid = buf->st_gid = buf->st_ino = 0; /* unused entries */
4b2ca02004-11-18Martin Stjernholm  buf->st_rdev = buf->st_dev = (_dev_t) (drive >= 0 ? drive : _getdrive() - 1); /* A=0, B=1, ... */
84f8952000-08-16Henrik Grubbström (Grubba) 
4b2ca02004-11-18Martin Stjernholm  return(0);
b602dc2000-06-16Fredrik Hübinette (Hubbe) }
f8b8012018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_truncate(const char *file, INT64 len) { p_wchar1 *fname = pike_dwim_utf8_to_utf16(file); HANDLE h; LONG high; if (!fname) { errno = ENOMEM; return -1; } h = CreateFileW(fname, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); free(fname); if (h == INVALID_HANDLE_VALUE) { errno = GetLastError(); return -1; }
faacc82018-05-09Henrik Grubbström (Grubba)  high = (LONG)(len >> 32);
f8b8012018-04-20Henrik Grubbström (Grubba)  len &= (INT64)0xffffffffUL;
faacc82018-05-09Henrik Grubbström (Grubba)  if (SetFilePointer(h, (long)len, &high, FILE_BEGIN) ==
f8b8012018-04-20Henrik Grubbström (Grubba)  INVALID_SET_FILE_POINTER) { DWORD err = GetLastError(); if (err != NO_ERROR) { errno = err; CloseHandle(h); return -1; } } if (!SetEndOfFile(h)) { errno = GetLastError(); CloseHandle(h); return -1; } CloseHandle(h); return 0; }
6f8c4d2018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_rmdir(const char *dir) { p_wchar1 *dname = pike_dwim_utf8_to_utf16(dir); int ret; if (!dname) { errno = ENOMEM; return -1; } ret = _wrmdir(dname);
0b90c82018-04-26Henrik Grubbström (Grubba)  if (ret && (errno == EACCES)) {
6f8c4d2018-04-20Henrik Grubbström (Grubba)  PIKE_STAT_T st; if (!fd_stat(dir, &st) && !(st.st_mode & _S_IWRITE) && !_wchmod(dname, st.st_mode | _S_IWRITE)) { /* Retry with write permission. */ ret = _wrmdir(dname); if (ret) { /* Failed anyway. Restore original permissions. */ int err = errno; _wchmod(dname, st.st_mode); errno = err; } } } free(dname); return ret; }
09e1e52018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_unlink(const char *file) { p_wchar1 *fname = pike_dwim_utf8_to_utf16(file); int ret; if (!fname) { errno = ENOMEM; return -1; } ret = _wunlink(fname);
0b90c82018-04-26Henrik Grubbström (Grubba)  if (ret && (errno == EACCES)) {
09e1e52018-04-20Henrik Grubbström (Grubba)  PIKE_STAT_T st; if (!fd_stat(file, &st) && !(st.st_mode & _S_IWRITE) && !_wchmod(fname, st.st_mode | _S_IWRITE)) { /* Retry with write permission. */ ret = _wunlink(fname); if (ret) { /* Failed anyway. Restore original permissions. */ int err = errno; _wchmod(fname, st.st_mode); errno = err; } } } free(fname); return ret; }
8778e92018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_mkdir(const char *dir, int mode) { p_wchar1 *dname = pike_dwim_utf8_to_utf16(dir); int ret; int mask; if (!dname) { errno = ENOMEM; return -1; } mask = _umask(~mode & 0777); _umask(~mode & mask & 0777); ret = _wmkdir(dname); _wchmod(dname, mode & ~mask & 0777); _umask(mask); free(dname); return ret; }
4487da2018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_rename(const char *old, const char *new) { p_wchar1 *oname = pike_dwim_utf8_to_utf16(old); p_wchar1 *nname; int ret; if (!oname) { errno = ENOMEM; return -1; } nname = pike_dwim_utf8_to_utf16(new); if (!nname) { free(oname); errno = ENOMEM; return -1; } if (Pike_NT_MoveFileExW) { int retried = 0; PIKE_STAT_T st; ret = 0; retry: if (!Pike_NT_MoveFileExW(oname, nname, MOVEFILE_REPLACE_EXISTING)) { DWORD err = GetLastError(); if ((err == ERROR_ACCESS_DENIED) && !retried) { /* This happens when the destination is an already existing * directory. On POSIX this operation is valid if oname and * nname are directories, and the nname directory is empty. */ if (!fd_stat(old, &st) && ((st.st_mode & S_IFMT) == S_IFDIR) && !fd_stat(new, &st) && ((st.st_mode & S_IFMT) == S_IFDIR) && !_wrmdir(nname)) { /* Succeeded in removing the destination. This implies * that it was an empty directory. * * Retry. */ retried = 1; goto retry; } } if (retried) { /* Recreate the destination directory that we deleted above. */ _wmkdir(nname); /* NB: st still contains the flags from the original nname dir. */ _wchmod(nname, st.st_mode & 0777); } ret = -1; set_errno_from_win32_error(err); } } else { /* Fall back to rename() for W98 and earlier. Unlike MoveFileEx, * it can't move directories between directories. */ ret = _wrename(oname, nname); } free(oname); free(nname); return ret; }
b1da372018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT int debug_fd_chdir(const char *dir) { p_wchar1 *dname = pike_dwim_utf8_to_utf16(dir); int ret; if (!dname) { errno = ENOMEM; return -1; } ret = _wchdir(dname); free(dname); return ret; }
4cd5602018-04-20Henrik Grubbström (Grubba) PMOD_EXPORT char *debug_fd_get_current_dir_name(void) { /* NB: Windows CRT _wgetcwd() has a special case for buf == NULL, * where the buffer is instead allocated with malloc(), and * len is the minimum buffer size to allocate. */ p_wchar1 *utf16buffer = _wgetcwd(NULL, 0); p_wchar0 *utf8buffer; if (!utf16buffer) { errno = ENOMEM; return NULL; } utf8buffer = pike_utf16_to_utf8(utf16buffer); libc_free(utf16buffer); if (!utf8buffer) { errno = ENOMEM; return NULL; } return utf8buffer; }
0557002018-05-11Henrik Grubbström (Grubba) PMOD_EXPORT char *debug_fd_normalize_path(const char *path) { p_wchar1 *pname = pike_dwim_utf8_to_utf16(path); p_wchar1 *buffer; char *res; size_t len; PIDLIST_ABSOLUTE idl; HRESULT hres; if (!pname) { errno = ENOMEM; return NULL; } /* First convert to an absolute path. */ len = MAX_PATH; do { size_t ret; buffer = malloc(len * sizeof(p_wchar1)); if (!buffer) { errno = ENOMEM; return NULL; } ret = GetFullPathNameW(pname, len, buffer, NULL); if (!ret) { set_errno_from_win32_error(GetLastError()); return NULL; } if (ret*2 < len) break; /* Buffer too small. Reallocate. * NB: We over allocate 100% to be able to reuse the * buffer safely with SHGetPathFromIDListW() below. */ free(buffer); len = (ret+1)*2; } while(1); free(pname); if ((hres = isf->lpVtbl->ParseDisplayName(isf, NULL, NULL, buffer, NULL, &idl, NULL)) != S_OK) { free(buffer); set_errno_from_win32_error(hres); return NULL; } if (!SHGetPathFromIDListW(idl, buffer)) { /* FIXME: Use SHGetPathFromIDListExW() (Vista/2008 and later), * to ensure that we don't overrun the buffer. * It however doesn't seem to be documented how * to detect whether it fails due to a too small * buffer or for some other reason, so we couldn't * use it to grow the res buffer and retry. */ free(buffer); CoTaskMemFree (idl); errno = EINVAL; return NULL; } CoTaskMemFree (idl); /* Remove trailing slashes, except after a drive letter. */ len = wcslen(buffer);
fa5b2a2018-05-14Henrik Grubbström (Grubba)  while(len && buffer[len-1]=='\\') {
0557002018-05-11Henrik Grubbström (Grubba)  len--; }
ca7dfd2018-05-14Henrik Grubbström (Grubba)  if (!len || (len == 2 && buffer[len-1] == ':')) { buffer[len++] = '\\'; }
0557002018-05-11Henrik Grubbström (Grubba)  buffer[len + 1] = 0; /* Convert host and share in an UNC path to lowercase since Windows * Shell doesn't do that consistently. */
205b602018-05-15Martin Nilsson  if (len>1) { if (buffer[0] == '\\' && buffer[1] == '\\') { size_t i; int segments; p_wchar1 c; for (i = segments = 2; (c = buffer[i]) && segments; i++) { if (c >= 256) continue; buffer[i] = tolower(buffer[i]); if (c == '\\') { segments--; }
0557002018-05-11Henrik Grubbström (Grubba)  }
205b602018-05-15Martin Nilsson  } else if ((buffer[1] == ':') && (buffer[0] < 256)) { /* Normalize the drive letter to upper-case. */ buffer[0] = toupper(buffer[0]);
0557002018-05-11Henrik Grubbström (Grubba)  } } res = pike_utf16_to_utf8(buffer); free(buffer); if (!res) { errno = ENOMEM; return NULL; } return res; }
d78ecb2001-04-23Marcus Comstedt PMOD_EXPORT FD debug_fd_open(const char *file, int open_mode, int create_mode)
5740881998-01-01Fredrik Hübinette (Hubbe) { HANDLE x; FD fd;
b657482004-11-20Martin Nilsson  DWORD omode,cmode = 0,amode;
b602dc2000-06-16Fredrik Hübinette (Hubbe) 
a045212018-04-19Henrik Grubbström (Grubba)  ptrdiff_t l; p_wchar1 *fname;
84f8952000-08-16Henrik Grubbström (Grubba) 
a045212018-04-19Henrik Grubbström (Grubba)  /* Note: On NT the following characters are illegal in filenames: * \ / : * ? " < > | * * The first three are valid in paths, so check for the remaining 6. */ if (strpbrk(file, "*?\"<>|"))
b602dc2000-06-16Fredrik Hübinette (Hubbe)  {
a045212018-04-19Henrik Grubbström (Grubba)  /* ENXIO: * "The file is a device special file and no corresponding device * exists." */ errno = ENXIO; return -1; } fname = pike_dwim_utf8_to_utf16(file); if (!fname) { errno = ENOMEM; return -1; } l = wcslen(fname); /* Get rid of terminating slashes. */ while (l && ISSEPARATOR(fname[l-1])) { fname[--l] = 0;
b602dc2000-06-16Fredrik Hübinette (Hubbe)  }
5740881998-01-01Fredrik Hübinette (Hubbe)  omode=0;
a045212018-04-19Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_open(%S, 0x%x, %o)\n", fname, open_mode, create_mode));
7bfa602018-04-25Henrik Grubbström (Grubba)  fd = allocate_fd(FD_FILE, INVALID_HANDLE_VALUE); if (fd < 0) {
a045212018-04-19Henrik Grubbström (Grubba)  free(fname);
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; } if(open_mode & fd_RDONLY) omode|=GENERIC_READ; if(open_mode & fd_WRONLY) omode|=GENERIC_WRITE;
13670c2015-05-25Martin Nilsson 
5740881998-01-01Fredrik Hübinette (Hubbe)  switch(open_mode & (fd_CREAT | fd_TRUNC | fd_EXCL)) { case fd_CREAT | fd_TRUNC: cmode=CREATE_ALWAYS; break; case fd_TRUNC: case fd_TRUNC | fd_EXCL: cmode=TRUNCATE_EXISTING; break; case fd_CREAT: cmode=OPEN_ALWAYS; break; case fd_CREAT | fd_EXCL: case fd_CREAT | fd_EXCL | fd_TRUNC: cmode=CREATE_NEW; break; case 0: case fd_EXCL: cmode=OPEN_EXISTING; break; }
e12e502002-03-15Tomas Nilsson  if(create_mode & 0222)
5740881998-01-01Fredrik Hübinette (Hubbe)  { amode=FILE_ATTRIBUTE_NORMAL; }else{ amode=FILE_ATTRIBUTE_READONLY; }
13670c2015-05-25Martin Nilsson 
a045212018-04-19Henrik Grubbström (Grubba)  x=CreateFileW(fname, omode, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, cmode, amode, NULL);
5740881998-01-01Fredrik Hübinette (Hubbe) 
13670c2015-05-25Martin Nilsson 
bd67392015-10-14Martin Nilsson  if(x == INVALID_HANDLE_VALUE)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
a56e682008-10-17Martin Stjernholm  unsigned long err = GetLastError();
a045212018-04-19Henrik Grubbström (Grubba)  free(fname);
a56e682008-10-17Martin Stjernholm  if (err == ERROR_INVALID_NAME) /* An invalid name means the file doesn't exist. This is * consistent with fd_stat, opendir, and unix. */ errno = ENOENT; else set_errno_from_win32_error (err);
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; }
5ed1a61998-05-05Fredrik Hübinette (Hubbe)  SetHandleInformation(x,HANDLE_FLAG_INHERIT|HANDLE_FLAG_PROTECT_FROM_CLOSE,0);
7bfa602018-04-25Henrik Grubbström (Grubba)  set_fd_handle(fd, x);
e42eaf1998-01-02Fredrik Hübinette (Hubbe) 
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
1d7b371998-05-01Fredrik Hübinette (Hubbe)  if(open_mode & fd_APPEND) fd_lseek(fd,0,SEEK_END);
a045212018-04-19Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Opened %S file as %d (%d)\n", fname, fd, x)); free(fname);
5740881998-01-01Fredrik Hübinette (Hubbe)  return fd; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT FD debug_fd_socket(int domain, int type, int proto)
5740881998-01-01Fredrik Hübinette (Hubbe) { FD fd; SOCKET s;
7bfa602018-04-25Henrik Grubbström (Grubba)  fd = allocate_fd(FD_SOCKET, (HANDLE)INVALID_SOCKET); if (fd < 0) return -1;
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
bcf9461998-01-27Fredrik Hübinette (Hubbe)  s=socket(domain, type, proto);
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
5740881998-01-01Fredrik Hübinette (Hubbe)  if(s==INVALID_SOCKET) {
7bfa602018-04-25Henrik Grubbström (Grubba)  DWORD err = WSAGetLastError(); free_fd(fd); set_errno_from_win32_error (err);
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; }
13670c2015-05-25Martin Nilsson 
948d282000-08-17Henrik Grubbström (Grubba)  SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT|HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
7bfa602018-04-25Henrik Grubbström (Grubba)  set_fd_handle(fd, (HANDLE)s);
e42eaf1998-01-02Fredrik Hübinette (Hubbe) 
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"New socket: %d (%d)\n",fd,s));
5740881998-01-01Fredrik Hübinette (Hubbe)  return fd; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_pipe(int fds[2] DMALLOC_LINE_ARGS)
bcf9461998-01-27Fredrik Hübinette (Hubbe) {
9fb5c12015-04-29Henrik Grubbström (Grubba)  int tmp_fds[2];
bcf9461998-01-27Fredrik Hübinette (Hubbe)  HANDLE files[2];
7bfa602018-04-25Henrik Grubbström (Grubba)  tmp_fds[0] = allocate_fd(FD_PIPE, INVALID_HANDLE_VALUE); if (tmp_fds[0] < 0) {
bcf9461998-01-27Fredrik Hübinette (Hubbe)  return -1; }
7bfa602018-04-25Henrik Grubbström (Grubba)  tmp_fds[1] = allocate_fd(FD_PIPE, INVALID_HANDLE_VALUE); if (tmp_fds[1] < 0) { free_fd(tmp_fds[0]);
bcf9461998-01-27Fredrik Hübinette (Hubbe)  return -1; }
9fb5c12015-04-29Henrik Grubbström (Grubba) 
bcf9461998-01-27Fredrik Hübinette (Hubbe)  if(!CreatePipe(&files[0], &files[1], NULL, 0)) {
7bfa602018-04-25Henrik Grubbström (Grubba)  DWORD err = GetLastError(); free_fd(tmp_fds[0]); free_fd(tmp_fds[1]); set_errno_from_win32_error (err);
bcf9461998-01-27Fredrik Hübinette (Hubbe)  return -1; }
13670c2015-05-25Martin Nilsson 
9fb5c12015-04-29Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "ReadHANDLE=%d WriteHANDLE=%d\n", files[0], files[1]));
13670c2015-05-25Martin Nilsson 
9fb5c12015-04-29Henrik Grubbström (Grubba)  SetHandleInformation(files[0], HANDLE_FLAG_INHERIT|HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); SetHandleInformation(files[1], HANDLE_FLAG_INHERIT|HANDLE_FLAG_PROTECT_FROM_CLOSE, 0); fds[0] = tmp_fds[0];
7bfa602018-04-25Henrik Grubbström (Grubba)  set_fd_handle(fds[0], files[0]);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fds[0]);
9fb5c12015-04-29Henrik Grubbström (Grubba)  fds[1] = tmp_fds[1];
7bfa602018-04-25Henrik Grubbström (Grubba)  set_fd_handle(fds[1], files[1]);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fds[1]);
9fb5c12015-04-29Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"New pipe: %d (%d) -> %d (%d)\n", fds[0], files[0], fds[1], files[1]));
bcf9461998-01-27Fredrik Hübinette (Hubbe) 
ec7d6d1999-05-13Fredrik Hübinette (Hubbe) #ifdef DEBUG_MALLOC
61cd252000-06-16Fredrik Hübinette (Hubbe)  debug_malloc_register_fd( fds[0], DMALLOC_LOCATION()); debug_malloc_register_fd( fds[1], DMALLOC_LOCATION());
ec7d6d1999-05-13Fredrik Hübinette (Hubbe) #endif
13670c2015-05-25Martin Nilsson 
bcf9461998-01-27Fredrik Hübinette (Hubbe)  return 0; }
6f1a2c2000-09-01Henrik Grubbström (Grubba) PMOD_EXPORT FD debug_fd_accept(FD fd, struct sockaddr *addr, ACCEPT_SIZE_T *addrlen)
5740881998-01-01Fredrik Hübinette (Hubbe) { FD new_fd; SOCKET s;
7bfa602018-04-25Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_accept(%d, %p, %p)...\n", fd, addr, addrlen));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_socket(fd, &s) < 0) return -1;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Accept on %d (%ld)..\n", fd, PTRDIFF_T_TO_LONG((ptrdiff_t)s)));
7bfa602018-04-25Henrik Grubbström (Grubba)  new_fd = allocate_fd(FD_SOCKET, (HANDLE)INVALID_SOCKET); if (new_fd < 0) return -1; s = accept(s, addr, addrlen);
ae65d52018-05-08Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  if(s==INVALID_SOCKET) {
7bfa602018-04-25Henrik Grubbström (Grubba)  DWORD err = WSAGetLastError(); free_fd(new_fd); set_errno_from_win32_error(err);
bcf9461998-01-27Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"Accept failed with errno %d\n",errno));
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; }
13670c2015-05-25Martin Nilsson 
948d282000-08-17Henrik Grubbström (Grubba)  SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT|HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
7bfa602018-04-25Henrik Grubbström (Grubba)  set_fd_handle(new_fd, (HANDLE)s);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(new_fd);
e42eaf1998-01-02Fredrik Hübinette (Hubbe) 
948d282000-08-17Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Accept on %d (%ld) returned new socket: %d (%ld)\n",
6da27e2016-02-12Martin Nilsson  fd, (long)(ptrdiff_t)da_handle[fd], new_fd, (long)(ptrdiff_t)s));
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return new_fd;
5740881998-01-01Fredrik Hübinette (Hubbe) }
61e9a01998-01-25Fredrik Hübinette (Hubbe) 
5740881998-01-01Fredrik Hübinette (Hubbe) #define SOCKFUN(NAME,X1,X2) \
e0111b2000-08-20Henrik Grubbström (Grubba) PMOD_EXPORT int PIKE_CONCAT(debug_fd_,NAME) X1 { \ SOCKET s; \ int ret; \
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_" #NAME "(%d, ...)...\n", fd)); \
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_socket(fd, &s) < 0) return -1; \
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, #NAME " on %d (%ld)\n", \ fd, (long)(ptrdiff_t)s)); \
e0111b2000-08-20Henrik Grubbström (Grubba)  ret = NAME X2; \
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd); \
e0111b2000-08-20Henrik Grubbström (Grubba)  if(ret == SOCKET_ERROR) { \
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (WSAGetLastError()); \
e0111b2000-08-20Henrik Grubbström (Grubba)  ret = -1; \ } \ FDDEBUG(fprintf(stderr, #NAME " returned %d (%d)\n", ret, errno)); \ return ret; \
5740881998-01-01Fredrik Hübinette (Hubbe) } #define SOCKFUN1(NAME,T1) \
e0111b2000-08-20Henrik Grubbström (Grubba)  SOCKFUN(NAME, (FD fd, T1 a), (s, a) )
5740881998-01-01Fredrik Hübinette (Hubbe)  #define SOCKFUN2(NAME,T1,T2) \
e0111b2000-08-20Henrik Grubbström (Grubba)  SOCKFUN(NAME, (FD fd, T1 a, T2 b), (s, a, b) )
5740881998-01-01Fredrik Hübinette (Hubbe)  #define SOCKFUN3(NAME,T1,T2,T3) \
e0111b2000-08-20Henrik Grubbström (Grubba)  SOCKFUN(NAME, (FD fd, T1 a, T2 b, T3 c), (s, a, b, c) )
5740881998-01-01Fredrik Hübinette (Hubbe)  #define SOCKFUN4(NAME,T1,T2,T3,T4) \
e0111b2000-08-20Henrik Grubbström (Grubba)  SOCKFUN(NAME, (FD fd, T1 a, T2 b, T3 c, T4 d), (s, a, b, c, d) )
5740881998-01-01Fredrik Hübinette (Hubbe)  #define SOCKFUN5(NAME,T1,T2,T3,T4,T5) \
e0111b2000-08-20Henrik Grubbström (Grubba)  SOCKFUN(NAME, (FD fd, T1 a, T2 b, T3 c, T4 d, T5 e), (s, a, b, c, d, e))
5740881998-01-01Fredrik Hübinette (Hubbe)  SOCKFUN2(bind, struct sockaddr *, int)
7b38502000-07-02Henrik Grubbström (Grubba) SOCKFUN4(getsockopt,int,int,void*,ACCEPT_SIZE_T *)
ec7d6d1999-05-13Fredrik Hübinette (Hubbe) SOCKFUN4(setsockopt,int,int,void*,int) SOCKFUN3(recv,void *,int,int)
7b38502000-07-02Henrik Grubbström (Grubba) SOCKFUN2(getsockname,struct sockaddr *,ACCEPT_SIZE_T *) SOCKFUN2(getpeername,struct sockaddr *,ACCEPT_SIZE_T *) SOCKFUN5(recvfrom,void *,int,int,struct sockaddr *,ACCEPT_SIZE_T *)
ec7d6d1999-05-13Fredrik Hübinette (Hubbe) SOCKFUN3(send,void *,int,int)
06e4c12000-06-27Henrik Grubbström (Grubba) SOCKFUN5(sendto,void *,int,int,struct sockaddr *,unsigned int)
ec7d6d1999-05-13Fredrik Hübinette (Hubbe) SOCKFUN1(shutdown, int) SOCKFUN1(listen, int)
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_connect (FD fd, struct sockaddr *a, int len)
61e9a01998-01-25Fredrik Hübinette (Hubbe) { SOCKET ret;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_connect(%d, %p, %d)...\n", fd, a, len)); if (fd_to_socket(fd, &ret) < 0) return -1;
948d282000-08-17Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "connect on %d (%ld)\n",
32fc1a2018-05-08Henrik Grubbström (Grubba)  fd, (long)(ptrdiff_t)ret);
1287a72018-04-27Henrik Grubbström (Grubba)  { int i; for(i = 0 ; i < len ; i++) fprintf(stderr," %02x",((unsigned char *)a)[i]); fprintf(stderr,"\n"); }
7bfa602018-04-25Henrik Grubbström (Grubba)  );
13670c2015-05-25Martin Nilsson  ret=connect(ret,a,len);
7bfa602018-04-25Henrik Grubbström (Grubba) 
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
a56e682008-10-17Martin Stjernholm  if(ret == SOCKET_ERROR) set_errno_from_win32_error (WSAGetLastError());
13670c2015-05-25Martin Nilsson  FDDEBUG(fprintf(stderr, "connect returned %d (%d)\n",ret,errno));
bd67392015-10-14Martin Nilsson  return (int)ret;
61e9a01998-01-25Fredrik Hübinette (Hubbe) }
5740881998-01-01Fredrik Hübinette (Hubbe) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_close(FD fd)
5740881998-01-01Fredrik Hübinette (Hubbe) {
948d282000-08-17Henrik Grubbström (Grubba)  HANDLE h;
a3d1241998-05-07Fredrik Hübinette (Hubbe)  int type;
7bfa602018-04-25Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_close(%d)...\n", fd));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, &h) < 0) return -1;
948d282000-08-17Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Closing %d (%ld)\n",
fc1e9b2018-04-26Henrik Grubbström (Grubba)  fd, (long)h));
7bfa602018-04-25Henrik Grubbström (Grubba)  free_fd(fd);
a3d1241998-05-07Fredrik Hübinette (Hubbe)  switch(type)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
a3d1241998-05-07Fredrik Hübinette (Hubbe)  case FD_SOCKET: if(closesocket((SOCKET)h)) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
948d282000-08-17Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Closing %d (%ld) failed with errno=%d\n",
32fc1a2018-05-08Henrik Grubbström (Grubba)  fd, (long)(ptrdiff_t)h, errno));
a3d1241998-05-07Fredrik Hübinette (Hubbe)  return -1; } break; default:
948d282000-08-17Henrik Grubbström (Grubba)  if(!CloseHandle(h))
a3d1241998-05-07Fredrik Hübinette (Hubbe)  {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
a3d1241998-05-07Fredrik Hübinette (Hubbe)  return -1; }
5740881998-01-01Fredrik Hübinette (Hubbe)  }
7bfa602018-04-25Henrik Grubbström (Grubba) 
32fc1a2018-05-08Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"%d (%ld) closed\n", fd, (ptrdiff_t)h));
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
5740881998-01-01Fredrik Hübinette (Hubbe)  return 0; }
3ddd122000-08-20Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t debug_fd_write(FD fd, void *buf, ptrdiff_t len)
5740881998-01-01Fredrik Hübinette (Hubbe) {
3ddd122000-08-20Henrik Grubbström (Grubba)  int kind;
948d282000-08-17Henrik Grubbström (Grubba)  HANDLE handle;
3ddd122000-08-20Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_write(%d, %p, %ld)...\n", fd, buf, (long)len));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &kind, &handle) < 0) return -1;
13670c2015-05-25Martin Nilsson 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Writing %d bytes to %d (%d)\n", len, fd, (long)(ptrdiff_t)handle));
3ddd122000-08-20Henrik Grubbström (Grubba)  switch(kind)
5740881998-01-01Fredrik Hübinette (Hubbe)  { case FD_SOCKET: {
bd67392015-10-14Martin Nilsson  ptrdiff_t ret = send((SOCKET)handle, buf, (int)len, 0);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
3ddd122000-08-20Henrik Grubbström (Grubba)  if(ret<0) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (WSAGetLastError());
3ddd122000-08-20Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Write on %d failed (%d)\n", fd, errno)); if (errno == 1) { /* UGLY kludge */ errno = WSAEWOULDBLOCK; } return -1;
9840431999-08-06Henrik Grubbström (Grubba)  }
3ddd122000-08-20Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Wrote %d bytes to %d)\n", len, fd)); return ret;
5740881998-01-01Fredrik Hübinette (Hubbe)  } case FD_CONSOLE: case FD_FILE:
bcf9461998-01-27Fredrik Hübinette (Hubbe)  case FD_PIPE:
5740881998-01-01Fredrik Hübinette (Hubbe)  {
3ddd122000-08-20Henrik Grubbström (Grubba)  DWORD ret = 0;
bd67392015-10-14Martin Nilsson  if(!WriteFile(handle, buf, (DWORD)len, &ret,0) && ret<=0)
3ddd122000-08-20Henrik Grubbström (Grubba)  {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
3ddd122000-08-20Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "Write on %d failed (%d)\n", fd, errno));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
3ddd122000-08-20Henrik Grubbström (Grubba)  return -1; } FDDEBUG(fprintf(stderr, "Wrote %ld bytes to %d)\n", (long)ret, fd));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
3ddd122000-08-20Henrik Grubbström (Grubba)  return ret;
5740881998-01-01Fredrik Hübinette (Hubbe)  } default: errno=ENOTSUPP;
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; } }
7bc62b2000-08-18Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t debug_fd_read(FD fd, void *to, ptrdiff_t len)
5740881998-01-01Fredrik Hübinette (Hubbe) {
7bfa602018-04-25Henrik Grubbström (Grubba)  int type;
5740881998-01-01Fredrik Hübinette (Hubbe)  DWORD ret;
7bc62b2000-08-18Henrik Grubbström (Grubba)  ptrdiff_t rret;
948d282000-08-17Henrik Grubbström (Grubba)  HANDLE handle;
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf("fd_read(%d, %p, %ld)...\n", fd, to, (long)len));
5a7ab61998-01-31Fredrik Hübinette (Hubbe) 
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, &handle) < 0) return -1;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Reading %d bytes from %d (%d) to %lx\n", len, fd, (long)(ptrdiff_t)h, (unsigned long)(ptrdiff_t)to));
7bfa602018-04-25Henrik Grubbström (Grubba)  switch(type)
5740881998-01-01Fredrik Hübinette (Hubbe)  { case FD_SOCKET:
bd67392015-10-14Martin Nilsson  rret=recv((SOCKET)handle, to, (int)len, 0);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  if(rret<0)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (WSAGetLastError());
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"Read on %d failed %ld\n",fd,errno));
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; }
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"Read on %d returned %ld\n",fd,rret)); return rret;
5740881998-01-01Fredrik Hübinette (Hubbe)  case FD_CONSOLE: case FD_FILE:
bcf9461998-01-27Fredrik Hübinette (Hubbe)  case FD_PIPE:
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  ret=0;
bd67392015-10-14Martin Nilsson  while(len && !ReadFile(handle, to, (DWORD)len, &ret, 0) && ret<=0) {
a56e682008-10-17Martin Stjernholm  unsigned int err = GetLastError();
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (err); switch(err)
5ed1a61998-05-05Fredrik Hübinette (Hubbe)  {
ccfebb2015-03-26Henrik Grubbström (Grubba)  case ERROR_NOT_ENOUGH_MEMORY: /* This can happen when reading from stdin, and can be due * to running out of OS io-buffers. cf ReadConsole(): * * | lpBuffer [out] * | A pointer to a buffer that receives the data read from * | the console input buffer. * | * | The storage for this buffer is allocated from a shared * | heap for the process that is 64 KB in size. The maximum * | size of the buffer will depend on heap usage. * * The limit seems to be 26608 bytes on Windows Server 2003, * and 31004 bytes on some versions of Windows XP. * * The gdb people ran into the same bug in 2006. * cf http://permalink.gmane.org/gmane.comp.gdb.patches/29669 * * FIXME: We ought to attempt to fill the remainder of * the buffer on success and full read, but as * this failure mode usually only happens with * the console, we would risk blocking, so let * the higher levels of code deal with the * resulting short reads. */ /* Halve the size of the request and retry. */ len = len >> 1; if (len) continue; /* Total failure. Fall out to the generic error return. */ break;
5ed1a61998-05-05Fredrik Hübinette (Hubbe)  case ERROR_BROKEN_PIPE:
ccfebb2015-03-26Henrik Grubbström (Grubba)  /* Pretend we reached the end of the file */
5ed1a61998-05-05Fredrik Hübinette (Hubbe)  return 0; }
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"Read failed %d\n",errno));
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; }
5a7ab61998-01-31Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"Read on %d returned %ld\n",fd,ret));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  return ret; default: errno=ENOTSUPP;
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; } }
0239412003-03-28Martin Stjernholm PMOD_EXPORT PIKE_OFF_T debug_fd_lseek(FD fd, PIKE_OFF_T pos, int where)
5740881998-01-01Fredrik Hübinette (Hubbe) {
0239412003-03-28Martin Stjernholm  PIKE_OFF_T ret;
7bfa602018-04-25Henrik Grubbström (Grubba)  int type;
948d282000-08-17Henrik Grubbström (Grubba)  HANDLE h;
7bc62b2000-08-18Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_lseek(%d)...\n", fd));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, &h) < 0) return -1; if(type != FD_FILE)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  errno=ENOTSUPP; return -1; }
7bfa602018-04-25Henrik Grubbström (Grubba) 
1d2ea71998-06-05Fredrik Hübinette (Hubbe) #if FILE_BEGIN != SEEK_SET || FILE_CURRENT != SEEK_CUR || FILE_END != SEEK_END switch(where) { case SEEK_SET: where=FILE_BEGIN; break; case SEEK_CUR: where=FILE_CURRENT; break; case SEEK_END: where=FILE_END; break; } #endif
5740881998-01-01Fredrik Hübinette (Hubbe) 
f24b322005-11-17Henrik Grubbström (Grubba)  {
1b61702005-11-18Henrik Grubbström (Grubba) #ifdef HAVE_SETFILEPOINTEREX /* Windows NT based. */
f24b322005-11-17Henrik Grubbström (Grubba)  LARGE_INTEGER li_pos; LARGE_INTEGER li_ret; li_pos.QuadPart = pos; li_ret.QuadPart = 0; if(!SetFilePointerEx(h, li_pos, &li_ret, where)) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
f24b322005-11-17Henrik Grubbström (Grubba)  return -1; } ret = li_ret.QuadPart;
1b61702005-11-18Henrik Grubbström (Grubba) #else /* !HAVE_SETFILEPOINTEREX */ /* Windows 9x based. */
bd67392015-10-14Martin Nilsson  LONG high = (LONG)(pos >> 32);
0239412003-03-28Martin Stjernholm  DWORD err;
9fa9a22006-07-05Martin Stjernholm  pos &= ((INT64) 1 << 32) - 1;
bd67392015-10-14Martin Nilsson  ret = SetFilePointer(h, (LONG)pos, &high, where);
0239412003-03-28Martin Stjernholm  if (ret == INVALID_SET_FILE_POINTER && (err = GetLastError()) != NO_ERROR) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (err);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
0239412003-03-28Martin Stjernholm  return -1; } ret += (INT64) high << 32;
1b61702005-11-18Henrik Grubbström (Grubba) #endif /* HAVE_SETFILEPOINTEREX */ }
0239412003-03-28Martin Stjernholm 
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  return ret; }
0239412003-03-28Martin Stjernholm PMOD_EXPORT int debug_fd_ftruncate(FD fd, PIKE_OFF_T len)
cdf56e1999-05-19Mirar (Pontus Hagland) {
7bfa602018-04-25Henrik Grubbström (Grubba)  int type;
948d282000-08-17Henrik Grubbström (Grubba)  HANDLE h;
0239412003-03-28Martin Stjernholm  LONG oldfp_lo, oldfp_hi, len_hi; DWORD err;
7bc62b2000-08-18Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_ftruncate(%d)...\n", fd));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, &h) < 0) return -1; if(type != FD_FILE)
cdf56e1999-05-19Mirar (Pontus Hagland)  {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
cdf56e1999-05-19Mirar (Pontus Hagland)  errno=ENOTSUPP; return -1; }
d505cf1999-06-02Marcus Comstedt  oldfp_hi = 0;
948d282000-08-17Henrik Grubbström (Grubba)  oldfp_lo = SetFilePointer(h, 0, &oldfp_hi, FILE_CURRENT);
7bc62b2000-08-18Henrik Grubbström (Grubba)  if(!~oldfp_lo) {
0239412003-03-28Martin Stjernholm  err = GetLastError(); if(err != NO_ERROR) {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (err);
d505cf1999-06-02Marcus Comstedt  return -1;
0239412003-03-28Martin Stjernholm  }
d505cf1999-06-02Marcus Comstedt  }
0239412003-03-28Martin Stjernholm 
bd67392015-10-14Martin Nilsson  len_hi = (LONG) (len >> 32);
9fa9a22006-07-05Martin Stjernholm  len &= ((INT64) 1 << 32) - 1;
0239412003-03-28Martin Stjernholm 
bd67392015-10-14Martin Nilsson  if (SetFilePointer (h, (LONG) len, &len_hi, FILE_BEGIN) ==
0239412003-03-28Martin Stjernholm  INVALID_SET_FILE_POINTER && (err = GetLastError()) != NO_ERROR) {
948d282000-08-17Henrik Grubbström (Grubba)  SetFilePointer(h, oldfp_lo, &oldfp_hi, FILE_BEGIN);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (err);
cdf56e1999-05-19Mirar (Pontus Hagland)  return -1; }
0239412003-03-28Martin Stjernholm  if(!SetEndOfFile(h)) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
0239412003-03-28Martin Stjernholm  SetFilePointer(h, oldfp_lo, &oldfp_hi, FILE_BEGIN);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
0239412003-03-28Martin Stjernholm  return -1;
d505cf1999-06-02Marcus Comstedt  }
0239412003-03-28Martin Stjernholm 
b657482004-11-20Martin Nilsson  if (oldfp_hi < len_hi || (oldfp_hi == len_hi && oldfp_lo < len))
0239412003-03-28Martin Stjernholm  if(!~SetFilePointer(h, oldfp_lo, &oldfp_hi, FILE_BEGIN)) { err = GetLastError(); if(err != NO_ERROR) {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (err);
0239412003-03-28Martin Stjernholm  return -1; } }
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
d505cf1999-06-02Marcus Comstedt  return 0;
cdf56e1999-05-19Mirar (Pontus Hagland) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_flock(FD fd, int oper)
d386e61998-03-20Fredrik Hübinette (Hubbe) { long ret;
7bfa602018-04-25Henrik Grubbström (Grubba)  int type;
948d282000-08-17Henrik Grubbström (Grubba)  HANDLE h;
7bfa602018-04-25Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_flock(%d)...\n", fd));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, &h) < 0) return -1; if(type != FD_FILE)
d386e61998-03-20Fredrik Hübinette (Hubbe)  {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
d386e61998-03-20Fredrik Hübinette (Hubbe)  errno=ENOTSUPP; return -1; } if(oper & fd_LOCK_UN) {
948d282000-08-17Henrik Grubbström (Grubba)  ret=UnlockFile(h,
d386e61998-03-20Fredrik Hübinette (Hubbe)  0, 0, 0xffffffff, 0xffffffff); }else{
b657482004-11-20Martin Nilsson  DWORD flags = 0;
d386e61998-03-20Fredrik Hübinette (Hubbe)  OVERLAPPED tmp;
21b12a2014-09-03Martin Nilsson  memset(&tmp, 0, sizeof(tmp));
d386e61998-03-20Fredrik Hübinette (Hubbe)  tmp.Offset=0; tmp.OffsetHigh=0; if(oper & fd_LOCK_EX) flags|=LOCKFILE_EXCLUSIVE_LOCK; if(oper & fd_LOCK_UN) flags|=LOCKFILE_FAIL_IMMEDIATELY;
948d282000-08-17Henrik Grubbström (Grubba)  ret=LockFileEx(h,
d386e61998-03-20Fredrik Hübinette (Hubbe)  flags, 0, 0xffffffff, 0xffffffff, &tmp); }
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
d386e61998-03-20Fredrik Hübinette (Hubbe)  if(ret<0) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
d386e61998-03-20Fredrik Hübinette (Hubbe)  return -1; }
13670c2015-05-25Martin Nilsson 
d386e61998-03-20Fredrik Hübinette (Hubbe)  return 0; }
4b2ca02004-11-18Martin Stjernholm /* Note: s->st_ctime is set to the file creation time. It should * probably be the last access time to be closer to the unix * counterpart, but the creation time is admittedly more useful. */
40962a2003-03-27Martin Stjernholm PMOD_EXPORT int debug_fd_fstat(FD fd, PIKE_STAT_T *s)
5740881998-01-01Fredrik Hübinette (Hubbe) {
7bfa602018-04-25Henrik Grubbström (Grubba)  int type; HANDLE h;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  FILETIME c,a,m;
6aa7152003-05-02Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_fstat(%d, %p)\n", fd, s));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(fd, &type, &h) < 0) return -1; if (type != FD_FILE)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
5740881998-01-01Fredrik Hübinette (Hubbe)  errno=ENOTSUPP; return -1; }
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fstat on %d (%ld)\n", fd, (long)(ptrdiff_t)h));
21b12a2014-09-03Martin Nilsson  memset(s, 0, sizeof(PIKE_STAT_T));
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  s->st_nlink=1;
7bfa602018-04-25Henrik Grubbström (Grubba)  switch(type)
5740881998-01-01Fredrik Hübinette (Hubbe)  {
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  case FD_SOCKET: s->st_mode=S_IFSOCK; break; default:
7bfa602018-04-25Henrik Grubbström (Grubba)  switch(GetFileType(h))
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  { default: case FILE_TYPE_UNKNOWN: s->st_mode=0; break;
4b2ca02004-11-18Martin Stjernholm 
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  case FILE_TYPE_DISK:
0239412003-03-28Martin Stjernholm  s->st_mode=S_IFREG;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  {
0239412003-03-28Martin Stjernholm  DWORD high, err;
7bfa602018-04-25Henrik Grubbström (Grubba)  s->st_size=GetFileSize(h, &high);
0239412003-03-28Martin Stjernholm  if (s->st_size == INVALID_FILE_SIZE && (err = GetLastError()) != NO_ERROR) {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (err);
0239412003-03-28Martin Stjernholm  return -1; }
9a70222016-02-11Martin Nilsson  s->st_size += (INT64) high << 32; }
7bfa602018-04-25Henrik Grubbström (Grubba)  if(!GetFileTime(h, &c, &a, &m))
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return -1; }
4b2ca02004-11-18Martin Stjernholm  /* FIXME: Determine the filesystem type to use * fat_filetimes_to_stattimes when necessary. */ nonfat_filetimes_to_stattimes (&c, &a, &m, s);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  break;
4b2ca02004-11-18Martin Stjernholm 
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  case FILE_TYPE_CHAR: s->st_mode=S_IFCHR; break;
bb86791999-06-19Fredrik Hübinette (Hubbe)  case FILE_TYPE_PIPE: s->st_mode=S_IFIFO; break;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  }
5740881998-01-01Fredrik Hübinette (Hubbe)  }
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  s->st_mode |= 0666; return 0;
5740881998-01-01Fredrik Hübinette (Hubbe) }
98524e1999-08-06Fredrik Hübinette (Hubbe)  #ifdef FD_DEBUG static void dump_FDSET(FD_SET *x, int fds) { if(x) { int e, first=1; fprintf(stderr,"[");
62949a2018-05-09Henrik Grubbström (Grubba)  for(e = 0; e < FD_SETSIZE; e++)
98524e1999-08-06Fredrik Hübinette (Hubbe)  { if(FD_ISSET(da_handle[e],x)) { if(!first) fprintf(stderr,",",e); fprintf(stderr,"%d",e); first=0; } } fprintf(stderr,"]"); }else{ fprintf(stderr,"0"); } } #endif /* FIXME: * select with no fds should call Sleep() * If the backend works correctly, fds is zero when there are no fds. * /Hubbe */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_select(int fds, FD_SET *a, FD_SET *b, FD_SET *c, struct timeval *t)
5740881998-01-01Fredrik Hübinette (Hubbe) { int ret;
98524e1999-08-06Fredrik Hübinette (Hubbe)  FDDEBUG( int e; fprintf(stderr,"Select(%d,",fds); dump_FDSET(a,fds); dump_FDSET(b,fds); dump_FDSET(c,fds); fprintf(stderr,",(%ld,%06ld));\n", (long) t->tv_sec,(long) t->tv_usec); )
5740881998-01-01Fredrik Hübinette (Hubbe)  ret=select(fds,a,b,c,t); if(ret==SOCKET_ERROR) {
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (WSAGetLastError());
98524e1999-08-06Fredrik Hübinette (Hubbe)  FDDEBUG(fprintf(stderr,"select->%d, errno=%d\n",ret,errno));
5740881998-01-01Fredrik Hübinette (Hubbe)  return -1; }
98524e1999-08-06Fredrik Hübinette (Hubbe)  FDDEBUG( fprintf(stderr," ->(%d,",fds); dump_FDSET(a,fds); dump_FDSET(b,fds); dump_FDSET(c,fds); fprintf(stderr,",(%ld,%06ld));\n", (long) t->tv_sec,(long) t->tv_usec); )
5740881998-01-01Fredrik Hübinette (Hubbe)  return ret; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int debug_fd_ioctl(FD fd, int cmd, void *data)
5740881998-01-01Fredrik Hübinette (Hubbe) { int ret;
7bfa602018-04-25Henrik Grubbström (Grubba)  SOCKET s;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_ioctl(%d, %d, %p)...\n", fd, cmd, data));
5740881998-01-01Fredrik Hübinette (Hubbe) 
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_socket(fd, &s) < 0) return -1;
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"ioctl(%d (%ld,%d,%p)\n", fd, (long)(ptrdiff_t)s, cmd, data));
7bfa602018-04-25Henrik Grubbström (Grubba)  ret = ioctlsocket(s, cmd, data); FDDEBUG(fprintf(stderr,"ioctlsocket returned %ld (%d)\n",ret,errno));
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
7bfa602018-04-25Henrik Grubbström (Grubba)  if(ret==SOCKET_ERROR) { set_errno_from_win32_error (WSAGetLastError());
fceb6c2015-04-29Henrik Grubbström (Grubba)  return -1; }
5740881998-01-01Fredrik Hübinette (Hubbe) 
7bfa602018-04-25Henrik Grubbström (Grubba)  return ret;
5740881998-01-01Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT FD debug_fd_dup(FD from)
5740881998-01-01Fredrik Hübinette (Hubbe) {
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  FD fd;
7bfa602018-04-25Henrik Grubbström (Grubba)  int type; HANDLE h,x,p=GetCurrentProcess();
6aa7152003-05-02Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_dup(%d)...\n", from));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(from, &type, &h) < 0) return -1; fd = allocate_fd(type, (type == FD_SOCKET)? (HANDLE)INVALID_SOCKET:INVALID_HANDLE_VALUE); if(!DuplicateHandle(p, h, p, &x, 0, 0, DUPLICATE_SAME_ACCESS))
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  {
7bfa602018-04-25Henrik Grubbström (Grubba)  DWORD err = GetLastError(); free_fd(fd);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(from);
7bfa602018-04-25Henrik Grubbström (Grubba)  set_errno_from_win32_error(err);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return -1; }
7bfa602018-04-25Henrik Grubbström (Grubba)  set_fd_handle(fd, x);
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Dup %d (%ld) to %d (%d)\n", from, (long)(ptrdiff_t)h, fd, (long)(ptrdiff_t)x)); release_fd(from);
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(fd);
13670c2015-05-25Martin Nilsson 
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return fd;
5740881998-01-01Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT FD debug_fd_dup2(FD from, FD to)
5740881998-01-01Fredrik Hübinette (Hubbe) {
1f16da2018-09-18Henrik Grubbström (Grubba)  struct Backend_struct *backend = NULL; struct fd_callback_box *box = NULL; struct object *box_obj = NULL; int box_events = 0;
7bfa602018-04-25Henrik Grubbström (Grubba)  int type; HANDLE h,x,p=GetCurrentProcess();
6aa7152003-05-02Henrik Grubbström (Grubba) 
7bfa602018-04-25Henrik Grubbström (Grubba)  if ((from == to) || (to < 0) || (to >= FD_SETSIZE)) { errno = EINVAL;
fceb6c2015-04-29Henrik Grubbström (Grubba)  return -1; }
7bfa602018-04-25Henrik Grubbström (Grubba) 
1287a72018-04-27Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr, "fd_dup2(%d, %d)...\n", from, to));
7bfa602018-04-25Henrik Grubbström (Grubba)  if (fd_to_handle(from, &type, &h) < 0) return -1; if(!DuplicateHandle(p, h, p, &x, 0, 0, DUPLICATE_SAME_ACCESS))
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(from);
a56e682008-10-17Martin Stjernholm  set_errno_from_win32_error (GetLastError());
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return -1; }
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(from);
1f16da2018-09-18Henrik Grubbström (Grubba)  backend = get_backend_for_fd(to); if (backend) { box = get_fd_callback_box_for_fd(backend, to); if (box) { /* Temporarily clear the events for the box, to make * sure no events are still registered for the old handle. * * NB: We need to keep a reference to the box object, in * case the only reference was held by the backend. */ box_obj = box->ref_obj; if (box_obj) add_ref(box_obj); box_events = box->events; set_fd_callback_events(box, 0, box->flags); } }
ddeb2a2018-04-26Henrik Grubbström (Grubba)  /* NB: Dead-lock proofed by never holding the busy lock for * both from and to. */
7bfa602018-04-25Henrik Grubbström (Grubba)  if (reallocate_fd(to, type, x) < 0) {
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(to);
1f16da2018-09-18Henrik Grubbström (Grubba)  if (box) { /* Restore the events for the box. */ set_fd_callback_events(box, box_events, box->flags); if (box_obj) free_object(box_obj); }
7bfa602018-04-25Henrik Grubbström (Grubba)  if (type == FD_SOCKET) { closesocket((SOCKET)x); } else { CloseHandle(x);
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  }
7bfa602018-04-25Henrik Grubbström (Grubba)  return -1;
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  }
ddeb2a2018-04-26Henrik Grubbström (Grubba)  release_fd(to);
e42eaf1998-01-02Fredrik Hübinette (Hubbe) 
1f16da2018-09-18Henrik Grubbström (Grubba)  if (box && (type == FD_SOCKET)) { /* Restore the events for the box, to register it with * the new handle. */ set_fd_callback_events(box, box_events, box->flags); }
7d0c8a2018-09-18Henrik Grubbström (Grubba)  if (box_obj) free_object(box_obj);
1f16da2018-09-18Henrik Grubbström (Grubba) 
948d282000-08-17Henrik Grubbström (Grubba)  FDDEBUG(fprintf(stderr,"Dup2 %d (%d) to %d (%d)\n",
32fc1a2018-05-08Henrik Grubbström (Grubba)  from, (long)(ptrdiff_t)h, to, x));
e42eaf1998-01-02Fredrik Hübinette (Hubbe)  return to;
5740881998-01-01Fredrik Hübinette (Hubbe) }
aef5152009-05-28Henrik Grubbström (Grubba) PMOD_EXPORT const char *debug_fd_inet_ntop(int af, const void *addr, char *cp, size_t sz) {
7506652015-04-29Henrik Grubbström (Grubba)  static char *(*inet_ntop_funp)(int, const void*, char *, size_t);
aef5152009-05-28Henrik Grubbström (Grubba)  static int tried; static HINSTANCE ws2_32lib; if (!inet_ntop_funp) { if (!tried) { tried = 1; if ((ws2_32lib = LoadLibrary("Ws2_32"))) { FARPROC proc; if ((proc = GetProcAddress(ws2_32lib, "InetNtopA"))) {
7506652015-04-29Henrik Grubbström (Grubba)  inet_ntop_funp = (char *(*)(int, const void *, char *, size_t))proc;
aef5152009-05-28Henrik Grubbström (Grubba)  } } } if (!inet_ntop_funp) { const unsigned char *q = (const unsigned char *)addr; if (af == AF_INET) { snprintf(cp, sz, "%d.%d.%d.%d", q[0], q[1], q[2], q[3]); return cp; #ifdef AF_INET6 } else if (af == AF_INET6) { int i; char *buf = cp; int got_zeros = 0; for (i=0; i < 8; i++) { size_t val = (q[0]<<8) | q[1]; if (!val) { if (!got_zeros) {
dcd2702009-05-29Henrik Grubbström (Grubba)  snprintf(buf, sz, ":");
aef5152009-05-28Henrik Grubbström (Grubba)  got_zeros = 1; goto next; } else if (got_zeros == 1) goto next; } got_zeros |= got_zeros << 1; if (i) { snprintf(buf, sz, ":%x", val); } else { snprintf(buf, sz, "%x", val); } next: sz -= strlen(buf); buf += strlen(buf); q += 2; }
dcd2702009-05-29Henrik Grubbström (Grubba)  if (got_zeros == 1) {
aef5152009-05-28Henrik Grubbström (Grubba)  snprintf(buf, sz, ":"); sz -= strlen(buf); } return cp; #endif } return NULL; } } return inet_ntop_funp(af, addr, cp, sz); }
3bbd5a2005-01-05Henrik Grubbström (Grubba) #endif /* HAVE_WINSOCK_H && !__GNUC__ */
bffaef1998-01-05Fredrik Hübinette (Hubbe) 
bb86791999-06-19Fredrik Hübinette (Hubbe) #ifdef EMULATE_DIRECT
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT DIR *opendir(char *dir)
bb86791999-06-19Fredrik Hübinette (Hubbe) {
4091e02018-04-19Henrik Grubbström (Grubba)  ptrdiff_t len; p_wchar1 *foo; DIR *ret = malloc(sizeof(DIR));
bb86791999-06-19Fredrik Hübinette (Hubbe)  if(!ret) { errno=ENOMEM; return 0; }
4091e02018-04-19Henrik Grubbström (Grubba)  foo = pike_dwim_utf8_to_utf16(dir); if (!foo) { free(ret); errno = ENOMEM; return NULL; } len = wcslen(foo); /* This may require appending a slash and a star... */ if(len && !ISSEPARATOR(foo[len-1])) foo[len++]='/';
bb86791999-06-19Fredrik Hübinette (Hubbe)  foo[len++]='*'; foo[len]=0;
4091e02018-04-19Henrik Grubbström (Grubba) /* fprintf(stderr, "opendir(%S)\n", foo); */ ret->h = FindFirstFileW(foo, &ret->find_data); free(foo);
faacc82018-05-09Henrik Grubbström (Grubba)  if(ret->h == INVALID_HANDLE_VALUE)
bb86791999-06-19Fredrik Hübinette (Hubbe)  {
4091e02018-04-19Henrik Grubbström (Grubba)  /* FIXME: Handle empty directories. */
bb86791999-06-19Fredrik Hübinette (Hubbe)  errno=ENOENT;
0ec7522014-04-27Martin Nilsson  free(ret);
4091e02018-04-19Henrik Grubbström (Grubba)  return NULL;
bb86791999-06-19Fredrik Hübinette (Hubbe)  }
4091e02018-04-19Henrik Grubbström (Grubba)  ret->direct.d_name = NULL;
bb86791999-06-19Fredrik Hübinette (Hubbe)  ret->first=1; return ret; }
4091e02018-04-19Henrik Grubbström (Grubba) PMOD_EXPORT struct dirent *readdir(DIR *dir)
bb86791999-06-19Fredrik Hübinette (Hubbe) {
4091e02018-04-19Henrik Grubbström (Grubba)  if(!dir->first)
bb86791999-06-19Fredrik Hübinette (Hubbe)  {
4091e02018-04-19Henrik Grubbström (Grubba)  if(!FindNextFileW(dir->h, &dir->find_data))
bb86791999-06-19Fredrik Hübinette (Hubbe)  {
4091e02018-04-19Henrik Grubbström (Grubba)  errno = ENOENT; return NULL;
bb86791999-06-19Fredrik Hübinette (Hubbe)  }
4091e02018-04-19Henrik Grubbström (Grubba)  } else { dir->first = 0;
bb86791999-06-19Fredrik Hübinette (Hubbe)  }
4091e02018-04-19Henrik Grubbström (Grubba)  if (dir->direct.d_name) { free(dir->direct.d_name); dir->direct.d_name = NULL;
bb86791999-06-19Fredrik Hübinette (Hubbe)  }
4091e02018-04-19Henrik Grubbström (Grubba)  dir->direct.d_name = pike_utf16_to_utf8(dir->find_data.cFileName); if (dir->direct.d_name) return &dir->direct; errno = ENOMEM; return NULL;
bb86791999-06-19Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void closedir(DIR *dir)
bb86791999-06-19Fredrik Hübinette (Hubbe) { FindClose(dir->h);
4091e02018-04-19Henrik Grubbström (Grubba)  if (dir->direct.d_name) { free(dir->direct.d_name); }
0ec7522014-04-27Martin Nilsson  free(dir);
bb86791999-06-19Fredrik Hübinette (Hubbe) } #endif
4cd5602018-04-20Henrik Grubbström (Grubba)  #if defined(HAVE_WINSOCK_H) && defined(USE_DL_MALLOC) /* NB: We use some calls above that allocate memory with the libc malloc. */ #undef free static inline void libc_free(void *ptr) { if (ptr) free(ptr); } #endif