Skip to content

Commit e5392c5

Browse files
dschogitster
authored andcommitted
Add is_absolute_path() and make_absolute_path()
This patch adds convenience functions to work with absolute paths. The function is_absolute_path() should help the efforts to integrate the MinGW fork. Note that make_absolute_path() returns a pointer to a static buffer. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 73a7a65 commit e5392c5

File tree

5 files changed

+98
-1
lines changed

5 files changed

+98
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ endif
944944

945945
### Testing rules
946946

947-
TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X
947+
TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X
948948

949949
all:: $(TEST_PROGRAMS)
950950

cache.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ int git_config_perm(const char *var, const char *value);
358358
int adjust_shared_perm(const char *path);
359359
int safe_create_leading_directories(char *path);
360360
char *enter_repo(char *path, int strict);
361+
static inline int is_absolute_path(const char *path)
362+
{
363+
return path[0] == '/';
364+
}
365+
const char *make_absolute_path(const char *path);
361366

362367
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
363368
extern int sha1_object_info(const unsigned char *, unsigned long *);

path.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,68 @@ int adjust_shared_perm(const char *path)
288288
return -2;
289289
return 0;
290290
}
291+
292+
/* We allow "recursive" symbolic links. Only within reason, though. */
293+
#define MAXDEPTH 5
294+
295+
const char *make_absolute_path(const char *path)
296+
{
297+
static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
298+
char cwd[1024] = "";
299+
int buf_index = 1, len;
300+
301+
int depth = MAXDEPTH;
302+
char *last_elem = NULL;
303+
struct stat st;
304+
305+
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
306+
die ("Too long path: %.*s", 60, path);
307+
308+
while (depth--) {
309+
if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
310+
char *last_slash = strrchr(buf, '/');
311+
if (last_slash) {
312+
*last_slash = '\0';
313+
last_elem = xstrdup(last_slash + 1);
314+
} else
315+
last_elem = xstrdup(buf);
316+
}
317+
318+
if (*buf) {
319+
if (!*cwd && !getcwd(cwd, sizeof(cwd)))
320+
die ("Could not get current working directory");
321+
322+
if (chdir(buf))
323+
die ("Could not switch to '%s'", buf);
324+
}
325+
if (!getcwd(buf, PATH_MAX))
326+
die ("Could not get current working directory");
327+
328+
if (last_elem) {
329+
int len = strlen(buf);
330+
if (len + strlen(last_elem) + 2 > PATH_MAX)
331+
die ("Too long path name: '%s/%s'",
332+
buf, last_elem);
333+
buf[len] = '/';
334+
strcpy(buf + len + 1, last_elem);
335+
free(last_elem);
336+
last_elem = NULL;
337+
}
338+
339+
if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
340+
len = readlink(buf, next_buf, PATH_MAX);
341+
if (len < 0)
342+
die ("Invalid symlink: %s", buf);
343+
next_buf[len] = '\0';
344+
buf = next_buf;
345+
buf_index = 1 - buf_index;
346+
next_buf = bufs[buf_index];
347+
} else
348+
break;
349+
}
350+
351+
if (*cwd && chdir(cwd))
352+
die ("Could not change back to '%s'", cwd);
353+
354+
return buf;
355+
}

t/t0000-basic.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,20 @@ test_expect_success 'update-index D/F conflict' '
281281
test $numpath0 = 1
282282
'
283283

284+
test_expect_success 'absolute path works as expected' '
285+
mkdir first &&
286+
ln -s ../.git first/.git &&
287+
mkdir second &&
288+
ln -s ../first second/other &&
289+
mkdir third &&
290+
dir="$(cd .git; pwd -P)" &&
291+
dir2=third/../second/other/.git &&
292+
test "$dir" = "$(test-absolute-path $dir2)" &&
293+
file="$dir"/index &&
294+
test "$file" = "$(test-absolute-path $dir2/index)" &&
295+
ln -s ../first/file .git/syml &&
296+
sym="$(cd first; pwd -P)"/file &&
297+
test "$sym" = "$(test-absolute-path $dir2/syml)"
298+
'
299+
284300
test_done

test-absolute-path.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "cache.h"
2+
3+
int main(int argc, char **argv)
4+
{
5+
while (argc > 1) {
6+
puts(make_absolute_path(argv[1]));
7+
argc--;
8+
argv++;
9+
}
10+
return 0;
11+
}

0 commit comments

Comments
 (0)