abspath.con commit real_path: convert real_path_internal to strbuf_realpath (a1ae484)
   1#include "cache.h"
   2
   3/*
   4 * Do not use this for inspecting *tracked* content.  When path is a
   5 * symlink to a directory, we do not want to say it is a directory when
   6 * dealing with tracked content in the working tree.
   7 */
   8int is_directory(const char *path)
   9{
  10        struct stat st;
  11        return (!stat(path, &st) && S_ISDIR(st.st_mode));
  12}
  13
  14/* removes the last path component from 'path' except if 'path' is root */
  15static void strip_last_component(struct strbuf *path)
  16{
  17        size_t offset = offset_1st_component(path->buf);
  18        size_t len = path->len;
  19
  20        /* Find start of the last component */
  21        while (offset < len && !is_dir_sep(path->buf[len - 1]))
  22                len--;
  23        /* Skip sequences of multiple path-separators */
  24        while (offset < len && is_dir_sep(path->buf[len - 1]))
  25                len--;
  26
  27        strbuf_setlen(path, len);
  28}
  29
  30/* get (and remove) the next component in 'remaining' and place it in 'next' */
  31static void get_next_component(struct strbuf *next, struct strbuf *remaining)
  32{
  33        char *start = NULL;
  34        char *end = NULL;
  35
  36        strbuf_reset(next);
  37
  38        /* look for the next component */
  39        /* Skip sequences of multiple path-separators */
  40        for (start = remaining->buf; is_dir_sep(*start); start++)
  41                ; /* nothing */
  42        /* Find end of the path component */
  43        for (end = start; *end && !is_dir_sep(*end); end++)
  44                ; /* nothing */
  45
  46        strbuf_add(next, start, end - start);
  47        /* remove the component from 'remaining' */
  48        strbuf_remove(remaining, 0, end - remaining->buf);
  49}
  50
  51/* We allow "recursive" symbolic links. Only within reason, though. */
  52#define MAXSYMLINKS 5
  53
  54/*
  55 * Return the real path (i.e., absolute path, with symlinks resolved
  56 * and extra slashes removed) equivalent to the specified path.  (If
  57 * you want an absolute path but don't mind links, use
  58 * absolute_path().)  Places the resolved realpath in the provided strbuf.
  59 *
  60 * The directory part of path (i.e., everything up to the last
  61 * dir_sep) must denote a valid, existing directory, but the last
  62 * component need not exist.  If die_on_error is set, then die with an
  63 * informative error message if there is a problem.  Otherwise, return
  64 * NULL on errors (without generating any output).
  65 */
  66char *strbuf_realpath(struct strbuf *resolved, const char *path,
  67                      int die_on_error)
  68{
  69        struct strbuf remaining = STRBUF_INIT;
  70        struct strbuf next = STRBUF_INIT;
  71        struct strbuf symlink = STRBUF_INIT;
  72        char *retval = NULL;
  73        int num_symlinks = 0;
  74        struct stat st;
  75
  76        if (!*path) {
  77                if (die_on_error)
  78                        die("The empty string is not a valid path");
  79                else
  80                        goto error_out;
  81        }
  82
  83        strbuf_reset(resolved);
  84
  85        if (is_absolute_path(path)) {
  86                /* absolute path; start with only root as being resolved */
  87                int offset = offset_1st_component(path);
  88                strbuf_add(resolved, path, offset);
  89                strbuf_addstr(&remaining, path + offset);
  90        } else {
  91                /* relative path; can use CWD as the initial resolved path */
  92                if (strbuf_getcwd(resolved)) {
  93                        if (die_on_error)
  94                                die_errno("unable to get current working directory");
  95                        else
  96                                goto error_out;
  97                }
  98                strbuf_addstr(&remaining, path);
  99        }
 100
 101        /* Iterate over the remaining path components */
 102        while (remaining.len > 0) {
 103                get_next_component(&next, &remaining);
 104
 105                if (next.len == 0) {
 106                        continue; /* empty component */
 107                } else if (next.len == 1 && !strcmp(next.buf, ".")) {
 108                        continue; /* '.' component */
 109                } else if (next.len == 2 && !strcmp(next.buf, "..")) {
 110                        /* '..' component; strip the last path component */
 111                        strip_last_component(resolved);
 112                        continue;
 113                }
 114
 115                /* append the next component and resolve resultant path */
 116                if (!is_dir_sep(resolved->buf[resolved->len - 1]))
 117                        strbuf_addch(resolved, '/');
 118                strbuf_addbuf(resolved, &next);
 119
 120                if (lstat(resolved->buf, &st)) {
 121                        /* error out unless this was the last component */
 122                        if (errno != ENOENT || remaining.len) {
 123                                if (die_on_error)
 124                                        die_errno("Invalid path '%s'",
 125                                                  resolved->buf);
 126                                else
 127                                        goto error_out;
 128                        }
 129                } else if (S_ISLNK(st.st_mode)) {
 130                        ssize_t len;
 131                        strbuf_reset(&symlink);
 132
 133                        if (num_symlinks++ > MAXSYMLINKS) {
 134                                if (die_on_error)
 135                                        die("More than %d nested symlinks "
 136                                            "on path '%s'", MAXSYMLINKS, path);
 137                                else
 138                                        goto error_out;
 139                        }
 140
 141                        len = strbuf_readlink(&symlink, resolved->buf,
 142                                              st.st_size);
 143                        if (len < 0) {
 144                                if (die_on_error)
 145                                        die_errno("Invalid symlink '%s'",
 146                                                  resolved->buf);
 147                                else
 148                                        goto error_out;
 149                        }
 150
 151                        if (is_absolute_path(symlink.buf)) {
 152                                /* absolute symlink; set resolved to root */
 153                                int offset = offset_1st_component(symlink.buf);
 154                                strbuf_reset(resolved);
 155                                strbuf_add(resolved, symlink.buf, offset);
 156                                strbuf_remove(&symlink, 0, offset);
 157                        } else {
 158                                /*
 159                                 * relative symlink
 160                                 * strip off the last component since it will
 161                                 * be replaced with the contents of the symlink
 162                                 */
 163                                strip_last_component(resolved);
 164                        }
 165
 166                        /*
 167                         * if there are still remaining components to resolve
 168                         * then append them to symlink
 169                         */
 170                        if (remaining.len) {
 171                                strbuf_addch(&symlink, '/');
 172                                strbuf_addbuf(&symlink, &remaining);
 173                        }
 174
 175                        /*
 176                         * use the symlink as the remaining components that
 177                         * need to be resloved
 178                         */
 179                        strbuf_swap(&symlink, &remaining);
 180                }
 181        }
 182
 183        retval = resolved->buf;
 184
 185error_out:
 186        strbuf_release(&remaining);
 187        strbuf_release(&next);
 188        strbuf_release(&symlink);
 189
 190        if (!retval)
 191                strbuf_reset(resolved);
 192
 193        return retval;
 194}
 195
 196const char *real_path(const char *path)
 197{
 198        static struct strbuf realpath = STRBUF_INIT;
 199        return strbuf_realpath(&realpath, path, 1);
 200}
 201
 202const char *real_path_if_valid(const char *path)
 203{
 204        static struct strbuf realpath = STRBUF_INIT;
 205        return strbuf_realpath(&realpath, path, 0);
 206}
 207
 208/*
 209 * Use this to get an absolute path from a relative one. If you want
 210 * to resolve links, you should use real_path.
 211 */
 212const char *absolute_path(const char *path)
 213{
 214        static struct strbuf sb = STRBUF_INIT;
 215        strbuf_reset(&sb);
 216        strbuf_add_absolute_path(&sb, path);
 217        return sb.buf;
 218}
 219
 220/*
 221 * Unlike prefix_path, this should be used if the named file does
 222 * not have to interact with index entry; i.e. name of a random file
 223 * on the filesystem.
 224 */
 225const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
 226{
 227        static struct strbuf path = STRBUF_INIT;
 228#ifndef GIT_WINDOWS_NATIVE
 229        if (!pfx_len || is_absolute_path(arg))
 230                return arg;
 231        strbuf_reset(&path);
 232        strbuf_add(&path, pfx, pfx_len);
 233        strbuf_addstr(&path, arg);
 234#else
 235        /* don't add prefix to absolute paths, but still replace '\' by '/' */
 236        strbuf_reset(&path);
 237        if (is_absolute_path(arg))
 238                pfx_len = 0;
 239        else if (pfx_len)
 240                strbuf_add(&path, pfx, pfx_len);
 241        strbuf_addstr(&path, arg);
 242        convert_slashes(path.buf + pfx_len);
 243#endif
 244        return path.buf;
 245}