Команда md5sum в двоичном и текстовом режиме

Команда md5sum в двоичном и текстовом режиме

Команда GNU md5sumимеет два режима:двоичныйрежим итекстmode. Я полагаю, разница только в том, как обрабатываются символы новой строки? Я прав?

В GNU/Linux оба режима всегда дают одинаковый результат, поэтому единственное использование параметров -bи -t— это указание флага ( *или ), используемого перед именем файла?

В каких случаях режимы могут давать разные результаты? На системах Windows/MacOS? (Есть ли версии для этих платформ?)

решение1

В GNU/Linux оба режима всегда дают одинаковый результат.

Да, определенно. От man md5sum:

Примечание:В системе GNU нет разницы между двоичным и текстовым режимами.

Это из md5sumреализации, которая поставляется с GNU coreutils 8.21; я заметил, что в более старой версии (8.12) такого уведомления нет, но предполагаю, что в любом случае это было бы верно.

Хотя AFAICT md5sumофициально не стандартизирован (например, POSIX), он доступен на различных платформах в различных реализациях, и, очевидно, прилагаются определенные усилия для того, чтобы сделать их совместимыми друг с другом для простоты использования в разных системах.

В связи с этим,Стандарт ISO/ANSI Cвключает высокоуровневые потоковые функции для доступа к файлам. Как часть стандарта, они доступны в любой операционной системе, которая реализует ISO C через общую библиотеку или компилятор. Поскольку практически все операционные системы имеют это в наличии (и сами чаще всего написаны на C), это своего рода универсальный язык, используемый для реализации потенциально очень переносимого программного обеспечения.

Учитывая то, что он делает, было бы вполне осуществимо написать, md5sumчто будет компилироваться и работать на любой операционной системе. Я не утверждаю, что это верно для версии GNU coreutils, но одна из упомянутых ранее высокоуровневых функций потока файлов — это fopen(), которая предписана ISO C включать bпереключатель, используемый при открытии файла, чтобы указать, что он открывается «как двоичный файл». Что это может означать или требовать от системыне являетсяпредусмотренный стандартом, он просто обязан существовать, чтобы его можно было использовать в системе, где могут быть некоторые (любой) причина этого.

В операционных системах linux/POSIX/*nix-style такой причины нет, поэтому переключатель ничего не делает. Из спецификации POSIX (надмножество ISO C) дляfopen():

Символ «b» не имеет никакого значения, но допускается для соответствия стандарту ISO C.

Итак, полностью переносимая md5sumреализация может использовать высокоуровневые функции потока файлов ISO, поскольку в ISO C нет других методов доступа к файлам (большинство платформ, включая совместимые с POSIX, также имеют свои собственные низкоуровневые методы, но их использование не будет переносимым, поскольку их нет в ISO C), и она также должна реализовать флаги -bи -tдля добавления или не добавления bопции fopen()при чтении файла. В системах, где это бессмысленно, это не будет иметь никакого значения.

Опять же, я не говорю, что md5sum от GNU написана таким полностью переносимым способом или получена из того, что есть, но очевидно, что она пытается соответствовать, по своей работоспособности, тому, что есть. Обратите внимание, что наличие флага, который ничего не делает, не то же самое, что отсутствие флага — в первом случае указано, что это нормально, но ничего не делает, тогда как в последнем случае его использование может быть ошибкой или привести кнеопределенное поведение.

решение2

Как уже отмечалось, в системах GNU и современных Windows эти параметры не имеют никакого эффекта.

Если взглянуть на исходный код, то при md5sumиспользовании с файлом параметры text/binary определяют, будет ли modeпараметр, используемый в , или . Во всех системах, соответствующих POSIX, просто игнорируется и не оказывает никакого эффекта.fopen(const char *pathname, const char *mode)"r""rb"b

При md5sumчтении стандартного ввода coreutilsпо умолчанию будет использоваться текстовый режимтогда и только тогда, когда все нижеперечисленное верно:

  • макрос времени компиляции O_BINARYопределен (т.е. существует разница между текстовым и двоичным режимами),
  • ввод поступает с терминала
  • и режим не переопределяется параметром командной строки.

В противном случае предполагается двоичный режим (если не переопределено параметром командной строки) и, если O_BINARYон определен, xset_binary_mode()вызывается для стандартного ввода.

xset_binary_mode()являетсяоболочка, определенная xbinary-io.hв gnulib.Если O_BINARYне определено, это будет фиктивная функция, которая будет оптимизирована любым хорошим компилятором C, так что, опять же, сравнение текста и двоичного кода не даст никакого эффекта, даже если функция будет вызвана по какой-то причине.

Но когда O_BINARYопределено, xset_binary_mode()будет оберткой для set_binary_mode(), объявленной вbinary-io.hизgnulib. Отсюда мы найдем первые подсказки о средах программирования, для которых «двоичный режим» действительно имеет значение:

#if O_BINARY
# if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__
#  include <io.h> /* declares setmode() */
#  define __gl_setmode setmode
# else
#  define __gl_setmode _setmode
#  undef fileno
#  define fileno _fileno
# endif
#else
  /* On reasonable systems, binary I/O is the only choice.  */
  /* Use a function rather than a macro, to avoid gcc warnings
     "warning: statement with no effect".  */
