I already read about realpath()
, but is there a function that I can pass a base directory and a filename that would give me the following result without resolving symlinks or checking whether files actually exist? Or do I have to use a modified realpath()
?
"/var/", "../etc///././/passwd" => "/etc/passwd"
Overwriting Symlinks If you try to create a symbolic link that already exists , the ln command will print an error message. To overwrite the destination path of the symlink, use the -f ( --force ) option.
The realpath() function returns the absolute pathname. This function removes all symbolic links (like '/./', '/../' and extra '/') and returns the absolute pathname.
A symbolic link, also known as a soft link or symlink, is a special file pointing to another file or directory using an absolute or relative path. Symbolic links are similar to shortcuts in Windows and are useful when you need quick access to files or folders with long paths.
The -L option tells du to process symbolic links by using the file or directory which the symbolic link references, rather than the link itself.
Here is a normalize_path() function:
If the given path is relative, the function starts by prepending the current working directory to it.
Then the special path components like ..
, .
or empty components are treated, and the result is returned.
For ..
, the last component is removed if there is one (/..
will just return /
).
For .
or empty components (double /
), this is just skipped.
The function ensures to not return empty an path (/
is returned instead).
#define _GNU_SOURCE /* memrchr() */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
char * normalize_path(const char * src, size_t src_len) {
char * res;
size_t res_len;
const char * ptr = src;
const char * end = &src[src_len];
const char * next;
if (src_len == 0 || src[0] != '/') {
// relative path
char pwd[PATH_MAX];
size_t pwd_len;
if (getcwd(pwd, sizeof(pwd)) == NULL) {
return NULL;
}
pwd_len = strlen(pwd);
res = malloc(pwd_len + 1 + src_len + 1);
memcpy(res, pwd, pwd_len);
res_len = pwd_len;
} else {
res = malloc((src_len > 0 ? src_len : 1) + 1);
res_len = 0;
}
for (ptr = src; ptr < end; ptr=next+1) {
size_t len;
next = memchr(ptr, '/', end-ptr);
if (next == NULL) {
next = end;
}
len = next-ptr;
switch(len) {
case 2:
if (ptr[0] == '.' && ptr[1] == '.') {
const char * slash = memrchr(res, '/', res_len);
if (slash != NULL) {
res_len = slash - res;
}
continue;
}
break;
case 1:
if (ptr[0] == '.') {
continue;
}
break;
case 0:
continue;
}
res[res_len++] = '/';
memcpy(&res[res_len], ptr, len);
res_len += len;
}
if (res_len == 0) {
res[res_len++] = '/';
}
res[res_len] = '\0';
return res;
}
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