How to get absolute path of file or directory, that does *not* exist?

前端 未结 2 983
灰色年华
灰色年华 2020-12-18 21:26

How can I determine the absolute path of a file or directory from a given relative path in C/C++ on GNU/Linux?
I know about realpath(), but it does not work

相关标签:
2条回答
  • 2020-12-18 22:15

    Try realpath. If it fails, start removing path components from the end one at a time and retrying realpath until it succeeds. Then append the components you removed back onto the result of the successful realpath call.

    If you're sure the containing directory exists and you just want to make a file there, you only have to remove at most one component.

    Another approach would be to just create the file first, then call realpath.

    0 讨论(0)
  • 2020-12-18 22:20

    As noted by @R.. GitHub, you can build this functionality on realpath(). Here is an example function, which uses realpath() to determine the canonical form of the portion of the path which exists, and appends the non-existent portion of the path to it.

    Since realpath() operates on C-style strings, I decided to use them here too. But the function can easily be re-written to use std::string (just don't forget to free canonical_file_path after copying it to an std::string!).

    Please note that duplicate "/" entries are not removed from the portion of the path which does not exist; it is simply appended to canonical form of the portion which does exist.

    ////////////////////////////////////////////////////////////////////////////////
    // Return the input path in a canonical form. This is achieved by expanding all
    // symbolic links, resolving references to "." and "..", and removing duplicate
    // "/" characters.
    //
    // If the file exists, its path is canonicalized and returned. If the file,
    // or parts of the containing directory, do not exist, path components are
    // removed from the end until an existing path is found. The remainder of the
    // path is then appended to the canonical form of the existing path,
    // and returned. Consequently, the returned path may not exist. The portion
    // of the path which exists, however, is represented in canonical form.
    //
    // If successful, this function returns a C-string, which needs to be freed by
    // the caller using free().
    //
    // ARGUMENTS:
    //   file_path
    //   File path, whose canonical form to return.
    //
    // RETURNS:
    //   On success, returns the canonical path to the file, which needs to be freed
    //   by the caller.
    //
    //   On failure, returns NULL.
    ////////////////////////////////////////////////////////////////////////////////
    char *make_file_name_canonical(char const *file_path)
    {
      char *canonical_file_path  = NULL;
      unsigned int file_path_len = strlen(file_path);
    
      if (file_path_len > 0)
      {
        canonical_file_path = realpath(file_path, NULL);
        if (canonical_file_path == NULL && errno == ENOENT)
        {
          // The file was not found. Back up to a segment which exists,
          // and append the remainder of the path to it.
          char *file_path_copy = NULL;
          if (file_path[0] == '/'                ||
              (strncmp(file_path, "./", 2) == 0) ||
              (strncmp(file_path, "../", 3) == 0))
          {
            // Absolute path, or path starts with "./" or "../"
            file_path_copy = strdup(file_path);
          }
          else
          {
            // Relative path
            file_path_copy = (char*)malloc(strlen(file_path) + 3);
            strcpy(file_path_copy, "./");
            strcat(file_path_copy, file_path);
          }
    
          // Remove path components from the end, until an existing path is found
          for (int char_idx = strlen(file_path_copy) - 1;
               char_idx >= 0 && canonical_file_path == NULL;
               --char_idx)
          {
            if (file_path_copy[char_idx] == '/')
            {
              // Remove the slash character
              file_path_copy[char_idx] = '\0';
    
              canonical_file_path = realpath(file_path_copy, NULL);
              if (canonical_file_path != NULL)
              {
                // An existing path was found. Append the remainder of the path
                // to a canonical form of the existing path.
                char *combined_file_path = (char*)malloc(strlen(canonical_file_path) + strlen(file_path_copy + char_idx + 1) + 2);
                strcpy(combined_file_path, canonical_file_path);
                strcat(combined_file_path, "/");
                strcat(combined_file_path, file_path_copy + char_idx + 1);
                free(canonical_file_path);
                canonical_file_path = combined_file_path;
              }
              else
              {
                // The path segment does not exist. Replace the slash character
                // and keep trying by removing the previous path component.
                file_path_copy[char_idx] = '/';
              }
            }
          }
    
          free(file_path_copy);
        }
      }
    
      return canonical_file_path;
    }
    
    0 讨论(0)
提交回复
热议问题