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