Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

realpath() without resolving symlinks?

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"
like image 224
thejh Avatar asked Jan 23 '11 13:01

thejh


People also ask

How do I bypass symlinks?

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.

What does Realpath function do?

The realpath() function returns the absolute pathname. This function removes all symbolic links (like '/./', '/../' and extra '/') and returns the absolute pathname.

Why symlinks are needed?

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.

Does du follow symlinks?

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.


1 Answers

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;
}
like image 150
Arnaud Le Blanc Avatar answered Oct 21 '22 20:10

Arnaud Le Blanc