Как проверить, ведет ли путь за пределы каталога в c? - PullRequest
1 голос
/ 10 апреля 2019

Я пытаюсь проверить, ведет ли путь к «верху» текущего каталога.Пример:

Я внутри "./"

Допустим, текущий каталог содержит папку с именем "folder"

Я хочу проверить, приведет ли меня cd "./folder/../../"вне "./".В этом случае мне ответили бы True.

Это связано с тем, что моя программа привязана к своей папке выполнения (я хочу, чтобы она выполняла ls, но никогда за ее пределами).

Ответы [ 3 ]

4 голосов
/ 10 апреля 2019

POSIX.1-2001 определяет realpath (3) :

#include <limits.h>
#include <stdlib.h>

char *realpath(const char *path, char *resolved_path);

realpath() разворачивает все символические ссылки и разрешает ссылки на /./, /../ и дополнительные '/' символы в строке с нулевым символом в конце, названной путем, чтобы создать канонизированный абсолютный путь. Полученный путь сохраняется в виде строки с нулевым символом в конце, максимум до PATH_MAX байтов, в буфере, указанном resolved_path. Полученный путь не будет иметь символической ссылки, компонентов /./ или /../.

Вы можете сравнить канонизированный путь с текущим каталогом и посмотреть, является ли первый потомком второго.

#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool is_inside(const char *parent, const char *child) {
    char *abs_parent = realpath(parent, NULL);
    if (!abs_parent) { perror(parent); exit(EXIT_FAILURE); }

    char *abs_child  = realpath(child,  NULL);
    if (!abs_child)  { perror(child);  exit(EXIT_FAILURE); }

    size_t parent_len = strlen(abs_parent);
    size_t child_len  = strlen(abs_child);

    bool result = strncmp(abs_parent, abs_child, parent_len) == 0 &&
        (child_len == parent_len || abs_child[parent_len] == '/');

    free(abs_parent);
    free(abs_child);

    return result;
}

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "usage: %s <parent> <child>\n", argv[0]);
        return 1;
    }

    printf("%s\n", is_inside(argv[1], argv[2]) ? "yes" : "no");
    return 0;
}

Обратите внимание, что это работает только при наличии путей.

0 голосов
/ 10 апреля 2019

Вы можете посчитать количество компонентов, которые соответствуют "..", ".",:

for (p = strtok(path, "/"); p; p = strtok(NULL, "/")) {
        if (strcmp(p, "..") == 0) {
                counters[Back]++;
        } else if (strcmp(p, ".") == 0) {
                counters[Self]++;
        } else if (*p) {  /* ignore /// runs */
                counters[Forw]++;
        }
        escaped |= (counters[Back] > counters[Forw]);
}

Экранированный фиксирует, пытался ли путь выйти из дерева подтекущий рабочий каталог.Вероятно, стоит использовать специальный регистр, начинающийся с «/», в качестве выхода.

Существуют и другие подходы, которые декодируют абсолютное пространство пути, но могут привести к избыточному охвату (imho, обычный отказ системы).Я, как владелец, мог бы хотеть, чтобы ваша программа принимала имена путей, которые выходят из вашего пространства имен, по крайней мере, ограниченным образом.Симлинки работают хорошо для этого, не требуют специального административного контроля и т. Д. ... Если ваша программа предотвращает такой тип конфигурации, то ее утилита уменьшается.

0 голосов
/ 10 апреля 2019

псевдокод:Получить текущий полный путь (pwd)
cd к новому пути
получить новый полный путь
, если новый полный путь начинается со старого полного пути, он находится в *

  • вам может понадобиться проверить наличие символических ссылок и c, но если это не проблема, это должно с этим справиться.

Не сделали C через некоторое время, но вот быстрый взломтой же логики в bash

$: pwd
/tmp/sandbox
$: cur=$(pwd)
$: cd ./folder/../../
$: pwd
/tmp
$: pwd|grep "^$cur" && echo in || echo out
out

$: cd -
/tmp/sandbox
$: pwd|grep "^$cur" && echo in || echo out
/tmp/sandbox
in

$: cd ./folder/
$: pwd|grep "^$cur" && echo in || echo out
/tmp/sandbox/folder
in
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...