]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tar/bsdtar_windows.c
Update vendor/libarchive/dist to b2c3ee7e2907511533eeb2a0f2ceecc1faa73185
[FreeBSD/FreeBSD.git] / tar / bsdtar_windows.c
1 /*-
2  * Copyright (c) 2009 Michihiro NAKAJIMA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #if defined(_WIN32) && !defined(__CYGWIN__)
29
30 #include "bsdtar_platform.h"
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <io.h>
35 #include <stddef.h>
36 #ifdef HAVE_SYS_UTIME_H
37 #include <sys/utime.h>
38 #endif
39 #include <sys/stat.h>
40 #include <process.h>
41 #include <stdlib.h>
42 #include <wchar.h>
43 #include <windows.h>
44 #include <sddl.h>
45
46 #include "bsdtar.h"
47 #include "err.h"
48
49 /* This may actually not be needed anymore.
50  * TODO: Review the error handling for chdir() failures and
51  * simply dump this if it's not really needed. */
52 static void __tar_dosmaperr(unsigned long);
53
54 /*
55  * Prepend "\\?\" to the path name and convert it to unicode to permit
56  * an extended-length path for a maximum total path length of 32767
57  * characters.
58  * see also http://msdn.microsoft.com/en-us/library/aa365247.aspx
59  */
60 static wchar_t *
61 permissive_name(const char *name)
62 {
63         wchar_t *wn, *wnp;
64         wchar_t *ws, *wsp;
65         DWORD l, len, slen, alloclen;
66         int unc;
67
68         len = (DWORD)strlen(name);
69         wn = malloc((len + 1) * sizeof(wchar_t));
70         if (wn == NULL)
71                 return (NULL);
72         l = MultiByteToWideChar(CP_ACP, 0, name, len, wn, len);
73         if (l == 0) {
74                 free(wn);
75                 return (NULL);
76         }
77         wn[l] = L'\0';
78
79         /* Get a full path names */
80         l = GetFullPathNameW(wn, 0, NULL, NULL);
81         if (l == 0) {
82                 free(wn);
83                 return (NULL);
84         }
85         wnp = malloc(l * sizeof(wchar_t));
86         if (wnp == NULL) {
87                 free(wn);
88                 return (NULL);
89         }
90         len = GetFullPathNameW(wn, l, wnp, NULL);
91         free(wn);
92         wn = wnp;
93
94         if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
95             wnp[2] == L'?' && wnp[3] == L'\\')
96                 /* We have already permissive names. */
97                 return (wn);
98
99         if (wnp[0] == L'\\' && wnp[1] == L'\\' &&
100                 wnp[2] == L'.' && wnp[3] == L'\\') {
101                 /* Device names */
102                 if (((wnp[4] >= L'a' && wnp[4] <= L'z') ||
103                      (wnp[4] >= L'A' && wnp[4] <= L'Z')) &&
104                     wnp[5] == L':' && wnp[6] == L'\\')
105                         wnp[2] = L'?';/* Not device names. */
106                 return (wn);
107         }
108
109         unc = 0;
110         if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
111                 wchar_t *p = &wnp[2];
112
113                 /* Skip server-name letters. */
114                 while (*p != L'\\' && *p != L'\0')
115                         ++p;
116                 if (*p == L'\\') {
117                         wchar_t *rp = ++p;
118                         /* Skip share-name letters. */
119                         while (*p != L'\\' && *p != L'\0')
120                                 ++p;
121                         if (*p == L'\\' && p != rp) {
122                                 /* Now, match patterns such as
123                                  * "\\server-name\share-name\" */
124                                 wnp += 2;
125                                 len -= 2;
126                                 unc = 1;
127                         }
128                 }
129         }
130
131         alloclen = slen = 4 + (unc * 4) + len + 1;
132         ws = wsp = malloc(slen * sizeof(wchar_t));
133         if (ws == NULL) {
134                 free(wn);
135                 return (NULL);
136         }
137         /* prepend "\\?\" */
138         wcsncpy(wsp, L"\\\\?\\", 4);
139         wsp += 4;
140         slen -= 4;
141         if (unc) {
142                 /* append "UNC\" ---> "\\?\UNC\" */
143                 wcsncpy(wsp, L"UNC\\", 4);
144                 wsp += 4;
145                 slen -= 4;
146         }
147         wcsncpy(wsp, wnp, slen);
148         free(wn);
149         ws[alloclen - 1] = L'\0';
150         return (ws);
151 }
152
153 int
154 __tar_chdir(const char *path)
155 {
156         wchar_t *ws;
157         int r;
158
159         r = SetCurrentDirectoryA(path);
160         if (r == 0) {
161                 if (GetLastError() != ERROR_FILE_NOT_FOUND) {
162                         __tar_dosmaperr(GetLastError());
163                         return (-1);
164                 }
165         } else
166                 return (0);
167         ws = permissive_name(path);
168         if (ws == NULL) {
169                 errno = EINVAL;
170                 return (-1);
171         }
172         r = SetCurrentDirectoryW(ws);
173         free(ws);
174         if (r == 0) {
175                 __tar_dosmaperr(GetLastError());
176                 return (-1);
177         }
178         return (0);
179 }
180
181 /*
182  * The following function was modified from PostgreSQL sources and is
183  * subject to the copyright below.
184  */
185 /*-------------------------------------------------------------------------
186  *
187  * win32error.c
188  *        Map win32 error codes to errno values
189  *
190  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
191  *
192  * IDENTIFICATION
193  *        $PostgreSQL: pgsql/src/port/win32error.c,v 1.4 2008/01/01 19:46:00 momjian Exp $
194  *
195  *-------------------------------------------------------------------------
196  */
197 /*
198 PostgreSQL Database Management System
199 (formerly known as Postgres, then as Postgres95)
200
201 Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
202
203 Portions Copyright (c) 1994, The Regents of the University of California
204
205 Permission to use, copy, modify, and distribute this software and its
206 documentation for any purpose, without fee, and without a written agreement
207 is hereby granted, provided that the above copyright notice and this
208 paragraph and the following two paragraphs appear in all copies.
209
210 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
211 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
212 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
213 DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
214 POSSIBILITY OF SUCH DAMAGE.
215
216 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
217 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
218 AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
219 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
220 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
221 */
222
223 static const struct {
224         DWORD           winerr;
225         int             doserr;
226 } doserrors[] =
227 {
228         {       ERROR_INVALID_FUNCTION, EINVAL  },
229         {       ERROR_FILE_NOT_FOUND, ENOENT    },
230         {       ERROR_PATH_NOT_FOUND, ENOENT    },
231         {       ERROR_TOO_MANY_OPEN_FILES, EMFILE       },
232         {       ERROR_ACCESS_DENIED, EACCES     },
233         {       ERROR_INVALID_HANDLE, EBADF     },
234         {       ERROR_ARENA_TRASHED, ENOMEM     },
235         {       ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
236         {       ERROR_INVALID_BLOCK, ENOMEM     },
237         {       ERROR_BAD_ENVIRONMENT, E2BIG    },
238         {       ERROR_BAD_FORMAT, ENOEXEC       },
239         {       ERROR_INVALID_ACCESS, EINVAL    },
240         {       ERROR_INVALID_DATA, EINVAL      },
241         {       ERROR_INVALID_DRIVE, ENOENT     },
242         {       ERROR_CURRENT_DIRECTORY, EACCES },
243         {       ERROR_NOT_SAME_DEVICE, EXDEV    },
244         {       ERROR_NO_MORE_FILES, ENOENT     },
245         {       ERROR_LOCK_VIOLATION, EACCES    },
246         {       ERROR_SHARING_VIOLATION, EACCES },
247         {       ERROR_BAD_NETPATH, ENOENT       },
248         {       ERROR_NETWORK_ACCESS_DENIED, EACCES     },
249         {       ERROR_BAD_NET_NAME, ENOENT      },
250         {       ERROR_FILE_EXISTS, EEXIST       },
251         {       ERROR_CANNOT_MAKE, EACCES       },
252         {       ERROR_FAIL_I24, EACCES  },
253         {       ERROR_INVALID_PARAMETER, EINVAL },
254         {       ERROR_NO_PROC_SLOTS, EAGAIN     },
255         {       ERROR_DRIVE_LOCKED, EACCES      },
256         {       ERROR_BROKEN_PIPE, EPIPE        },
257         {       ERROR_DISK_FULL, ENOSPC },
258         {       ERROR_INVALID_TARGET_HANDLE, EBADF      },
259         {       ERROR_INVALID_HANDLE, EINVAL    },
260         {       ERROR_WAIT_NO_CHILDREN, ECHILD  },
261         {       ERROR_CHILD_NOT_COMPLETE, ECHILD        },
262         {       ERROR_DIRECT_ACCESS_HANDLE, EBADF       },
263         {       ERROR_NEGATIVE_SEEK, EINVAL     },
264         {       ERROR_SEEK_ON_DEVICE, EACCES    },
265         {       ERROR_DIR_NOT_EMPTY, ENOTEMPTY  },
266         {       ERROR_NOT_LOCKED, EACCES        },
267         {       ERROR_BAD_PATHNAME, ENOENT      },
268         {       ERROR_MAX_THRDS_REACHED, EAGAIN },
269         {       ERROR_LOCK_FAILED, EACCES       },
270         {       ERROR_ALREADY_EXISTS, EEXIST    },
271         {       ERROR_FILENAME_EXCED_RANGE, ENOENT      },
272         {       ERROR_NESTING_NOT_ALLOWED, EAGAIN       },
273         {       ERROR_NOT_ENOUGH_QUOTA, ENOMEM  }
274 };
275
276 static void
277 __tar_dosmaperr(unsigned long e)
278 {
279         int                     i;
280
281         if (e == 0)     {
282                 errno = 0;
283                 return;
284         }
285
286         for (i = 0; i < (int)sizeof(doserrors); i++) {
287                 if (doserrors[i].winerr == e) {
288                         errno = doserrors[i].doserr;
289                         return;
290                 }
291         }
292
293         /* fprintf(stderr, "unrecognized win32 error code: %lu", e); */
294         errno = EINVAL;
295         return;
296 }
297
298 #endif