]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/cygpath.cc
* dcrt0.cc (_dll_crt0): Fix formatting.
[newlib-cygwin.git] / winsup / utils / cygpath.cc
CommitLineData
e05f3227 1/* cygpath.cc -- convert pathnames between Windows and Unix format
71148bfc
CV
2 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2009, 2010, 2011 Red Hat, Inc.
1fd5e000
CF
4
5This file is part of Cygwin.
6
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
10
3cdacffc
CV
11#define NOCOMATTRIBUTE
12
71148bfc 13#define WINVER 0x0600
3cdacffc 14#include <shlobj.h>
1fd5e000
CF
15#include <stdio.h>
16#include <string.h>
26fb7ef5
CV
17#include <wchar.h>
18#include <locale.h>
1fd5e000
CF
19#include <stdlib.h>
20#include <limits.h>
21#include <getopt.h>
e73a56e9 22#include <windows.h>
71148bfc 23#include <userenv.h>
138d4f51
CF
24#include <io.h>
25#include <sys/fcntl.h>
1fd5e000 26#include <sys/cygwin.h>
92b499ac 27#include <cygwin/version.h>
418068d4 28#include <ctype.h>
7c03f799 29#include <errno.h>
2dba45f4
CV
30#include <ddk/ntddk.h>
31#include <ddk/winddk.h>
32#include <ddk/ntifs.h>
26fb7ef5 33#include "wide_path.h"
71d8f118 34#include "loadlib.h"
1fd5e000
CF
35
36static char *prog_name;
ca902991 37static char *file_arg, *output_arg;
418068d4 38static int path_flag, unix_flag, windows_flag, absolute_flag;
5bb52de4
CV
39static int shortname_flag, longname_flag;
40static int ignore_flag, allusers_flag, output_flag;
fc200025 41static int mixed_flag, options_from_file_flag, mode_flag;
0a23799a 42static UINT codepage;
fc200025 43
1050e57c 44static const char *format_type_arg;
1fd5e000 45
6a344609 46static struct option long_options[] = {
6a344609 47 {(char *) "absolute", no_argument, NULL, 'a'},
1050e57c
CF
48 {(char *) "close", required_argument, NULL, 'c'},
49 {(char *) "dos", no_argument, NULL, 'd'},
50 {(char *) "file", required_argument, NULL, 'f'},
51 {(char *) "help", no_argument, NULL, 'h'},
52 {(char *) "ignore", no_argument, NULL, 'i'},
53 {(char *) "long-name", no_argument, NULL, 'l'},
54 {(char *) "mixed", no_argument, NULL, 'm'},
f135dd3e 55 {(char *) "mode", no_argument, NULL, 'M'},
6a344609
CF
56 {(char *) "option", no_argument, NULL, 'o'},
57 {(char *) "path", no_argument, NULL, 'p'},
1050e57c
CF
58 {(char *) "short-name", no_argument, NULL, 's'},
59 {(char *) "type", required_argument, NULL, 't'},
6a344609 60 {(char *) "unix", no_argument, NULL, 'u'},
92b499ac 61 {(char *) "version", no_argument, NULL, 'V'},
6a344609 62 {(char *) "windows", no_argument, NULL, 'w'},
6a344609
CF
63 {(char *) "allusers", no_argument, NULL, 'A'},
64 {(char *) "desktop", no_argument, NULL, 'D'},
e355de81 65 {(char *) "homeroot", no_argument, NULL, 'H'},
ca902991 66 {(char *) "mydocs", no_argument, NULL, 'O'},
1050e57c
CF
67 {(char *) "smprograms", no_argument, NULL, 'P'},
68 {(char *) "sysdir", no_argument, NULL, 'S'},
69 {(char *) "windir", no_argument, NULL, 'W'},
ca902991 70 {(char *) "folder", required_argument, NULL, 'F'},
0a23799a 71 {(char *) "codepage", required_argument, NULL, 'C'},
6a344609 72 {0, no_argument, 0, 0}
1fd5e000
CF
73};
74
92b499ac 75static char options[] = "ac:df:hilmMopst:uVwAC:DHOPSWF:";
9b566b96 76
1fd5e000 77static void
6a344609 78usage (FILE * stream, int status)
1fd5e000 79{
45b80bb4
CF
80 if (!ignore_flag || !status)
81 fprintf (stream, "\
92b499ac
CV
82Usage: %1$s (-d|-m|-u|-w|-t TYPE) [-f FILE] [OPTION]... NAME...\n\
83 %1$s [-c HANDLE] \n\
84 %1$s [-ADHOPSW] \n\
85 %1$s [-F ID] \n\
86\n\
aa275fe0 87Convert Unix and Windows format paths, or output system path information\n\
bd79b736 88\n\
1050e57c 89Output type options:\n\
92b499ac 90\n\
ca902991 91 -d, --dos print DOS (short) form of NAMEs (C:\\PROGRA~1\\)\n\
1050e57c 92 -m, --mixed like --windows, but with regular slashes (C:/WINNT)\n\
ca902991
CV
93 -M, --mode report on mode of file (binmode or textmode)\n\
94 -u, --unix (default) print Unix form of NAMEs (/cygdrive/c/winnt)\n\
4c634492 95 -w, --windows print Windows form of NAMEs (C:\\WINNT)\n\
1050e57c 96 -t, --type TYPE print TYPE form: 'dos', 'mixed', 'unix', or 'windows'\n\
92b499ac 97\n\
33bd2d12 98Path conversion options:\n\
92b499ac 99\n\
1050e57c 100 -a, --absolute output absolute path\n\
ca902991
CV
101 -l, --long-name print Windows long form of NAMEs (with -w, -m only)\n\
102 -p, --path NAME is a PATH list (i.e., '/bin:/usr/bin')\n\
103 -s, --short-name print DOS (short) form of NAMEs (with -w, -m only)\n\
0a23799a
CV
104 -C, --codepage CP print DOS, Windows, or mixed pathname in Windows\n\
105 codepage CP. CP can be a numeric codepage identifier,\n\
106 or one of the reserved words ANSI, OEM, or UTF8.\n\
92b499ac 107 If this option is missing, %1$s defaults to the\n\
0a23799a 108 character set defined by the current locale.\n\
92b499ac 109\n\
1050e57c 110System information:\n\
92b499ac 111\n\
ca902991
CV
112 -A, --allusers use `All Users' instead of current user for -D, -O, -P\n\
113 -D, --desktop output `Desktop' directory and exit\n\
1050e57c 114 -H, --homeroot output `Profiles' directory (home root) and exit\n\
ca902991
CV
115 -O, --mydocs output `My Documents' directory and exit\n\
116 -P, --smprograms output Start Menu `Programs' directory and exit\n\
117 -S, --sysdir output system directory and exit\n\
118 -W, --windir output `Windows' directory and exit\n\
119 -F, --folder ID output special folder with numeric ID and exit\n\
92b499ac 120", prog_name);
befdf18b
CF
121 if (ignore_flag)
122 /* nothing to do */;
123 else if (stream != stdout)
124 fprintf(stream, "Try `%s --help' for more information.\n", prog_name);
125 else
1050e57c 126 {
befdf18b 127 fprintf (stream, "\
92b499ac 128\n\
33bd2d12 129Other options:\n\
92b499ac 130\n\
1050e57c
CF
131 -f, --file FILE read FILE for input; use - to read from STDIN\n\
132 -o, --option read options from FILE as well (for use with --file)\n\
133 -c, --close HANDLE close HANDLE (for use in captured process)\n\
ca902991 134 -i, --ignore ignore missing argument\n\
1050e57c 135 -h, --help output usage information and exit\n\
92b499ac
CV
136 -V, --version output version information and exit\n\
137\n");
1050e57c 138 }
45b80bb4
CF
139 exit (ignore_flag ? 0 : status);
140}
141
2dba45f4
CV
142static inline BOOLEAN
143RtlAllocateUnicodeString (PUNICODE_STRING uni, ULONG size)
144{
145 uni->Length = 0;
d2cc418e 146 uni->MaximumLength = size / sizeof (WCHAR);
2dba45f4
CV
147 uni->Buffer = (WCHAR *) malloc (size);
148 return uni->Buffer != NULL;
149}
150
d2cc418e
CV
151static inline BOOLEAN
152RtlEqualUnicodePathPrefix (PUNICODE_STRING path, PUNICODE_STRING prefix,
153 BOOLEAN caseinsensitive)
154 {
155 UNICODE_STRING p;
156
157 p.Length = p.MaximumLength = prefix->Length < path->Length
158 ? prefix->Length : path->Length;
159 p.Buffer = path->Buffer;
160 return RtlEqualUnicodeString (&p, prefix, caseinsensitive);
161 }
162
0a23799a
CV
163static size_t
164my_wcstombs (char *dest, const wchar_t *src, size_t n)
165{
166 if (codepage)
167 return WideCharToMultiByte (codepage, 0, src, -1, dest, n, NULL, NULL);
168 else
169 return wcstombs (dest, src, n);
170}
171
d2cc418e
CV
172#define HARDDISK_PREFIX L"\\Device\\Harddisk"
173#define GLOBALROOT_PREFIX "\\\\.\\GLOBALROOT"
174
2dba45f4
CV
175static char *
176get_device_name (char *path)
177{
178 UNICODE_STRING ntdev, tgtdev, ntdevdir;
179 ANSI_STRING ans;
180 OBJECT_ATTRIBUTES ntobj;
181 NTSTATUS status;
182 HANDLE lnk, dir;
d2cc418e 183 bool got_one = false;
2dba45f4
CV
184 char *ret = strdup (path);
185 PDIRECTORY_BASIC_INFORMATION odi = (PDIRECTORY_BASIC_INFORMATION)
186 alloca (4096);
187 BOOLEAN restart;
188 ULONG cont;
189
d2cc418e
CV
190 if (!strncasecmp (path, GLOBALROOT_PREFIX "\\", sizeof (GLOBALROOT_PREFIX)))
191 path += sizeof (GLOBALROOT_PREFIX) - 1;
2dba45f4
CV
192 if (strncasecmp (path, "\\Device\\", 8))
193 return ret;
194
d2cc418e 195 if (!RtlAllocateUnicodeString (&ntdev, 65534))
2dba45f4 196 return ret;
d2cc418e 197 if (!RtlAllocateUnicodeString (&tgtdev, 65534))
2dba45f4
CV
198 return ret;
199 RtlInitAnsiString (&ans, path);
200 RtlAnsiStringToUnicodeString (&ntdev, &ans, FALSE);
201
202 /* First check if the given device name is a symbolic link itself. If so,
203 query it and use the new name as actual device name to search for in the
204 DOS device name directory. If not, just use the incoming device name. */
205 InitializeObjectAttributes (&ntobj, &ntdev, OBJ_CASE_INSENSITIVE, NULL, NULL);
206 status = ZwOpenSymbolicLinkObject (&lnk, SYMBOLIC_LINK_QUERY, &ntobj);
207 if (NT_SUCCESS (status))
208 {
209 status = ZwQuerySymbolicLinkObject (lnk, &tgtdev, NULL);
210 ZwClose (lnk);
211 if (!NT_SUCCESS (status))
212 goto out;
213 RtlCopyUnicodeString (&ntdev, &tgtdev);
214 }
d2cc418e
CV
215 else if (status != STATUS_OBJECT_TYPE_MISMATCH
216 && status != STATUS_OBJECT_PATH_SYNTAX_BAD)
2dba45f4
CV
217 goto out;
218
219 for (int i = 0; i < 2; ++i)
220 {
221 /* There are two DOS device directories, the local and the global dir.
222 Try both, local first. */
223 RtlInitUnicodeString (&ntdevdir, i ? L"\\GLOBAL??" : L"\\??");
224
225 /* Open the directory... */
226 InitializeObjectAttributes (&ntobj, &ntdevdir, OBJ_CASE_INSENSITIVE,
227 NULL, NULL);
228 status = ZwOpenDirectoryObject (&dir, DIRECTORY_QUERY, &ntobj);
229 if (!NT_SUCCESS (status))
230 break;
231
232 /* ...and scan it. */
233 for (restart = TRUE, cont = 0;
234 NT_SUCCESS (ZwQueryDirectoryObject (dir, odi, 4096, TRUE,
235 restart, &cont, NULL));
236 restart = FALSE)
237 {
238 /* For each entry check if it's a symbolic link. */
239 InitializeObjectAttributes (&ntobj, &odi->ObjectName,
240 OBJ_CASE_INSENSITIVE, dir, NULL);
241 status = ZwOpenSymbolicLinkObject (&lnk, SYMBOLIC_LINK_QUERY, &ntobj);
242 if (!NT_SUCCESS (status))
243 continue;
244 tgtdev.Length = 0;
245 tgtdev.MaximumLength = 512;
246 /* If so, query it and compare the target of the symlink with the
247 incoming device name. */
248 status = ZwQuerySymbolicLinkObject (lnk, &tgtdev, NULL);
249 ZwClose (lnk);
250 if (!NT_SUCCESS (status))
251 continue;
d2cc418e
CV
252 if (tgtdev.Length /* There's actually a symlink pointing to an
253 empty string: \??\GLOBALROOT -> "" */
254 && RtlEqualUnicodePathPrefix (&ntdev, &tgtdev, TRUE))
2dba45f4
CV
255 {
256 /* If the comparison succeeds, the name of the directory entry is
257 a valid DOS device name, if prepended with "\\.\". Return that
258 valid DOS path. */
d2cc418e
CV
259 wchar_t *trailing = NULL;
260 if (ntdev.Length > tgtdev.Length)
261 trailing = ntdev.Buffer + tgtdev.Length / sizeof (WCHAR);
2dba45f4 262 ULONG len = RtlUnicodeStringToAnsiSize (&odi->ObjectName);
d2cc418e
CV
263 if (trailing)
264 len += my_wcstombs (NULL, trailing, 0);
bf4b8020 265 free (ret);
2dba45f4
CV
266 ret = (char *) malloc (len + 4);
267 strcpy (ret, "\\\\.\\");
268 ans.Length = 0;
269 ans.MaximumLength = len;
270 ans.Buffer = ret + 4;
271 RtlUnicodeStringToAnsiString (&ans, &odi->ObjectName, FALSE);
d2cc418e
CV
272 if (trailing)
273 my_wcstombs (ans.Buffer + ans.Length, trailing,
274 ans.MaximumLength - ans.Length);
275 ans.Buffer[ans.MaximumLength - 1] = '\0';
276 got_one = true;
708bbfd0
CV
277 /* Special case for local disks: It's most feasible if the
278 DOS device name reflects the DOS drive, so we check for this
279 explicitly and only return prematurely if so. */
708bbfd0
CV
280 if (ntdev.Length < wcslen (HARDDISK_PREFIX)
281 || wcsncasecmp (ntdev.Buffer, HARDDISK_PREFIX, 8) != 0
282 || (odi->ObjectName.Length == 2 * sizeof (WCHAR)
283 && odi->ObjectName.Buffer[1] == L':'))
284 {
d2cc418e
CV
285 if (trailing)
286 {
287 /* If there's a trailing path, it's a perfectly valid
288 DOS pathname without the \\.\ prefix. Unless it's
289 longer than MAX_PATH - 1 in which case it needs
290 the \\?\ prefix. */
ac5d7dcd 291 if ((len = strlen (ret + 4)) >= MAX_PATH)
d2cc418e
CV
292 ret[2] = '?';
293 else
294 memmove (ret, ret + 4, strlen (ret + 4) + 1);
295 }
708bbfd0
CV
296 ZwClose (dir);
297 goto out;
298 }
2dba45f4
CV
299 }
300 }
301 ZwClose (dir);
302 }
303
304out:
305 free (tgtdev.Buffer);
306 free (ntdev.Buffer);
d2cc418e
CV
307 if (!got_one)
308 {
309 free (ret);
310 ret = (char *) malloc (sizeof (GLOBALROOT_PREFIX) + strlen (path));
311 if (ret)
312 stpcpy (stpcpy (ret, GLOBALROOT_PREFIX), path);
313 }
2dba45f4
CV
314 return ret;
315}
316
317static char *
318get_device_paths (char *path)
319{
320 char *sbuf;
321 char *ptr;
322 int n = 1;
323
324 ptr = path;
325 while ((ptr = strchr (ptr, ';')))
326 {
327 ptr++;
328 n++;
329 }
330
331 char *paths[n];
332 DWORD acc = 0;
333 int i;
334 if (!n)
335 return strdup ("");
336
337 for (i = 0, ptr = path; ptr; i++)
338 {
339 char *next = ptr;
340 ptr = strchr (ptr, ';');
341 if (ptr)
342 *ptr++ = 0;
343 paths[i] = get_device_name (next);
344 acc += strlen (paths[i]) + 1;
345 }
346
347 sbuf = (char *) malloc (acc + 1);
348 if (sbuf == NULL)
349 {
350 fprintf (stderr, "%s: out of memory\n", prog_name);
351 exit (1);
352 }
353
354 sbuf[0] = '\0';
355 for (i = 0; i < n; i++)
356 {
357 strcat (strcat (sbuf, paths[i]), ";");
358 free (paths[i]);
359 }
360
361 strchr (sbuf, '\0')[-1] = '\0';
362 return sbuf;
363}
364
45b80bb4
CF
365static char *
366get_short_paths (char *path)
367{
26fb7ef5
CV
368 wchar_t *sbuf;
369 wchar_t *sptr;
45b80bb4
CF
370 char *next;
371 char *ptr = path;
372 char *end = strrchr (path, 0);
373 DWORD acc = 0;
374 DWORD len;
375
376 while (ptr != NULL)
45b80bb4 377 {
6a344609
CF
378 next = ptr;
379 ptr = strchr (ptr, ';');
380 if (ptr)
381 *ptr++ = 0;
26fb7ef5
CV
382 wide_path wpath (next);
383 len = GetShortPathNameW (wpath, NULL, 0);
cc3ce0bb 384 if (!len)
6a344609 385 {
92b499ac
CV
386 fprintf (stderr, "%s: cannot create short name of %s\n",
387 prog_name, next);
6a344609
CF
388 exit (2);
389 }
390 acc += len + 1;
45b80bb4 391 }
26fb7ef5 392 sptr = sbuf = (wchar_t *) malloc ((acc + 1) * sizeof (wchar_t));
45b80bb4 393 if (sbuf == NULL)
45b80bb4 394 {
6a344609
CF
395 fprintf (stderr, "%s: out of memory\n", prog_name);
396 exit (1);
45b80bb4 397 }
6a344609
CF
398 ptr = path;
399 for (;;)
400 {
26fb7ef5
CV
401 wide_path wpath (ptr);
402 len = GetShortPathNameW (wpath, sptr, acc);
cc3ce0bb 403 if (!len)
6a344609 404 {
92b499ac
CV
405 fprintf (stderr, "%s: cannot create short name of %s\n",
406 prog_name, ptr);
6a344609
CF
407 exit (2);
408 }
45b80bb4 409
6a344609 410 ptr = strrchr (ptr, 0);
26fb7ef5 411 sptr = wcsrchr (sptr, 0);
6a344609
CF
412 if (ptr == end)
413 break;
26fb7ef5 414 *sptr = L';';
6a344609 415 ++ptr, ++sptr;
5bb52de4 416 acc -= len + 1;
6a344609 417 }
0a23799a 418 len = my_wcstombs (NULL, sbuf, 0) + 1;
26fb7ef5
CV
419 ptr = (char *) malloc (len);
420 if (ptr == NULL)
421 {
422 fprintf (stderr, "%s: out of memory\n", prog_name);
423 exit (1);
424 }
0a23799a 425 my_wcstombs (ptr, sbuf, len);
26fb7ef5 426 return ptr;
45b80bb4
CF
427}
428
429static char *
430get_short_name (const char *filename)
431{
26fb7ef5
CV
432 wchar_t buf[32768];
433 char *sbuf;
434 wide_path wpath (filename);
435 DWORD len = GetShortPathNameW (wpath, buf, 32768);
cc3ce0bb 436 if (!len)
6a344609 437 {
92b499ac
CV
438 fprintf (stderr, "%s: cannot create short name of %s\n",
439 prog_name, filename);
6a344609
CF
440 exit (2);
441 }
0a23799a 442 len = my_wcstombs (NULL, buf, 0) + 1;
26fb7ef5 443 sbuf = (char *) malloc (len);
45b80bb4 444 if (sbuf == NULL)
6a344609
CF
445 {
446 fprintf (stderr, "%s: out of memory\n", prog_name);
447 exit (1);
448 }
0a23799a 449 my_wcstombs (sbuf, buf, len);
26fb7ef5 450 return sbuf;
5bb52de4
CV
451}
452
5bb52de4 453static char *
cf157504 454get_long_name (const char *filename, DWORD& len)
5bb52de4 455{
26fb7ef5
CV
456 char *sbuf;
457 wchar_t buf[32768];
26fb7ef5 458 wide_path wpath (filename);
acc31d1a 459
71148bfc
CV
460 if (!GetLongPathNameW (wpath, buf, 32768))
461 wcscpy (buf, wpath);
0a23799a 462 len = my_wcstombs (NULL, buf, 0);
cf157504
CF
463 sbuf = (char *) malloc (len + 1);
464 if (!sbuf)
5bb52de4
CV
465 {
466 fprintf (stderr, "%s: out of memory\n", prog_name);
467 exit (1);
468 }
0a23799a 469 my_wcstombs (sbuf, buf, len + 1);
26fb7ef5 470 return sbuf;
5bb52de4
CV
471}
472
473static char *
cf157504 474get_long_paths (char *path)
5bb52de4 475{
cf157504
CF
476 char *sbuf;
477 char *ptr;
478 int n = 1;
479
480 ptr = path;
481 while ((ptr = strchr (ptr, ';')))
6a344609 482 {
cf157504
CF
483 ptr++;
484 n++;
6a344609 485 }
cf157504
CF
486
487 char *paths[n];
488 DWORD acc = 0;
489 int i;
490 if (!n)
491 return strdup ("");
492
493 for (i = 0, ptr = path; ptr; i++)
494 {
495 DWORD len;
496 char *next = ptr;
497 ptr = strchr (ptr, ';');
498 if (ptr)
499 *ptr++ = 0;
500 paths[i] = get_long_name (next, len);
501 acc += len + 1;
502 }
503
504 sbuf = (char *) malloc (acc + 1);
5bb52de4
CV
505 if (sbuf == NULL)
506 {
507 fprintf (stderr, "%s: out of memory\n", prog_name);
508 exit (1);
509 }
cf157504
CF
510
511 sbuf[0] = '\0';
512 for (i = 0; i < n; i++)
513 {
514 strcat (strcat (sbuf, paths[i]), ";");
515 free (paths[i]);
516 }
517
518 strchr (sbuf, '\0')[-1] = '\0';
519 return sbuf;
5bb52de4
CV
520}
521
33bd2d12
CF
522static void
523convert_slashes (char* name)
524{
525 while ((name = strchr (name, '\\')) != NULL)
526 {
527 if (*name == '\\')
528 *name = '/';
529 name++;
530 }
531}
532
ca902991 533static bool
71148bfc 534get_special_folder (PWCHAR wpath, int id)
ca902991 535{
ca902991
CV
536 LPITEMIDLIST pidl = 0;
537 if (SHGetSpecialFolderLocation (NULL, id, &pidl) != S_OK)
538 return false;
175e39bb 539 if (!SHGetPathFromIDListW (pidl, wpath) || !wpath[0])
ca902991
CV
540 return false;
541 return true;
542}
543
5bb52de4 544static void
fc200025 545do_sysfolders (char option)
5bb52de4 546{
175e39bb 547 WCHAR wbuf[MAX_PATH];
71148bfc 548 char buf[PATH_MAX];
cf157504 549
71148bfc 550 wbuf[0] = L'\0';
5bb52de4
CV
551 switch (option)
552 {
553 case 'D':
71148bfc 554 get_special_folder (wbuf, allusers_flag ? CSIDL_COMMON_DESKTOPDIRECTORY
175e39bb 555 : CSIDL_DESKTOPDIRECTORY);
5bb52de4
CV
556 break;
557
558 case 'P':
71148bfc 559 get_special_folder (wbuf, allusers_flag ? CSIDL_COMMON_PROGRAMS
175e39bb 560 : CSIDL_PROGRAMS);
ca902991
CV
561 break;
562
563 case 'O':
71148bfc 564 get_special_folder (wbuf, allusers_flag ? CSIDL_COMMON_DOCUMENTS
175e39bb 565 : CSIDL_PERSONAL);
ca902991
CV
566 break;
567
568 case 'F':
569 {
570 int val = -1, len = -1;
571 if (!(sscanf (output_arg, "%i%n", &val, &len) == 1
572 && len == (int) strlen (output_arg) && val >= 0))
573 {
574 fprintf (stderr, "%s: syntax error in special folder ID %s\n",
575 prog_name, output_arg);
576 exit (1);
577 }
71148bfc 578 get_special_folder (wbuf, val);
ca902991 579 }
5bb52de4
CV
580 break;
581
582 case 'H':
71148bfc
CV
583 {
584 DWORD len = MAX_PATH;
585 GetProfilesDirectoryW (wbuf, &len);
586 }
5bb52de4
CV
587 break;
588
589 case 'S':
175e39bb
CV
590 {
591 HANDLE fh;
71148bfc 592 WIN32_FIND_DATAW w32_fd;
175e39bb
CV
593
594 GetSystemDirectoryW (wbuf, MAX_PATH);
71148bfc
CV
595 /* The path returned by GetSystemDirectoryW is not case preserving.
596 The below code is a trick to get the correct case of the system
597 directory from Windows. */
175e39bb
CV
598 if ((fh = FindFirstFileW (wbuf, &w32_fd)) != INVALID_HANDLE_VALUE)
599 {
600 FindClose (fh);
601 wcscpy (wcsrchr (wbuf, L'\\') + 1, w32_fd.cFileName);
602 }
175e39bb 603 }
5bb52de4
CV
604 break;
605
606 case 'W':
71148bfc 607 GetSystemWindowsDirectoryW (wbuf, MAX_PATH);
5bb52de4
CV
608 break;
609
610 default:
611 usage (stderr, 1);
612 }
613
71148bfc 614 if (!wbuf[0])
ca902991 615 {
92b499ac
CV
616 fprintf (stderr, "%s: failed to retrieve special folder path\n",
617 prog_name);
ca902991
CV
618 }
619 else if (!windows_flag)
5bb52de4 620 {
71148bfc
CV
621 if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, wbuf, buf, PATH_MAX))
622 fprintf (stderr, "%s: error converting \"%ls\" - %s\n",
623 prog_name, wbuf, strerror (errno));
5bb52de4
CV
624 }
625 else
626 {
627 if (shortname_flag)
71148bfc
CV
628 /* System paths are never longer than MAX_PATH. The buffer pointers
629 in a call to GetShortPathNameW may point to the same buffer. */
630 GetShortPathNameW (wbuf, wbuf, MAX_PATH);
631 my_wcstombs (buf, wbuf, MAX_PATH);
33bd2d12 632 if (mixed_flag)
1b526b48 633 convert_slashes (buf);
5bb52de4
CV
634 }
635 printf ("%s\n", buf);
1fd5e000
CF
636}
637
f135dd3e
CF
638static void
639report_mode (char *filename)
640{
641 switch (cygwin_internal (CW_GET_BINMODE, filename))
642 {
643 case O_BINARY:
644 printf ("%s: binary\n", filename);
645 break;
646 case O_TEXT:
647 printf ("%s: text\n", filename);
648 break;
649 default:
92b499ac
CV
650 fprintf (stderr, "%s: file '%s' - %s\n", prog_name,
651 filename, strerror (errno));
f135dd3e
CF
652 break;
653 }
654}
655
138d4f51 656static void
fc200025 657do_pathconv (char *filename)
138d4f51 658{
bf4b8020
CV
659 char *buf = NULL, *tmp;
660 wchar_t *buf2 = NULL;
71148bfc 661 DWORD len = 32768;
2b2b42cf 662 ssize_t err;
80206d7f 663 bool print_tmp = false;
2b2b42cf 664 cygwin_conv_path_t conv_func =
71148bfc
CV
665 (unix_flag ? CCP_WIN_W_TO_POSIX : CCP_POSIX_TO_WIN_W)
666 | (absolute_flag ? CCP_ABSOLUTE : CCP_RELATIVE);
138d4f51 667
71148bfc 668 if (!filename || !filename[0])
c02e32c9 669 {
71148bfc
CV
670 if (ignore_flag)
671 return;
672 fprintf (stderr, "%s: can't convert empty path\n", prog_name);
673 exit (1);
c02e32c9 674 }
138d4f51
CF
675
676 buf = (char *) malloc (len);
71148bfc 677 if (!unix_flag)
26fb7ef5 678 buf2 = (wchar_t *) malloc (len * sizeof (wchar_t));
138d4f51
CF
679 if (buf == NULL)
680 {
681 fprintf (stderr, "%s: out of memory\n", prog_name);
682 exit (1);
683 }
684
685 if (path_flag)
686 {
71148bfc
CV
687 if (unix_flag)
688 {
689 wide_path wpath (filename);
690 err = cygwin_conv_path_list (conv_func, wpath, buf, len);
691 }
692 else
693 err = cygwin_conv_path_list (conv_func, filename, buf2, len);
694 if (err)
695 {
696 fprintf (stderr, "%s: error converting \"%s\" - %s\n",
697 prog_name, filename, strerror (errno));
698 exit (1);
699 }
2b2b42cf 700 if (!unix_flag)
6a344609 701 {
71148bfc 702 my_wcstombs (buf, buf2, 32768);
bf4b8020
CV
703 buf = get_device_paths (tmp = buf);
704 free (tmp);
6a344609 705 if (shortname_flag)
bf4b8020
CV
706 {
707 buf = get_short_paths (tmp = buf);
708 free (tmp);
709 }
5bb52de4 710 if (longname_flag)
bf4b8020
CV
711 {
712 buf = get_long_paths (tmp = buf);
713 free (tmp);
714 }
2bd6505b 715 if (mixed_flag)
1b526b48 716 convert_slashes (buf);
6a344609 717 }
138d4f51
CF
718 }
719 else
720 {
71148bfc
CV
721 if (unix_flag)
722 {
723 wide_path wpath (filename);
724 err = cygwin_conv_path (conv_func, wpath, (void *) buf, len);
725 }
726 else
727 err = cygwin_conv_path (conv_func, filename, (void *) buf2, len);
7c03f799 728 if (err)
6a344609 729 {
7c03f799
CF
730 fprintf (stderr, "%s: error converting \"%s\" - %s\n",
731 prog_name, filename, strerror (errno));
6a344609
CF
732 exit (1);
733 }
5bb52de4
CV
734 if (!unix_flag)
735 {
0a23799a 736 my_wcstombs (buf, buf2, 32768);
bf4b8020
CV
737 buf = get_device_name (tmp = buf);
738 free (tmp);
7ca68b7e 739 if (shortname_flag)
bf4b8020
CV
740 {
741 buf = get_short_name (tmp = buf);
742 free (tmp);
743 }
7ca68b7e 744 if (longname_flag)
bf4b8020
CV
745 {
746 buf = get_long_name (tmp = buf, len);
747 free (tmp);
748 }
bf4b8020 749 tmp = buf;
8c3a79bb 750 if (strncmp (buf, "\\\\?\\", 4) == 0)
26fb7ef5 751 {
d2cc418e
CV
752 len = 0;
753 if (buf[5] == ':')
754 len = 4;
755 else if (!strncmp (buf + 4, "UNC\\", 4))
8c3a79bb 756 len = 6;
d2cc418e 757 if (len && strlen (buf) < MAX_PATH + len)
8c3a79bb 758 {
03ac74c1 759 tmp += len;
8c3a79bb 760 if (len == 6)
03ac74c1 761 *tmp = '\\';
80206d7f 762 print_tmp = true;
8c3a79bb 763 }
26fb7ef5 764 }
8c3a79bb 765 if (mixed_flag)
03ac74c1 766 convert_slashes (tmp);
5bb52de4 767 }
138d4f51
CF
768 }
769
80206d7f 770 puts (print_tmp ? tmp : buf);
bf4b8020
CV
771 if (buf2)
772 free (buf2);
773 if (buf)
03ac74c1 774 free (buf);
138d4f51
CF
775}
776
6a344609
CF
777static void
778print_version ()
779{
92b499ac
CV
780 printf ("cygpath (cygwin) %d.%d.%d\n"
781 "Path Conversion Utility\n"
782 "Copyright (C) 1998 - %s Red Hat, Inc.\n"
783 "This is free software; see the source for copying conditions. There is NO\n"
784 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
785 CYGWIN_VERSION_DLL_MAJOR / 1000,
786 CYGWIN_VERSION_DLL_MAJOR % 1000,
787 CYGWIN_VERSION_DLL_MINOR,
788 strrchr (__DATE__, ' ') + 1);
6a344609
CF
789}
790
fc200025
CV
791static int
792do_options (int argc, char **argv, int from_file)
1fd5e000 793{
6a344609 794 int c, o = 0;
1fd5e000 795 path_flag = 0;
fc200025 796 unix_flag = 0;
1fd5e000 797 windows_flag = 0;
45b80bb4 798 shortname_flag = 0;
5bb52de4 799 longname_flag = 0;
2bd6505b 800 mixed_flag = 0;
45b80bb4 801 ignore_flag = 0;
3cdacffc
CV
802 allusers_flag = 0;
803 output_flag = 0;
f135dd3e 804 mode_flag = 0;
0a23799a 805 codepage = 0;
fc200025
CV
806 if (!from_file)
807 options_from_file_flag = 0;
808 optind = 0;
9b566b96 809 while ((c = getopt_long (argc, argv, options,
2bd6505b 810 long_options, (int *) NULL)) != EOF)
1fd5e000
CF
811 {
812 switch (c)
813 {
418068d4
CF
814 case 'a':
815 absolute_flag = 1;
816 break;
817
818 case 'c':
fc200025
CV
819 if (!optarg)
820 usage (stderr, 1);
418068d4
CF
821 CloseHandle ((HANDLE) strtoul (optarg, NULL, 16));
822 break;
823
1050e57c 824 case 'd':
1050e57c
CF
825 windows_flag = 1;
826 shortname_flag = 1;
827 break;
828
138d4f51 829 case 'f':
fc200025
CV
830 if (from_file || !optarg)
831 usage (stderr, 1);
138d4f51
CF
832 file_arg = optarg;
833 break;
834
f135dd3e
CF
835 case 'M':
836 mode_flag = 1;
837 break;
838
418068d4 839 case 'o':
fc200025
CV
840 if (from_file)
841 usage (stderr, 1);
418068d4
CF
842 options_from_file_flag = 1;
843 break;
844
1fd5e000
CF
845 case 'p':
846 path_flag = 1;
847 break;
848
849 case 'u':
1fd5e000
CF
850 unix_flag = 1;
851 break;
852
853 case 'w':
1fd5e000
CF
854 windows_flag = 1;
855 break;
856
1050e57c 857 case 'm':
1050e57c
CF
858 windows_flag = 1;
859 mixed_flag = 1;
860 break;
861
5bb52de4 862 case 'l':
5bb52de4
CV
863 longname_flag = 1;
864 break;
865
45b80bb4 866 case 's':
45b80bb4
CF
867 shortname_flag = 1;
868 break;
869
fc200025
CV
870 case 't':
871 if (!optarg)
2bd6505b
CF
872 usage (stderr, 1);
873
1050e57c
CF
874 format_type_arg = (*optarg == '=') ? (optarg + 1) : (optarg);
875 if (strcasecmp (format_type_arg, "dos") == 0)
cf157504 876 {
fc200025
CV
877 windows_flag = 1;
878 shortname_flag = 1;
cf157504 879 }
fc200025 880 else if (!strcasecmp (format_type_arg, "mixed"))
cf157504 881 {
fc200025
CV
882 windows_flag = 1;
883 mixed_flag = 1;
cf157504 884 }
fc200025 885 else if (!strcasecmp (format_type_arg, "unix"))
1050e57c 886 unix_flag = 1;
fc200025 887 else if (!strcasecmp (format_type_arg, "windows"))
cf157504 888 windows_flag = 1;
2bd6505b
CF
889 else
890 usage (stderr, 1);
891 break;
892
3cdacffc
CV
893 case 'A':
894 allusers_flag = 1;
895 break;
896
0a23799a
CV
897 case 'C':
898 if (!optarg)
899 usage (stderr, 1);
900 if (!strcasecmp (optarg, "ANSI"))
901 codepage = GetACP ();
902 else if (!strcasecmp (optarg, "OEM"))
903 codepage = GetOEMCP ();
904 else if (!strcasecmp (optarg, "UTF8")
905 || !strcasecmp (optarg, "UTF-8"))
906 codepage = CP_UTF8;
907 else
908 {
909 char *c;
910 codepage = (UINT) strtoul (optarg, &c, 10);
911 if (*c)
912 usage (stderr, 1);
913 }
914 break;
915
3cdacffc 916 case 'D':
e355de81 917 case 'H':
ca902991 918 case 'O':
3cdacffc 919 case 'P':
f00c1d2c 920 case 'S':
3cdacffc 921 case 'W':
fc200025 922 ++output_flag;
e355de81 923 o = c;
3cdacffc 924 break;
f00c1d2c 925
ca902991 926 case 'F':
fc200025 927 if (!optarg)
ca902991 928 usage (stderr, 1);
fc200025 929 ++output_flag;
ca902991
CV
930 output_arg = optarg;
931 o = c;
932 break;
933
45b80bb4
CF
934 case 'i':
935 ignore_flag = 1;
936 break;
937
1fd5e000
CF
938 case 'h':
939 usage (stdout, 0);
940 break;
941
92b499ac 942 case 'V':
6a344609 943 print_version ();
1fd5e000
CF
944 exit (0);
945
946 default:
92b499ac
CV
947 fprintf (stderr, "Try `%s --help' for more information.\n",
948 prog_name);
949 exit (1);
1fd5e000
CF
950 }
951 }
952
fc200025 953 /* If none of the "important" flags are set, -u is default. */
df1841c3
CV
954 if (!unix_flag && !windows_flag && !mode_flag
955 && (!from_file ? !options_from_file_flag : 1))
fc200025
CV
956 unix_flag = 1;
957
958 /* Only one of ... */
df1841c3 959 if (unix_flag + windows_flag + mode_flag > 1
fc200025 960 + (!from_file ? options_from_file_flag : 0))
418068d4
CF
961 usage (stderr, 1);
962
fc200025
CV
963 /* options_from_file_flag requires a file. */
964 if (!from_file && options_from_file_flag && !file_arg)
1050e57c
CF
965 usage (stderr, 1);
966
fc200025
CV
967 /* longname and shortname don't play well together. */
968 if (longname_flag && shortname_flag)
1050e57c
CF
969 usage (stderr, 1);
970
fc200025
CV
971 /* longname and shortname only make sense with Windows paths. */
972 if ((longname_flag || shortname_flag) && !windows_flag)
1fd5e000
CF
973 usage (stderr, 1);
974
fc200025
CV
975 return o;
976}
977
978static void
979action (int argc, char **argv, int opt)
980{
981 if (output_flag)
1fd5e000 982 {
fc200025
CV
983 if (argv[optind])
984 usage (stderr, 1);
5bb52de4 985
fc200025
CV
986 do_sysfolders (opt);
987 }
988 else
989 {
0a5ea947 990 if (optind > argc - 1)
138d4f51 991 usage (stderr, 1);
1fd5e000 992
f135dd3e
CF
993 for (int i = optind; argv[i]; i++)
994 if (mode_flag)
995 report_mode (argv[i]);
996 else
fc200025 997 do_pathconv (argv[i]);
138d4f51 998 }
fc200025
CV
999}
1000
1001int
1002main (int argc, char **argv)
1003{
1004 int o;
1005
73535010 1006 setlocale (LC_CTYPE, "");
92b499ac 1007 prog_name = program_invocation_short_name;
fc200025
CV
1008
1009 o = do_options (argc, argv, 0);
1010
1011 if (!file_arg)
1012 action (argc, argv, o);
1fd5e000
CF
1013 else
1014 {
138d4f51
CF
1015 FILE *fp;
1016 char buf[PATH_MAX * 2 + 1];
1fd5e000 1017
138d4f51
CF
1018 if (argv[optind])
1019 usage (stderr, 1);
1fd5e000 1020
fc200025
CV
1021 if (strcmp (file_arg, "-"))
1022 {
1023 if (!(fp = fopen (file_arg, "rt")))
1024 {
1025 perror ("cygpath");
1026 exit (1);
1027 }
1028 }
1fd5e000 1029 else
138d4f51
CF
1030 {
1031 fp = stdin;
1032 setmode (0, O_TEXT);
1033 }
418068d4 1034 setbuf (stdout, NULL);
fc200025
CV
1035
1036 while (fgets (buf, sizeof (buf), fp))
138d4f51 1037 {
6004370b
CV
1038 int ac = 0;
1039 char *av[4] = { NULL, NULL, NULL, NULL };
fc200025 1040 char *p = strchr (buf, '\n');
138d4f51
CF
1041 if (p)
1042 *p = '\0';
6004370b
CV
1043 p = buf;
1044 av[ac++] = prog_name;
1045 av[ac++] = p;
1046 if (options_from_file_flag && *p == '-')
fc200025 1047 {
6004370b
CV
1048 while (*p && !isspace (*p))
1049 ++p;
1050 if (*p)
1051 {
1052 *p++ = '\0';
1053 while (*p && isspace (*p))
1054 ++p;
1055 av[ac++] = p;
1056 }
1057 o = do_options (ac, av, 1);
fc200025 1058 }
6004370b 1059 else
418068d4 1060 {
6004370b
CV
1061 output_flag = 0;
1062 optind = 1;
418068d4 1063 }
fc200025 1064 action (ac, av, o);
138d4f51
CF
1065 }
1066 }
1fd5e000
CF
1067 exit (0);
1068}
This page took 0.375759 seconds and 5 git commands to generate.