Pull to refresh

Comments 109

По хорошему, драйвер (ifs) файловой системы не должен был позволять создавать файлы с одинаковыми именами. Равно как chkdsk должен эту ситуацию обнаруживать и разрешать. Раз уж изначально для NTFS приняли case-insensitive подход.
Дело в том, что сама NTFS case sensitive и хранить в ней файлы по именам, различающимся только регистром, совершенно корректно. Case-insensitive подход приняли не в NTFS, а в Windows.
Скорее, в MS-DOS, а уже оттуда для совместимости было притащено в Windows. А в DOS это, скорее всего, попало от CP/M.
В MS-DOS LFN проецируется в 8.3, так что в Windows можно было разрешить case sensitive, и это не помешало бы MS-DOS.

И это правильно, как минимум когда в системе приняты полноценные названия, вроде Documents and Settings, то вспоминать где там большие буквы — занятие очень такое себе.
Case sensitive можно применять там, где /usr/

В linux речь идёт, вообще‐то, совершенно не о чувствительности к регистру. Имя файла здесь — это произвольный набор байт, в котором не может быть только косой черты (прямой, обратная может быть), разделяющей каталоги, и нулевого байта, исторически означающего конец строки. Это позволяет обрабатывать доступ к файлам весьма эффективно: вам не нужно нормализовывать имена перед сравнением и делать кэши нормализованных имён просто чтобы файловый доступ работал быстро (где‐то на хабре, кстати, проскакивала статья про эти кэши).


Соответственно в linux если вы не хотите помнить «где большие буквы», то вы просто настраиваете автодополнение. В GUI оно обычно так и работает (и не настраивается), в командной строке — не всегда. Может быть не очень удобно, но это делает разработку linux проще, а доступ к файлам быстрее. (Ещё, конечно, это создаёт целый класс ошибок (иногда потенциально приводящих к уязвимостям) в скриптах на *sh, но тут я бы спрашивал с разработчиков языка и с тех, кто до сих пор его не заменил.)


Конечно есть и ещё один минус: если имя файла — произвольная последовательность байт, то сразу начинается проблема с определением, в какой кодировке оно записано и, соответственно, как интерпретировать имя файла для отображения в GUI. К счастью, современные системы все просто используют UTF-8, а во всех стандартных каталогах ASCII.

набор байт

Де факто, это и есть нечувствительный к регистру режим.


PS. Имхо, «но тут я бы спрашивал с разработчиков языка и с тех, кто до сих пор его не заменил.)» — это сродни «с нашей стороны пули вылетели». На мой взгляд, ОС характеризуется не только рекордами в скорости файлового доступа, но организацией защиты от дурака.

Запрещение звёздочек в имени файла — это защита от дурака в неправильном месте. В *sh вам даже пробелы в имени проблем доставят — теперь запретить пробелы в ядре? Просто кому‐то надо было собраться и исправить язык командной оболочки пока не было слишком поздно (т.е. слишком много скриптов).

Я не слышал про проблемы с экранированием, к примеру, в C, которые бы реально решались запретом символов. Пока имя файла — это имя файла или, хотя бы, просто одна строка никаких проблем нет. Проблемы начинаются, либо когда вы используете eval в той или иной форме (в т.ч. формируете snprintf’ом строку для system() вместо использования execv() (или аналога из libuv, если в системе execv() не поддерживается)) и должны сформировать для него строку, либо когда строка неявно преобразовывается во что‐то (в вашем примере glob должен реально получить что‐то вроде списка ["C:\\abc\\afolderwith[test]\\", glob.STAR], потому что семантически вход — отнюдь не простая строка; — но это, очевидно, неудобно). На POSIX shell написать сложный скрипт без eval невозможно, вдобавок все *sh (в т.ч. те, где eval не так нужен) любят внезапно преобразовывать строку в список glob’ов, которые они же сразу раскроют.


И здесь «десяток символов» вам не поможет. Насколько я знаю, безопасный набор — это ASCII, причём только буквы, цифры и подчёркивание. Всё остальное либо имеет где‐то какое‐либо специальное значение, либо может быть неверно воспринято из‐за проблем с кодировками. Особенно приколен Windows с его обратными косыми чертами, которые так же являются символом экранирования в большинстве языков программирования.


Так что зачем запрещать символы, если всё, на что способен запрет — это улучшить несколько частных случаев, при этом как ухудшив производительность файловой системы, так и взаимодействие с пользователем? К примеру, в названиях книг встречаются двоеточия, поэтому нельзя взять и сохранить книгу в файле с именем, совпадающим с названием книги — нужно его как‐то преобразовывать. Результат, как правило, выглядит хуже, чем оригинальное название.

> Пока имя файла — это имя файла или, хотя бы, просто одна строка никаких проблем нет.

У меня ощущение, что я прослушал лекцию яблоковода о «мне это не нужно».

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

Это не «не нужно», это «зачем люди придумали строгую типизацию». А прямые косые черты принимаются не везде. Вынос путей из исходников никак не решает проблему, скорее наоборот: пока в вашем скрипте пути внутри вы можете написать glob.glob("C:\\Foo\\*"). Когда вместо C:\Foo у вас путь из настроек вам внезапно нужно экранирование этого пути. Я не говорю, что это не нужно делать: даже не предоставляя настроек в скрипте я часто выношу пути в отдельные константы, определяемые наверху файла. Но проблему «если вы собираете код/регулярное выражение/команду shell/… из кусочков, то вам нужно думать об экранировании» ни вынос части этих кусочков в конфиг, ни запрет символов не решит. Сборка же не в строку, а в более сложную структуру — решит.

> Это не «не нужно», это «зачем люди придумали строгую типизацию»

Вы предлагаете в ответ прочитать лекцию почему придумали нестрогую?

> Когда вместо C:\Foo у вас путь из настроек вам внезапно нужно экранирование этого пути.

Действительно внезапно. Но нет, я обхожусь без экранирования — мне сложно разделить вашу боль.
Вы предлагаете в ответ прочитать лекцию почему придумали нестрогую?

