|
17 | 17 | #include "environment.h" |
18 | 18 | #include "gettext.h" |
19 | 19 | #include "name-hash.h" |
20 | | -#include "object-file.h" |
21 | 20 | #include "object-store-ll.h" |
22 | 21 | #include "path.h" |
23 | 22 | #include "refs.h" |
@@ -4132,3 +4131,109 @@ int path_match_flags(const char *const str, const enum path_match_flags flags) |
4132 | 4131 | return is_xplatform_dir_sep(*p); |
4133 | 4132 | BUG("unreachable"); |
4134 | 4133 | } |
| 4134 | + |
| 4135 | +int mkdir_in_gitdir(const char *path) |
| 4136 | +{ |
| 4137 | + if (mkdir(path, 0777)) { |
| 4138 | + int saved_errno = errno; |
| 4139 | + struct stat st; |
| 4140 | + struct strbuf sb = STRBUF_INIT; |
| 4141 | + |
| 4142 | + if (errno != EEXIST) |
| 4143 | + return -1; |
| 4144 | + /* |
| 4145 | + * Are we looking at a path in a symlinked worktree |
| 4146 | + * whose original repository does not yet have it? |
| 4147 | + * e.g. .git/rr-cache pointing at its original |
| 4148 | + * repository in which the user hasn't performed any |
| 4149 | + * conflict resolution yet? |
| 4150 | + */ |
| 4151 | + if (lstat(path, &st) || !S_ISLNK(st.st_mode) || |
| 4152 | + strbuf_readlink(&sb, path, st.st_size) || |
| 4153 | + !is_absolute_path(sb.buf) || |
| 4154 | + mkdir(sb.buf, 0777)) { |
| 4155 | + strbuf_release(&sb); |
| 4156 | + errno = saved_errno; |
| 4157 | + return -1; |
| 4158 | + } |
| 4159 | + strbuf_release(&sb); |
| 4160 | + } |
| 4161 | + return adjust_shared_perm(the_repository, path); |
| 4162 | +} |
| 4163 | + |
| 4164 | +static enum scld_error safe_create_leading_directories_1(char *path, int share) |
| 4165 | +{ |
| 4166 | + char *next_component = path + offset_1st_component(path); |
| 4167 | + enum scld_error ret = SCLD_OK; |
| 4168 | + |
| 4169 | + while (ret == SCLD_OK && next_component) { |
| 4170 | + struct stat st; |
| 4171 | + char *slash = next_component, slash_character; |
| 4172 | + |
| 4173 | + while (*slash && !is_dir_sep(*slash)) |
| 4174 | + slash++; |
| 4175 | + |
| 4176 | + if (!*slash) |
| 4177 | + break; |
| 4178 | + |
| 4179 | + next_component = slash + 1; |
| 4180 | + while (is_dir_sep(*next_component)) |
| 4181 | + next_component++; |
| 4182 | + if (!*next_component) |
| 4183 | + break; |
| 4184 | + |
| 4185 | + slash_character = *slash; |
| 4186 | + *slash = '\0'; |
| 4187 | + if (!stat(path, &st)) { |
| 4188 | + /* path exists */ |
| 4189 | + if (!S_ISDIR(st.st_mode)) { |
| 4190 | + errno = ENOTDIR; |
| 4191 | + ret = SCLD_EXISTS; |
| 4192 | + } |
| 4193 | + } else if (mkdir(path, 0777)) { |
| 4194 | + if (errno == EEXIST && |
| 4195 | + !stat(path, &st) && S_ISDIR(st.st_mode)) |
| 4196 | + ; /* somebody created it since we checked */ |
| 4197 | + else if (errno == ENOENT) |
| 4198 | + /* |
| 4199 | + * Either mkdir() failed because |
| 4200 | + * somebody just pruned the containing |
| 4201 | + * directory, or stat() failed because |
| 4202 | + * the file that was in our way was |
| 4203 | + * just removed. Either way, inform |
| 4204 | + * the caller that it might be worth |
| 4205 | + * trying again: |
| 4206 | + */ |
| 4207 | + ret = SCLD_VANISHED; |
| 4208 | + else |
| 4209 | + ret = SCLD_FAILED; |
| 4210 | + } else if (share && adjust_shared_perm(the_repository, path)) { |
| 4211 | + ret = SCLD_PERMS; |
| 4212 | + } |
| 4213 | + *slash = slash_character; |
| 4214 | + } |
| 4215 | + return ret; |
| 4216 | +} |
| 4217 | + |
| 4218 | +enum scld_error safe_create_leading_directories(char *path) |
| 4219 | +{ |
| 4220 | + return safe_create_leading_directories_1(path, 1); |
| 4221 | +} |
| 4222 | + |
| 4223 | +enum scld_error safe_create_leading_directories_no_share(char *path) |
| 4224 | +{ |
| 4225 | + return safe_create_leading_directories_1(path, 0); |
| 4226 | +} |
| 4227 | + |
| 4228 | +enum scld_error safe_create_leading_directories_const(const char *path) |
| 4229 | +{ |
| 4230 | + int save_errno; |
| 4231 | + /* path points to cache entries, so xstrdup before messing with it */ |
| 4232 | + char *buf = xstrdup(path); |
| 4233 | + enum scld_error result = safe_create_leading_directories(buf); |
| 4234 | + |
| 4235 | + save_errno = errno; |
| 4236 | + free(buf); |
| 4237 | + errno = save_errno; |
| 4238 | + return result; |
| 4239 | +} |
0 commit comments