# define win32_error(err_code)
#endif /* !ENABLE_ERROR_MESSAGES */
+static int
+win32_error_to_errno(DWORD err_code)
+{
+ /* This mapping is that used in Cygwin.
+ * Some of these choices are arbitrary. */
+ switch (err_code) {
+ case ERROR_ACCESS_DENIED:
+ return EACCES;
+ case ERROR_ACTIVE_CONNECTIONS:
+ return EAGAIN;
+ case ERROR_ALREADY_EXISTS:
+ return EEXIST;
+ case ERROR_BAD_DEVICE:
+ return ENODEV;
+ case ERROR_BAD_EXE_FORMAT:
+ return ENOEXEC;
+ case ERROR_BAD_NETPATH:
+ return ENOENT;
+ case ERROR_BAD_NET_NAME:
+ return ENOENT;
+ case ERROR_BAD_NET_RESP:
+ return ENOSYS;
+ case ERROR_BAD_PATHNAME:
+ return ENOENT;
+ case ERROR_BAD_PIPE:
+ return EINVAL;
+ case ERROR_BAD_UNIT:
+ return ENODEV;
+ case ERROR_BAD_USERNAME:
+ return EINVAL;
+ case ERROR_BEGINNING_OF_MEDIA:
+ return EIO;
+ case ERROR_BROKEN_PIPE:
+ return EPIPE;
+ case ERROR_BUSY:
+ return EBUSY;
+ case ERROR_BUS_RESET:
+ return EIO;
+ case ERROR_CALL_NOT_IMPLEMENTED:
+ return ENOSYS;
+ case ERROR_CANNOT_MAKE:
+ return EPERM;
+ case ERROR_CHILD_NOT_COMPLETE:
+ return EBUSY;
+ case ERROR_COMMITMENT_LIMIT:
+ return EAGAIN;
+ case ERROR_CRC:
+ return EIO;
+ case ERROR_DEVICE_DOOR_OPEN:
+ return EIO;
+ case ERROR_DEVICE_IN_USE:
+ return EAGAIN;
+ case ERROR_DEVICE_REQUIRES_CLEANING:
+ return EIO;
+ case ERROR_DIRECTORY:
+ return ENOTDIR;
+ case ERROR_DIR_NOT_EMPTY:
+ return ENOTEMPTY;
+ case ERROR_DISK_CORRUPT:
+ return EIO;
+ case ERROR_DISK_FULL:
+ return ENOSPC;
+#ifdef ENOTUNIQ
+ case ERROR_DUP_NAME:
+ return ENOTUNIQ;
+#endif
+ case ERROR_EAS_DIDNT_FIT:
+ return ENOSPC;
+ case ERROR_EAS_NOT_SUPPORTED:
+ return ENOTSUP;
+ case ERROR_EA_LIST_INCONSISTENT:
+ return EINVAL;
+ case ERROR_EA_TABLE_FULL:
+ return ENOSPC;
+ case ERROR_END_OF_MEDIA:
+ return ENOSPC;
+ case ERROR_EOM_OVERFLOW:
+ return EIO;
+ case ERROR_EXE_MACHINE_TYPE_MISMATCH:
+ return ENOEXEC;
+ case ERROR_EXE_MARKED_INVALID:
+ return ENOEXEC;
+ case ERROR_FILEMARK_DETECTED:
+ return EIO;
+ case ERROR_FILENAME_EXCED_RANGE:
+ return ENAMETOOLONG;
+ case ERROR_FILE_CORRUPT:
+ return EEXIST;
+ case ERROR_FILE_EXISTS:
+ return EEXIST;
+ case ERROR_FILE_INVALID:
+ return ENXIO;
+ case ERROR_FILE_NOT_FOUND:
+ return ENOENT;
+ case ERROR_HANDLE_DISK_FULL:
+ return ENOSPC;
+#ifdef ENODATA
+ case ERROR_HANDLE_EOF:
+ return ENODATA;
+#endif
+ case ERROR_INVALID_ADDRESS:
+ return EINVAL;
+ case ERROR_INVALID_AT_INTERRUPT_TIME:
+ return EINTR;
+ case ERROR_INVALID_BLOCK_LENGTH:
+ return EIO;
+ case ERROR_INVALID_DATA:
+ return EINVAL;
+ case ERROR_INVALID_DRIVE:
+ return ENODEV;
+ case ERROR_INVALID_EA_NAME:
+ return EINVAL;
+ case ERROR_INVALID_EXE_SIGNATURE:
+ return ENOEXEC;
+#ifdef EBADRQC
+ case ERROR_INVALID_FUNCTION:
+ return EBADRQC;
+#endif
+ case ERROR_INVALID_HANDLE:
+ return EBADF;
+ case ERROR_INVALID_NAME:
+ return ENOENT;
+ case ERROR_INVALID_PARAMETER:
+ return EINVAL;
+ case ERROR_INVALID_SIGNAL_NUMBER:
+ return EINVAL;
+ case ERROR_IOPL_NOT_ENABLED:
+ return ENOEXEC;
+ case ERROR_IO_DEVICE:
+ return EIO;
+ case ERROR_IO_INCOMPLETE:
+ return EAGAIN;
+ case ERROR_IO_PENDING:
+ return EAGAIN;
+ case ERROR_LOCK_VIOLATION:
+ return EBUSY;
+ case ERROR_MAX_THRDS_REACHED:
+ return EAGAIN;
+ case ERROR_META_EXPANSION_TOO_LONG:
+ return EINVAL;
+ case ERROR_MOD_NOT_FOUND:
+ return ENOENT;
+#ifdef EMSGSIZE
+ case ERROR_MORE_DATA:
+ return EMSGSIZE;
+#endif
+ case ERROR_NEGATIVE_SEEK:
+ return EINVAL;
+ case ERROR_NETNAME_DELETED:
+ return ENOENT;
+ case ERROR_NOACCESS:
+ return EFAULT;
+ case ERROR_NONE_MAPPED:
+ return EINVAL;
+ case ERROR_NONPAGED_SYSTEM_RESOURCES:
+ return EAGAIN;
+#ifdef ENOLINK
+ case ERROR_NOT_CONNECTED:
+ return ENOLINK;
+#endif
+ case ERROR_NOT_ENOUGH_MEMORY:
+ return ENOMEM;
+ case ERROR_NOT_OWNER:
+ return EPERM;
+#ifdef ENOMEDIUM
+ case ERROR_NOT_READY:
+ return ENOMEDIUM;
+#endif
+ case ERROR_NOT_SAME_DEVICE:
+ return EXDEV;
+ case ERROR_NOT_SUPPORTED:
+ return ENOSYS;
+ case ERROR_NO_DATA:
+ return EPIPE;
+ case ERROR_NO_DATA_DETECTED:
+ return EIO;
+#ifdef ENOMEDIUM
+ case ERROR_NO_MEDIA_IN_DRIVE:
+ return ENOMEDIUM;
+#endif
+#ifdef ENMFILE
+ case ERROR_NO_MORE_FILES:
+ return ENMFILE;
+#endif
+#ifdef ENMFILE
+ case ERROR_NO_MORE_ITEMS:
+ return ENMFILE;
+#endif
+ case ERROR_NO_MORE_SEARCH_HANDLES:
+ return ENFILE;
+ case ERROR_NO_PROC_SLOTS:
+ return EAGAIN;
+ case ERROR_NO_SIGNAL_SENT:
+ return EIO;
+ case ERROR_NO_SYSTEM_RESOURCES:
+ return EFBIG;
+ case ERROR_NO_TOKEN:
+ return EINVAL;
+ case ERROR_OPEN_FAILED:
+ return EIO;
+ case ERROR_OPEN_FILES:
+ return EAGAIN;
+ case ERROR_OUTOFMEMORY:
+ return ENOMEM;
+ case ERROR_PAGED_SYSTEM_RESOURCES:
+ return EAGAIN;
+ case ERROR_PAGEFILE_QUOTA:
+ return EAGAIN;
+ case ERROR_PATH_NOT_FOUND:
+ return ENOENT;
+ case ERROR_PIPE_BUSY:
+ return EBUSY;
+ case ERROR_PIPE_CONNECTED:
+ return EBUSY;
+#ifdef ECOMM
+ case ERROR_PIPE_LISTENING:
+ return ECOMM;
+ case ERROR_PIPE_NOT_CONNECTED:
+ return ECOMM;
+#endif
+ case ERROR_POSSIBLE_DEADLOCK:
+ return EDEADLOCK;
+ case ERROR_PRIVILEGE_NOT_HELD:
+ return EPERM;
+ case ERROR_PROCESS_ABORTED:
+ return EFAULT;
+ case ERROR_PROC_NOT_FOUND:
+ return ESRCH;
+#ifdef ENONET
+ case ERROR_REM_NOT_LIST:
+ return ENONET;
+#endif
+ case ERROR_SECTOR_NOT_FOUND:
+ return EINVAL;
+ case ERROR_SEEK:
+ return EINVAL;
+ case ERROR_SETMARK_DETECTED:
+ return EIO;
+ case ERROR_SHARING_BUFFER_EXCEEDED:
+ return ENOLCK;
+ case ERROR_SHARING_VIOLATION:
+ return EBUSY;
+ case ERROR_SIGNAL_PENDING:
+ return EBUSY;
+ case ERROR_SIGNAL_REFUSED:
+ return EIO;
+#ifdef ELIBBAD
+ case ERROR_SXS_CANT_GEN_ACTCTX:
+ return ELIBBAD;
+#endif
+ case ERROR_THREAD_1_INACTIVE:
+ return EINVAL;
+ case ERROR_TOO_MANY_LINKS:
+ return EMLINK;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ return EMFILE;
+ case ERROR_WAIT_NO_CHILDREN:
+ return ECHILD;
+ case ERROR_WORKING_SET_QUOTA:
+ return EAGAIN;
+ case ERROR_WRITE_PROTECT:
+ return EROFS;
+ default:
+ return -1;
+ }
+}
+
+static void
+set_errno_from_GetLastError()
+{
+ errno = win32_error_to_errno(GetLastError());
+}
+
/* Pointers to functions that are not available on all targetted versions of
* Windows (XP and later). NOTE: The WINAPI annotations seem to be important; I
* assume it specifies a certain calling convention. */
len = min(len, wim_resource_size(lte) - ctx->offset);
- if (read_partial_wim_resource_into_buf(lte, len, ctx->offset, data, false))
+ if (read_partial_wim_resource_into_buf(lte, len, ctx->offset, data))
return ERROR_READ_FAULT;
ctx->offset += len;
HANDLE h;
h = (HANDLE)_get_osfhandle(fd);
- if (h == INVALID_HANDLE_VALUE) {
- err = GetLastError();
- ERROR("Could not get Windows handle for file descriptor");
- win32_error(err);
- errno = EBADF;
- return -1;
- }
- if (!FlushFileBuffers(h)) {
- err = GetLastError();
- ERROR("Could not flush file buffers to disk");
- win32_error(err);
- errno = EIO;
- return -1;
- }
+ if (h == INVALID_HANDLE_VALUE)
+ goto err;
+ if (!FlushFileBuffers(h))
+ goto err;
return 0;
+err:
+ set_errno_from_GetLastError();
+ return -1;
}
/* Use the Win32 API to get the number of processors */
realpath(const wchar_t *path, wchar_t *resolved_path)
{
DWORD ret;
- wimlib_assert(resolved_path == NULL);
DWORD err;
+ wimlib_assert(resolved_path == NULL);
ret = GetFullPathNameW(path, 0, NULL, NULL);
if (!ret) {
}
goto out;
fail_win32:
- win32_error(err);
- errno = -1;
+ errno = win32_error_to_errno(err);
out:
return resolved_path;
}
if (MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) {
return 0;
} else {
- /* As usual, the possible error values are not documented */
- errno = -1;
+ set_errno_from_GetLastError();
return -1;
}
}
fail:
if (err == NO_ERROR)
err = GetLastError();
- ERROR("Can't truncate \"%ls\" to %"PRIu64" bytes", path, size);
- win32_error(err);
- errno = -1;
+ errno = win32_error_to_errno(err);
return -1;
}
return 0;
}
+static int
+do_pread_or_pwrite(int fd, void *buf, size_t count, off_t offset,
+ bool is_pwrite)
+{
+ HANDLE h;
+ LARGE_INTEGER orig_offset;
+ DWORD bytes_read_or_written;
+ LARGE_INTEGER relative_offset;
+ OVERLAPPED overlapped;
+ BOOL bret;
+
+ wimlib_assert(count <= 0xffffffff);
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if (h == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* Get original position */
+ relative_offset.QuadPart = 0;
+ if (!SetFilePointerEx(h, relative_offset, &orig_offset, FILE_CURRENT))
+ goto err;
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ overlapped.Offset = offset;
+ overlapped.OffsetHigh = offset >> 32;
+
+ /* Do the read or write at the specified offset */
+ if (is_pwrite)
+ bret = WriteFile(h, buf, count, &bytes_read_or_written, &overlapped);
+ else
+ bret = ReadFile(h, buf, count, &bytes_read_or_written, &overlapped);
+ if (!bret)
+ goto err;
+
+ /* Restore the original position */
+ if (!SetFilePointerEx(h, orig_offset, NULL, FILE_BEGIN))
+ goto err;
+
+ return bytes_read_or_written;
+err:
+ set_errno_from_GetLastError();
+ return -1;
+}
+
+/* Dumb Windows implementation of pread(). It temporarily changes the file
+ * offset, so it is not safe to use with readers/writers on the same file
+ * descriptor. */
+extern ssize_t
+win32_pread(int fd, void *buf, size_t count, off_t offset)
+{
+ return do_pread_or_pwrite(fd, buf, count, offset, false);
+}
+
+/* Dumb Windows implementation of pwrite(). It temporarily changes the file
+ * offset, so it is not safe to use with readers/writers on the same file
+ * descriptor. */
+extern ssize_t
+win32_pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+ return do_pread_or_pwrite(fd, (void*)buf, count, offset, true);
+}
+
+/* Dumb Windows implementation of writev(). It writes the vectors one at a
+ * time. */
+extern ssize_t
+win32_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ size_t total_bytes_written = 0;
+ for (int i = 0; i < iovcnt; i++) {
+ size_t bytes_written;
+
+ bytes_written = full_write(fd, iov[i].iov_base, iov[i].iov_len);
+ total_bytes_written += bytes_written;
+ if (bytes_written != iov[i].iov_len)
+ break;
+ }
+ return total_bytes_written;
+}
+
#endif /* __WIN32__ */