Если эта лекция поддержит вашу позицию по поводу необходимости запрета определённых символов — пожалуйста, почему нет.


Действительно внезапно. Но нет, я обхожусь без экранирования — мне сложно разделить вашу боль.

Это значит что вы либо получаете уязвимости или плохую привычку (первое если вы распространяете своё ПО, второе — если нет, но можете в будущем), либо используете языки и библиотеки, в которых оно не требуется. В примере с glob вполне можно обойтись без экранирования, если переписать код с использованием os.listdir, но он будет длиннее.

> либо используете языки и библиотеки

и ОС, что уж )
Ну, которая с десятком запрещенных символов

> Если эта лекция поддержит вашу позицию по поводу необходимости запрета определённых символов — пожалуйста, почему нет.

это не необходимость, а другой способ.

> В примере с glob вполне можно обойтись без экранирования, если переписать код с использованием os.listdir, но он будет длиннее.

А я и не участвую в конкурсе на самый короткий.

Если у вас в конфиге в одном месте экранируется потому, что в коде glob, а в другом нет, потому, что os.listdir — у вас проблемы с конфигом. Или с языком. Или с библиотекой. Или с ОС. Но что-то пора менять, искать другой способ.
Если у вас в конфиге в одном месте экранируется потому, что в коде glob, а в другом нет, потому, что os.listdir — у вас проблемы с конфигом. Или с языком. Или с библиотекой. Или с ОС. Но что-то пора менять, искать другой способ.

Что?! Экранирование происходит в коде, а не конфиге. В случае с glob.glob("C:\\foo\\*") ничего не экранируется, потому что нечего и это сразу видно. В случае с glob.glob(os.path.join(globescape(config.foodir), '*')) вам нужно иметь функцию globescape. И не забывать её применять. В случае с glob.glob([config.foodir, glob.STAR]) вы не можете забыть её применить, поскольку она не нужна (предполагается, что glob.STAR — это экземпляр специального класса, а не строка '*').


Единственное, что в данном случае сделает запрет специальных символов, с которым «жить было бы легче» — это позволит засунуть проверку на них туда, где вы читаете из файла настроек, создав контракт «в настройке типа „путь к каталогу“ не может быть символов из набора …» и таким образом убрав необходимость писать globescape. И то только до тех пор, пока вы не захотите вместо glob.glob подсунуть строку, к примеру, в re.compile (если, конечно, вы действительно не предлагаете убрать все символы, кроме a-zA-Z0-9_). К тому же, это хорошо только при условии, что вы точно знаете, что ваше ПО не будет запускаться на других платформах.


Т.е. жить сильно легче не станет, зато добавится головная боль разработчикам ядра и оно, к тому же, станет работать медленнее.

> В случае с glob.glob(«C:\\foo\\*») ничего не экранируется

Давайте тогда с терминами определимся. У вас слеши 2 раза — это не экранирование?

> вам нужно иметь функцию globescape

Вы про такую?
glob.escape(pathname)
Escape all special characters ('?', '*' and '['). This is useful if you want to match an arbitrary literal string that may have special characters in it. Special characters in drive/UNC sharepoints are not escaped, e.g. on Windows escape('//?/c:/Quo vadis?.txt') returns '//?/c:/Quo vadis[?].txt'.

Так там прямым текстом, что она про спецсимволы ('?', '*' and '[') — у меня таких быть не может, запрещены (Ну, '[' — нет, но он нужен для экранирования, которое не нужно).

То есть эти все заморочки растут из того, что оптимизаторы не запретили '?' и '*' и теперь их надо от wildcard отличать с приседанием.

На сколько затормозиться ядро в среднем, если при создании файла сделать проверку на наличие десятка символов — это вообще страшные цифры (нет).
Давайте тогда с терминами определимся. У вас слеши 2 раза — это не экранирование?

Это тоже экранирование, но на другом уровне: оно для того, чтобы в glob вообще попала обратная косая черта. Экранирование вроде []] — это уже для glob. Так что я несколько не прав и моё утверждение о том, что в примере ничего не экранируется вообще‐то следовало написать как «ничего не экранируется специально для glob».


Так там прямым текстом, что она про спецсимволы ('?', '*' and '[') — у меня таких быть не может, запрещены (Ну, '[' — нет, но он нужен для экранирования, которое не нужно).

То есть эти все заморочки растут из того, что оптимизаторы не запретили '?' и '*' и теперь их надо от wildcard отличать с приседанием.

На сколько затормозиться ядро в среднем, если при создании файла сделать проверку на наличие десятка символов — это вообще страшные цифры (нет).

