mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +00:00 
			
		
		
		
	On *nix, use a realpath(3) variant (which does not expand symlinks) in NormalizePath
Before this commit, when a source file is a symlink, cquery is not able to serve LSP requests for it.
This commit is contained in:
		
							parent
							
								
									38ff70ebc3
								
							
						
					
					
						commit
						eac644d81a
					
				@ -29,10 +29,8 @@
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h> /* For O_* constants */
 | 
			
		||||
#include <semaphore.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <sys/stat.h> /* For mode constants */
 | 
			
		||||
 | 
			
		||||
#ifndef __APPLE__
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
@ -42,6 +40,73 @@
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
// Returns the canonicalized absolute pathname, without expanding symbolic links.
 | 
			
		||||
// This is a variant of realpath(2), C++ rewrite of
 | 
			
		||||
// https://github.com/freebsd/freebsd/blob/master/lib/libc/stdlib/realpath.c
 | 
			
		||||
optional<std::string> RealPathNotExpandSymlink(std::string path) {
 | 
			
		||||
  if (path.empty()) {
 | 
			
		||||
    errno = EINVAL;
 | 
			
		||||
    return nullopt;
 | 
			
		||||
  }
 | 
			
		||||
  if (path[0] == '\0') {
 | 
			
		||||
    errno = ENOENT;
 | 
			
		||||
    return nullopt;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Do not use PATH_MAX because it is tricky on Linux.
 | 
			
		||||
  // See https://eklitzke.org/path-max-is-tricky
 | 
			
		||||
  char tmp[1024];
 | 
			
		||||
  std::string resolved;
 | 
			
		||||
  size_t i = 0;
 | 
			
		||||
  struct stat sb;
 | 
			
		||||
  if (path[0] == '/') {
 | 
			
		||||
    resolved = "/";
 | 
			
		||||
    i = 1;
 | 
			
		||||
  } else {
 | 
			
		||||
    if (!getcwd(tmp, sizeof tmp))
 | 
			
		||||
      return nullopt;
 | 
			
		||||
    resolved = tmp;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  while (i < path.size()) {
 | 
			
		||||
    auto j = path.find('/', i);
 | 
			
		||||
    if (j == std::string::npos)
 | 
			
		||||
      j = path.size();
 | 
			
		||||
    auto next_token = path.substr(i, j - i);
 | 
			
		||||
    i = j + 1;
 | 
			
		||||
    if (resolved.back() != '/')
 | 
			
		||||
      resolved += '/';
 | 
			
		||||
    if (next_token.empty() || next_token == ".") {
 | 
			
		||||
      // Handle consequential slashes and "."
 | 
			
		||||
      continue;
 | 
			
		||||
    } else if (next_token == "..") {
 | 
			
		||||
      // Strip the last path component except when it is single "/"
 | 
			
		||||
      if (resolved.size() > 1)
 | 
			
		||||
        resolved.resize(resolved.rfind('/', resolved.size() - 2) + 1);
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
    // Append the next path component.
 | 
			
		||||
    // Here we differ from realpath(3), we use stat(2) instead of
 | 
			
		||||
    // lstat(2) because we do not want to resolve symlinks.
 | 
			
		||||
    resolved += next_token;
 | 
			
		||||
    if (stat(resolved.c_str(), &sb) != 0)
 | 
			
		||||
      return nullopt;
 | 
			
		||||
    if (!S_ISDIR(sb.st_mode) && j < path.size()) {
 | 
			
		||||
      errno = ENOTDIR;
 | 
			
		||||
      return nullopt;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Remove trailing slash except when a single "/".
 | 
			
		||||
  if (resolved.size() > 1 && resolved.back() == '/')
 | 
			
		||||
    resolved.pop_back();
 | 
			
		||||
  return resolved;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
struct PlatformMutexLinux : public PlatformMutex {
 | 
			
		||||
  sem_t* sem_ = nullptr;
 | 
			
		||||
 | 
			
		||||
@ -155,12 +220,8 @@ std::string GetWorkingDirectory() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string NormalizePath(const std::string& path) {
 | 
			
		||||
  errno = 0;
 | 
			
		||||
  char name[PATH_MAX + 1];
 | 
			
		||||
  (void)realpath(path.c_str(), name);
 | 
			
		||||
  if (errno)
 | 
			
		||||
    return path;
 | 
			
		||||
  return name;
 | 
			
		||||
  optional<std::string> resolved = RealPathNotExpandSymlink(path);
 | 
			
		||||
  return resolved ? *resolved : path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TryMakeDirectory(const std::string& absolute_path) {
 | 
			
		||||
 | 
			
		||||
@ -158,4 +158,4 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
 | 
			
		||||
 | 
			
		||||
float GetProcessMemoryUsedInMb();
 | 
			
		||||
 | 
			
		||||
std::string FormatMicroseconds(long long microseconds);
 | 
			
		||||
std::string FormatMicroseconds(long long microseconds);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user