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/* We allow "recursive" symbolic links. Only within reason, though. */ 15#define MAXDEPTH 5 16 17/* 18 * Return the real path (i.e., absolute path, with symlinks resolved 19 * and extra slashes removed) equivalent to the specified path. (If 20 * you want an absolute path but don't mind links, use 21 * absolute_path().) The return value is a pointer to a static 22 * buffer. 23 * 24 * The input and all intermediate paths must be shorter than MAX_PATH. 25 * The directory part of path (i.e., everything up to the last 26 * dir_sep) must denote a valid, existing directory, but the last 27 * component need not exist. If die_on_error is set, then die with an 28 * informative error message if there is a problem. Otherwise, return 29 * NULL on errors (without generating any output). 30 * 31 * If path is our buffer, then return path, as it's already what the 32 * user wants. 33 */ 34static const char*real_path_internal(const char*path,int die_on_error) 35{ 36static struct strbuf sb = STRBUF_INIT; 37char*retval = NULL; 38 39/* 40 * If we have to temporarily chdir(), store the original CWD 41 * here so that we can chdir() back to it at the end of the 42 * function: 43 */ 44struct strbuf cwd = STRBUF_INIT; 45 46int depth = MAXDEPTH; 47char*last_elem = NULL; 48struct stat st; 49 50/* We've already done it */ 51if(path == sb.buf) 52return path; 53 54if(!*path) { 55if(die_on_error) 56die("The empty string is not a valid path"); 57else 58goto error_out; 59} 60 61strbuf_reset(&sb); 62strbuf_addstr(&sb, path); 63 64while(depth--) { 65if(!is_directory(sb.buf)) { 66char*last_slash =find_last_dir_sep(sb.buf); 67if(last_slash) { 68 last_elem =xstrdup(last_slash +1); 69strbuf_setlen(&sb, last_slash - sb.buf +1); 70}else{ 71 last_elem =xmemdupz(sb.buf, sb.len); 72strbuf_reset(&sb); 73} 74} 75 76if(sb.len) { 77if(!cwd.len &&strbuf_getcwd(&cwd)) { 78if(die_on_error) 79die_errno("Could not get current working directory"); 80else 81goto error_out; 82} 83 84if(chdir(sb.buf)) { 85if(die_on_error) 86die_errno("Could not switch to '%s'", 87 sb.buf); 88else 89goto error_out; 90} 91} 92if(strbuf_getcwd(&sb)) { 93if(die_on_error) 94die_errno("Could not get current working directory"); 95else 96goto error_out; 97} 98 99if(last_elem) { 100if(sb.len && !is_dir_sep(sb.buf[sb.len -1])) 101strbuf_addch(&sb,'/'); 102strbuf_addstr(&sb, last_elem); 103free(last_elem); 104 last_elem = NULL; 105} 106 107if(!lstat(sb.buf, &st) &&S_ISLNK(st.st_mode)) { 108struct strbuf next_sb = STRBUF_INIT; 109 ssize_t len =strbuf_readlink(&next_sb, sb.buf,0); 110if(len <0) { 111if(die_on_error) 112die_errno("Invalid symlink '%s'", 113 sb.buf); 114else 115goto error_out; 116} 117strbuf_swap(&sb, &next_sb); 118strbuf_release(&next_sb); 119}else 120break; 121} 122 123 retval = sb.buf; 124error_out: 125free(last_elem); 126if(cwd.len &&chdir(cwd.buf)) 127die_errno("Could not change back to '%s'", cwd.buf); 128strbuf_release(&cwd); 129 130return retval; 131} 132 133const char*real_path(const char*path) 134{ 135returnreal_path_internal(path,1); 136} 137 138const char*real_path_if_valid(const char*path) 139{ 140returnreal_path_internal(path,0); 141} 142 143/* 144 * Use this to get an absolute path from a relative one. If you want 145 * to resolve links, you should use real_path. 146 */ 147const char*absolute_path(const char*path) 148{ 149static struct strbuf sb = STRBUF_INIT; 150strbuf_reset(&sb); 151strbuf_add_absolute_path(&sb, path); 152return sb.buf; 153} 154 155/* 156 * Unlike prefix_path, this should be used if the named file does 157 * not have to interact with index entry; i.e. name of a random file 158 * on the filesystem. 159 */ 160const char*prefix_filename(const char*pfx,int pfx_len,const char*arg) 161{ 162static struct strbuf path = STRBUF_INIT; 163#ifndef GIT_WINDOWS_NATIVE 164if(!pfx_len ||is_absolute_path(arg)) 165return arg; 166strbuf_reset(&path); 167strbuf_add(&path, pfx, pfx_len); 168strbuf_addstr(&path, arg); 169#else 170char*p; 171/* don't add prefix to absolute paths, but still replace '\' by '/' */ 172strbuf_reset(&path); 173if(is_absolute_path(arg)) 174 pfx_len =0; 175else if(pfx_len) 176strbuf_add(&path, pfx, pfx_len); 177strbuf_addstr(&path, arg); 178for(p = path.buf + pfx_len; *p; p++) 179if(*p =='\\') 180*p ='/'; 181#endif 182return path.buf; 183}