А теперь вы хотите вместо glob поискать имя файла где‐то регулярным выражением. Или вместо очень ограниченных шаблонов с ?, * и [ хотите написать шаблон для zsh, где в список спецсимволов попадают ещё %, ( и < (я не про перенаправление), также #, |, ^ и ~ с включённым EXTENDED_GLOB или @, + и ! с включённым KSH_GLOB.


Т.е. вы своим запретом решаете весьма частный случай, при этом также лишая дополнительных средств выразительности (кстати, напомню про пример с именами книг: вопросительный знак там также встречается). Если не запретить всё подряд, то экранировать где‐то что‐то придётся, поэтому гораздо полезнее приучать программиста либо экранировать всё и всегда, либо не использовать функции, где экранирование нужно.

Когда частный случай — 99% реального использования, то это не частный случай. '*.pdf' отбирает каждая первая программа чтения pdf, regexp для выбора файлов вряд ли использует хоть одна. Да и мне в моей жизни пока не приходилось отбирать файлы регулярками.

Так что вряд ли вы меня убедите, что wildcard и регулярки — одно и то же. Это вы пытаетесь непонятно что оправдать частными случаями.

> поэтому гораздо полезнее приучать программиста

Только в реальности это сизифов труд, а не «полезнее» (не говоря о том, что и надо не «всегда»).

Я не говорю, что это одно и то же. Я говорю, что это схожие случаи: «нужно запихнуть имя файла куда‐то, где часть символов обрабатываются особенным образом». Это решается экранированием, а не запретом символов. И wildcard, кстати, под капотом часто преобразуются в регулярные выражения: и glob из Python, и реализация из Vim поступают именно так.


Кстати, то что программа чтения pdf показывает *.pdf в выпадающем списке совершенно не означает, что внутри она вообще использует что‐то похожее на glob.glob(). Если диалог открытия файлов не самописный, то об этом будет заботиться тулкит, создающий диалог, который нужно написать один раз и которому на вход пойдёт wildcard для файлов в каталоге отдельно от собственно каталога — здесь не нужно никакого экранирования вообще. Ни в читалке — она просто передаёт каталог отдельно от фильтров (иногда неявно: к примеру, стандартный диалог открытия файлов для Windows использует текущий каталог процесса), ни в собственно тулките: вариант с os.listdir в таком случае более чем уместен, особенно учитывая, что тулкиты обычно написаны на C++.

Кстати, то что программа чтения pdf показывает *.pdf в выпадающем списке совершенно не означает, что внутри она вообще использует что‐то похожее на glob.glob()

В той же Windows в самом API функции FindFirstFile директория и фильтр передаются отдельными параметрами, поэтому проблема с экранированием в данном случае возникнуть не может.

> И wildcard, кстати, под капотом часто преобразуются в регулярные выражения: и glob из Python

Давайте всё же договоримся, что «под капотом glob из Python» — это один раз, т.е. «редко», а весь остальной софт на Python так не делает — это «часто». С любым тулкитом — аналогично.

Потом можно подумать есть ли там экранирование при преобразовании в регулярку, но т.к. это «редко», то я не стану.

> которому на вход пойдёт wildcard для файлов в каталоге отдельно от собственно каталога — здесь не нужно никакого экранирования вообще

Так как же вы в wildcardмаске без экранирования отличите "*.pdf" от "[*].pdf", если "*.pdf" может быть и именем файла, которое приложение хочет открыть? Открытие через диалог файла с предзаданным именем вполне практикуется.

В маске обычно просто статические строки, которые разработчик выбирает сам ещё на этапе компиляции. Там может быть что‐то вроде статического .htaccess, если нужный тип файла вдобавок имеет фиксированное имя, но предзаданное генерируемое имя файла в маске я никогда не видел, видел имя файла по‐умолчанию в поле File name. Это отдельное поле, и, да, здесь‐таки нужно экранирование, если диалог поддерживает маски от пользователя в этом поле — а, насколько я понимаю, это нередкая ситуация.

На сколько затормозиться ядро в среднем, если при создании файла сделать проверку на наличие десятка символов — это вообще страшные цифры (нет).

То есть вы предлагаете зарезервировать некоторое подмножество символов для их использования в исключительно прикладных программах в служебных целях?

0) Мы же в контексте имен файлов говорим?
1) Это как-бы свершившийся факт, а не я предлагаю. Подозреваю, что даже в линуксе назвать файл "*" не будет удачной идеей.
2) «символ» — это что? Глиф? Код? Место на клавиатуре?

Ещё в ASCII первые 32 символа имеют служебные цели. Вот практика показала, что вопросительный знак и звездочка — катят, а SUBSTITUTE — нет. Я думаю потому, что SUBSTITUTE — это неведомая хтоническая хрень и людям не близка.

Может можно было воплотить лучше, но сейчас едва ли поменяешь.

> Но ведь существует полно случаев, когда экранирование используется как будто так и надо: SQL, HTML

Ненене, когда я в html использую &gt; — это язык HTML, с такой вот специальной разметкой. Меня интригует появление специального glob-языка для экранирования glob. Он же уникален для конкретного вот места применения, а язык должен быть переиспользуемым, универсальным.
0) Мы же в контексте имен файлов говорим?

Естественно.


1) Это как-бы свершившийся факт, а не я предлагаю. Подозреваю, что даже в линуксе назвать файл "*" не будет удачной идеей.

Это моё личное дело, как мне удобно называть файлы.


2) «символ» — это что? Глиф? Код? Место на клавиатуре?

В контексте имён файлов этот ответ очевиден. В случае файловых систем, обычно используемых в Linux — это просто произвольный байт, в случае NTFS — uint16.


Ненене, когда я в html использую > — это язык HTML, с такой вот специальной разметкой. Меня интригует появление специального glob-языка для экранирования glob. Он же уникален для конкретного вот места применения, а язык должен быть переиспользуемым, универсальным.

Так может, тогда дело в glob, раз его создатели придумали какой-то свой язык?

> Это моё личное дело, как мне удобно называть файлы.

Ок, а моёВаси личное дело не эскейпить, так что если приложение упадёт при встрече с вашим файлом — это ваше личное дело. У вас там опенсорс, форкните-почините, если что.

> В контексте имён файлов этот ответ очевиден.

Ну как-бы нет: есть символы, которые с клавиатуры хрен введешь, и глифа им не положено (что сразу ограничивает применение в именах файлов только у больших затейников). Так что вряд ли вас расстроит использование символа с кодом 15776(random), но и меня использование вместо звездочки не порадует. Мне звездочку-вопросик на клавиатуре надо бы иметь.

> Так может, тогда дело в glob, раз его создатели придумали какой-то свой язык?

Виноватого нашли, ок, этих расстреляем. А как проблему решать?
Ок, а моёВаси личное дело не эскейпить, так что если приложение упадёт при встрече с вашим файлом — это ваше личное дело. У вас там опенсорс, форкните-почините, если что.

Неиспользование экранирования сразу вывешивает флаг «здесь водятся уязвимости», а такие фразы ещё вызовут реакцию «этот чувак не Линус Торвальдс, но чего‐то он заборзел». Если у вас нет большой базы пользователей, а ПО открытое, то позволить вы себе такого не можете. Если есть большая база, а ПО всё ещё открытое, то можете получить форк‐конкурента, а не форк для PR с исправлением. Иногда они даже успешные.

