2 * Copyright (c) 2000, 2001, Red Hat, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
12 * Written by Robert Collins <rbtcollins@redhat.com>
16 /* The purpose of this file is to put all general purpose file manipulation
22 #include "filemanip.h"
23 #include "io_stream.h"
31 * Clients should use io_stream.get_size() */
33 get_file_size (const std::string
& name
)
35 io_stream
*theFile
= io_stream::open (name
, "", 0);
37 /* To consider: throw an exception ? */
39 ssize_t rv
= theFile
->get_size();
44 /* returns the number of characters of path that
45 * precede the extension
48 find_tar_ext (const char *path
)
50 char *p
= strchr (path
, '\0') - 9;
53 if ((p
= strstr (p
, ".tar")) != NULL
)
59 /* Parse a filename into package, version, and extension components. */
61 parse_filename (const std::string
&fn
, fileparse
& f
)
66 if (!(n
= find_tar_ext (fn
.c_str ())))
72 f
.tail
= fn
.substr (n
, std::string::npos
);
74 p
= new_cstr_char_array (fn
.substr (0, n
));
76 /* TODO: make const and non-const trail variant. */
77 if ((ext
= trail (p
, "-src")))
82 else if ((ext
= trail (p
, "-patch")))
87 for (ver
= p
; *ver
; ver
++)
96 else if (strcasecmp (ver
, "-src") == 0 ||
97 strcasecmp (ver
, "-patch") == 0)
101 f
.what
= strlwr (ver
);
102 ver
= strchr (ver
, '\0');
113 char *p1
= strchr (ver
, '\0');
114 if ((p1
-= 4) >= ver
&& strcasecmp (p1
, "-src") == 0)
116 else if ((p1
-= 2) >= ver
&& strcasecmp (p1
, "-patch") == 0)
122 // get the 'src' or 'patch'.
127 f
.ver
= *ver
? ver
: "0.0";
133 trail (const char *haystack
, const char *needle
)
135 /* See if the path ends with a specific suffix.
136 Just return if it doesn't. */
137 unsigned len
= strlen (haystack
);
138 int prefix_len
= len
- strlen (needle
);
140 || strcasecmp (haystack
+= prefix_len
, needle
) != 0)
146 backslash(const std::string
& s
)
150 for (std::string::iterator it
= rv
.begin(); it
!= rv
.end(); ++it
)
157 wchar_t tfx_chars
[] = {
158 0, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
159 0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
160 0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
161 0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
162 ' ', '!', 0xf000 | '"', '#', '$', '%', '&', 39,
163 '(', ')', 0xf000 | '*', '+', ',', '-', '.', '\\',
164 '0', '1', '2', '3', '4', '5', '6', '7',
165 '8', '9', 0xf000 | ':', ';', 0xf000 | '<', '=', 0xf000 | '>', 0xf000 | '?',
166 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
167 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
168 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
169 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
170 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
171 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
172 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
173 'x', 'y', 'z', '{', 0xf000 | '|', '}', '~', 127
177 mklongpath (wchar_t *tgt
, const char *src
, size_t len
)
183 wcscpy (tgt
, L
"\\\\?\\");
186 if (isdirsep (src
[0]) && isdirsep (src
[1]))
192 ++src
; /* Skip one leading backslash. */
195 ts
= tp
+ 2; /* Skip colon in leading drive specifier. */
197 memset (&mb
, 0, sizeof mb
);
200 n
= mbrtowc (tp
, src
, 6, &mb
);
201 if (n
== (size_t) -1 || n
== (size_t) -2)
206 /* Transform char according to Cygwin rules. */
207 if (tp
>= ts
&& *tp
< 128)
208 *tp
= tfx_chars
[*tp
];
209 /* Skip multiple backslashes. */
210 if (*tp
== L
'\\' && tp
[-1] == L
'\\')
212 /* Skip "." and ".." path components. They result in annoying error
214 if (*tp
== L
'.' && tp
[-1] == L
'\\')
218 if (isdirsep (src
[0]))
223 if (src
[0] == '.' && isdirsep (src
[1]))
226 /* Set tp back to start of previous path component. */
234 while (tp
> ts
&& tp
[-1] != L
'\\');
244 /* Always remove trailing backslash. */
245 if (tgt
[ret
- 1] == L
'\\')
251 mklongrelpath (wchar_t *tgt
, const char *src
, size_t len
)
258 memset (&mb
, 0, sizeof mb
);
262 n
= mbrtowc (tp
, src
, 6, &mb
);
263 if (n
== (size_t) -1 || n
== (size_t) -2)
268 /* Transform char according to Cygwin rules. */
270 *tp
= tfx_chars
[*tp
];
277 /* Replacement functions for Win32 API functions. The joke here is that the
278 replacement functions always use the FILE_OPEN_FOR_BACKUP_INTENT flag. */
280 extern "C" DWORD WINAPI
281 GetFileAttributesW (LPCWSTR wpath
)
286 UNICODE_STRING uname
;
287 OBJECT_ATTRIBUTES attr
;
288 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
290 PWCHAR wname
= (PWCHAR
) wpath
;
292 RtlInitUnicodeString (&uname
, wname
);
293 InitializeObjectAttributes (&attr
, &uname
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
294 status
= NtOpenFile (&h
, READ_CONTROL
| FILE_READ_ATTRIBUTES
, &attr
, &io
,
295 FILE_SHARE_VALID_FLAGS
,
296 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT
);
298 if (NT_SUCCESS (status
))
300 FILE_BASIC_INFORMATION fbi
;
302 status
= NtQueryInformationFile (h
, &io
, &fbi
, sizeof fbi
,
303 FileBasicInformation
);
304 if (NT_SUCCESS (status
))
305 ret
= fbi
.FileAttributes
;
308 if (!NT_SUCCESS (status
))
309 SetLastError (RtlNtStatusToDosError (status
));
313 extern "C" BOOL WINAPI
314 SetFileAttributesW (LPCWSTR wpath
, DWORD attribs
)
319 UNICODE_STRING uname
;
320 OBJECT_ATTRIBUTES attr
;
322 PWCHAR wname
= (PWCHAR
) wpath
;
324 RtlInitUnicodeString (&uname
, wname
);
325 InitializeObjectAttributes (&attr
, &uname
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
326 status
= NtOpenFile (&h
, READ_CONTROL
| FILE_WRITE_ATTRIBUTES
, &attr
, &io
,
327 FILE_SHARE_VALID_FLAGS
,
328 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT
);
330 if (NT_SUCCESS (status
))
332 FILE_BASIC_INFORMATION fbi
;
334 memset (&fbi
, 0, sizeof fbi
);
335 fbi
.FileAttributes
= attribs
?: FILE_ATTRIBUTE_NORMAL
;
336 status
= NtSetInformationFile (h
, &io
, &fbi
, sizeof fbi
,
337 FileBasicInformation
);
340 if (!NT_SUCCESS (status
))
341 SetLastError (RtlNtStatusToDosError (status
));
342 return NT_SUCCESS (status
);
345 extern "C" BOOL WINAPI
346 MoveFileW (LPCWSTR from
, LPCWSTR to
)
351 UNICODE_STRING uname
;
352 OBJECT_ATTRIBUTES attr
;
354 PWCHAR wfrom
= (PWCHAR
) from
;
356 RtlInitUnicodeString (&uname
, wfrom
);
357 InitializeObjectAttributes (&attr
, &uname
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
358 status
= NtOpenFile (&h
, READ_CONTROL
| DELETE
,
359 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
360 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT
);
362 if (NT_SUCCESS (status
))
364 size_t len
= wcslen (to
) * sizeof (WCHAR
);
365 PFILE_RENAME_INFORMATION pfri
= (PFILE_RENAME_INFORMATION
)
366 malloc (sizeof (FILE_RENAME_INFORMATION
) + len
);
367 pfri
->ReplaceIfExists
= TRUE
;
368 pfri
->RootDirectory
= NULL
;
369 pfri
->FileNameLength
= len
;
370 memcpy (pfri
->FileName
, to
, len
);
371 pfri
->FileName
[1] = L
'?';
372 status
= NtSetInformationFile(h
, &io
, pfri
,
373 sizeof (FILE_RENAME_INFORMATION
) + len
,
374 FileRenameInformation
);
378 if (!NT_SUCCESS (status
))
379 SetLastError (RtlNtStatusToDosError (status
));
380 return NT_SUCCESS (status
);
384 unlink (LPCWSTR wpath
, ULONG file_attr
)
389 UNICODE_STRING uname
;
390 OBJECT_ATTRIBUTES attr
;
392 PWCHAR wname
= (PWCHAR
) wpath
;
394 RtlInitUnicodeString (&uname
, wname
);
395 InitializeObjectAttributes (&attr
, &uname
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
396 status
= NtOpenFile (&h
, READ_CONTROL
| DELETE
,
397 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
398 FILE_OPEN_FOR_BACKUP_INTENT
399 | FILE_OPEN_REPARSE_POINT
402 if (NT_SUCCESS (status
))
404 FILE_DISPOSITION_INFORMATION fdi
= { TRUE
};
405 status
= NtSetInformationFile (h
, &io
, &fdi
, sizeof fdi
,
406 FileDispositionInformation
);
409 if (!NT_SUCCESS (status
))
410 SetLastError (RtlNtStatusToDosError (status
));
411 return NT_SUCCESS (status
);
414 extern "C" BOOL WINAPI
415 DeleteFileW (LPCWSTR wpath
)
417 return unlink (wpath
, FILE_NON_DIRECTORY_FILE
);
420 extern "C" BOOL WINAPI
421 RemoveDirectoryW (LPCWSTR wpath
)
423 return unlink (wpath
, FILE_DIRECTORY_FILE
);
426 /* Perms of 0 means no POSIX perms. */
428 nt_wfopen (const wchar_t *wpath
, const char *mode
, mode_t perms
)
433 UNICODE_STRING uname
;
434 OBJECT_ATTRIBUTES attr
;
435 SECURITY_DESCRIPTOR sd
;
444 access
= STANDARD_RIGHTS_READ
| GENERIC_READ
;
448 access
= STANDARD_RIGHTS_WRITE
| GENERIC_WRITE
;
449 disp
= FILE_OVERWRITE_IF
;
452 access
= STANDARD_RIGHTS_WRITE
| GENERIC_WRITE
;
460 for (c
= mode
+ 1; *c
; ++c
)
464 access
= STANDARD_RIGHTS_WRITE
| GENERIC_READ
| GENERIC_WRITE
;
484 case GENERIC_READ
| GENERIC_WRITE
:
488 PWCHAR wname
= (PWCHAR
) wpath
;
490 RtlInitUnicodeString (&uname
, wname
);
491 InitializeObjectAttributes (&attr
, &uname
, OBJ_CASE_INSENSITIVE
, NULL
,
492 disp
== FILE_OPEN
|| perms
== 0
494 : nt_sec
.GetPosixPerms ("", NULL
, NULL
,
496 status
= NtCreateFile (&h
, access
| SYNCHRONIZE
, &attr
, &io
, NULL
,
497 FILE_ATTRIBUTE_NORMAL
, FILE_SHARE_VALID_FLAGS
, disp
,
498 FILE_OPEN_FOR_BACKUP_INTENT
499 | FILE_OPEN_REPARSE_POINT
500 | FILE_SYNCHRONOUS_IO_NONALERT
,
502 if (!NT_SUCCESS (status
))
504 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
505 || status
== STATUS_OBJECT_PATH_NOT_FOUND
506 || status
== STATUS_NO_SUCH_FILE
)
508 else if (status
== STATUS_OBJECT_NAME_INVALID
)
516 int fd
= _open_osfhandle ((intptr_t) h
, oflags
);
519 return _fdopen (fd
, mode
);
523 nt_fopen (const char *path
, const char *mode
, mode_t perms
)
525 size_t len
= strlen (path
) + 8;
527 mklongpath (wpath
, path
, len
);
528 return nt_wfopen (wpath
, mode
, perms
);
531 /* Override C file io functions for the sake of the download side of setup.
532 These overrides eliminate the problem that the ANSI file API limits the
533 filename length to MAX_PATH. */
535 remove (const char *path
)
537 size_t len
= strlen (path
) + 8;
539 mklongpath (wpath
, path
, len
);
540 return unlink (wpath
, 0) ? 0 : -1;
544 rename (const char *oldpath
, const char *newpath
)
546 size_t len
= strlen (oldpath
) + 8;
548 mklongpath (woldpath
, oldpath
, len
);
550 len
= strlen (newpath
) + 8;
552 mklongpath (wnewpath
, newpath
, len
);
554 return MoveFileW (woldpath
, wnewpath
) ? 0 : -1;
558 _access (const char *path
, int /* ignored */)
560 size_t len
= strlen (path
) + 8;
562 mklongpath (wpath
, path
, len
);
563 return (GetFileAttributesW (wpath
) != INVALID_FILE_ATTRIBUTES
) ? 0 : -1;