Как распаковать безопасно, не загрязняя текущий каталог в случае tarbomb?

33

Солидные проекты освободить архивы дегтя, содержащие один каталог, например , zyrgus-3.18.tar.gzсодержит zyrgus-3.18папку , которая , в свою очередь , содержит src, build, distи т.д.

Но некоторые панк-проекты помещают все в корень: '- (Это приводит к полному беспорядку при разархивировании. Создание папки каждый раз вручную - это боль и ненужная большая часть времени.

  • Существует ли сверхбыстрый способ определить, содержит ли файл .tar или .tar.gz несколько корневых каталогов? Даже для большого архива.
  • Или даже лучше, есть ли инструмент, который в таких случаях будет создавать каталог (имя архива без расширения) и помещать все внутри?
Николас Рауль
источник
2
Я думаю, что сломанная упаковка стоит сообщения об ошибке автору пакета.
14
Я исторически (с середины 90-х) просто всегда оставался в подкаталоге. Если все это поместить в один каталог (как и должно быть), его содержимое затем можно переместить в нужное место с помощью mv, тогда вы можете удалить лишний дополнительный каталог. Да, два дополнительных шага, но это лучше, чем убирать беспорядок из неправильно созданного файла tar.
TED
6
But some punk projects put everything at the root :'-(И некоторые панк-проекты совершенно бесполезно помещают все в папку, учитывая, что они уже помещают все в прилагаемый архив, поэтому, когда вы загружаете и распаковываете его в свою собственную папку, как это делал бы любой умный пользователь, вы в конечном итоге получаете все содержание похоронило еще один слой вниз. ;-)
Мейсон Уилер
2
@MasonWheeler Для архивов tar существует своего рода «стандарт де-факто», в котором все находится внутри одной папки.
glglgl

Ответы:

30

patool обрабатывает различные виды архивов и создает подкаталог на тот случай, если архив содержит несколько файлов, чтобы не загромождать рабочий каталог извлеченными файлами.

Извлечь архив

patool extract archive.tar

Чтобы получить список поддерживаемых форматов, используйте patool formats.

Marco
источник
К вашему сведению: нашел его на sourceforge.net/projects/patool . Это rpm, и я alienконвертировал его в deb для Ubuntu.
Джо
patoolдолжен быть в репозиториях для Debian и Ubuntu, если вы используете текущую версию.
Марко
12

Вы могли бы сделать что-то вроде

tar tf thefile.tar | cut -d/ -f1 | sort -u

посмотреть, какие записи верхнего уровня есть у tar; труба, чтобы wc -lпроверить, если есть больше чем один. Обратите внимание, что есть несколько случаев, когда это может не сработать, например, если tar содержит пути к файлам формы, somedir/whateverа также ./somedir/whatever(или что-то более безумное); это должно быть необычным, хотя.

Это прочитает весь tar-файл перед выводом чего-либо, потому что sort, хотя это должно быть быстрее, чем на самом деле извлечение, потому что это только одно последовательное чтение, и оно может пропускать большие файлы.

Если вы делаете это в интерактивном режиме, и файл может быть большим, вы можете изменить sort -uк uniqи Control+ Cесли он печатает более чем одну вещь.

Дугал
источник
2
sort | uniqможно сократить до sort -u.
Марко
4
если вы не хотите делатьuniq -c
cas
7

ты можешь сделать:

pax <some.tar

... для просмотра содержимого tarфайла.

если вы хотите узнать, сколько уровней он проходит, вы можете сделать:

pax <some.tar | tr -dc /\\n | sort -r | head -n1

Вы можете явно запретить взрыв при извлечении с помощью:

mkdir some.tar
pax -'rs|^|some.tar/|' <some.tar
mikeserv
источник
2

Это должно делать то, что вы хотите. Я уверен, что кто-то может улучшить это. В этих примерах я предполагаю сжатый архивом gzip tar, поскольку он является наиболее распространенным.

Вы хотите архив, в котором нет дочерних узлов в дереве каталогов корневого уровня.

Каждая запись в списке содержимого tar должна начинаться с одного и того же шаблона. Этот шаблон является базовым путем к каталогу, который должны совместно использоваться всеми записями в архиве. Если любые две записи не начинаются с одного и того же шаблона, то они являются братьями и сестрами.

Первая строка в списке содержимого tar предоставит вам минимальный шаблон, который вы должны проверить. Это BASEPATH.

BASEPATH=$(tar ztf example.tar.gz | (read line; echo $line))

Затем, чтобы проверить наличие взрывоопасных тарболов, вам нужно проверить , не начинается ли какая-либо строка списка содержимого tar с BASEPATH.

tar ztf example.tar.gz | grep -qv "^${BASEPATH}"

Преврати это в функцию оболочки:

is_explosive() {
    TARBALL_NAME=$1
    tar ztf "${TARBALL_NAME}" | grep -qv "^$(tar ztf "${TARBALL_NAME}" | (read line; echo ${line}))"
    return $?
}

Отсюда вы можете написать безопасную функцию извлечения архива tar.

is_explosive() {
    TARBALL_NAME=$1
    tar ztf "${TARBALL_NAME}" | grep -qv "^$(tar ztf "${TARBALL_NAME}" | (read line; echo ${line}))"
    return $?
}

safe_tar_x() {
    TARBALL_NAME=$1
    if is_explosive ${TARBALL_NAME}; then
        SUBDIR=${TARBALL_NAME%.tar.gz}
        SUBDIR=${SUBDIR##*/}
        mkdir "${SUBDIR}"
        echo "WARNING: This tarball is explosive. Opening in subdirectory, ${SUBDIR}, for safety." >&2
    else
        SUBDIR="."
    fi
    # Tar quirks: "--directory" must be last, and using more than
    #     one option group requires that all groups start with a dash.
    tar -zxf "${TARBALL_NAME}" --directory "${SUBDIR}"
    return $?
}
Ноа Спурриер
источник