Blame cpio/cpio_windows.c

Packit Service 1d0348
/*-
Packit Service 1d0348
 * Copyright (c) 2009 Michihiro NAKAJIMA
Packit Service 1d0348
 * All rights reserved.
Packit Service 1d0348
 *
Packit Service 1d0348
 * Redistribution and use in source and binary forms, with or without
Packit Service 1d0348
 * modification, are permitted provided that the following conditions
Packit Service 1d0348
 * are met:
Packit Service 1d0348
 * 1. Redistributions of source code must retain the above copyright
Packit Service 1d0348
 *    notice, this list of conditions and the following disclaimer.
Packit Service 1d0348
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 1d0348
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 1d0348
 *    documentation and/or other materials provided with the distribution.
Packit Service 1d0348
 *
Packit Service 1d0348
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
Packit Service 1d0348
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit Service 1d0348
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit Service 1d0348
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit Service 1d0348
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit Service 1d0348
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit Service 1d0348
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit Service 1d0348
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service 1d0348
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit Service 1d0348
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service 1d0348
 *
Packit Service 1d0348
 * $FreeBSD$
Packit Service 1d0348
 */
Packit Service 1d0348
Packit Service 1d0348
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit Service 1d0348
Packit Service 1d0348
#include "cpio_platform.h"
Packit Service 1d0348
#include <ctype.h>
Packit Service 1d0348
#include <errno.h>
Packit Service 1d0348
#include <fcntl.h>
Packit Service 1d0348
#include <io.h>
Packit Service 1d0348
#include <stddef.h>
Packit Service 1d0348
#ifdef HAVE_SYS_UTIME_H
Packit Service 1d0348
#include <sys/utime.h>
Packit Service 1d0348
#endif
Packit Service 1d0348
#include <sys/stat.h>
Packit Service 1d0348
#include <process.h>
Packit Service 1d0348
#include <stdlib.h>
Packit Service 1d0348
#include <wchar.h>
Packit Service 1d0348
#include <windows.h>
Packit Service 1d0348
#include <sddl.h>
Packit Service 1d0348
Packit Service 1d0348
#include "cpio.h"
Packit Service 1d0348
#include "err.h"
Packit Service 1d0348
Packit Service 1d0348
#define EPOC_TIME	(116444736000000000ULL)
Packit Service 1d0348
Packit Service 1d0348
static void cpio_dosmaperr(unsigned long);
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * Prepend "\\?\" to the path name and convert it to unicode to permit
Packit Service 1d0348
 * an extended-length path for a maximum total path length of 32767
Packit Service 1d0348
 * characters.
Packit Service 1d0348
 * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
Packit Service 1d0348
 */
Packit Service 1d0348
static wchar_t *
Packit Service 1d0348
permissive_name(const char *name)
Packit Service 1d0348
{
Packit Service 1d0348
	wchar_t *wn, *wnp;
Packit Service 1d0348
	wchar_t *ws, *wsp;
Packit Service 1d0348
	DWORD l, len, slen, alloclen;
Packit Service 1d0348
	int unc;
Packit Service 1d0348
Packit Service 1d0348
	len = (DWORD)strlen(name);
Packit Service 1d0348
	wn = malloc((len + 1) * sizeof(wchar_t));
Packit Service 1d0348
	if (wn == NULL)
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
Packit Service 1d0348
	if (l == 0) {
Packit Service 1d0348
		free(wn);
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	}
Packit Service 1d0348
	wn[l] = L'\0';
Packit Service 1d0348
Packit Service 1d0348
	/* Get a full path names */
Packit Service 1d0348
	l = GetFullPathNameW(wn, 0, NULL, NULL);
Packit Service 1d0348
	if (l == 0) {
Packit Service 1d0348
		free(wn);
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	}
Packit Service 1d0348
	wnp = malloc(l * sizeof(wchar_t));
Packit Service 1d0348
	if (wnp == NULL) {
Packit Service 1d0348
		free(wn);
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	}
Packit Service 1d0348
	len = GetFullPathNameW(wn, l, wnp, NULL);
Packit Service 1d0348
	free(wn);
Packit Service 1d0348
	wn = wnp;
Packit Service 1d0348
Packit Service 1d0348
	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
Packit Service 1d0348
	    wnp[2] == L'?' && wnp[3] == L'\\')
Packit Service 1d0348
		/* We have already permissive names. */
Packit Service 1d0348
		return (wn);
Packit Service 1d0348
Packit Service 1d0348
	if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
