return NULL;
}
} else {
- sanitized = xmalloc(len + strlen(path) + 1);
- if (len)
- memcpy(sanitized, prefix, len);
- strcpy(sanitized + len, path);
+ sanitized = xstrfmt("%.*s%s", len, prefix, path);
if (remaining_prefix)
*remaining_prefix = len;
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
}
int get_common_dir(struct strbuf *sb, const char *gitdir)
+{
+ const char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
+ if (git_env_common_dir) {
+ strbuf_addstr(sb, git_env_common_dir);
+ return 1;
+ } else {
+ return get_common_dir_noenv(sb, gitdir);
+ }
+}
+
+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)
{
struct strbuf data = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
- const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
int ret = 0;
- if (git_common_dir) {
- strbuf_addstr(sb, git_common_dir);
- return 1;
- }
+
strbuf_addf(&path, "%s/commondir", gitdir);
if (file_exists(path.buf)) {
if (strbuf_read_file(&data, path.buf, 0) <= 0)
strbuf_addf(&path, "%s/gitdir", gitdir);
if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
- write_file(path.buf, 1, "%s\n", gitfile);
+ write_file(path.buf, "%s", gitfile);
strbuf_release(&path);
}
/*
* Try to read the location of the git directory from the .git file,
* return path to git directory if found.
+ *
+ * On failure, if return_error_code is not NULL, return_error_code
+ * will be set to an error code and NULL will be returned. If
+ * return_error_code is NULL the function will die instead (for most
+ * cases).
*/
-const char *read_gitfile(const char *path)
+const char *read_gitfile_gently(const char *path, int *return_error_code)
{
- char *buf;
- char *dir;
+ const int max_file_size = 1 << 20; /* 1MB */
+ int error_code = 0;
+ char *buf = NULL;
+ char *dir = NULL;
const char *slash;
struct stat st;
int fd;
ssize_t len;
- if (stat(path, &st))
- return NULL;
- if (!S_ISREG(st.st_mode))
- return NULL;
+ if (stat(path, &st)) {
+ error_code = READ_GITFILE_ERR_STAT_FAILED;
+ goto cleanup_return;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ error_code = READ_GITFILE_ERR_NOT_A_FILE;
+ goto cleanup_return;
+ }
+ if (st.st_size > max_file_size) {
+ error_code = READ_GITFILE_ERR_TOO_LARGE;
+ goto cleanup_return;
+ }
fd = open(path, O_RDONLY);
- if (fd < 0)
- die_errno("Error opening '%s'", path);
+ if (fd < 0) {
+ error_code = READ_GITFILE_ERR_OPEN_FAILED;
+ goto cleanup_return;
+ }
buf = xmalloc(st.st_size + 1);
len = read_in_full(fd, buf, st.st_size);
close(fd);
- if (len != st.st_size)
- die("Error reading %s", path);
+ if (len != st.st_size) {
+ error_code = READ_GITFILE_ERR_READ_FAILED;
+ goto cleanup_return;
+ }
buf[len] = '\0';
- if (!starts_with(buf, "gitdir: "))
- die("Invalid gitfile format: %s", path);
+ if (!starts_with(buf, "gitdir: ")) {
+ error_code = READ_GITFILE_ERR_INVALID_FORMAT;
+ goto cleanup_return;
+ }
while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
len--;
- if (len < 9)
- die("No path in gitfile: %s", path);
+ if (len < 9) {
+ error_code = READ_GITFILE_ERR_NO_PATH;
+ goto cleanup_return;
+ }
buf[len] = '\0';
dir = buf + 8;
if (!is_absolute_path(dir) && (slash = strrchr(path, '/'))) {
size_t pathlen = slash+1 - path;
- size_t dirlen = pathlen + len - 8;
- dir = xmalloc(dirlen + 1);
- strncpy(dir, path, pathlen);
- strncpy(dir + pathlen, buf + 8, len - 8);
- dir[dirlen] = '\0';
+ dir = xstrfmt("%.*s%.*s", (int)pathlen, path,
+ (int)(len - 8), buf + 8);
free(buf);
buf = dir;
}
-
- if (!is_git_directory(dir))
- die("Not a git repository: %s", dir);
-
+ if (!is_git_directory(dir)) {
+ error_code = READ_GITFILE_ERR_NOT_A_REPO;
+ goto cleanup_return;
+ }
update_linked_gitdir(path, dir);
path = real_path(dir);
+cleanup_return:
+ if (return_error_code)
+ *return_error_code = error_code;
+ else if (error_code) {
+ switch (error_code) {
+ case READ_GITFILE_ERR_STAT_FAILED:
+ case READ_GITFILE_ERR_NOT_A_FILE:
+ /* non-fatal; follow return path */
+ break;
+ case READ_GITFILE_ERR_OPEN_FAILED:
+ die_errno("Error opening '%s'", path);
+ case READ_GITFILE_ERR_TOO_LARGE:
+ die("Too large to be a .git file: '%s'", path);
+ case READ_GITFILE_ERR_READ_FAILED:
+ die("Error reading %s", path);
+ case READ_GITFILE_ERR_INVALID_FORMAT:
+ die("Invalid gitfile format: %s", path);
+ case READ_GITFILE_ERR_NO_PATH:
+ die("No path in gitfile: %s", path);
+ case READ_GITFILE_ERR_NOT_A_REPO:
+ die("Not a git repository: %s", dir);
+ default:
+ assert(0);
+ }
+ }
+
free(buf);
- return path;
+ return error_code ? NULL : path;
}
static const char *setup_explicit_git_dir(const char *gitdirenv,