Blame cpio/cpio_windows.c

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