Library code for user-relative paths, take three.
This patch provides the work-horse of the user-relative paths feature, using Linus' idea of a blind chdir() and getcwd() which makes it remarkably simple. Signed-off-by: Andreas Ericsson <ae@op5.se> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
942c1f53ae
commit
54f4b87454
1
cache.h
1
cache.h
@ -192,6 +192,7 @@ extern int diff_rename_limit_default;
|
||||
|
||||
/* Return a statically allocated filename matching the sha1 signature */
|
||||
extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern char *enter_repo(char *path, int strict);
|
||||
extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
|
||||
extern char *sha1_file_name(const unsigned char *sha1);
|
||||
extern char *sha1_pack_name(const unsigned char *sha1);
|
||||
|
72
path.c
72
path.c
@ -11,6 +11,7 @@
|
||||
* which is what it's designed for.
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include <pwd.h>
|
||||
|
||||
static char pathname[PATH_MAX];
|
||||
static char bad_path[] = "/bad-path/";
|
||||
@ -89,3 +90,74 @@ char *safe_strncpy(char *dest, const char *src, size_t n)
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
static char *current_dir()
|
||||
{
|
||||
return getcwd(pathname, sizeof(pathname));
|
||||
}
|
||||
|
||||
/* Take a raw path from is_git_repo() and canonicalize it using Linus'
|
||||
* idea of a blind chdir() and getcwd(). */
|
||||
static const char *canonical_path(char *path, int strict)
|
||||
{
|
||||
char *dir = path;
|
||||
|
||||
if(strict && *dir != '/')
|
||||
return NULL;
|
||||
|
||||
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 NULL;
|
||||
|
||||
if(!slash || !slash[1]) /* no path following username */
|
||||
return current_dir();
|
||||
|
||||
dir = slash + 1;
|
||||
}
|
||||
|
||||
/* ~foo/path/to/repo is now path/to/repo and we're in foo's homedir */
|
||||
if(chdir(dir) < 0)
|
||||
return NULL;
|
||||
|
||||
return current_dir();
|
||||
}
|
||||
|
||||
char *enter_repo(char *path, int strict)
|
||||
{
|
||||
if(!path)
|
||||
return NULL;
|
||||
|
||||
if(!canonical_path(path, strict)) {
|
||||
if(strict || !canonical_path(mkpath("%s.git", path), strict))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is perfectly safe, and people tend to think of the directory
|
||||
* where they ran git-init-db as their repository, so humour them. */
|
||||
(void)chdir(".git");
|
||||
|
||||
if(access("objects", X_OK) == 0 && access("refs", X_OK) == 0) {
|
||||
putenv("GIT_DIR=.");
|
||||
return current_dir();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user