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