1) Это как-бы свершившийся факт, а не я предлагаю. Подозреваю, что даже в линуксе назвать файл "*" не будет удачной идеей.

Не замечал такого. Я как‐то некоторое время назад решил, что вместо того, чтобы просто иметь свою и чужую (т.н. dotfiles) помойку в $HOME лучше иметь чужую помойку в $HOME, свою в $HOME/tmp, и переносить всё нужное куда‐то под $HOME/.. Практически всё с таким именем каталога нормально справлялось, пока экранирование звёздочек при наборе команд в оболочке не надоело мне.


С чем будут реальные проблемы в огромном количестве мест — это с символом \n (LF) в имени файла: если нормально написанные программы на нормальных языках программирования (т.е. большинство что я видел, кроме того, что написано на *sh (т.е. скриптов) и VimL (т.е. дополнений для Vim)) такое имя файла отлично переварят, то написать даже bash скрипт, корректно обрабатывающий такие имена, часто может быть проблемой. Я уж не говорю про POSIX shell. Всё остальное нормально работает.


Ненене, когда я в html использую > — это язык HTML, с такой вот специальной разметкой. Меня интригует появление специального glob-языка для экранирования glob. Он же уникален для конкретного вот места применения, а язык должен быть переиспользуемым, универсальным.

А где, простите, общий стандарт на glob, чтобы можно было говорить об универсальности? Вот man glob ссылается на POSIX.1-2001, POSIX.1-2008, POSIX.2 — если я напишу в Windows [[=а=]], он меня поймёт?

> Практически всё с таким именем каталога нормально справлялось

«Практически всё» — это «редко» или «часто»? Я не говорил, что что-то не справиться, я сказал, что плохая идея.

> В маске обычно просто статические

«обычно» — это «часто» или «редко»? Если надо необычно — надо другой тулкит искать? Удобно.

> Это отдельное поле, и, да, здесь‐таки нужно экранирование

Там нужно, тут не нужно. Опять удобно!

> если диалог поддерживает маски от пользователя в этом поле — а, насколько я понимаю, это нередкая ситуация.

Редкая ситуация — это когда пользователь способен вспомнить как ему надо заэскейпить в этом очередном тулките. Не программист — пользователь.

> А где, простите, общий стандарт на glob, чтобы можно было говорить об универсальности?

А я о чем? )
Стандарт есть, что ему соответствует — неизвестно. Удобно!!!
«Практически всё» — это «редко» или «часто»? Я не говорил, что что-то не справиться, я сказал, что плохая идея.

«Практически всё» — это все GUI программы, что я использовал, все программы на C (я в основном про coreutils), но не некоторые скрипты (бо́льшая часть — это от того, что у меня ещё не было привычки всё экранировать, то что из скриптов есть в системе не только обычно хорошо написано, но ещё и не имеет причин лезть в $HOME).


«обычно» — это «часто» или «редко»? Если надо необычно — надо другой тулкит искать? Удобно.

«Обычно» — это я ни разу не видел, чтобы маска определялась из источника, который может содержать произвольное имя файла. Так что на вопрос лучше ответите вы. И с какой радости нужно искать новый тулкит, а не функцию экранирования в старом?


Там нужно, тут не нужно. Опять удобно!

Если бы вместо масок была нормальная статическая типизация, то не было бы нужно/не нужно. Было бы «здесь у нас вход типа „имя каталога“ (ну или хотя бы просто строка), здесь — структура, определяющая маску».


А так всегда нужно читать документацию.


Редкая ситуация — это когда пользователь способен вспомнить как ему надо заэскейпить в этом очередном тулките. Не программист — пользователь.

Редкая ситуация — это когда пользователь вообще что‐то там пишет. Обычно проще просто натыкать мышкой. Я вот про то, что поле с именем файла принимает маски не только в Vivaldi (где какой‐то нестандартный диалог) только сейчас узнал, когда пошёл проверять.

«бо́льшая часть — это от того… не имеет причин лезть в $HOME» — по вашей интонации не скажешь, но кажется вы таки согласны, что идея была не очень. Даже не очень важно почему именно, просто жизнь такая.

> здесь — структура, определяющая маску

Давайте правильно сформулируем: строка маски(пути/regexp/чеготамещё) — это и есть сериализованная структура, всё это экранирование — это про правила сериализации. Инициализировать структуры без промежуточного строкового представления — удовольствие так себе. Или вы знаете другой удобный способ ввести маску в поле с именем файла в том же диалоге открытия?

Что вы под статической типизацией тут понимаете — для меня загадка, структуры статической/динамической типизации ортогональны.

> А так всегда нужно читать документацию.

Ну раз нужно — тогда да, а вообще — нет.
Вы немножко отвлекитесь от мысли что нужно всех передрессировать — этого просто не случится.

Вообще как только возникает мысль, что вам все что-то должны — должно приходить чувство безысходности.

> только сейчас узнал, когда пошёл проверять

Как же вы этим диалогом пользовались, не ознакомившись с мануалом? Всегда нужно читать документацию!
Давайте правильно сформулируем: строка маски(пути/regexp/чеготамещё) — это и есть сериализованная структура, всё это экранирование — это про правила сериализации. Инициализировать структуры без промежуточного строкового представления — удовольствие так себе. Или вы знаете другой удобный способ ввести маску в поле с именем файла в том же диалоге открытия?

Да, это сериализованная структура. Инициализировать структуры в C — удовольствие действительно так себе. Но сейчас есть другие варианты.


Что вы под статической типизацией тут понимаете — для меня загадка, структуры статической/динамической типизации ортогональны.

Я имею ввиду, что вместо строки "PDF files\0*.pdf\0\0" для представления маски будет использоваться


DialogFilters filters = {
    .size = 1,
    .filters = (DialogFilter []) {
        {
            .name = "PDF files",
            .globs_count = 1,
            .globs = (GlobPattern []) {
                {
                    .size = 2,
                    .parts = (GlobPatternPart []) {
                        { .type = kFilterGlobStar },
                        { .type = kFilterGlobLiteral, .data.text = ".pdf" },
                    }
                },
            }
        },
    }
};

