* which is what it's designed for.
*/
#include "cache.h"
+#include <pwd.h>
static char pathname[PATH_MAX];
static char bad_path[] = "/bad-path/";
char *git_path(const char *fmt, ...)
{
- const char *git_dir;
+ const char *git_dir = get_git_dir();
va_list args;
unsigned len;
- git_dir = gitenv(GIT_DIR_ENVIRONMENT);
- if (!git_dir) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
len = strlen(git_dir);
if (len > PATH_MAX-100)
return bad_path;
return dest;
}
+
+int validate_symref(const char *path)
+{
+ struct stat st;
+ char *buf, buffer[256];
+ int len, fd;
+
+ if (lstat(path, &st) < 0)
+ return -1;
+
+ /* Make sure it is a "refs/.." symlink */
+ if (S_ISLNK(st.st_mode)) {
+ len = readlink(path, buffer, sizeof(buffer)-1);
+ if (len >= 5 && !memcmp("refs/", buffer, 5))
+ return 0;
+ return -1;
+ }
+
+ /*
+ * Anything else, just open it and try to see if it is a symbolic ref.
+ */
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ len = read(fd, buffer, sizeof(buffer)-1);
+ close(fd);
+
+ /*
+ * Is it a symbolic ref?
+ */
+ if (len < 4 || memcmp("ref:", buffer, 4))
+ return -1;
+ buf = buffer + 4;
+ len -= 4;
+ while (len && isspace(*buf))
+ buf++, len--;
+ if (len >= 5 && !memcmp("refs/", buf, 5))
+ return 0;
+ return -1;
+}
+
+static char *current_dir(void)
+{
+ return getcwd(pathname, sizeof(pathname));
+}
+
+static int user_chdir(char *path)
+{
+ char *dir = path;
+
+ if(*dir == '~') { /* user-relative path */
+ struct passwd *pw;
+ char *slash = strchr(dir, '/');
+
+ dir++;
+ /* '~/' and '~' (no slash) means users own home-dir */
+ if(!*dir || *dir == '/')
+ pw = getpwuid(getuid());
+ else {
+ if (slash) {
+ *slash = '\0';
+ pw = getpwnam(dir);
+ *slash = '/';
+ }
+ else
+ pw = getpwnam(dir);
+ }
+
+ /* make sure we got something back that we can chdir() to */
+ if(!pw || chdir(pw->pw_dir) < 0)
+ return -1;
+
+ if(!slash || !slash[1]) /* no path following username */
+ return 0;
+
+ dir = slash + 1;
+ }
+
+ /* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
+ if(chdir(dir) < 0)
+ return -1;
+
+ return 0;
+}
+
+char *enter_repo(char *path, int strict)
+{
+ if(!path)
+ return NULL;
+
+ if (strict) {
+ if (chdir(path) < 0)
+ return NULL;
+ }
+ else {
+ if (!*path)
+ ; /* happy -- no chdir */
+ else if (!user_chdir(path))
+ ; /* happy -- as given */
+ else if (!user_chdir(mkpath("%s.git", path)))
+ ; /* happy -- uemacs --> uemacs.git */
+ else
+ return NULL;
+ (void)chdir(".git");
+ }
+
+ if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
+ validate_symref("HEAD") == 0) {
+ putenv("GIT_DIR=.");
+ check_repository_format();
+ return current_dir();
+ }
+
+ return NULL;
+}