git_path(): be aware of file relocation in $GIT_DIR
[git] / path.c
1 /*
2  * Utilities for paths and pathnames
3  */
4 #include "cache.h"
5 #include "strbuf.h"
6 #include "string-list.h"
7
8 static int get_st_mode_bits(const char *path, int *mode)
9 {
10         struct stat st;
11         if (lstat(path, &st) < 0)
12                 return -1;
13         *mode = st.st_mode;
14         return 0;
15 }
16
17 static char bad_path[] = "/bad-path/";
18
19 static struct strbuf *get_pathname(void)
20 {
21         static struct strbuf pathname_array[4] = {
22                 STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
23         };
24         static int index;
25         struct strbuf *sb = &pathname_array[3 & ++index];
26         strbuf_reset(sb);
27         return sb;
28 }
29
30 static char *cleanup_path(char *path)
31 {
32         /* Clean it up */
33         if (!memcmp(path, "./", 2)) {
34                 path += 2;
35                 while (*path == '/')
36                         path++;
37         }
38         return path;
39 }
40
41 static void strbuf_cleanup_path(struct strbuf *sb)
42 {
43         char *path = cleanup_path(sb->buf);
44         if (path > sb->buf)
45                 strbuf_remove(sb, 0, path - sb->buf);
46 }
47
48 char *mksnpath(char *buf, size_t n, const char *fmt, ...)
49 {
50         va_list args;
51         unsigned len;
52
53         va_start(args, fmt);
54         len = vsnprintf(buf, n, fmt, args);
55         va_end(args);
56         if (len >= n) {
57                 strlcpy(buf, bad_path, n);
58                 return buf;
59         }
60         return cleanup_path(buf);
61 }
62
63 static int dir_prefix(const char *buf, const char *dir)
64 {
65         int len = strlen(dir);
66         return !strncmp(buf, dir, len) &&
67                 (is_dir_sep(buf[len]) || buf[len] == '\0');
68 }
69
70 /* $buf =~ m|$dir/+$file| but without regex */
71 static int is_dir_file(const char *buf, const char *dir, const char *file)
72 {
73         int len = strlen(dir);
74         if (strncmp(buf, dir, len) || !is_dir_sep(buf[len]))
75                 return 0;
76         while (is_dir_sep(buf[len]))
77                 len++;
78         return !strcmp(buf + len, file);
79 }
80
81 static void replace_dir(struct strbuf *buf, int len, const char *newdir)
82 {
83         int newlen = strlen(newdir);
84         int need_sep = (buf->buf[len] && !is_dir_sep(buf->buf[len])) &&
85                 !is_dir_sep(newdir[newlen - 1]);
86         if (need_sep)
87                 len--;   /* keep one char, to be replaced with '/'  */
88         strbuf_splice(buf, 0, len, newdir, newlen);
89         if (need_sep)
90                 buf->buf[newlen] = '/';
91 }
92
93 static void adjust_git_path(struct strbuf *buf, int git_dir_len)
94 {
95         const char *base = buf->buf + git_dir_len;
96         if (git_graft_env && is_dir_file(base, "info", "grafts"))
97                 strbuf_splice(buf, 0, buf->len,
98                               get_graft_file(), strlen(get_graft_file()));
99         else if (git_index_env && !strcmp(base, "index"))
100                 strbuf_splice(buf, 0, buf->len,
101                               get_index_file(), strlen(get_index_file()));
102         else if (git_db_env && dir_prefix(base, "objects"))
103                 replace_dir(buf, git_dir_len + 7, get_object_directory());
104 }
105
106 static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
107 {
108         int gitdir_len;
109         strbuf_addstr(buf, get_git_dir());
110         if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
111                 strbuf_addch(buf, '/');
112         gitdir_len = buf->len;
113         strbuf_vaddf(buf, fmt, args);
114         adjust_git_path(buf, gitdir_len);
115         strbuf_cleanup_path(buf);
116 }
117
118 void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
119 {
120         va_list args;
121         va_start(args, fmt);
122         do_git_path(sb, fmt, args);
123         va_end(args);
124 }
125
126 const char *git_path(const char *fmt, ...)
127 {
128         struct strbuf *pathname = get_pathname();
129         va_list args;
130         va_start(args, fmt);
131         do_git_path(pathname, fmt, args);
132         va_end(args);
133         return pathname->buf;
134 }
135
136 char *git_pathdup(const char *fmt, ...)
137 {
138         struct strbuf path = STRBUF_INIT;
139         va_list args;
140         va_start(args, fmt);
141         do_git_path(&path, fmt, args);
142         va_end(args);
143         return strbuf_detach(&path, NULL);
144 }
145
146 char *mkpathdup(const char *fmt, ...)
147 {
148         struct strbuf sb = STRBUF_INIT;
149         va_list args;
150         va_start(args, fmt);
151         strbuf_vaddf(&sb, fmt, args);
152         va_end(args);
153         strbuf_cleanup_path(&sb);
154         return strbuf_detach(&sb, NULL);
155 }
156
157 const char *mkpath(const char *fmt, ...)
158 {
159         va_list args;
160         struct strbuf *pathname = get_pathname();
161         va_start(args, fmt);
162         strbuf_vaddf(pathname, fmt, args);
163         va_end(args);
164         return cleanup_path(pathname->buf);
165 }
166
167 void home_config_paths(char **global, char **xdg, char *file)
168 {
169         char *xdg_home = getenv("XDG_CONFIG_HOME");
170         char *home = getenv("HOME");
171         char *to_free = NULL;
172
173         if (!home) {
174                 if (global)
175                         *global = NULL;
176         } else {
177                 if (!xdg_home) {
178                         to_free = mkpathdup("%s/.config", home);
179                         xdg_home = to_free;
180                 }
181                 if (global)
182                         *global = mkpathdup("%s/.gitconfig", home);
183         }
184
185         if (xdg) {
186                 if (!xdg_home)
187                         *xdg = NULL;
188                 else
189                         *xdg = mkpathdup("%s/git/%s", xdg_home, file);
190         }
191
192         free(to_free);
193 }
194
195 const char *git_path_submodule(const char *path, const char *fmt, ...)
196 {
197         struct strbuf *buf = get_pathname();
198         const char *git_dir;
199         va_list args;
200
201         strbuf_addstr(buf, path);
202         if (buf->len && buf->buf[buf->len - 1] != '/')
203                 strbuf_addch(buf, '/');
204         strbuf_addstr(buf, ".git");
205
206         git_dir = read_gitfile(buf->buf);
207         if (git_dir) {
208                 strbuf_reset(buf);
209                 strbuf_addstr(buf, git_dir);
210         }
211         strbuf_addch(buf, '/');
212
213         va_start(args, fmt);
214         strbuf_vaddf(buf, fmt, args);
215         va_end(args);
216         strbuf_cleanup_path(buf);
217         return buf->buf;
218 }
219
220 int validate_headref(const char *path)
221 {
222         struct stat st;
223         char *buf, buffer[256];
224         unsigned char sha1[20];
225         int fd;
226         ssize_t len;
227
228         if (lstat(path, &st) < 0)
229                 return -1;
230
231         /* Make sure it is a "refs/.." symlink */
232         if (S_ISLNK(st.st_mode)) {
233                 len = readlink(path, buffer, sizeof(buffer)-1);
234                 if (len >= 5 && !memcmp("refs/", buffer, 5))
235                         return 0;
236                 return -1;
237         }
238
239         /*
240          * Anything else, just open it and try to see if it is a symbolic ref.
241          */
242         fd = open(path, O_RDONLY);
243         if (fd < 0)
244                 return -1;
245         len = read_in_full(fd, buffer, sizeof(buffer)-1);
246         close(fd);
247
248         /*
249          * Is it a symbolic ref?
250          */
251         if (len < 4)
252                 return -1;
253         if (!memcmp("ref:", buffer, 4)) {
254                 buf = buffer + 4;
255                 len -= 4;
256                 while (len && isspace(*buf))
257                         buf++, len--;
258                 if (len >= 5 && !memcmp("refs/", buf, 5))
259                         return 0;
260         }
261
262         /*
263          * Is this a detached HEAD?
264          */
265         if (!get_sha1_hex(buffer, sha1))
266                 return 0;
267
268         return -1;
269 }
270
271 static struct passwd *getpw_str(const char *username, size_t len)
272 {
273         struct passwd *pw;
274         char *username_z = xmemdupz(username, len);
275         pw = getpwnam(username_z);
276         free(username_z);
277         return pw;
278 }
279
280 /*
281  * Return a string with ~ and ~user expanded via getpw*.  If buf != NULL,
282  * then it is a newly allocated string. Returns NULL on getpw failure or
283  * if path is NULL.
284  */
285 char *expand_user_path(const char *path)
286 {
287         struct strbuf user_path = STRBUF_INIT;
288         const char *to_copy = path;
289
290         if (path == NULL)
291                 goto return_null;
292         if (path[0] == '~') {
293                 const char *first_slash = strchrnul(path, '/');
294                 const char *username = path + 1;
295                 size_t username_len = first_slash - username;
296                 if (username_len == 0) {
297                         const char *home = getenv("HOME");
298                         if (!home)
299                                 goto return_null;
300                         strbuf_addstr(&user_path, home);
301                 } else {
302                         struct passwd *pw = getpw_str(username, username_len);
303                         if (!pw)
304                                 goto return_null;
305                         strbuf_addstr(&user_path, pw->pw_dir);
306                 }
307                 to_copy = first_slash;
308         }
309         strbuf_addstr(&user_path, to_copy);
310         return strbuf_detach(&user_path, NULL);
311 return_null:
312         strbuf_release(&user_path);
313         return NULL;
314 }
315
316 /*
317  * First, one directory to try is determined by the following algorithm.
318  *
319  * (0) If "strict" is given, the path is used as given and no DWIM is
320  *     done. Otherwise:
321  * (1) "~/path" to mean path under the running user's home directory;
322  * (2) "~user/path" to mean path under named user's home directory;
323  * (3) "relative/path" to mean cwd relative directory; or
324  * (4) "/absolute/path" to mean absolute directory.
325  *
326  * Unless "strict" is given, we try access() for existence of "%s.git/.git",
327  * "%s/.git", "%s.git", "%s" in this order.  The first one that exists is
328  * what we try.
329  *
330  * Second, we try chdir() to that.  Upon failure, we return NULL.
331  *
332  * Then, we try if the current directory is a valid git repository.
333  * Upon failure, we return NULL.
334  *
335  * If all goes well, we return the directory we used to chdir() (but
336  * before ~user is expanded), avoiding getcwd() resolving symbolic
337  * links.  User relative paths are also returned as they are given,
338  * except DWIM suffixing.
339  */
340 const char *enter_repo(const char *path, int strict)
341 {
342         static char used_path[PATH_MAX];
343         static char validated_path[PATH_MAX];
344
345         if (!path)
346                 return NULL;
347
348         if (!strict) {
349                 static const char *suffix[] = {
350                         "/.git", "", ".git/.git", ".git", NULL,
351                 };
352                 const char *gitfile;
353                 int len = strlen(path);
354                 int i;
355                 while ((1 < len) && (path[len-1] == '/'))
356                         len--;
357
358                 if (PATH_MAX <= len)
359                         return NULL;
360                 strncpy(used_path, path, len); used_path[len] = 0 ;
361                 strcpy(validated_path, used_path);
362
363                 if (used_path[0] == '~') {
364                         char *newpath = expand_user_path(used_path);
365                         if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
366                                 free(newpath);
367                                 return NULL;
368                         }
369                         /*
370                          * Copy back into the static buffer. A pity
371                          * since newpath was not bounded, but other
372                          * branches of the if are limited by PATH_MAX
373                          * anyway.
374                          */
375                         strcpy(used_path, newpath); free(newpath);
376                 }
377                 else if (PATH_MAX - 10 < len)
378                         return NULL;
379                 len = strlen(used_path);
380                 for (i = 0; suffix[i]; i++) {
381                         struct stat st;
382                         strcpy(used_path + len, suffix[i]);
383                         if (!stat(used_path, &st) &&
384                             (S_ISREG(st.st_mode) ||
385                             (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
386                                 strcat(validated_path, suffix[i]);
387                                 break;
388                         }
389                 }
390                 if (!suffix[i])
391                         return NULL;
392                 gitfile = read_gitfile(used_path) ;
393                 if (gitfile)
394                         strcpy(used_path, gitfile);
395                 if (chdir(used_path))
396                         return NULL;
397                 path = validated_path;
398         }
399         else if (chdir(path))
400                 return NULL;
401
402         if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
403             validate_headref("HEAD") == 0) {
404                 set_git_dir(".");
405                 check_repository_format();
406                 return path;
407         }
408
409         return NULL;
410 }
411
412 static int calc_shared_perm(int mode)
413 {
414         int tweak;
415
416         if (shared_repository < 0)
417                 tweak = -shared_repository;
418         else
419                 tweak = shared_repository;
420
421         if (!(mode & S_IWUSR))
422                 tweak &= ~0222;
423         if (mode & S_IXUSR)
424                 /* Copy read bits to execute bits */
425                 tweak |= (tweak & 0444) >> 2;
426         if (shared_repository < 0)
427                 mode = (mode & ~0777) | tweak;
428         else
429                 mode |= tweak;
430
431         return mode;
432 }
433
434
435 int adjust_shared_perm(const char *path)
436 {
437         int old_mode, new_mode;
438
439         if (!shared_repository)
440                 return 0;
441         if (get_st_mode_bits(path, &old_mode) < 0)
442                 return -1;
443
444         new_mode = calc_shared_perm(old_mode);
445         if (S_ISDIR(old_mode)) {
446                 /* Copy read bits to execute bits */
447                 new_mode |= (new_mode & 0444) >> 2;
448                 new_mode |= FORCE_DIR_SET_GID;
449         }
450
451         if (((old_mode ^ new_mode) & ~S_IFMT) &&
452                         chmod(path, (new_mode & ~S_IFMT)) < 0)
453                 return -2;
454         return 0;
455 }
456
457 static int have_same_root(const char *path1, const char *path2)
458 {
459         int is_abs1, is_abs2;
460
461         is_abs1 = is_absolute_path(path1);
462         is_abs2 = is_absolute_path(path2);
463         return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) ||
464                (!is_abs1 && !is_abs2);
465 }
466
467 /*
468  * Give path as relative to prefix.
469  *
470  * The strbuf may or may not be used, so do not assume it contains the
471  * returned path.
472  */
473 const char *relative_path(const char *in, const char *prefix,
474                           struct strbuf *sb)
475 {
476         int in_len = in ? strlen(in) : 0;
477         int prefix_len = prefix ? strlen(prefix) : 0;
478         int in_off = 0;
479         int prefix_off = 0;
480         int i = 0, j = 0;
481
482         if (!in_len)
483                 return "./";
484         else if (!prefix_len)
485                 return in;
486
487         if (have_same_root(in, prefix)) {
488                 /* bypass dos_drive, for "c:" is identical to "C:" */
489                 if (has_dos_drive_prefix(in)) {
490                         i = 2;
491                         j = 2;
492                 }
493         } else {
494                 return in;
495         }
496
497         while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
498                 if (is_dir_sep(prefix[i])) {
499                         while (is_dir_sep(prefix[i]))
500                                 i++;
501                         while (is_dir_sep(in[j]))
502                                 j++;
503                         prefix_off = i;
504                         in_off = j;
505                 } else {
506                         i++;
507                         j++;
508                 }
509         }
510
511         if (
512             /* "prefix" seems like prefix of "in" */
513             i >= prefix_len &&
514             /*
515              * but "/foo" is not a prefix of "/foobar"
516              * (i.e. prefix not end with '/')
517              */
518             prefix_off < prefix_len) {
519                 if (j >= in_len) {
520                         /* in="/a/b", prefix="/a/b" */
521                         in_off = in_len;
522                 } else if (is_dir_sep(in[j])) {
523                         /* in="/a/b/c", prefix="/a/b" */
524                         while (is_dir_sep(in[j]))
525                                 j++;
526                         in_off = j;
527                 } else {
528                         /* in="/a/bbb/c", prefix="/a/b" */
529                         i = prefix_off;
530                 }
531         } else if (
532                    /* "in" is short than "prefix" */
533                    j >= in_len &&
534                    /* "in" not end with '/' */
535                    in_off < in_len) {
536                 if (is_dir_sep(prefix[i])) {
537                         /* in="/a/b", prefix="/a/b/c/" */
538                         while (is_dir_sep(prefix[i]))
539                                 i++;
540                         in_off = in_len;
541                 }
542         }
543         in += in_off;
544         in_len -= in_off;
545
546         if (i >= prefix_len) {
547                 if (!in_len)
548                         return "./";
549                 else
550                         return in;
551         }
552
553         strbuf_reset(sb);
554         strbuf_grow(sb, in_len);
555
556         while (i < prefix_len) {
557                 if (is_dir_sep(prefix[i])) {
558                         strbuf_addstr(sb, "../");
559                         while (is_dir_sep(prefix[i]))
560                                 i++;
561                         continue;
562                 }
563                 i++;
564         }
565         if (!is_dir_sep(prefix[prefix_len - 1]))
566                 strbuf_addstr(sb, "../");
567
568         strbuf_addstr(sb, in);
569
570         return sb->buf;
571 }
572
573 /*
574  * A simpler implementation of relative_path
575  *
576  * Get relative path by removing "prefix" from "in". This function
577  * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
578  * to increase performance when traversing the path to work_tree.
579  */
580 const char *remove_leading_path(const char *in, const char *prefix)
581 {
582         static char buf[PATH_MAX + 1];
583         int i = 0, j = 0;
584
585         if (!prefix || !prefix[0])
586                 return in;
587         while (prefix[i]) {
588                 if (is_dir_sep(prefix[i])) {
589                         if (!is_dir_sep(in[j]))
590                                 return in;
591                         while (is_dir_sep(prefix[i]))
592                                 i++;
593                         while (is_dir_sep(in[j]))
594                                 j++;
595                         continue;
596                 } else if (in[j] != prefix[i]) {
597                         return in;
598                 }
599                 i++;
600                 j++;
601         }
602         if (
603             /* "/foo" is a prefix of "/foo" */
604             in[j] &&
605             /* "/foo" is not a prefix of "/foobar" */
606             !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
607            )
608                 return in;
609         while (is_dir_sep(in[j]))
610                 j++;
611         if (!in[j])
612                 strcpy(buf, ".");
613         else
614                 strcpy(buf, in + j);
615         return buf;
616 }
617
618 /*
619  * It is okay if dst == src, but they should not overlap otherwise.
620  *
621  * Performs the following normalizations on src, storing the result in dst:
622  * - Ensures that components are separated by '/' (Windows only)
623  * - Squashes sequences of '/'.
624  * - Removes "." components.
625  * - Removes ".." components, and the components the precede them.
626  * Returns failure (non-zero) if a ".." component appears as first path
627  * component anytime during the normalization. Otherwise, returns success (0).
628  *
629  * Note that this function is purely textual.  It does not follow symlinks,
630  * verify the existence of the path, or make any system calls.
631  *
632  * prefix_len != NULL is for a specific case of prefix_pathspec():
633  * assume that src == dst and src[0..prefix_len-1] is already
634  * normalized, any time "../" eats up to the prefix_len part,
635  * prefix_len is reduced. In the end prefix_len is the remaining
636  * prefix that has not been overridden by user pathspec.
637  */
638 int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
639 {
640         char *dst0;
641
642         if (has_dos_drive_prefix(src)) {
643                 *dst++ = *src++;
644                 *dst++ = *src++;
645         }
646         dst0 = dst;
647
648         if (is_dir_sep(*src)) {
649                 *dst++ = '/';
650                 while (is_dir_sep(*src))
651                         src++;
652         }
653
654         for (;;) {
655                 char c = *src;
656
657                 /*
658                  * A path component that begins with . could be
659                  * special:
660                  * (1) "." and ends   -- ignore and terminate.
661                  * (2) "./"           -- ignore them, eat slash and continue.
662                  * (3) ".." and ends  -- strip one and terminate.
663                  * (4) "../"          -- strip one, eat slash and continue.
664                  */
665                 if (c == '.') {
666                         if (!src[1]) {
667                                 /* (1) */
668                                 src++;
669                         } else if (is_dir_sep(src[1])) {
670                                 /* (2) */
671                                 src += 2;
672                                 while (is_dir_sep(*src))
673                                         src++;
674                                 continue;
675                         } else if (src[1] == '.') {
676                                 if (!src[2]) {
677                                         /* (3) */
678                                         src += 2;
679                                         goto up_one;
680                                 } else if (is_dir_sep(src[2])) {
681                                         /* (4) */
682                                         src += 3;
683                                         while (is_dir_sep(*src))
684                                                 src++;
685                                         goto up_one;
686                                 }
687                         }
688                 }
689
690                 /* copy up to the next '/', and eat all '/' */
691                 while ((c = *src++) != '\0' && !is_dir_sep(c))
692                         *dst++ = c;
693                 if (is_dir_sep(c)) {
694                         *dst++ = '/';
695                         while (is_dir_sep(c))
696                                 c = *src++;
697                         src--;
698                 } else if (!c)
699                         break;
700                 continue;
701
702         up_one:
703                 /*
704                  * dst0..dst is prefix portion, and dst[-1] is '/';
705                  * go up one level.
706                  */
707                 dst--;  /* go to trailing '/' */
708                 if (dst <= dst0)
709                         return -1;
710                 /* Windows: dst[-1] cannot be backslash anymore */
711                 while (dst0 < dst && dst[-1] != '/')
712                         dst--;
713                 if (prefix_len && *prefix_len > dst - dst0)
714                         *prefix_len = dst - dst0;
715         }
716         *dst = '\0';
717         return 0;
718 }
719
720 int normalize_path_copy(char *dst, const char *src)
721 {
722         return normalize_path_copy_len(dst, src, NULL);
723 }
724
725 /*
726  * path = Canonical absolute path
727  * prefixes = string_list containing normalized, absolute paths without
728  * trailing slashes (except for the root directory, which is denoted by "/").
729  *
730  * Determines, for each path in prefixes, whether the "prefix"
731  * is an ancestor directory of path.  Returns the length of the longest
732  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
733  * is an ancestor.  (Note that this means 0 is returned if prefixes is
734  * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
735  * are not considered to be their own ancestors.  path must be in a
736  * canonical form: empty components, or "." or ".." components are not
737  * allowed.
738  */
739 int longest_ancestor_length(const char *path, struct string_list *prefixes)
740 {
741         int i, max_len = -1;
742
743         if (!strcmp(path, "/"))
744                 return -1;
745
746         for (i = 0; i < prefixes->nr; i++) {
747                 const char *ceil = prefixes->items[i].string;
748                 int len = strlen(ceil);
749
750                 if (len == 1 && ceil[0] == '/')
751                         len = 0; /* root matches anything, with length 0 */
752                 else if (!strncmp(path, ceil, len) && path[len] == '/')
753                         ; /* match of length len */
754                 else
755                         continue; /* no match */
756
757                 if (len > max_len)
758                         max_len = len;
759         }
760
761         return max_len;
762 }
763
764 /* strip arbitrary amount of directory separators at end of path */
765 static inline int chomp_trailing_dir_sep(const char *path, int len)
766 {
767         while (len && is_dir_sep(path[len - 1]))
768                 len--;
769         return len;
770 }
771
772 /*
773  * If path ends with suffix (complete path components), returns the
774  * part before suffix (sans trailing directory separators).
775  * Otherwise returns NULL.
776  */
777 char *strip_path_suffix(const char *path, const char *suffix)
778 {
779         int path_len = strlen(path), suffix_len = strlen(suffix);
780
781         while (suffix_len) {
782                 if (!path_len)
783                         return NULL;
784
785                 if (is_dir_sep(path[path_len - 1])) {
786                         if (!is_dir_sep(suffix[suffix_len - 1]))
787                                 return NULL;
788                         path_len = chomp_trailing_dir_sep(path, path_len);
789                         suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
790                 }
791                 else if (path[--path_len] != suffix[--suffix_len])
792                         return NULL;
793         }
794
795         if (path_len && !is_dir_sep(path[path_len - 1]))
796                 return NULL;
797         return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
798 }
799
800 int daemon_avoid_alias(const char *p)
801 {
802         int sl, ndot;
803
804         /*
805          * This resurrects the belts and suspenders paranoia check by HPA
806          * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
807          * does not do getcwd() based path canonicalization.
808          *
809          * sl becomes true immediately after seeing '/' and continues to
810          * be true as long as dots continue after that without intervening
811          * non-dot character.
812          */
813         if (!p || (*p != '/' && *p != '~'))
814                 return -1;
815         sl = 1; ndot = 0;
816         p++;
817
818         while (1) {
819                 char ch = *p++;
820                 if (sl) {
821                         if (ch == '.')
822                                 ndot++;
823                         else if (ch == '/') {
824                                 if (ndot < 3)
825                                         /* reject //, /./ and /../ */
826                                         return -1;
827                                 ndot = 0;
828                         }
829                         else if (ch == 0) {
830                                 if (0 < ndot && ndot < 3)
831                                         /* reject /.$ and /..$ */
832                                         return -1;
833                                 return 0;
834                         }
835                         else
836                                 sl = ndot = 0;
837                 }
838                 else if (ch == 0)
839                         return 0;
840                 else if (ch == '/') {
841                         sl = 1;
842                         ndot = 0;
843                 }
844         }
845 }