С этой структурой вполне очевидно, почему никто так не делал: большая и невыразительная, даже в случае с C99 лучше оставить первый вариант, в случае же с C89 не следует даже пытаться такое писать — будет много непонятных магических цифр и никаких подсказок вроде .size, так что при редактировании вы ещё больше раз забудете обновить размеры. На Rust выглядит гораздо лучше, и не нужно ни ставить размеры, ни менять их на терминаторы просто чтобы не заморачиваться с их обновлением:


let filters = [
    DialogFilter {
        name: "PDF files",
        globs: &[globpattern!("*.pdf")],
        // Имеет смысл, если вместо ".pdf" у вас переменная:
        //globs: &[
        //    &[GlobPatternPart::Star, GlobPatternPart::Literal(".pdf")],
        //],
    },
];
> Я имею ввиду, что вместо строки «PDF files\0*.pdf\0\0» для представления маски будет использоваться

10 строк тулкитзависимого и языкозависимого кода.

> globs: &[globpattern!("*.pdf")]

И как это помогает с проблемой '*.pdf' vs '[*].pdf'?

> globs: &[&[GlobPatternPart::Star, GlobPatternPart::Literal(".pdf")],

Ну да, можно так. Только это не про статическую типизацию, а «как добавить в маску GlobStar, если * занята».

Теперь попробуйте "*n?????d*.p?f", потом размножьте результат 10 раз с небольшими правками (нам несколько масок надо) и поймёте почему так не делают.

То есть весь сыр-бор из-за того, что программист ленится вызывать escape? Но ведь существует полно случаев, когда экранирование используется как будто так и надо: SQL, HTML, URI, XML, JSON, RegExp и т.д. И почему-то никто не требует запрета использования различных символов в этих случаях.

В MS-DOS LFN проецируется в 8.3, так что в Windows можно было разрешить case sensitive, и это не помешало бы MS-DOS

А как тогда в Windows быть с короткими именами файлов, которые укладываются в 8.3? Получается, они от регистра не зависят (для совместимости с DOS), а длинные зависят? Как объяснить пользователю, что A.txt и a.txt — один и тот же файл, а вот SomeLongName.txtx и somelongname.txt уже разные?
Например, в Windows пусть все зависят. Конечно мы должны мочь создать A.txt и a.txt как разные файлы.

LFN — это не обязательно длинное, это [было бы] «второе» длинное/case sensitive имя.
Например, в Windows пусть все

Тогда при переходе из 3.1 в 95 сломалось бы куча Windows-программ, написанных в предположении, что ФС не регистрочувствительна. Тут никакие LFN не помогут — или мы ломаем совместимость, или нет. В Microsoft решили не ломать.
Я думаю вы драматизируете, приложениям это достаточно безразлично.
Да и для приложений Win 3.1 можно было песочницу со своими правилами оставить.
Вашими бы устами… хотя, впрочем, нет. Как раз разработчики десктопных диструбутивов именно так думают — потому использование Linux успешно и держится на уровне одного процента (иногда двух… пока кто-нибудь опять что-нибудь не поломает).

А вот там, где одного-двух процентов «гиков» недостаточно — пилят патчи к ядру

Не понял что вам не понравилось, но если вам вдруг показалось, что я case sensitive подход форшу — нет. Я просто описал когда и как его могли внедрить, если бы хотели.


И, кстати, популярный Linux называется android. И там вообще мало кто знает о существовании имен файлов.

Похоже что вы так ничего и не поняли.

Я просто описал когда и как его могли внедрить, если бы хотели.
Не «если бы хотели», а «если бы Microsoft не было важно, сколько у них будет пользовалей».

Вот с Windows Phone — Microsoft уже поступил, как вы описываете. Долой легаси! Кто не следует правилам — мы не виноваты! Даёшь чистую систему!

Ну и где теперь та Windows Phone?

И, кстати, популярный Linux называется android.
Так точно.

И там вообще мало кто знает о существовании имен файлов.
Из разработчиков? Или из пользователей? Если вы про пользователей — так и среди пользователей Windows мало кто знает о существовании имён файлов, расширений и прочей подобной ерунды. А если о разработчиках — ну так программы, созданные этими разработчиками как раз и заставляют поддерживать /sdcard в case-insensitive состоянии.

И если Android хочет иметь долю рынка близкую к той, что у Windows на десктопе, а не к той, что у Windows Phone на мобильниках — то так будет и впредь…
В этот раз сверху напишу, что бы точно прочитали: приложения win 3.1 можно было запускать в песочнице, с 8.3, без потери совместимости ВООБЩЕ.

> Не «если бы хотели», а «если бы Microsoft не было важно, сколько у них будет пользовалей».

Вы тут видите противоречие? Ну то есть, вы видимо «держали свечку», раз уточняете, что именно из-за боязни что-то там сломать, непонятно в чем, в обратной совместимости они не захотели, но они не захотели.
Я думаю, они не захотели совсем по другим причинам.

> Вот с Windows Phone — Microsoft уже поступил, как вы описываете. Долой легаси! Кто не следует правилам — мы не виноваты! Даёшь чистую систему!

Я действительно ничего не понимаю. «Внедрение case sensetive» = «Даёшь чистую систему!»? Серьезно? Лучше аналогии не придумалось?

А, например, запрет хранения конфигов в Program files, сломавший каждую вторую, прогу вы не считаете нарушением обратной совместимости?

> так и среди пользователей Windows мало кто знает о существовании имён файлов

Остальные ваши факты той же степени достоверности?
UFO just landed and posted this here
В Vista и старше, на сколько я помню.

А ограничения прав неожиданно появилось в десктопном xp
UFO just landed and posted this here
> Права доступа на Program Files не менялись как минимум с Windows 2000.

Только Windows 2000 никто не пользовался, в отличии от XP, по пришествию которого и встречал нежданчик.

Я там специально «десктопный» написал.
UFO just landed and posted this here
> Win2k имеет десктопные релизы наряду с серверными.

Ещё они имели релиз windows home server, например. Или WinXP x64.

Ну ок, те маргиналы, что ставили w2k/NT (включая серверные) наступали на эти грабли раньше. Но софт, в массовом порядке, от этого более совместимым не стал до прихода XP.
UFO just landed and posted this here
Ну да, во времена XP все поголовно сидели под админами, потому, что иначе нихрена не работало.
UFO just landed and posted this here

Если вы хотите меня убедить, что за 2001-2007 никто не правил софт под ограничения — у вас не получилось.


Вы, вроде, приходили с рассказом как удобно работает перенаправление папок в Vista, а теперь говорите, что в Vista веселье и началось. Вы, собственно, что именно донести хотите?

Ну то есть, вы видимо «держали свечку», раз уточняете, что именно из-за боязни что-то там сломать, непонятно в чем, в обратной совместимости они не захотели, но они не захотели.
Свечку не держал, но Windows 95 в c:\Program Files\Windows ставил.

Она туда, кстати, встала. А вот DirectX — уже не встал. Вернее встал, но не запустился: всё требовал свои файлы перенести из C:\PROGRA~1\WINDOWS в C:\PROGRAM FILES\WINDOWS…

В этот раз сверху напишу, что бы точно прочитали: приложения win 3.1 можно было запускать в песочнице, с 8.3, без потери совместимости ВООБЩЕ.
А новые программы будут с нуля написаны, да? С Windows Phone попробовали. Результат мы знаем.

Проблема же не только в старых программах, но и в библиотеках. Которые, как выяснилось, могут и upcase «для красоты» делать (MS DOS превращал все символы в большие, но некоторые библиотеки превращали FileName.Ext в FILENAME.EXT принудительно) и отказываться работать, если у системного каталога имя в 8.3 не помещается и делать много разных других чудес.

А, например, запрет хранения конфигов в Program files, сломавший каждую вторую, прогу вы не считаете нарушением обратной совместимости?
Нет, потому что Workaround известен всем и каждому — запусти программу под Админом — она и перестанет ругаться.
> Свечку не держал, но Windows 95 в c:\Program Files\Windows ставил.

«Но если бы у рыбы была шерсть...»

Вы как-то яснее мысль излагайте, а то я не улавливаю связи багов в DirectX с запуском софта Windows 3.1 на Win32 и ощущение, что вы случайные факты набрасываете.
macOS регистронезависимо работает с файлами, хотя ФС, вроде поддерживает регистрозависимые имена. Видимо это «user friendly» считается.

При этом в iOS ФС регистрозависимая, но симулятор iOS использует ФС macOS с её регистронезависимостью. Долго не мог понять почему на симуляторе всё отлично работает а на устройстве — нет.
Не спец по линуксам, но изредка ковыряясь в нем, обратил внимание, что чувствительность к регистру в нем стараются избегать написанием названий всех файлов строчными буквами. На мой взгляд у чувствительности к регистру больше минусов, чем плюсов. Не уверен, что какие-то значимые плюсы вообще есть.
Не уверен, что какие-то значимые плюсы вообще есть.

значимые плюсы будут в скорости доступа (наверно хоть и небольшие, но будут). Все-таки при чувствительности к регистру это фактически по битовое соответствие. А при нечувствительности наверно придется сначала привести оба значения к одному регистру, если нет лучшего алгоритма.
Для того чтобы выполнять сравнение без учета регистра разработчикам Windows пришлось приложить значительные усилия. Сравнивать нужно не только латинские буквы, но и национальные.
Windows тоже считает что Ласточка и ласточка это один и тот же файл.
А приведение национальных символов к одному регистру это сложная задача.
Например, в греческом алфавите есть заглавная буква которой соответствует две различные строчные буквы. Правила, по котором используется одна или другая буква, учитывает расположение буквы в слове и предшествующую букву.
А в Турецком языке заглавной букве I соответствует строчная буква i, только без точки. И т.д.
Так что, для выполнения сравнения без учёта регистра в Windows приняли некоторые упрощенные правила приведения к верхнему регистру.
Зная все эти сложности я понимаю почему в Linux используется сравнение без учёта регистра.
вот поэтому при чувствительности к регистру и будет скорость быстрее. О чем я и сказал.
Кроме скорости у ФС есть и другие характеристики.

Регистронезависимое сравнение очень шаткое и сильно зависит от локали.
К примеру, в Турции windows/WİNDOWS не то же самое, что WINDOWS/wındows.

чувствительность к регистру в нем стараются избегать написанием названий всех файлов строчными буквами.
Никто ничего не избегает, просто в юниксах традиционно отдаётся предпочтение нижнему регистру; это касается имен пользователей (логинов), названий команд, заголовочных файлов, функций базовых API (POSIX) и т.д. Прописные буквы при этом не запрещены и никак не ущемляются в правах (взгляните на API и файлы тех же X11, SDL, OpenGL и др.).
Не уверен, что какие-то значимые плюсы вообще есть.
Это вы просто к венде привыкли. :-) Я вот каждый раз чертыхаюсь, когда напарываюсь на регистронезависимость венды: «да блин, ну это же разные имена!» Кроме того, это приучает к аккуратности, ибо нефиг писать #include <stdafx.h>, когда файл на самом деле называется StdAfx.h. :-)
Если выбирать между аккуратностью и тратой меньшего количества памяти на запоминание названий файлов, то я выберу, конечно второе. К тому же, на запоминание регестрозависимого файла я приложу больше чем вдвое. Т.к. имя файла обычно запоминающееся и можно запомнить мнемонически, а расположение прописных букв — уже как бог на душу положит — сидеть вспоминать как там было название папки camera или Camera на карте памяти — так себе удовольствие и аккуратность тут не при чем.
Это лишь один пример (про имена инклюдов). Если погуглить, там много было историй, когда регистронезависимость файлухи внезапно жалила в пятку. Это действительно создает больше проблем чем решает, причем решает-то оно сиюминутные проблемы (типа camera vs. Camera, хотя тут tab-completion помогает), а создает отложенные, про которые заранее не знаешь и не ожидаешь их, пока они не выстрелят.
Я не очень понял что с этими инклюдами не так. В си (или что это?) тоже регистрозависимость? Ну, тогда это не винда жалит, а си, нет?
Как раз винда которая позволяет преароцессору при #include A.h видеть файл a.h и подставлять его содержимое
И чем это жалит? Ну кроме «нефиг так писать»? Ну разве что если так написать на винде, а сломается сборка на линухе, но это люди один раз проходят, разве нет? Я вот ленивый и всегда пишу %appdata%, %userprofile% и так далее, я не помню, как там правильно %appdata%, %Appdata%, %AppData%? Просто набираю как мне удобно, дальше система разбереться. Чем это плохо? Неряшливость когда должна быть дисциплина? А как же правила, что любое АПИ должно быть толерантным к входу и консервативным к выходу? Почему мы к ФС его не применяем?

