From 979f792951913d75f992f87022b75610303a614f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sun, 28 Nov 2010 10:37:32 +0700 Subject: get_sha1: support relative path ":path" syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently :path and ref:path can be used to refer to a specific object in index or ref respectively. "path" component is absolute path. This patch allows "path" to be written as "./path" or "../path", which is relative to user's original cwd. This does not work in commands for which startup_info is NULL (i.e. non-builtin ones, it seems none of them needs this anyway). Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- sha1_name.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) (limited to 'sha1_name.c') diff --git a/sha1_name.c b/sha1_name.c index 484081de8..f918faf5c 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -1046,6 +1046,23 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, return ret; } +static char *resolve_relative_path(const char *rel) +{ + if (prefixcmp(rel, "./") && prefixcmp(rel, "../")) + return NULL; + + if (!startup_info) + die("BUG: startup_info struct is not initialized."); + + if (!is_inside_work_tree()) + die("relative path syntax can't be used outside working tree."); + + /* die() inside prefix_path() if resolved path is outside worktree */ + return prefix_path(startup_info->prefix, + startup_info->prefix ? strlen(startup_info->prefix) : 0, + rel); +} + int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *oc, int gently, const char *prefix) @@ -1060,25 +1077,31 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, if (!ret) return ret; /* sha1:path --> object name of path in ent sha1 - * :path -> object name of path in index + * :path -> object name of absolute path in index + * :./path -> object name of path relative to cwd in index * :[0-3]:path -> object name of path in index at stage * :/foo -> recent commit matching foo */ if (name[0] == ':') { int stage = 0; struct cache_entry *ce; + char *new_path = NULL; int pos; if (namelen > 2 && name[1] == '/') return get_sha1_oneline(name + 2, sha1); if (namelen < 3 || name[2] != ':' || - name[1] < '0' || '3' < name[1]) + name[1] < '0' || '3' < name[1]) { cp = name + 1; + new_path = resolve_relative_path(cp); + if (new_path) + cp = new_path; + } else { stage = name[1] - '0'; cp = name + 3; } - namelen = namelen - (cp - name); + namelen = strlen(cp); strncpy(oc->path, cp, sizeof(oc->path)); @@ -1096,12 +1119,14 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, break; if (ce_stage(ce) == stage) { hashcpy(sha1, ce->sha1); + free(new_path); return 0; } pos++; } if (!gently) diagnose_invalid_index_path(stage, prefix, cp); + free(new_path); return -1; } for (cp = name, bracket_depth = 0; *cp; cp++) { @@ -1122,6 +1147,11 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, } if (!get_sha1_1(name, cp-name, tree_sha1)) { const char *filename = cp+1; + char *new_filename = NULL; + + new_filename = resolve_relative_path(filename); + if (new_filename) + filename = new_filename; ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode); if (!gently) { diagnose_invalid_sha1_path(prefix, filename, @@ -1133,6 +1163,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, sizeof(oc->path)); oc->path[sizeof(oc->path)-1] = '\0'; + free(new_filename); return ret; } else { if (!gently) -- cgit v1.2.1 From 3d6e0f745e5b958387c9116ff5ba6247b990e6e7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 9 Dec 2010 13:38:05 -0800 Subject: get_sha1: teach ":$n:" the same relative path logic We taught the object name parser to take ":./", ":../", etc. and understand them to be relative to the current working directory. Given that ":" is just a short-hand for ":0:" (i.e. "take stage #0 of that path"), we should allow ":$n:" to interpret them the same way. Signed-off-by: Junio C Hamano --- sha1_name.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'sha1_name.c') diff --git a/sha1_name.c b/sha1_name.c index f918faf5c..207405688 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -1091,17 +1091,19 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, return get_sha1_oneline(name + 2, sha1); if (namelen < 3 || name[2] != ':' || - name[1] < '0' || '3' < name[1]) { + name[1] < '0' || '3' < name[1]) cp = name + 1; - new_path = resolve_relative_path(cp); - if (new_path) - cp = new_path; - } else { stage = name[1] - '0'; cp = name + 3; } - namelen = strlen(cp); + new_path = resolve_relative_path(cp); + if (!new_path) { + namelen = namelen - (cp - name); + } else { + cp = new_path; + namelen = strlen(cp); + } strncpy(oc->path, cp, sizeof(oc->path)); -- cgit v1.2.1