BINARY_IO_INLINE int
__gl_setmode (int fd _GL_UNUSED, int mode _GL_UNUSED)
{
  return O_BINARY;
}
#endif

Видимо, __EMX__являетсяЭберхард Маттес eXtender, 32-битная среда программирования для MS-DOS и OS/2. Аналогично, __DJGPP__относится кDJGPP 32-битная система разработки для MS-DOS. И есть ещеCygwin. Все эти среды программирования основаны на setmode()объявленном в <io.h>.

Для других сред программирования, которые определяют O_BINARY, _setmode()будет использоваться (как определено соответствующей средой программирования).

Одним из примеров операционных систем, где текстовый режим против двоичного режима может быть важен, является OpenVMS. Он также знает способ хранения текста в стиле Unix как простого потока символов. В мире OpenVMS это, по-видимому, известно как формат Stream_LF- и тот факт, что у него есть определенное имя, должен быть намеком на то, что этоне единственный возможный способ форматирования текстовых файлов.

Для любопытных:http://neilrieck.net/docs/openvms_notes_text_files.html

Подводя итог, можно сказать, что в OpenVMS non-stream simple textформат файла содержит ноль или более записей (строк), максимальный размер которых определяется в метаданных файла (может составлять до 32767 байт). Каждая строка предваряется 16-битным значением, указывающим количество байтов в каждой строке. Не существует такого понятия, как «символ конца строки»: строка заканчивается, когда прочитано указанное количество байтов. Если количество байтов в строке нечетное, 0x00добавляется байт заполнения, чтобы начало следующей строки находилось по адресу, выровненному по слову. Этот байт заполнения никогда не учитывается в длине строки.

GNU Coreutils, безусловно, былперенесено на OpenVMS.

решение3

В качестве дополнения я бы добавил информацию, что на Windows md5sumтакже нет разницы в расчетах в режиме --textили --binary. Протестировано на md5sum(GNU coreutils) 8.31 для Windows.

c:\temp\file-fingerprint-test\work-copy1\file-fingerprint-eol (master -> origin)
2021-05-30 - 7:35:52 PM
λ xxd unix-eol.txt
00000000: 7468 6973 2066 696c 6520 6861 7320 756e  this file has un
00000010: 6978 206c 696e 6520 656e 6469 6e67 730a  ix line endings.
00000020: 7468 6973 206d 6561 6e20 6974 2068 6173  this mean it has
00000030: 206f 6e6c 7920 4c46 0a                    only LF.

c:\temp\file-fingerprint-test\work-copy1\file-fingerprint-eol (master -> origin)
2021-05-30 - 7:36:08 PM
λ xxd win-eol.txt
00000000: 7468 6973 2066 696c 6520 6861 7320 7769  this file has wi
00000010: 6e20 206c 696e 6520 656e 6469 6e67 730d  n  line endings.
00000020: 0a74 6869 7320 6d65 616e 2069 7420 6861  .this mean it ha
00000030: 7320 2020 4352 204c 460d 0a              s   CR LF..

c:\temp\file-fingerprint-test\work-copy1\file-fingerprint-eol (master -> origin)
2021-05-30 - 7:36:15 PM
λ md5sum.exe --text *.txt
c8a8c7bb97ab554cff96a76b2a8f89fa  unix-eol.txt
03b3b1458cddff2cf1c15819b1255af3  win-eol.txt

c:\temp\file-fingerprint-test\work-copy1\file-fingerprint-eol (master -> origin)
2021-05-30 - 7:36:46 PM
λ md5sum.exe --bin *.txt
c8a8c7bb97ab554cff96a76b2a8f89fa *unix-eol.txt
03b3b1458cddff2cf1c15819b1255af3 *win-eol.txt

c:\temp\file-fingerprint-test\work-copy1\file-fingerprint-eol (master -> origin)
2021-05-30 - 7:36:57 PM
λ md5sum.exe --version
md5sum (GNU coreutils) 8.31
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Ulrich Drepper, Scott Miller, and David Madore.

Связанный контент