Для того, чтобы помнить, как правильно, есть соглашения о стиле именования. На linux все переменные среды с особым значением в UPPER_CASE. Вам сложно запомнить одно соглашение? Кроме того, заметьте, что ни %userprofile%, ни $PATH не имеют ни пространства имён, из которого их нужно импортировать, ни просто какого‐то префикса. Т.е. в Windows вы не можете знать, не будет ли переменная из вашего скрипта в будущем иметь какое‐то особенное значение. В linux вы можете писать в своём скрипте на POSIX shell for path in * ; do … done и быть уверенным, что специального значения у path нет.


Правда, я не зря уточнил про POSIX shell: я не помню, чтобы какая‐то программа забрала под себя переменную окружения вида LuaInit вместо «правильного» LUA_INIT, но вот zsh в «режиме эмуляции zsh» $path содержит массив путей из $PATH — хороший пример того, как нормальные скрипты ломают поведение другой программы из‐за внезапно возникшего специального значения используемой ими переменной — при редактировании массива $PATH также обновляется и в случае с for path in * там просто окажется последнее имя файла без пути. Также показывает, зачем вообще нужны такие соглашения.

> Вам сложно запомнить одно соглашение?

Правильно «ещё одно соглашение».

> Т.е. в Windows вы не можете знать, не будет ли переменная из вашего скрипта в будущем иметь какое‐то особенное значение.

