]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000, Red Hat, Inc. | |
3 | * | |
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. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by DJ Delorie <dj@cygnus.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* see mkdir.h */ | |
17 | ||
18 | #include "win32.h" | |
19 | #include "ntdll.h" | |
20 | ||
21 | #include <sys/stat.h> | |
22 | ||
23 | #include "mkdir.h" | |
24 | #include "filemanip.h" | |
25 | #include "LogSingleton.h" | |
26 | ||
27 | /* Return 0 on success. | |
28 | A mode of 0 means no POSIX perms. */ | |
29 | int | |
30 | mkdir_p (int isadir, const char *in_path, mode_t mode) | |
31 | { | |
32 | char saved_char, *slash = 0; | |
33 | char *c; | |
34 | const size_t len = strlen (in_path) + 1; | |
35 | char path[len]; | |
36 | DWORD d, gse; | |
37 | WCHAR wpath[len + 6]; | |
38 | ||
39 | strcpy (path, in_path); | |
40 | mklongpath (wpath, path, len + 6); | |
41 | ||
42 | d = GetFileAttributesW (wpath); | |
43 | if (d != INVALID_FILE_ATTRIBUTES && d & FILE_ATTRIBUTE_DIRECTORY) | |
44 | return 0; | |
45 | ||
46 | if (isadir) | |
47 | { | |
48 | NTSTATUS status; | |
49 | HANDLE dir; | |
50 | UNICODE_STRING upath; | |
51 | OBJECT_ATTRIBUTES attr; | |
52 | IO_STATUS_BLOCK io; | |
53 | SECURITY_DESCRIPTOR sd; | |
54 | acl_t acl; | |
55 | ||
56 | wpath[1] = '?'; | |
57 | upath.Length = wcslen (wpath) * sizeof (WCHAR); | |
58 | upath.MaximumLength = upath.Length + sizeof (WCHAR); | |
59 | upath.Buffer = wpath; | |
60 | InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, | |
61 | mode == 0 ? NULL | |
62 | : nt_sec.GetPosixPerms (path, NULL, NULL, | |
63 | S_IFDIR | mode, | |
64 | sd, acl)); | |
65 | status = NtCreateFile (&dir, SYNCHRONIZE | READ_CONTROL | |
66 | | FILE_LIST_DIRECTORY, | |
67 | &attr, &io, NULL, FILE_ATTRIBUTE_DIRECTORY, | |
68 | FILE_SHARE_VALID_FLAGS, FILE_CREATE, | |
69 | FILE_DIRECTORY_FILE | |
70 | | FILE_SYNCHRONOUS_IO_NONALERT | |
71 | | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0); | |
72 | if (NT_SUCCESS (status)) | |
73 | { | |
74 | NtClose (dir); | |
75 | return 0; | |
76 | } | |
77 | else | |
78 | SetLastError (RtlNtStatusToDosError (status)); | |
79 | gse = GetLastError (); | |
80 | if (gse != ERROR_PATH_NOT_FOUND && gse != ERROR_FILE_NOT_FOUND) | |
81 | { | |
82 | if (gse == ERROR_ALREADY_EXISTS) | |
83 | { | |
84 | Log (LOG_TIMESTAMP) << "warning: deleting \"" << path | |
85 | << "\" so I can make a directory there" << endLog; | |
86 | if (DeleteFileW (wpath)) | |
87 | return mkdir_p (isadir, path, mode ? 0755 : 0); | |
88 | } | |
89 | return 1; | |
90 | } | |
91 | } | |
92 | ||
93 | for (c = path; *c; c++) | |
94 | { | |
95 | if (*c == '/' || *c == '\\') | |
96 | slash = c; | |
97 | } | |
98 | ||
99 | if (!slash) | |
100 | return 0; | |
101 | ||
102 | // Trying to create a drive... It's time to give up. | |
103 | if (((slash - path) == 2) && (path[1] == ':')) | |
104 | return 1; | |
105 | ||
106 | saved_char = *slash; | |
107 | *slash = 0; | |
108 | if (mkdir_p (1, path, mode ? 0755 : 0)) | |
109 | { | |
110 | *slash = saved_char; | |
111 | return 1; | |
112 | } | |
113 | ||
114 | *slash = saved_char; | |
115 | ||
116 | if (!isadir) | |
117 | return 0; | |
118 | ||
119 | return mkdir_p (isadir, path, mode); | |
120 | } |