Packit Service 1d0348
		wnp[2] == L'.' && wnp[3] == L'\\') {
Packit Service 1d0348
		/* Device names */
Packit Service 1d0348
		if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
Packit Service 1d0348
		     (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
Packit Service 1d0348
		    wnp[5] == L':' && wnp[6] == L'\\')
Packit Service 1d0348
			wnp[2] = L'?';/* Not device names. */
Packit Service 1d0348
		return (wn);
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	unc = 0;
Packit Service 1d0348
	if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
Packit Service 1d0348
		wchar_t *p = &wnp[2];
Packit Service 1d0348
Packit Service 1d0348
		/* Skip server-name letters. */
Packit Service 1d0348
		while (*p != L'\\' && *p != L'\0')
Packit Service 1d0348
			++p;
Packit Service 1d0348
		if (*p == L'\\') {
Packit Service 1d0348
			wchar_t *rp = ++p;
Packit Service 1d0348
			/* Skip share-name letters. */
Packit Service 1d0348
			while (*p != L'\\' && *p != L'\0')
Packit Service 1d0348
				++p;
Packit Service 1d0348
			if (*p == L'\\' && p != rp) {
Packit Service 1d0348
				/* Now, match patterns such as
Packit Service 1d0348
				 * "\\server-name\share-name\" */
Packit Service 1d0348
				wnp += 2;
Packit Service 1d0348
				len -= 2;
Packit Service 1d0348
				unc = 1;
Packit Service 1d0348
			}
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	alloclen = slen = 4 + (unc * 4) + len + 1;
Packit Service 1d0348
	ws = wsp = malloc(slen * sizeof(wchar_t));
Packit Service 1d0348
	if (ws == NULL) {
Packit Service 1d0348
		free(wn);
Packit Service 1d0348
		return (NULL);
Packit Service 1d0348
	}
Packit Service 1d0348
	/* prepend "\\?\" */
Packit Service 1d0348
	wcsncpy(wsp, L"\\\\?\\", 4);
Packit Service 1d0348
	wsp += 4;
Packit Service 1d0348
	slen -= 4;
Packit Service 1d0348
	if (unc) {
Packit Service 1d0348
		/* append "UNC\" ---> "\\?\UNC\" */
Packit Service 1d0348
		wcsncpy(wsp, L"UNC\\", 4);
Packit Service 1d0348
		wsp += 4;
Packit Service 1d0348
		slen -= 4;
Packit Service 1d0348
	}
Packit Service 1d0348
	wcsncpy(wsp, wnp, slen);
Packit Service 1d0348
	free(wn);
Packit Service 1d0348
	ws[alloclen - 1] = L'\0';
Packit Service 1d0348
	return (ws);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
static HANDLE
Packit Service 1d0348
cpio_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
Packit Service 1d0348
    LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
Packit Service 1d0348
    DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
Packit Service 1d0348
{
Packit Service 1d0348
	wchar_t *wpath;
Packit Service 1d0348
	HANDLE handle;
Packit Service 1d0348
Packit Service 1d0348
	handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
Packit Service 1d0348
	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
Packit Service 1d0348
	    hTemplateFile);
Packit Service 1d0348
	if (handle != INVALID_HANDLE_VALUE)
Packit Service 1d0348
		return (handle);
Packit Service 1d0348
	if (GetLastError() != ERROR_PATH_NOT_FOUND)
Packit Service 1d0348
		return (handle);
Packit Service 1d0348
	wpath = permissive_name(path);
Packit Service 1d0348
	if (wpath == NULL)
Packit Service 1d0348
		return (handle);
Packit Service 1d0348
	handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode,
Packit Service 1d0348
	    lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
Packit Service 1d0348
	    hTemplateFile);
Packit Service 1d0348
	free(wpath);
Packit Service 1d0348
	return (handle);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
#define WINTIME(sec, usec)	((Int32x32To64(sec, 10000000) + EPOC_TIME) + (usec * 10))
Packit Service 1d0348
static int
Packit Service 1d0348
__hutimes(HANDLE handle, const struct __timeval *times)
Packit Service 1d0348
{
Packit Service 1d0348
	ULARGE_INTEGER wintm;
Packit Service 1d0348
	FILETIME fatime, fmtime;
Packit Service 1d0348
Packit Service 1d0348
	wintm.QuadPart = WINTIME(times[0].tv_sec, times[0].tv_usec);
Packit Service 1d0348
	fatime.dwLowDateTime = wintm.LowPart;
Packit Service 1d0348
	fatime.dwHighDateTime = wintm.HighPart;
Packit Service 1d0348
	wintm.QuadPart = WINTIME(times[1].tv_sec, times[1].tv_usec);
Packit Service 1d0348
	fmtime.dwLowDateTime = wintm.LowPart;
Packit Service 1d0348
	fmtime.dwHighDateTime = wintm.HighPart;
Packit Service 1d0348
	if (SetFileTime(handle, NULL, &fatime, &fmtime) == 0) {
Packit Service 1d0348
		errno = EINVAL;
Packit Service 1d0348
		return (-1);
Packit Service 1d0348
	}
Packit Service 1d0348
	return (0);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
int
Packit Service 1d0348
futimes(int fd, const struct __timeval *times)
Packit Service 1d0348
{
Packit Service 1d0348
Packit Service 1d0348
	return (__hutimes((HANDLE)_get_osfhandle(fd), times));
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
int
Packit Service 1d0348
utimes(const char *name, const struct __timeval *times)
Packit Service 1d0348
{
Packit Service 1d0348
	int ret;
Packit Service 1d0348
	HANDLE handle;
Packit Service 1d0348
Packit Service 1d0348
	handle = cpio_CreateFile(name, GENERIC_READ | GENERIC_WRITE,
Packit Service 1d0348
	    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
Packit Service 1d0348
	    FILE_FLAG_BACKUP_SEMANTICS, NULL);
Packit Service 1d0348
	if (handle == INVALID_HANDLE_VALUE) {
Packit Service 1d0348
		cpio_dosmaperr(GetLastError());
Packit Service 1d0348
		return (-1);
Packit Service 1d0348
	}
Packit Service 1d0348
	ret = __hutimes(handle, times);
Packit Service 1d0348
	CloseHandle(handle);
Packit Service 1d0348
	return (ret);
Packit Service 1d0348
}
Packit Service 1d0348
Packit Service 1d0348
/*
Packit Service 1d0348
 * The following function was modified from PostgreSQL sources and is
Packit Service 1d0348
 * subject to the copyright below.
Packit Service 1d0348
 */
Packit Service 1d0348
/*-------------------------------------------------------------------------
Packit Service 1d0348
 *
Packit Service 1d0348
 * win32error.c
Packit Service 1d0348
 *	  Map win32 error codes to errno values
Packit Service 1d0348
 *
Packit Service 1d0348
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
Packit Service 1d0348
 *
Packit Service 1d0348
 * IDENTIFICATION
Packit Service 1d0348
 *	  $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
Packit Service 1d0348
 *
Packit Service 1d0348
 *-------------------------------------------------------------------------
Packit Service 1d0348
 */
Packit Service 1d0348
/*
Packit Service 1d0348
PostgreSQL Database Management System
Packit Service 1d0348
(formerly known as Postgres, then as Postgres95)
Packit Service 1d0348
Packit Service 1d0348
Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
Packit Service 1d0348
Packit Service 1d0348
Portions Copyright (c) 1994, The Regents of the University of California
Packit Service 1d0348
Packit Service 1d0348
Permission to use, copy, modify, and distribute this software and its
Packit Service 1d0348
documentation for any purpose, without fee, and without a written agreement
Packit Service 1d0348
is hereby granted, provided that the above copyright notice and this
Packit Service 1d0348
paragraph and the following two paragraphs appear in all copies.
Packit Service 1d0348
Packit Service 1d0348
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
Packit Service 1d0348
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
Packit Service 1d0348
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
Packit Service 1d0348
DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
Packit Service 1d0348
POSSIBILITY OF SUCH DAMAGE.
Packit Service 1d0348
Packit Service 1d0348
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
Packit Service 1d0348
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
Packit Service 1d0348
AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Packit Service 1d0348
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
Packit Service 1d0348
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit Service 1d0348
*/
Packit Service 1d0348
Packit Service 1d0348
static const struct {
Packit Service 1d0348
	DWORD		winerr;
Packit Service 1d0348
	int		doserr;
Packit Service 1d0348
} doserrors[] =
Packit Service 1d0348
{
Packit Service 1d0348
	{	ERROR_INVALID_FUNCTION, EINVAL	},
Packit Service 1d0348
	{	ERROR_FILE_NOT_FOUND, ENOENT	},
Packit Service 1d0348
	{	ERROR_PATH_NOT_FOUND, ENOENT	},
Packit Service 1d0348
	{	ERROR_TOO_MANY_OPEN_FILES, EMFILE	},
Packit Service 1d0348
	{	ERROR_ACCESS_DENIED, EACCES	},
Packit Service 1d0348
	{	ERROR_INVALID_HANDLE, EBADF	},
Packit Service 1d0348
	{	ERROR_ARENA_TRASHED, ENOMEM	},
Packit Service 1d0348
	{	ERROR_NOT_ENOUGH_MEMORY, ENOMEM	},
Packit Service 1d0348
	{	ERROR_INVALID_BLOCK, ENOMEM	},
Packit Service 1d0348
	{	ERROR_BAD_ENVIRONMENT, E2BIG	},
Packit Service 1d0348
	{	ERROR_BAD_FORMAT, ENOEXEC	},
Packit Service 1d0348
	{	ERROR_INVALID_ACCESS, EINVAL	},
Packit Service 1d0348
	{	ERROR_INVALID_DATA, EINVAL	},
Packit Service 1d0348
	{	ERROR_INVALID_DRIVE, ENOENT	},
Packit Service 1d0348
	{	ERROR_CURRENT_DIRECTORY, EACCES	},
Packit Service 1d0348
	{	ERROR_NOT_SAME_DEVICE, EXDEV	},
Packit Service 1d0348
	{	ERROR_NO_MORE_FILES, ENOENT	},
Packit Service 1d0348
	{	ERROR_LOCK_VIOLATION, EACCES	},
Packit Service 1d0348
	{	ERROR_SHARING_VIOLATION, EACCES	},
Packit Service 1d0348
	{	ERROR_BAD_NETPATH, ENOENT	},
Packit Service 1d0348
	{	ERROR_NETWORK_ACCESS_DENIED, EACCES	},
Packit Service 1d0348
	{	ERROR_BAD_NET_NAME, ENOENT	},
Packit Service 1d0348
	{	ERROR_FILE_EXISTS, EEXIST	},
Packit Service 1d0348
	{	ERROR_CANNOT_MAKE, EACCES	},
Packit Service 1d0348
	{	ERROR_FAIL_I24, EACCES	},
Packit Service 1d0348
	{	ERROR_INVALID_PARAMETER, EINVAL	},
Packit Service 1d0348
	{	ERROR_NO_PROC_SLOTS, EAGAIN	},
Packit Service 1d0348
	{	ERROR_DRIVE_LOCKED, EACCES	},
Packit Service 1d0348
	{	ERROR_BROKEN_PIPE, EPIPE	},
Packit Service 1d0348
	{	ERROR_DISK_FULL, ENOSPC	},
Packit Service 1d0348
	{	ERROR_INVALID_TARGET_HANDLE, EBADF	},
Packit Service 1d0348
	{	ERROR_INVALID_HANDLE, EINVAL	},
Packit Service 1d0348
	{	ERROR_WAIT_NO_CHILDREN, ECHILD	},
Packit Service 1d0348
	{	ERROR_CHILD_NOT_COMPLETE, ECHILD	},
Packit Service 1d0348
	{	ERROR_DIRECT_ACCESS_HANDLE, EBADF	},
Packit Service 1d0348
	{	ERROR_NEGATIVE_SEEK, EINVAL	},
Packit Service 1d0348
	{	ERROR_SEEK_ON_DEVICE, EACCES	},
Packit Service 1d0348
	{	ERROR_DIR_NOT_EMPTY, ENOTEMPTY	},
Packit Service 1d0348
	{	ERROR_NOT_LOCKED, EACCES	},
Packit Service 1d0348
	{	ERROR_BAD_PATHNAME, ENOENT	},
Packit Service 1d0348
	{	ERROR_MAX_THRDS_REACHED, EAGAIN	},
Packit Service 1d0348
	{	ERROR_LOCK_FAILED, EACCES	},
Packit Service 1d0348
	{	ERROR_ALREADY_EXISTS, EEXIST	},
Packit Service 1d0348
	{	ERROR_FILENAME_EXCED_RANGE, ENOENT	},
Packit Service 1d0348
	{	ERROR_NESTING_NOT_ALLOWED, EAGAIN	},
Packit Service 1d0348
	{	ERROR_NOT_ENOUGH_QUOTA, ENOMEM	}
Packit Service 1d0348
};
Packit Service 1d0348
Packit Service 1d0348
static void
Packit Service 1d0348
cpio_dosmaperr(unsigned long e)
Packit Service 1d0348
{
Packit Service 1d0348
	int			i;
Packit Service 1d0348
Packit Service 1d0348
	if (e == 0)	{
Packit Service 1d0348
		errno = 0;
Packit Service 1d0348
		return;
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	for (i = 0; i < (int)sizeof(doserrors); i++) {
Packit Service 1d0348
		if (doserrors[i].winerr == e) {
Packit Service 1d0348
			errno = doserrors[i].doserr;
Packit Service 1d0348
			return;
Packit Service 1d0348
		}
Packit Service 1d0348
	}
Packit Service 1d0348
Packit Service 1d0348
	/* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
Packit Service 1d0348
	errno = EINVAL;
Packit Service 1d0348
	return;
Packit Service 1d0348
}
Packit Service 1d0348
#endif