Я сейчас заглянул, в переменных окружения 22 переменных, половина стандартных системных. Половина остальных имеют явные префиксы (вторая — неявные): %MEmu_Path%, например.

И вы можете смело использовать переменную с префиксом, %ZyXI_path% никто не займёт. Вам не сложно запомнить такое соглашение?
Вам сложно запомнить одно соглашение?

Если я буду выбирать между двумя равноценными ОС, я выберу ту, где мне не надо под неё подстраиваться и запоминать соглашения. Я не зря про АПИ упомянул: быть толерантным к входу при проектировании какого-нибудь REST считается хорошими манерами, а вот то же самое для ввода пользователя в ФС почему-то в *nix-мире воспринимается как безалаберность, а пользователь расслабляться не должен!
Я не зря про АПИ упомянул: быть толерантным к входу при проектировании какого-нибудь REST считается хорошими манерами
Это у кого это так считается? Времена HTML, который в угоду совместимости с MS IE 6 имеет многостраничные правила обработки неправильных входных данных давно прошли. Если вы пошлёте невалидный XML или JSON на вход современную сервису — то вы получите только лишь сообщение о том, что он невалиден и ничего больше.

И это не случайно — даже специальный RFC есть, объясняющий почему это плохо. И современные браузеры стараются «закручивать гайки» постепенно. Именно потому что в долгосрочной перспектива многоуровневые коллекции костылей — это путь в никуда.
А как же правила, что любое АПИ должно быть толерантным к входу и консервативным к выходу?
Вообще-то на тему ошибочности этого постулата даже специальный RFC есть.

Чем это плохо?
Тем что не работает. Именно подобные подходы приводят к рекомендации использоваться исключительно английский (русский, немецкий — далее по вкусу) интерфейс для сборки/запуска программ и прочему.

Особенно весело, когда одна программа работает только в одной локали (скажем английской), а другая — исключительно в другой (какой-нибудь корейской). Вот тот вспоминаешь «любителей удобств» незлым тихим словом.

Собственно это типичная ситуация, когда приходится подпирать костыли другими костылями, которые нужны для того, чтобы когда-то давным-давно использованные затычки для проблем, о которых все уже давно забыли, не испортились…

И всякие разные дыры в безопасности — тоже оттуда.
Ответ на этот вопрос есть в замечательной книге Эви Немета сотоварищи «UNIX: Руководство системного администратора». Просто надоедает переключать регистр )
Мне почему то кажется, что подход винды намного более интуитивен, в этом вопросе. Ведь человек тоже воспринимает «ЛАСТОЧКА» и «ласточка» как одно и тоже.
но Ласточка и ласточка — разное
Лопата и лопата
Например, в том, что Ласточка может быть кличкой, а ласточка — видом птиц. Не думаю впрочем, что такое часто встречается, но оно есть.
Ласточка — скоростная электричка, Лопата — фамилия украинского генерала.
А еще могут быть папки imageРазобрать срочно, imageРазобрать СРОЧНО и imageРАЗОБРАТЬ СРОЧНО
А когда и эти три забиты, создаётся РаЗоБрАтЬ онҺоdɔ!
Скорее, 111 РАЗОБРАТЬ СРОЧНО, ### РАЗОБРАТЬ СРОЧНО и потом!!! РАЗОБРАТЬ СРОЧНО, но это уже не относиться к теме нашего обсуждения.
Можно сделать значок для конкретной папки такой же, но красного цвета.
Если у вас есть такие папки, то проблема не в файловой системе. Проблема в планировании.
На верхнем уровне в Linux/Unix то же самое — для человека поиск человеческий, с учётом локалей. И дело не только в больших/маленьких буквах, а и в подмене е/ё в русском, c/ç во французском, португальском. Просто «для себя» компьютеры перелопачивают гораздо больше файлов, чем документов для человека.
Ср. Земля (планета) и земля (грунт).
ИМХО. Лучше бы сделали такой алгоритм:
* если файл/папка в единственном экземпляре – брать его
* если нет – то если есть с нужным регистром – брать его, если нет…
** если папка, то искать с первой буквой в верхнем, если тютю – смотреть только в нижнем, если и его тютю – обламывать
** если файл – смотреть только в нижнем, если тютю – обламывать

