5
5
static int inside_git_dir = -1 ;
6
6
static int inside_work_tree = -1 ;
7
7
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
+
8
72
/*
9
73
* Normalize "path", prepending the "prefix" for relative paths. If
10
74
* remaining_prefix is not NULL, return the actual prefix still
@@ -22,38 +86,28 @@ char *prefix_path_gently(const char *prefix, int len,
22
86
const char * orig = path ;
23
87
char * sanitized ;
24
88
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 );
28
90
if (remaining_prefix )
29
91
* 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
+ }
30
100
} else {
31
101
sanitized = xmalloc (len + strlen (path ) + 1 );
32
102
if (len )
33
103
memcpy (sanitized , prefix , len );
34
104
strcpy (sanitized + len , path );
35
105
if (remaining_prefix )
36
106
* 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 )) {
51
108
free (sanitized );
52
109
return NULL ;
53
110
}
54
- if (sanitized [len ] == '/' )
55
- len ++ ;
56
- memmove (sanitized , sanitized + len , total - len );
57
111
}
58
112
return sanitized ;
59
113
}
0 commit comments