55static int inside_git_dir = -1 ;
66static int inside_work_tree = -1 ;
77
8+ /*
9+ * The input parameter must contain an absolute path, and it must already be
10+ * normalized.
11+ *
12+ * Find the part of an absolute path that lies inside the work tree by
13+ * dereferencing symlinks outside the work tree, for example:
14+ * /dir1/repo/dir2/file (work tree is /dir1/repo) -> dir2/file
15+ * /dir/file (work tree is /) -> dir/file
16+ * /dir/symlink1/symlink2 (symlink1 points to work tree) -> symlink2
17+ * /dir/repolink/file (repolink points to /dir/repo) -> file
18+ * /dir/repo (exactly equal to work tree) -> (empty string)
19+ */
20+ static int abspath_part_inside_repo (char * path )
21+ {
22+ size_t len ;
23+ size_t wtlen ;
24+ char * path0 ;
25+ int off ;
26+ const char * work_tree = get_git_work_tree ();
27+
28+ if (!work_tree )
29+ return -1 ;
30+ wtlen = strlen (work_tree );
31+ len = strlen (path );
32+ off = offset_1st_component (path );
33+
34+ /* check if work tree is already the prefix */
35+ if (wtlen <= len && !strncmp (path , work_tree , wtlen )) {
36+ if (path [wtlen ] == '/' ) {
37+ memmove (path , path + wtlen + 1 , len - wtlen );
38+ return 0 ;
39+ } else if (path [wtlen - 1 ] == '/' || path [wtlen ] == '\0' ) {
40+ /* work tree is the root, or the whole path */
41+ memmove (path , path + wtlen , len - wtlen + 1 );
42+ return 0 ;
43+ }
44+ /* work tree might match beginning of a symlink to work tree */
45+ off = wtlen ;
46+ }
47+ path0 = path ;
48+ path += off ;
49+
50+ /* check each '/'-terminated level */
51+ while (* path ) {
52+ path ++ ;
53+ if (* path == '/' ) {
54+ * path = '\0' ;
55+ if (strcmp (real_path (path0 ), work_tree ) == 0 ) {
56+ memmove (path0 , path + 1 , len - (path - path0 ));
57+ return 0 ;
58+ }
59+ * path = '/' ;
60+ }
61+ }
62+
63+ /* check whole path */
64+ if (strcmp (real_path (path0 ), work_tree ) == 0 ) {
65+ * path0 = '\0' ;
66+ return 0 ;
67+ }
68+
69+ return -1 ;
70+ }
71+
872/*
973 * Normalize "path", prepending the "prefix" for relative paths. If
1074 * remaining_prefix is not NULL, return the actual prefix still
@@ -22,38 +86,28 @@ char *prefix_path_gently(const char *prefix, int len,
2286 const char * orig = path ;
2387 char * sanitized ;
2488 if (is_absolute_path (orig )) {
25- const char * temp = real_path (path );
26- sanitized = xmalloc (len + strlen (temp ) + 1 );
27- strcpy (sanitized , temp );
89+ sanitized = xmalloc (strlen (path ) + 1 );
2890 if (remaining_prefix )
2991 * remaining_prefix = 0 ;
92+ if (normalize_path_copy_len (sanitized , path , remaining_prefix )) {
93+ free (sanitized );
94+ return NULL ;
95+ }
96+ if (abspath_part_inside_repo (sanitized )) {
97+ free (sanitized );
98+ return NULL ;
99+ }
30100 } else {
31101 sanitized = xmalloc (len + strlen (path ) + 1 );
32102 if (len )
33103 memcpy (sanitized , prefix , len );
34104 strcpy (sanitized + len , path );
35105 if (remaining_prefix )
36106 * remaining_prefix = len ;
37- }
38- if (normalize_path_copy_len (sanitized , sanitized , remaining_prefix ))
39- goto error_out ;
40- if (is_absolute_path (orig )) {
41- size_t root_len , len , total ;
42- const char * work_tree = get_git_work_tree ();
43- if (!work_tree )
44- goto error_out ;
45- len = strlen (work_tree );
46- root_len = offset_1st_component (work_tree );
47- total = strlen (sanitized ) + 1 ;
48- if (strncmp (sanitized , work_tree , len ) ||
49- (len > root_len && sanitized [len ] != '\0' && sanitized [len ] != '/' )) {
50- error_out :
107+ if (normalize_path_copy_len (sanitized , sanitized , remaining_prefix )) {
51108 free (sanitized );
52109 return NULL ;
53110 }
54- if (sanitized [len ] == '/' )
55- len ++ ;
56- memmove (sanitized , sanitized + len , total - len );
57111 }
58112 return sanitized ;
59113}
0 commit comments