* which is what it's designed for.
*/
#include "cache.h"
-#include <pwd.h>
static char bad_path[] = "/bad-path/";
/* git_mkstemp() - create tmp file honoring TMPDIR variable */
int git_mkstemp(char *path, size_t len, const char *template)
{
- char *env, *pch = path;
+ const char *tmp;
+ size_t n;
- if ((env = getenv("TMPDIR")) == NULL) {
- strcpy(pch, "/tmp/");
- len -= 5;
- pch += 5;
- } else {
- size_t n = snprintf(pch, len, "%s/", env);
-
- len -= n;
- pch += n;
+ tmp = getenv("TMPDIR");
+ if (!tmp)
+ tmp = "/tmp";
+ n = snprintf(path, len, "%s/%s", tmp, template);
+ if (len <= n) {
+ errno = ENAMETOOLONG;
+ return -1;
}
-
- strlcpy(pch, template, len);
-
return mkstemp(path);
}
-int validate_symref(const char *path)
+int validate_headref(const char *path)
{
struct stat st;
char *buf, buffer[256];
+ unsigned char sha1[20];
int len, fd;
if (lstat(path, &st) < 0)
fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
- len = read(fd, buffer, sizeof(buffer)-1);
+ len = read_in_full(fd, buffer, sizeof(buffer)-1);
close(fd);
/*
* Is it a symbolic ref?
*/
- if (len < 4 || memcmp("ref:", buffer, 4))
+ if (len < 4)
return -1;
- buf = buffer + 4;
- len -= 4;
- while (len && isspace(*buf))
- buf++, len--;
- if (len >= 5 && !memcmp("refs/", buf, 5))
+ if (!memcmp("ref:", buffer, 4)) {
+ buf = buffer + 4;
+ len -= 4;
+ while (len && isspace(*buf))
+ buf++, len--;
+ if (len >= 5 && !memcmp("refs/", buf, 5))
+ return 0;
+ }
+
+ /*
+ * Is this a detached HEAD?
+ */
+ if (!get_sha1_hex(buffer, sha1))
return 0;
+
return -1;
}
return NULL;
if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
- validate_symref("HEAD") == 0) {
- putenv("GIT_DIR=.");
+ validate_headref("HEAD") == 0) {
+ setenv(GIT_DIR_ENVIRONMENT, ".", 1);
check_repository_format();
return path;
}
: 0));
if (S_ISDIR(mode))
mode |= S_ISGID;
- if (chmod(path, mode) < 0)
+ if ((mode & st.st_mode) != mode && chmod(path, mode) < 0)
return -2;
return 0;
}
+
+/* We allow "recursive" symbolic links. Only within reason, though. */
+#define MAXDEPTH 5
+
+const char *make_absolute_path(const char *path)
+{
+ static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+ char cwd[1024] = "";
+ int buf_index = 1, len;
+
+ int depth = MAXDEPTH;
+ char *last_elem = NULL;
+ struct stat st;
+
+ if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+ die ("Too long path: %.*s", 60, path);
+
+ while (depth--) {
+ if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
+ char *last_slash = strrchr(buf, '/');
+ if (last_slash) {
+ *last_slash = '\0';
+ last_elem = xstrdup(last_slash + 1);
+ } else
+ last_elem = xstrdup(buf);
+ }
+
+ if (*buf) {
+ if (!*cwd && !getcwd(cwd, sizeof(cwd)))
+ die ("Could not get current working directory");
+
+ if (chdir(buf))
+ die ("Could not switch to '%s'", buf);
+ }
+ if (!getcwd(buf, PATH_MAX))
+ die ("Could not get current working directory");
+
+ if (last_elem) {
+ int len = strlen(buf);
+ if (len + strlen(last_elem) + 2 > PATH_MAX)
+ die ("Too long path name: '%s/%s'",
+ buf, last_elem);
+ buf[len] = '/';
+ strcpy(buf + len + 1, last_elem);
+ free(last_elem);
+ last_elem = NULL;
+ }
+
+ if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
+ len = readlink(buf, next_buf, PATH_MAX);
+ if (len < 0)
+ die ("Invalid symlink: %s", buf);
+ next_buf[len] = '\0';
+ buf = next_buf;
+ buf_index = 1 - buf_index;
+ next_buf = bufs[buf_index];
+ } else
+ break;
+ }
+
+ if (*cwd && chdir(cwd))
+ die ("Could not change back to '%s'", cwd);
+
+ return buf;
+}