I have researched a lot on this topic but could not get anything substantial. By normalize/canonicalize I mean to remove all the "..", ".", multiple slashes etc from a file path and get a simple absolute path. e.g.
"/rootdir/dir1/dir2/dir3/../././././dir4//////////" to "/rootdir/dir1/dir2/dir4"
On windows I have GetFullPathName() and I can get the canonical filepath name, but for Linux I cannot find any such API which can do the same work for me, realpath() is there, but even realpath() needs the filepath to be present on the file system to be able to output normalized path, e.g. if the path /rootdir/dir1/dir2/dir4 is not on file system - realpath() will throw error on the above specified complex filepath input. Is there any way by which one could get the normalized file path even if it is not existing on the file system?
realpath(3) does not resolve missing filenames.
But GNU core utilities (https://www.gnu.org/software/coreutils/) have a program realpath(1) which is similar to realpath(3) function, but have option:
-m, --canonicalize-missing no components of the path need exist
And your task can be done by canonicalize_filename_mode() function from file lib/canonicalize.c of the coreutils source.
canonicalize_filename_mode()
from Gnulib
is a great option but cannot be used in commercial software (GPL License)
We use the following implementation that depends on cwalk
library:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include "cwalk.h"
/* extended version of canonicalize_file_name(3) that can handle non existing paths*/
static char *canonicalize_file_name_missing(const char *path) {
char *resolved_path = canonicalize_file_name(path);
if (resolved_path != NULL) {
return resolved_path;
}
/* handle missing files*/
char *cwd = get_current_dir_name();
if (cwd == NULL) {
/* cannot detect current working directory */
return NULL;
}
size_t resolved_path_len = cwk_path_get_absolute(cwd, path, NULL, 0);
if (resolved_path_len == 0) {
return NULL;
}
resolved_path = malloc(resolved_path_len + 1);
cwk_path_get_absolute(cwd, path, resolved_path, resolved_path_len + 1);
free(cwd);
return resolved_path;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With