if (errno == EEXIST && state->force &&
!unlink_or_warn(buf) && !mkdir(buf, 0777))
continue;
- die("cannot create directory at %s", buf);
+ die_errno("cannot create directory at '%s'", buf);
}
}
free(buf);
char *name;
if (!dir)
- die("cannot opendir %s (%s)", path, strerror(errno));
+ die_errno("cannot opendir '%s'", path);
strcpy(pathbuf, path);
name = pathbuf + strlen(path);
*name++ = '/';
continue;
strcpy(name, de->d_name);
if (lstat(pathbuf, &st))
- die("cannot lstat %s (%s)", pathbuf, strerror(errno));
+ die_errno("cannot lstat '%s'", pathbuf);
if (S_ISDIR(st.st_mode))
remove_subtree(pathbuf);
else if (unlink(pathbuf))
- die("cannot unlink %s (%s)", pathbuf, strerror(errno));
+ die_errno("cannot unlink '%s'", pathbuf);
}
closedir(dir);
if (rmdir(path))
- die("cannot rmdir %s (%s)", path, strerror(errno));
+ die_errno("cannot rmdir '%s'", path);
}
static int create_file(const char *path, unsigned int mode)
return 0;
}
+/*
+ * This is like 'lstat()', except it refuses to follow symlinks
+ * in the path, after skipping "skiplen".
+ */
+static int check_path(const char *path, int len, struct stat *st, int skiplen)
+{
+ const char *slash = path + len;
+
+ while (path < slash && *slash != '/')
+ slash--;
+ if (!has_dirs_only_path(path, slash - path, skiplen)) {
+ errno = ENOENT;
+ return -1;
+ }
+ return lstat(path, st);
+}
+
int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
{
static char path[PATH_MAX + 1];
strcpy(path + len, ce->name);
len += ce_namelen(ce);
- if (!lstat(path, &st)) {
- unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
+ if (!check_path(path, len, &st, state->base_dir_len)) {
+ unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
if (!changed)
return 0;
if (!state->force) {