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