Никак не могу представить — для чего такая лихая идеология?

Хм. Вот, допустим, процесс 1 хочет открыть файл file.txt, но в папке есть только FILE.txt. В соответствии с вашим алгоритмом, процесс открывает этот файл и работает с ним. В это время процесс 2 создает рядом файл File.txt. После этого процесс 1 проверяет наличие файла с именем file.txt — и не находит его! «Как же так?» — думает он, — «Я ж держу дескриптор открытым, а файл исчез!» И от отчаяния накладывает на себя руки вываливает ошибку.
И что в таком случае должен получить процесс? В папке стало 2 файла. Лучше обломить процесс, чем подсунуть ему фиктивный файл.
Изначально мой вариант был короче, но вспомнил, что в винде обычно в именах системных папок первые буквы слов большие, а большинство системных файлов (все не проверял) – мелкий регистр.
Или с помощью API можно получить реальное (т.е. с регистром) имя файла, уже держа дескриптор, то проблем нет (не знаю, есть ли такая возможность). Если нет – значит «неопределенное поведение».

Можно установить флаг HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\kernel\ObCaseInsensitive=dword:00000000 и использовать Cygwin. Подробнее здесь.


На одной работе у нас был репозиторий с парочкой таких файлов. Рабочие машины на Винде. Столько возни было, пока патч не смержили. Stash не сделать, rebase не сделать, reset не работает, ветки не все переключаются. При необходимости делали через Cygwin с его медленным git.

UFO just landed and posted this here
Скорее всего да. Потому что есть много программ, которые, по неизвестной науке причине, делают для имён UpCase, перед тем, как открывать их.

Именно поэтому в «старые добрые времена» регистронезависимость включалась не на уровне папок, а на уровне процессов. То есть сначала, конечно, старый добрый ObCaseInsensitive, а потом ещё каждый процесс должен был не забывать про FILE_FLAG_POSIX_SEMANTICS. Иначе птичка не вылетала…
UFO just landed and posted this here
Да. Вот тут прямо под вашим комментарием пример того, что происходит, если просто сделать поиск файлов регистрозависимым — программы не находят то, что ищут. Причем если в нескольких программах (или в нескольких местах одной) используется один и тот же файл, но к нему обращаются про разным именам, то совсем все грустно.
Это, наверное, можно обойти тотальным переименованием большинства файлов в системе, с созданием для них хардлинков, сразу после определения всех мест, где возникла такая проблема. В общем, в реальности это будет невозможно починить.
Много лет назад решил я поиграть в Oblivion под Wine. Под виндой все чудесно работало, но вот под онтопиком почему-то некоторые модели и текстуры из дополнений пропадали.
Уже понятно в чем дело, да? Суть в том, что игра сначала искала файлы на диске (их там раскладывали моды), а потом искала в архиве с ресурсами. Разработчики модов называли файлы как бог на душу положит, а вот игра искала строго ImperialCityMageGuildBlahBlah. Ну в винде это не было проблемой, а вот ext4 отказывался считать, что это один и тот же файл.
Теперь ломать java приложения на винде станет чуть проще.
UFO just landed and posted this here
О да. Файл aux.cpp. Такое не забывается.
А создавать файлы в одним именем, но разных регистрах, мне бы и в голову не пришло
Некоторые текстовые редакторы предлагают имя файла при первом сохранении из первых слов текста.
Ещё весело имена файлов с backslash '\' создавать, ну или с двоеточиями.
Кто вдруг будет мучиться c этим, есть пути \\?\путь
Можно создавать и удалять папки/файлы, писать в файл и читать из них через командную строку стандартными командами.
Типа:
> echo hello > "\\?\D:\123\aux.cpp"
> more "\\?\D:\123\aux.cpp"
hello
> del "\\?\D:\123\aux.cpp"
> more "\\?\D:\123\aux.cpp"
Не удается получить доступ к файлу \\?\D:\123\aux.cpp
UFO just landed and posted this here
Что то я вообще не помню такой проблемы. Вина и раньше мне не позволяла создавать папки с разными регистрами но одинаковым названием и сейчас не позволяет. В каких параллельных мирах эта проблема существует?
UFO just landed and posted this here
Ты или писал этот коммент сильно уставшим или был сильно пьян, ежели нет то жаль уже мне тебя. Прочти свой комментарий еще раз, прочти статью и мой комментарий. Автор пишет что в винде(по крайней мере до 8 включительно) можно создавать папки с подобными именами: «новая папка» и «Новая папка» и винда это схавает. Однако нет, не дала мне ни 7 ни 8 так сделать. А если другие ОС чувствительны к регистру то у них и такой проблемы быть не может. Из этого и вопрос последовал, отсюда и параллельные миры
sumanai Ты или писал этот коммент сильно уставшим или был сильно пьян, ежели нет то жаль уже мне тебя. Прочти свой комментарий еще раз, прочти статью и мой комментарий. Автор пишет что в винде(по крайней мере до 8 включительно) можно создавать папки с подобными именами: «новая папка» и «Новая папка» и винда это схавает. Однако нет, не дала мне ни 7 ни 8 так сделать. А если другие ОС чувствительны к регистру то у них и такой проблемы быть не может. Из этого и вопрос последовал, отсюда и параллельные миры.
на случай если сейчас придут умники и напишут про дублирование коммента и кнопку ответить, я не знаю почему комментарий задублировался и не пошел в ответ, кнопку я нажимал
UFO just landed and posted this here
Sign up to leave a comment.