Example #1
0
char *str_dup(char *s)
{
    char *ret = NULL;
    uint32 len = 0;

    /* buffer */
    len = str_len(s) + 1; /* for '\0' */
    ret = __builtin_alloca(len);

    /* copy */
    str_move(ret, s, len);

    return ret;
}
Example #2
0
void
custom_canonicalize_pathname (char *path, CANON_PATH_FLAGS flags)
{
    char *p, *s;
    char *lpath = path;         /* path without leading UNC part */
    const size_t url_delim_len = strlen (VFS_PATH_URL_DELIMITER);

    /* Detect and preserve UNC paths: //server/... */
    if ((flags & CANON_PATH_GUARDUNC) != 0 && IS_PATH_SEP (path[0]) && IS_PATH_SEP (path[1]))
    {
        p = path + 2;
        while (p[0] != '\0' && !IS_PATH_SEP (p[0]))
            p++;
        if (IS_PATH_SEP (p[0]) && p > path + 2)
            lpath = p;
    }

    if (!lpath[0] || !lpath[1])
        return;

    if (flags & CANON_PATH_JOINSLASHES)
    {
        /* Collapse multiple slashes */
        p = lpath;
        while (*p)
        {
            if (IS_PATH_SEP (p[0]) && IS_PATH_SEP (p[1]) && (p == lpath || *(p - 1) != ':'))
            {
                s = p + 1;
                while (IS_PATH_SEP (*(++s)))
                    ;
                str_move (p + 1, s);
            }
            p++;
        }
    }

    if (flags & CANON_PATH_JOINSLASHES)
    {
        /* Collapse "/./" -> "/" */
        p = lpath;
        while (*p)
        {
            if (IS_PATH_SEP (p[0]) && p[1] == '.' && IS_PATH_SEP (p[2]))
                str_move (p, p + 2);
            else
                p++;
        }
    }

    if (flags & CANON_PATH_REMSLASHDOTS)
    {
        size_t len;

        /* Remove trailing slashes */
        p = lpath + strlen (lpath) - 1;
        while (p > lpath && IS_PATH_SEP (*p))
        {
            if (p >= lpath + url_delim_len - 1
                && strncmp (p - url_delim_len + 1, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
                break;
            *p-- = 0;
        }

        /* Remove leading "./" */
        if (lpath[0] == '.' && IS_PATH_SEP (lpath[1]))
        {
            if (lpath[2] == 0)
            {
                lpath[1] = 0;
                return;
            }
            else
            {
                str_move (lpath, lpath + 2);
            }
        }

        /* Remove trailing "/" or "/." */
        len = strlen (lpath);
        if (len < 2)
            return;
        if (IS_PATH_SEP (lpath[len - 1])
            && (len < url_delim_len
                || strncmp (lpath + len - url_delim_len, VFS_PATH_URL_DELIMITER,
                            url_delim_len) != 0))
        {
            lpath[len - 1] = '\0';
        }
        else
        {
            if (lpath[len - 1] == '.' && IS_PATH_SEP (lpath[len - 2]))
            {
                if (len == 2)
                {
                    lpath[1] = '\0';
                    return;
                }
                else
                {
                    lpath[len - 2] = '\0';
                }
            }
        }
    }

    if (flags & CANON_PATH_REMDOUBLEDOTS)
    {
#ifdef HAVE_CHARSET
        const size_t enc_prefix_len = strlen (VFS_ENCODING_PREFIX);
#endif /* HAVE_CHARSET */

        /* Collapse "/.." with the previous part of path */
        p = lpath;
        while (p[0] && p[1] && p[2])
        {
            if (!IS_PATH_SEP (p[0]) || p[1] != '.' || p[2] != '.'
                || (!IS_PATH_SEP (p[3]) && p[3] != '\0'))
            {
                p++;
                continue;
            }

            /* search for the previous token */
            s = p - 1;
            if (s >= lpath + url_delim_len - 2
                && strncmp (s - url_delim_len + 2, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
            {
                s -= (url_delim_len - 2);
                while (s >= lpath && !IS_PATH_SEP (*s--))
                    ;
            }

            while (s >= lpath)
            {
                if (s - url_delim_len > lpath
                    && strncmp (s - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
                {
                    char *vfs_prefix = s - url_delim_len;
                    struct vfs_class *vclass;

                    while (vfs_prefix > lpath && !IS_PATH_SEP (*--vfs_prefix))
                        ;
                    if (IS_PATH_SEP (*vfs_prefix))
                        vfs_prefix++;
                    *(s - url_delim_len) = '\0';

                    vclass = vfs_prefix_to_class (vfs_prefix);
                    *(s - url_delim_len) = *VFS_PATH_URL_DELIMITER;

                    if (vclass != NULL)
                    {
                        struct vfs_s_subclass *sub = (struct vfs_s_subclass *) vclass->data;
                        if (sub != NULL && sub->flags & VFS_S_REMOTE)
                        {
                            s = vfs_prefix;
                            continue;
                        }
                    }
                }

                if (IS_PATH_SEP (*s))
                    break;

                s--;
            }

            s++;

            /* If the previous token is "..", we cannot collapse it */
            if (s[0] == '.' && s[1] == '.' && s + 2 == p)
            {
                p += 3;
                continue;
            }

            if (p[3] != 0)
            {
                if (s == lpath && IS_PATH_SEP (*s))
                {
                    /* "/../foo" -> "/foo" */
                    str_move (s + 1, p + 4);
                }
                else
                {
                    /* "token/../foo" -> "foo" */
#ifdef HAVE_CHARSET
                    if ((strncmp (s, VFS_ENCODING_PREFIX, enc_prefix_len) == 0)
                        && (is_supported_encoding (s + enc_prefix_len)))
                        /* special case: remove encoding */
                        str_move (s, p + 1);
                    else
#endif /* HAVE_CHARSET */
                        str_move (s, p + 4);
                }
                p = (s > lpath) ? s - 1 : s;
                continue;
            }

            /* trailing ".." */
            if (s == lpath)
            {
                /* "token/.." -> "." */
                if (!IS_PATH_SEP (lpath[0]))
                    lpath[0] = '.';
                lpath[1] = '\0';
            }
            else
            {
                /* "foo/token/.." -> "foo" */
                if (s == lpath + 1)
                    s[0] = '\0';
#ifdef HAVE_CHARSET
                else if ((strncmp (s, VFS_ENCODING_PREFIX, enc_prefix_len) == 0)
                         && (is_supported_encoding (s + enc_prefix_len)))
                {
                    /* special case: remove encoding */
                    s[0] = '.';
                    s[1] = '.';
                    s[2] = '\0';

                    /* search for the previous token */
                    /* IS_PATH_SEP (s[-1]) */
                    p = s - 1;
                    while (p >= lpath && !IS_PATH_SEP (*p))
                        p--;

                    if (p >= lpath)
                        continue;
                }
#endif /* HAVE_CHARSET */
                else
                {
                    if (s >= lpath + url_delim_len
                        && strncmp (s - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
                        *s = '\0';
                    else
                        s[-1] = '\0';
                }
            }

            break;
        }
    }
}