]>
Commit | Line | Data |
---|---|---|
23c9e63c DD |
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 | ||
b24c88b3 RC |
18 | #if 0 |
19 | static const char *cvsid = | |
20 | "\n%%% $Id$\n"; | |
21 | #endif | |
8507f105 | 22 | |
aa1e3b4d | 23 | #if defined(WIN32) && !defined (_CYGWIN_) |
23c9e63c | 24 | #include "win32.h" |
6dcfeb7d | 25 | #include "ntdll.h" |
ac949c48 MB |
26 | #else |
27 | #include <unistd.h> | |
28 | #include <string.h> | |
29 | #include <errno.h> | |
aa1e3b4d | 30 | #endif |
89cc2408 CV |
31 | |
32 | #include <sys/stat.h> | |
23c9e63c DD |
33 | #include <stdio.h> |
34 | ||
35 | #include "mkdir.h" | |
2f0315ad | 36 | #include "filemanip.h" |
23c9e63c | 37 | |
d2a5fdfb | 38 | /* A mode of 0 means no POSIX perms. */ |
23c9e63c | 39 | int |
b41c2908 | 40 | mkdir_p (int isadir, const char *in_path, mode_t mode) |
23c9e63c DD |
41 | { |
42 | char saved_char, *slash = 0; | |
43 | char *c; | |
2f0315ad CV |
44 | const size_t len = strlen (in_path) + 1; |
45 | char path[len]; | |
aa1e3b4d RC |
46 | #if defined(WIN32) && !defined (_CYGWIN_) |
47 | DWORD d, gse; | |
2f0315ad CV |
48 | WCHAR wpath[len + 6]; |
49 | ||
85b43844 | 50 | strcpy (path, in_path); |
2f0315ad CV |
51 | if (IsWindowsNT ()) |
52 | mklongpath (wpath, path, len + 6); | |
23c9e63c | 53 | |
2f0315ad CV |
54 | d = IsWindowsNT () ? GetFileAttributesW (wpath) : GetFileAttributesA (path); |
55 | if (d != INVALID_FILE_ATTRIBUTES && d & FILE_ATTRIBUTE_DIRECTORY) | |
23c9e63c DD |
56 | return 0; |
57 | ||
58 | if (isadir) | |
59 | { | |
b41c2908 CV |
60 | if (IsWindowsNT ()) |
61 | { | |
62 | NTSTATUS status; | |
63 | HANDLE dir; | |
64 | UNICODE_STRING upath; | |
65 | OBJECT_ATTRIBUTES attr; | |
66 | IO_STATUS_BLOCK io; | |
26922cd2 CV |
67 | SECURITY_DESCRIPTOR sd; |
68 | acl_t acl; | |
b41c2908 | 69 | |
b41c2908 CV |
70 | wpath[1] = '?'; |
71 | upath.Length = wcslen (wpath) * sizeof (WCHAR); | |
72 | upath.MaximumLength = upath.Length + sizeof (WCHAR); | |
73 | upath.Buffer = wpath; | |
26922cd2 | 74 | InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, |
d2a5fdfb CV |
75 | mode == 0 ? NULL |
76 | : nt_sec.GetPosixPerms (path, NULL, NULL, | |
77 | S_IFDIR | mode, | |
78 | sd, acl)); | |
26922cd2 | 79 | status = NtCreateFile (&dir, SYNCHRONIZE | READ_CONTROL |
21aa9a8b | 80 | | FILE_LIST_DIRECTORY, |
6dcfeb7d CV |
81 | &attr, &io, NULL, FILE_ATTRIBUTE_DIRECTORY, |
82 | FILE_SHARE_VALID_FLAGS, FILE_CREATE, | |
83 | FILE_DIRECTORY_FILE | |
84 | | FILE_SYNCHRONOUS_IO_NONALERT | |
85 | | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0); | |
b41c2908 CV |
86 | if (NT_SUCCESS (status)) |
87 | { | |
6dcfeb7d | 88 | NtClose (dir); |
b41c2908 CV |
89 | return 0; |
90 | } | |
91 | else | |
6dcfeb7d | 92 | SetLastError (RtlNtStatusToDosError (status)); |
b41c2908 CV |
93 | } |
94 | else if (CreateDirectoryA (path, 0)) | |
23c9e63c DD |
95 | return 0; |
96 | gse = GetLastError (); | |
89725f30 | 97 | if (gse != ERROR_PATH_NOT_FOUND && gse != ERROR_FILE_NOT_FOUND) |
23c9e63c DD |
98 | { |
99 | if (gse == ERROR_ALREADY_EXISTS) | |
100 | { | |
b24c88b3 RC |
101 | fprintf (stderr, |
102 | "warning: deleting \"%s\" so I can make a directory there\n", | |
1fd6d0a2 | 103 | path); |
2f0315ad | 104 | if (IsWindowsNT () ? DeleteFileW (wpath) : DeleteFileA (path)) |
d2a5fdfb | 105 | return mkdir_p (isadir, path, mode ? 0755 : 0); |
23c9e63c DD |
106 | } |
107 | return 1; | |
108 | } | |
109 | } | |
aa1e3b4d | 110 | #else |
ac949c48 | 111 | struct stat st; |
aa1e3b4d | 112 | strcpy (path, in_path); |
23c9e63c | 113 | |
ac949c48 MB |
114 | if (stat(path,&st) == 0 && S_ISDIR(st.st_mode)) |
115 | return 0; | |
116 | ||
117 | if (isadir) | |
118 | { | |
119 | if (mkdir (path, 0777)) | |
120 | return 0; | |
121 | if (errno != ENOENT) | |
122 | { | |
123 | if (errno == EEXIST) | |
124 | { | |
125 | fprintf (stderr, | |
126 | "warning: deleting \"%s\" so I can make a directory there\n", | |
127 | path); | |
128 | if (unlink (path)) | |
129 | return mkdir_p (isadir, path); | |
130 | } | |
131 | return 1; | |
132 | } | |
133 | } | |
aa1e3b4d RC |
134 | #endif |
135 | ||
85b43844 | 136 | for (c = path; *c; c++) |
23c9e63c DD |
137 | { |
138 | if (*c == ':') | |
139 | slash = 0; | |
140 | if (*c == '/' || *c == '\\') | |
141 | slash = c; | |
142 | } | |
143 | ||
144 | if (!slash) | |
145 | return 0; | |
146 | ||
f2e49cf8 RC |
147 | // Trying to create a drive... It's time to give up. |
148 | if (((slash - path) == 2) && (path[1] == ':')) | |
149 | return 1; | |
150 | ||
23c9e63c DD |
151 | saved_char = *slash; |
152 | *slash = 0; | |
d2a5fdfb | 153 | if (mkdir_p (1, path, mode ? 0755 : 0)) |
23c9e63c DD |
154 | { |
155 | *slash = saved_char; | |
156 | return 1; | |
157 | } | |
f2e49cf8 | 158 | |
23c9e63c DD |
159 | *slash = saved_char; |
160 | ||
161 | if (!isadir) | |
162 | return 0; | |
163 | ||
b41c2908 | 164 | return mkdir_p (isadir, path, mode); |
23c9e63c | 165 | } |