summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/checkout.c2
-rw-r--r--src/config_file.c39
-rw-r--r--src/fileops.c251
-rw-r--r--src/fileops.h17
-rw-r--r--src/odb_loose.c4
-rw-r--r--src/path.c11
-rw-r--r--src/path.h8
-rw-r--r--src/refdb_fs.c3
-rw-r--r--src/repository.c12
-rw-r--r--src/win32/posix_w32.c11
10 files changed, 256 insertions, 102 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 8c06b3335..2a8bfd558 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1366,7 +1366,7 @@ static int checkout_mkdir(
mkdir_opts.dir_map = data->mkdir_map;
mkdir_opts.pool = &data->pool;
- error = git_futils_mkdir_ext(
+ error = git_futils_mkdir_relative(
path, base, mode, flags, &mkdir_opts);
data->perfdata.mkdir_calls += mkdir_opts.perfdata.mkdir_calls;
diff --git a/src/config_file.c b/src/config_file.c
index a3fec1b34..46f21c0f1 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -1711,6 +1711,7 @@ static const char *quotes_for_value(const char *value)
struct write_data {
git_buf *buf;
+ git_buf buffered_comment;
unsigned int in_section : 1,
preg_replaced : 1;
const char *section;
@@ -1719,16 +1720,21 @@ struct write_data {
const char *value;
};
-static int write_line(struct write_data *write_data, const char *line, size_t line_len)
+static int write_line_to(git_buf *buf, const char *line, size_t line_len)
{
- int result = git_buf_put(write_data->buf, line, line_len);
+ int result = git_buf_put(buf, line, line_len);
if (!result && line_len && line[line_len-1] != '\n')
- result = git_buf_printf(write_data->buf, "\n");
+ result = git_buf_printf(buf, "\n");
return result;
}
+static int write_line(struct write_data *write_data, const char *line, size_t line_len)
+{
+ return write_line_to(write_data->buf, line, line_len);
+}
+
static int write_value(struct write_data *write_data)
{
const char *q;
@@ -1770,6 +1776,14 @@ static int write_on_section(
write_data->in_section = strcmp(current_section, write_data->section) == 0;
+ /*
+ * If there were comments just before this section, dump them as well.
+ */
+ if (!result) {
+ result = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size);
+ git_buf_clear(&write_data->buffered_comment);
+ }
+
if (!result)
result = write_line(write_data, line, line_len);
@@ -1787,10 +1801,19 @@ static int write_on_variable(
{
struct write_data *write_data = (struct write_data *)data;
bool has_matched = false;
+ int error;
GIT_UNUSED(reader);
GIT_UNUSED(current_section);
+ /*
+ * If there were comments just before this variable, let's dump them as well.
+ */
+ if ((error = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size)) < 0)
+ return error;
+
+ git_buf_clear(&write_data->buffered_comment);
+
/* See if we are to update this name/value pair; first examine name */
if (write_data->in_section &&
strcasecmp(write_data->name, var_name) == 0)
@@ -1825,7 +1848,7 @@ static int write_on_comment(struct reader **reader, const char *line, size_t lin
GIT_UNUSED(reader);
write_data = (struct write_data *)data;
- return write_line(write_data, line, line_len);
+ return write_line_to(&write_data->buffered_comment, line, line_len);
}
static int write_on_eof(struct reader **reader, void *data)
@@ -1835,6 +1858,12 @@ static int write_on_eof(struct reader **reader, void *data)
GIT_UNUSED(reader);
+ /*
+ * If we've buffered comments when reaching EOF, make sure to dump them.
+ */
+ if ((result = git_buf_put(write_data->buf, write_data->buffered_comment.ptr, write_data->buffered_comment.size)) < 0)
+ return result;
+
/* If we are at the EOF and have not written our value (again, for a
* simple name/value set, not a multivar) then we have never seen the
* section in question and should create a new section and write the
@@ -1892,6 +1921,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
section = git__strndup(key, ldot - key);
write_data.buf = &buf;
+ git_buf_init(&write_data.buffered_comment, 0);
write_data.section = section;
write_data.in_section = 0;
write_data.preg_replaced = 0;
@@ -1901,6 +1931,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
result = config_parse(reader, write_on_section, write_on_variable, write_on_comment, write_on_eof, &write_data);
git__free(section);
+ git_buf_free(&write_data.buffered_comment);
if (result < 0) {
git_filebuf_cleanup(&file);
diff --git a/src/fileops.c b/src/fileops.c
index b7b55159f..57d2ce9c3 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -18,7 +18,7 @@ GIT__USE_STRMAP
int git_futils_mkpath2file(const char *file_path, const mode_t mode)
{
return git_futils_mkdir(
- file_path, NULL, mode,
+ file_path, mode,
GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
}
@@ -289,97 +289,230 @@ void git_futils_mmap_free(git_map *out)
p_munmap(out);
}
-GIT_INLINE(int) validate_existing(
- const char *make_path,
+GIT_INLINE(int) mkdir_validate_dir(
+ const char *path,
struct stat *st,
mode_t mode,
uint32_t flags,
- struct git_futils_mkdir_perfdata *perfdata)
+ struct git_futils_mkdir_options *opts)
{
+ /* with exclusive create, existing dir is an error */
+ if ((flags & GIT_MKDIR_EXCL) != 0) {
+ giterr_set(GITERR_FILESYSTEM,
+ "Failed to make directory '%s': directory exists", path);
+ return GIT_EEXISTS;
+ }
+
if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) ||
(S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) {
- if (p_unlink(make_path) < 0) {
+ if (p_unlink(path) < 0) {
giterr_set(GITERR_OS, "Failed to remove %s '%s'",
- S_ISLNK(st->st_mode) ? "symlink" : "file", make_path);
+ S_ISLNK(st->st_mode) ? "symlink" : "file", path);
return GIT_EEXISTS;
}
- perfdata->mkdir_calls++;
+ opts->perfdata.mkdir_calls++;
- if (p_mkdir(make_path, mode) < 0) {
- giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path);
+ if (p_mkdir(path, mode) < 0) {
+ giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
return GIT_EEXISTS;
}
}
else if (S_ISLNK(st->st_mode)) {
/* Re-stat the target, make sure it's a directory */
- perfdata->stat_calls++;
+ opts->perfdata.stat_calls++;
- if (p_stat(make_path, st) < 0) {
- giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path);
+ if (p_stat(path, st) < 0) {
+ giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
return GIT_EEXISTS;
}
}
else if (!S_ISDIR(st->st_mode)) {
giterr_set(GITERR_FILESYSTEM,
- "Failed to make directory '%s': directory exists", make_path);
+ "Failed to make directory '%s': directory exists", path);
return GIT_EEXISTS;
}
return 0;
}
-int git_futils_mkdir_ext(
+GIT_INLINE(int) mkdir_validate_mode(
const char *path,
- const char *base,
+ struct stat *st,
+ bool terminal_path,
mode_t mode,
uint32_t flags,
struct git_futils_mkdir_options *opts)
{
- int error = -1;
- git_buf make_path = GIT_BUF_INIT;
- ssize_t root = 0, min_root_len, root_len;
- char lastch = '/', *tail;
- struct stat st;
+ if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) ||
+ (flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) {
- /* build path and find "root" where we should start calling mkdir */
- if (git_path_join_unrooted(&make_path, path, base, &root) < 0)
- return -1;
+ opts->perfdata.chmod_calls++;
- if (make_path.size == 0) {
- giterr_set(GITERR_OS, "Attempt to create empty path");
- goto done;
+ if (p_chmod(path, mode) < 0) {
+ giterr_set(GITERR_OS, "failed to set permissions on '%s'", path);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+GIT_INLINE(int) mkdir_canonicalize(
+ git_buf *path,
+ uint32_t flags)
+{
+ ssize_t root_len;
+
+ if (path->size == 0) {
+ giterr_set(GITERR_OS, "attempt to create empty path");
+ return -1;
}
/* Trim trailing slashes (except the root) */
- if ((root_len = git_path_root(make_path.ptr)) < 0)
+ if ((root_len = git_path_root(path->ptr)) < 0)
root_len = 0;
else
root_len++;
- while (make_path.size > (size_t)root_len &&
- make_path.ptr[make_path.size - 1] == '/')
- make_path.ptr[--make_path.size] = '\0';
+ while (path->size > (size_t)root_len && path->ptr[path->size - 1] == '/')
+ path->ptr[--path->size] = '\0';
/* if we are not supposed to made the last element, truncate it */
if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
- git_path_dirname_r(&make_path, make_path.ptr);
+ git_path_dirname_r(path, path->ptr);
flags |= GIT_MKDIR_SKIP_LAST;
}
if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
- git_path_dirname_r(&make_path, make_path.ptr);
+ git_path_dirname_r(path, path->ptr);
}
/* We were either given the root path (or trimmed it to
- * the root), we don't have anything to do.
+ * the root), we don't have anything to do.
+ */
+ if (path->size <= (size_t)root_len)
+ git_buf_clear(path);
+
+ return 0;
+}
+
+int git_futils_mkdir(
+ const char *path,
+ mode_t mode,
+ uint32_t flags)
+{
+ git_buf make_path = GIT_BUF_INIT, parent_path = GIT_BUF_INIT;
+ const char *relative;
+ struct git_futils_mkdir_options opts = { 0 };
+ struct stat st;
+ size_t depth = 0;
+ int len = 0, root_len, error;
+
+ if ((error = git_buf_puts(&make_path, path)) < 0 ||
+ (error = mkdir_canonicalize(&make_path, flags)) < 0 ||
+ (error = git_buf_puts(&parent_path, make_path.ptr)) < 0 ||
+ make_path.size == 0)
+ goto done;
+
+ root_len = git_path_root(make_path.ptr);
+
+ /* find the first parent directory that exists. this will be used
+ * as the base to dirname_relative.
*/
- if (make_path.size <= (size_t)root_len) {
- error = 0;
+ for (relative = make_path.ptr; parent_path.size; ) {
+ error = p_lstat(parent_path.ptr, &st);
+
+ if (error == 0) {
+ break;
+ } else if (errno != ENOENT) {
+ giterr_set(GITERR_OS, "failed to stat '%s'", parent_path.ptr);
+ goto done;
+ }
+
+ depth++;
+
+ /* examine the parent of the current path */
+ if ((len = git_path_dirname_r(&parent_path, parent_path.ptr)) < 0) {
+ error = len;
+ goto done;
+ }
+
+ assert(len);
+
+ /* we've walked all the given path's parents and it's either relative
+ * or rooted. either way, give up and make the entire path.
+ */
+ if ((len == 1 && parent_path.ptr[0] == '.') || len == root_len+1) {
+ relative = make_path.ptr;
+ break;
+ }
+
+ relative = make_path.ptr + len + 1;
+
+ /* not recursive? just make this directory relative to its parent. */
+ if ((flags & GIT_MKDIR_PATH) == 0)
+ break;
+ }
+
+ /* we found an item at the location we're trying to create,
+ * validate it.
+ */
+ if (depth == 0) {
+ error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts);
+
+ if (!error)
+ error = mkdir_validate_mode(
+ make_path.ptr, &st, true, mode, flags, &opts);
+
goto done;
}
+ /* we already took `SKIP_LAST` and `SKIP_LAST2` into account when
+ * canonicalizing `make_path`.
+ */
+ flags &= ~(GIT_MKDIR_SKIP_LAST2 | GIT_MKDIR_SKIP_LAST);
+
+ error = git_futils_mkdir_relative(relative,
+ parent_path.size ? parent_path.ptr : NULL, mode, flags, &opts);
+
+done:
+ git_buf_free(&make_path);
+ git_buf_free(&parent_path);
+ return error;
+}
+
+int git_futils_mkdir_r(const char *path, const mode_t mode)
+{
+ return git_futils_mkdir(path, mode, GIT_MKDIR_PATH);
+}
+
+int git_futils_mkdir_relative(
+ const char *relative_path,
+ const char *base,
+ mode_t mode,
+ uint32_t flags,
+ struct git_futils_mkdir_options *opts)
+{
+ git_buf make_path = GIT_BUF_INIT;
+ ssize_t root = 0, min_root_len;
+ char lastch = '/', *tail;
+ struct stat st;
+ struct git_futils_mkdir_options empty_opts = {0};
+ int error;
+
+ if (!opts)
+ opts = &empty_opts;
+
+ /* build path and find "root" where we should start calling mkdir */
+ if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0)
+ return -1;
+
+ if ((error = mkdir_canonicalize(&make_path, flags)) < 0 ||
+ make_path.size == 0)
+ goto done;
+
/* if we are not supposed to make the whole path, reset root */
if ((flags & GIT_MKDIR_PATH) == 0)
root = git_buf_rfind(&make_path, '/');
@@ -437,32 +570,15 @@ retry_lstat:
goto done;
}
} else {
- /* with exclusive create, existing dir is an error */
- if ((flags & GIT_MKDIR_EXCL) != 0) {
- giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr);
- error = GIT_EEXISTS;
+ if ((error = mkdir_validate_dir(
+ make_path.ptr, &st, mode, flags, opts)) < 0)
goto done;
- }
-
- if ((error = validate_existing(
- make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0)
- goto done;
}
/* chmod if requested and necessary */
- if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 ||
- (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
- st.st_mode != mode) {
-
- opts->perfdata.chmod_calls++;
-
- if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
- lastch == '\0') {
- giterr_set(GITERR_OS, "Failed to set permissions on '%s'",
- make_path.ptr);
- goto done;
- }
- }
+ if ((error = mkdir_validate_mode(
+ make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0)
+ goto done;
if (opts->dir_map && opts->pool) {
char *cache_path;
@@ -501,21 +617,6 @@ done:
return error;
}
-int git_futils_mkdir(
- const char *path,
- const char *base,
- mode_t mode,
- uint32_t flags)
-{
- struct git_futils_mkdir_options options = {0};
- return git_futils_mkdir_ext(path, base, mode, flags, &options);
-}
-
-int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
-{
- return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH);
-}
-
typedef struct {
const char *base;
size_t baselen;
@@ -777,7 +878,7 @@ static int _cp_r_mkdir(cp_r_info *info, git_buf *from)
/* create root directory the first time we need to create a directory */
if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) {
error = git_futils_mkdir(
- info->to_root, NULL, info->dirmode,
+ info->to_root, info->dirmode,
(info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0);
info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT;
@@ -785,9 +886,9 @@ static int _cp_r_mkdir(cp_r_info *info, git_buf *from)
/* create directory with root as base to prevent excess chmods */
if (!error)
- error = git_futils_mkdir(
+ error = git_futils_mkdir_relative(
from->ptr + info->from_prefix, info->to_root,
- info->dirmode, info->mkdir_flags);
+ info->dirmode, info->mkdir_flags, NULL);
return error;
}
diff --git a/src/fileops.h b/src/fileops.h
index 0f6466c59..572ff01a5 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -55,12 +55,9 @@ extern int git_futils_creat_locked(const char *path, const mode_t mode);
extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode);
/**
- * Create a path recursively
- *
- * If a base parameter is being passed, it's expected to be valued with a
- * path pointing to an already existing directory.
+ * Create a path recursively.
*/
-extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode);
+extern int git_futils_mkdir_r(const char *path, const mode_t mode);
/**
* Flags to pass to `git_futils_mkdir`.
@@ -111,20 +108,20 @@ struct git_futils_mkdir_options
* and optionally chmods the directory immediately after (or each part of the
* path if requested).
*
- * @param path The path to create.
+ * @param path The path to create, relative to base.
* @param base Root for relative path. These directories will never be made.
* @param mode The mode to use for created directories.
* @param flags Combination of the mkdir flags above.
- * @param opts Extended options, use `git_futils_mkdir` if you are not interested.
+ * @param opts Extended options, or null.
* @return 0 on success, else error code
*/
-extern int git_futils_mkdir_ext(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
+extern int git_futils_mkdir_relative(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts);
/**
- * Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
+ * Create a directory or entire path. Similar to `git_futils_mkdir_relative`
* without performance data.
*/
-extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uint32_t flags);
+extern int git_futils_mkdir(const char *path, mode_t mode, uint32_t flags);
/**
* Create all the folders required to contain
diff --git a/src/odb_loose.c b/src/odb_loose.c
index 99b8f7c91..730c4b1e1 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -84,9 +84,9 @@ static int object_file_name(
static int object_mkdir(const git_buf *name, const loose_backend *be)
{
- return git_futils_mkdir(
+ return git_futils_mkdir_relative(
name->ptr + be->objects_dirlen, be->objects_dir, be->object_dir_mode,
- GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
+ GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR, NULL);
}
static size_t get_binary_object_header(obj_hdr *hdr, git_buf *obj)
diff --git a/src/path.c b/src/path.c
index cb11acee3..72cb289e0 100644
--- a/src/path.c
+++ b/src/path.c
@@ -526,6 +526,17 @@ bool git_path_isfile(const char *path)
return S_ISREG(st.st_mode) != 0;
}
+bool git_path_islink(const char *path)
+{
+ struct stat st;
+
+ assert(path);
+ if (p_lstat(path, &st) < 0)
+ return false;
+
+ return S_ISLNK(st.st_mode) != 0;
+}
+
#ifdef GIT_WIN32
bool git_path_is_empty_dir(const char *path)
diff --git a/src/path.h b/src/path.h
index 971603ea7..7e156fce8 100644
--- a/src/path.h
+++ b/src/path.h
@@ -72,7 +72,7 @@ extern const char *git_path_topdir(const char *path);
* This will return a number >= 0 which is the offset to the start of the
* path, if the path is rooted (i.e. "/rooted/path" returns 0 and
* "c:/windows/rooted/path" returns 2). If the path is not rooted, this
- * returns < 0.
+ * returns -1.
*/
extern int git_path_root(const char *path);
@@ -169,6 +169,12 @@ extern bool git_path_isdir(const char *path);
extern bool git_path_isfile(const char *path);
/**
+ * Check if the given path points to a symbolic link.
+ * @return true or false
+ */
+extern bool git_path_islink(const char *path);
+
+/**
* Check if the given path is a directory, and is empty.
*/
extern bool git_path_is_empty_dir(const char *path);
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index 1ddce4649..921f7862b 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -1413,7 +1413,8 @@ static int setup_namespace(git_buf *path, git_repository *repo)
git__free(parts);
/* Make sure that the folder with the namespace exists */
- if (git_futils_mkdir_r(git_buf_cstr(path), repo->path_repository, 0777) < 0)
+ if (git_futils_mkdir_relative(git_buf_cstr(path), repo->path_repository,
+ 0777, GIT_MKDIR_PATH, NULL) < 0)
return -1;
/* Return root of the namespaced path, i.e. without the trailing '/refs' */
diff --git a/src/repository.c b/src/repository.c
index cbdfd5826..77145cfc8 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -1457,8 +1457,8 @@ static int repo_init_structure(
if (chmod)
mkdir_flags |= GIT_MKDIR_CHMOD;
- error = git_futils_mkdir(
- tpl->path, repo_dir, dmode, mkdir_flags);
+ error = git_futils_mkdir_relative(
+ tpl->path, repo_dir, dmode, mkdir_flags, NULL);
}
else if (!external_tpl) {
const char *content = tpl->content;
@@ -1480,7 +1480,7 @@ static int mkdir_parent(git_buf *buf, uint32_t mode, bool skip2)
* don't try to set gid or grant world write access
*/
return git_futils_mkdir(
- buf->ptr, NULL, mode & ~(S_ISGID | 0002),
+ buf->ptr, mode & ~(S_ISGID | 0002),
GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR |
(skip2 ? GIT_MKDIR_SKIP_LAST2 : GIT_MKDIR_SKIP_LAST));
}
@@ -1584,14 +1584,14 @@ static int repo_init_directories(
/* create path #4 */
if (wd_path->size > 0 &&
(error = git_futils_mkdir(
- wd_path->ptr, NULL, dirmode & ~S_ISGID,
+ wd_path->ptr, dirmode & ~S_ISGID,
GIT_MKDIR_VERIFY_DIR)) < 0)
return error;
/* create path #2 (if not the same as #4) */
if (!natural_wd &&
(error = git_futils_mkdir(
- repo_path->ptr, NULL, dirmode & ~S_ISGID,
+ repo_path->ptr, dirmode & ~S_ISGID,
GIT_MKDIR_VERIFY_DIR | GIT_MKDIR_SKIP_LAST)) < 0)
return error;
}
@@ -1601,7 +1601,7 @@ static int repo_init_directories(
has_dotgit)
{
/* create path #1 */
- error = git_futils_mkdir(repo_path->ptr, NULL, dirmode,
+ error = git_futils_mkdir(repo_path->ptr, dirmode,
GIT_MKDIR_VERIFY_DIR | ((dirmode & S_ISGID) ? GIT_MKDIR_CHMOD : 0));
}
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index c909af6cc..414cb4701 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -148,12 +148,19 @@ static int lstat_w(
return git_win32__file_attribute_to_stat(buf, &fdata, path);
}
- errno = ENOENT;
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ errno = EACCES;
+ break;
+ default:
+ errno = ENOENT;
+ break;
+ }
/* To match POSIX behavior, set ENOTDIR when any of the folders in the
* file path is a regular file, otherwise set ENOENT.
*/
- if (posix_enotdir) {
+ if (errno == ENOENT && posix_enotdir) {
size_t path_len = wcslen(path);
/* scan up path until we find an existing item */