readdir — Получить элемент каталога по его дескриптору


Содержание

Получить имя файла из файлового дескриптора в C

Можно ли получить имя файла дескриптора файла (Linux) в C?

Вы можете использовать readlink в /proc/self/fd/NNN , где NNN — файловый дескриптор. Это даст вам имя файла, как оно было, когда оно было открыто — однако, если файл был перемещен или удален с тех пор, он может быть не более точным (хотя Linux может отслеживать переименование в некоторых случаях). Чтобы проверить, stat имя файла и fstat значение fd у вас есть, и убедитесь, что st_dev и st_ino совпадают.

Конечно, не все дескрипторы файлов относятся к файлам, и для них вы увидите некоторые нечетные текстовые строки, например pipe:[1538488] . Поскольку все настоящие имена файлов будут абсолютными путями, вы можете определить, какие из них достаточно просты. Кроме того, как отмечали другие, файлы могут иметь несколько жестких ссылок, указывающих на них — это будет сообщать только тот, с которым он был открыт. Если вы хотите найти все имена для данного файла, вам просто нужно пройти всю файловую систему.

У меня была эта проблема в Mac OS X. У нас нет виртуальной файловой системы /proc , поэтому принятое решение не может работать.

Вместо этого мы имеем команду F_GETPATH для fcntl :

Итак, чтобы получить файл, связанный с файловым дескриптором, вы можете использовать этот фрагмент:

Так как я никогда не помню, где MAXPATHLEN определено, я думал, что PATH_MAX из syslimits будет в порядке.

В Windows с GetFileInformationByHandleEx, передавая FileNameInfo, вы можете получить имя файла.

Как указывает Тайлер, нет никакого способа сделать то, что вам нужно «прямо и надежно», поскольку данный FD может соответствовать 0 именам файлов (в разных случаях) или > 1 (несколько «жестких ссылок» — это то, как последняя ситуация как правило, описывается). Если вам все еще нужна функциональность со всеми ограничениями (по скорости И по возможности получать 0, 2. результаты, а не 1), вот как вы можете это сделать: во-первых, fstat FD — это сообщает вам, в результате struct stat , какое устройство живет в файле, сколько жестких ссылок он имеет, будь то специальный файл и т.д. Это может уже ответить на ваш вопрос — например если 0 жестких ссылок вы будете ЗНАТЬ, на самом деле нет соответствующего имени файла на диске.

Если статистика дает вам надежду, тогда вам нужно «ходить по дереву» каталогов на соответствующем устройстве, пока не найдете все жесткие ссылки (или только первые, если вам не нужно больше одного и любого другого один сделаю). Для этой цели вы используете readdir (и, конечно, opendir и c), рекурсивно открывая подкаталоги, пока не найдете в полученном таким образом struct dirent тот же номер inode, который у вас был в исходном struct stat (когда вам нужен весь путь, а не просто имя, вам нужно будет пройти цепочку каталогов назад, чтобы восстановить его).

Если этот общий подход является приемлемым, но вам нужен более подробный код C, сообщите нам, что его будет сложно написать (хотя я бы предпочел написать его, если он бесполезен, т.е. вы не можете противостоять неизбежно медленному производительность или возможность получения!= 1 результат для вашей заявки; -).

Прежде чем записать это как невозможное, я предлагаю вам посмотреть исходный код команды lsof.

Могут быть ограничения, но lsof кажется способным определять дескриптор файла и имя файла. Эта информация существует в файловой системе /proc, поэтому она должна быть доступна из вашей программы.

readdir

readdir — Получить элемент каталога по его дескриптору

Описание

Возвращает имя следующего по порядку элемента каталога. Имена элементов возвращаются в порядке, зависящем от файловой системы.

Обратите внимание на способ проверки значения, возвращаемого функцией readdir() в приведенном ниже примере. В этом примере осуществляется проверка значения на идентичность (выражения идентичны, когда они равны и являются значениями одного типа — за более подробной информацией обратитесь к главе Операторы сравнения) значению FALSE, поскольку в ином случае, любой элемент каталога, чье имя может быть выражено как FALSE, остановит цикл (например, элемент с именем «0»).

Пример #1 Вывести список всех файлов в каталоге

// Обратите внимание, что оператор !== не существовал до версии 4.0.0-RC2

if ( $handle = opendir ( ‘/path/to/files’ )) <
echo «Дескриптор каталога: $handle\n» ;
echo «Файлы:\n» ;

/* Именно этот способ чтения элементов каталога является правильным. */
while ( false !== ( $file = readdir ( $handle ))) <
echo «$file\n» ;
>

/* Этот способ НЕВЕРЕН. */
while ( $file = readdir ( $handle )) <
echo «$file\n» ;
>

Обратите внимание, что функция readdir() также возвращает элементы с именами . и ... Если вы не хотите получать эти значения, просто отбрасывайте их:

Пример #2 Получить список файлов в текущем каталоге и отбросить элементы с именами . и ..

См.также описания функций is_dir() и glob().

Заметки web-разработчика

Ccskrb

воскресенье, 16 апреля 2020 г.

PHP. Работа с файлами. Просмотр содержимого директории

opendir() — открывает дескриптор каталога.
readdir() — получает элемент каталога по его дескриптору.
closedir() — освобождает дескриптор каталога.

$dir = «.»; // означает текущую рабочую директорию
if(is_dir($dir)) < // если это директория
if($dir_handle = opendir($dir)) < // получаем указатель и если это успешно
while($filename = readdir($dir_handle)) < // пока есть возможность получить что-либо
echo «filename: <$filename>
«;
>

// rewinddir — позволяет перепрыгнуть вверх папки.

closedir($dir_handle); // если мы смогли ее открыть, то ее нужно и закрыть
>
>

// scandir — Получает список файлов и каталогов, расположенных по указанному пути
// Читает все файлы в массив. Делает сортировку и вывод в обратном порядке проще.
echo » «;

if(is_dir($dir)) <
$dir_array = scandir($dir);

foreach($dir_array as $file) <
// stripos — возвращает позицию первого вхождения подстроки без учета регистра. Ищет позицию первого вхождения подстроки needle в строку haystack . В отличие от strpos() , эта функция не учитывает регистр символов.
// уберем файлы, начинающиеся на точку

Как я могу получить дескриптор файлов в каталоге и его поддиректорах?

3 Eli [2011-06-20 23:59:00]

Итак, я недавно заметил использование opendir в script и хотел бы немного изменить его, чтобы он возвращал файлы во вложенные папки каталога, а также файлы в самом каталоге. После расследования я не смог найти какой-либо рекурсивный вариант для opendir, и у меня возникли проблемы с получением glob для возврата скаляра. Таким образом, вместо того, чтобы притворяться еще одним, я решил, что было бы более разумным просто спросить: какой стандартный способ получить доступ ко всем файлам в каталоге и его поддиректорах?

4 ответа

7 Решение FMc [2011-06-21 00:26:00]

Классический способ заключается в File:: Find, который имеет преимущество в качестве основного модуля, но может быть немного боль. Если вы можете использовать сторонний модуль, File:: Util довольно удобно:

find2perl создает примерный код для рекурсивных вызовов по всем файлам в дереве каталогов.

Используйте его как шаблон при необходимости.

Изменить: я загрузил эту базовую структуру в CPAN как File::chdir::WalkDir (должен скоро жить), который экспортирует walkdir , который аналогичен показанному ниже.

Я нахожу, что функция хоста рекурсивного каталога, использующая идеальных партнеров opendir / readdir и File::chdir (мой модуль CPAN, отлично подходит для кросс-платформенной) позволяет легко и четко манипулировать чем-либо в каталоге, включая при необходимости, подкаталоги (если нет, опустите рекурсию).

Пример (простой глубокий ls ):

На самом деле, вероятно, для этого есть модуль CPAN, но я бы просто сделал рекурсию:

Это включает каталоги в результатах — если вы хотите только файлы, замените первый вызов map() на map < -d $_ ? find($_) : $_ >.

Единственное, что вам нужно запомнить, это то, что путь до сих пор должен быть добавлен к readdir() и что он возвращает . и .. , поэтому их необходимо устранить — второй вызов map() (который применяется первым) выполняет обе эти вещи. Если вы знаете ОС, на котором вы работаете, вы можете просто интерполировать / или \ вместо вызова File::Spec->catfile() , но последнее полезно для переносимости.

Дескрипторы объекта и таблица дескрипторов процесса Windows

Когда процесс создает или открывает объект по его имени, он получает дескриптор, дающий ему доступ к объекту. Ссылаться на объект по его дескриптору быстрее, чем использовать его имя, поскольку диспетчер объектов может не заниматься поиском по имени и находить объект напрямую.

Процессы могут также получать дескрипторы объектов путем наследования дескрипторов во время создания процесса (когда создатель устанавливает флаг наследования дескрипторов при вызове функции CreateProcess, и дескриптор помечен как наследуемый либо в процессе своего создания, либо после создания путем использования Windows-функции SetHandleInformation) или путем получения продублированного дескриптора от другого процесса (см. Windows-функцию DuplicateHandle).

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

Например, библиотеки времени выполнения C и Pascal (более старого языка программирования, аналогичного Delphi) возвращают дескрипторы открытых файлов. Дескрипторы служат в качестве косвенных указателей на ресурсы системы; эта косвенность не дает прикладным программам напрямую манипулировать структурами системных данных.

ПРИМЕЧАНИЕ. Компоненты исполняющей системы и драйверы устройств могут обращаться к объектам непосредственно, поскольку они запущены в режиме ядра и поэтому имеют доступ к структурам объекта в системной памяти. Но они должны объявить о своем использовании объекта, увеличив значение счетчика ссылок, чтобы объект не мог быть удален из памяти, пока он все еще используется.

Однако для успешного использования объекта драйверы устройств должны знать определение внутренней структуры объекта, а для многих объектов она не предоставляется. Взамен драйверам устройств рекомендуется использовать соответствующие API-функции ядра для изменения или чтения информации из объекта. Например, хотя драйверы устройств могут получить указатель на объект типа «процесс» (EPROCESS), его структура им не известна, и должны быть использованы API-функции вида Ps*.

Для других объектов непрозрачен сам тип (это касается большинства объектов исполняющей системы, в которые заключен диспетчер объектов, в качестве примеров можно привести события или мьютексы). Для таких объектов драйверы должны использовать такие же системные вызовы, которые в конечном итоге используются приложениями пользовательского режима (такие как ZwCreateEvent), и использовать дескрипторы, а не указатели на объекты.

Дескрипторы объектов дают дополнительные преимущества. Во-первых, за исключением того, к чему они относятся, нет никакой разницы между дескрипторами файла, события и процесса. Эта схожесть обеспечивает единый интерфейс для ссылки на объекты, независимо от их типа. Во-вторых, диспетчер объектов имеет исключительное право на создание дескрипторов и на определение местоположения объекта, который относится к дескриптору. Это означает, что диспетчер объектов может проверять каждое действие в пользовательском режиме, влияющее на объект, чтобы убедиться в том, что профиль безопасности вызывающей программы разрешает проводить запрашиваемую операцию над данным объектом.

Илон Маск рекомендует:  Write - Процедура Delphi

Просмотр открытых дескрипторов.

Запустите Process Explorer и убедитесь, что нижняя панель включена и настроена на показ открытых дескрипторов. (View (Вид) — Lower Pane View (Просмотр нижней панели) — Handles (Дескрипторы)). После этого откройте окно командной строки и просмотрите таблицу дескрипторов для нового процесса Cmd.exe. Вы должны увидеть дескриптор открытого файла для текущего каталога. Например, предположим, что текущим является каталог C:\Users\Administrator, тогда Process Explorer покажет следующее.

Теперь поставьте Process Explorer на паузу, нажав клавишу Пробел или щелкнув на пунктах View (Вид) — Update Speed (Изменить скорость) — Pause (Пауза).

Затем измените текущий каталог с помощью команды cd и нажмите клавишу F5, чтобы обновить отображаемую информацию. Вы увидите в Process Explorer, что дескриптор предыдущего текущего каталога закрыт и открыт новый дескриптор для нового текущего каталога. Предыдущий дескриптор выделен красным цветом, а новый дескриптор выделен зеленым цветом.

Свойство выделения разным цветом, имеющееся в Process Explorer, делает заметнее изменения в таблице дескрипторов. Например, если процесс допускает утечку дескрипторов, просмотр таблицы дескрипторов с помощью Process Explorer может быстро показать, какой дескриптор или какие дескрипторы были открыты, но не были закрыты. (Обычно виден длинный список дескрипторов для одного и того же объекта.) Эта информация поможет программисту обнаружить утечку дескрипторов.

Монитор ресурсов также показывает открытые (именованные) дескрипторы для процессов, выбранных путем установки флажков напротив их имен. Вот как выглядят дескрипторы открытого окна командной строки.

Таблицу открытых дескрипторов можно также вывести, используя средство командной строки Handle из серии программных продуктов Sysinternals.

Посмотрите, к примеру, на следующий, частично показанный вывод, полученный с помощью средства Handle при изучении дескрипторов файловых объектов, находящихся в таблице дескрипторов для процесса Cmd.exe до и после изменения каталога. По умолчанию Handle отфильтровывает нефайловые дескрипторы, пока не будет использован ключ –a, который приводит к выводу всех дескрипторов в процессе, аналогично Process Explorer.

C:\>handle -p cmd.exe

Copyright (C) 1997-2011 Mark Russinovich

cmd.exe pid: 5124 Alex-Laptop\Alex Ionescu

3C: File (R-D) C:\Windows\System32\en-US\KernelBase.dll.mui

C:\Windows>handle -p cmd.exe

Copyright (C) 1997-2011 Mark Russinovich

cmd.exe pid: 5124 Alex-Laptop\Alex Ionescu

3C: File (R-D) C:\Windows\System32\en-US\KernelBase.dll.mui

40: File (RW-) C:\Windows

Дескриптор объекта является индексом в таблице дескрипторов, относящейся к конкретному процессу. Этот индекс указывается исполнительным блоком процесса (EPROCESS). Первый индекс дескриптора имеет значение 4, второй — 8 и т. д. Таблица дескрипторов процесса содержит указатели на все объекты, которые процесс открыл для своей работы.

Таблицы дескрипторов реализованы по древовидной схеме, подобной той, которую реализует блок управления памятью x86 для перевода виртуальных адресов в физические, которая дает максимальное значение, превышающее 16 000 000 дескрипторов на процесс.

ПРИМЕЧАНИЕ. В древовидной схеме таблиц таблица верхнего уровня может содержать страницу, заполненную указателями на таблицы среднего уровня, что позволяет иметь более половины миллиарда дескрипторов. Но чтобы поддержать совместимость со схемой дескрипторов, имевшейся в Windows 2000, и унаследовать ограничение в 16 777 216 дескрипторов, таблица верхнего уровня содержит не более 32 указателей на таблицы среднего уровня, устанавливая для более новых версий Windows тот же предел.

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

Например, для систем x86 страница составляет 4096 байт и поделена на записи таблицы дескрипторов размером 8 байт, которых получается 512 минус 1, то есть всего 511 записей в таблице дескрипторов самого низкого уровня. Таблица дескрипторов среднего уровня содержит полную страницу указателей на таблицы нижнего уровня, поэтому количество таблиц дескрипторов нижнего уровня зависит от размера страницы и размера указателя для платформы. Схема таблицы дескрипторов в системе Windows показана на следующем рисунке.

Создание максимального количества дескрипторов.

Тестовая программа Testlimit из коллекции Sysinternals предоставляет возможность открывать дескрипторы объекта до тех пор, пока она не сможет больше открыть ни одного дополнительного дескриптора. Этим можно воспользоваться, чтобы посмотреть, сколько дескрипторов может быть создано отдельно взятым процессом на вашей системе. Поскольку под таблицы дескрипторов выделяется место в выгружаемом пуле памяти, до достижения максимального количества дескрипторов, доступного для создания в рамках отдельно взятого процесса, вы можете выйти за рамки выгружаемого пула.

Чтобы увидеть, сколько дескрипторов можно создать на вашей системе, выполните следующие действия:

  1. Загрузите с адреса http://live.sysinternals.com/WindowsInternals исполняемый файл Testlimit, необходимой вам версии для 32- или 64-разрядной версии Windows.
  2. Запустите программу Process Explorer, щелкните на пункте View (Вид) — System Information (Информация о системе) — Memory (Память). Обратите внимание на текущий и максимальный размер выгружаемого пула.

Чтобы показать максимальный размер пула, Process Explorer должен быть правильно настроен на доступ к символам образа ядра, Ntoskrnl.exe. Оставьте это отображение системной информации работающим, чтобы можно было следить за использованием пула при запуске программы Testlimit.

  1. Откройте окно командной строки.
  2. Запустите программу Testlimit с ключом –h (путем ввода команды testlimit –h). Когда программа Testlimit не сможет открыть новый дескриптор, она покажет общее количество тех дескрипторов, которые ей удалось создать. Если количество будет меньше, чем примерно 16 миллионов, значит, вы, наверное, вышли за пределы выгружаемого пула памяти еще до достижения теоретического лимита дескрипторов на один процесс.
  3. Закройте окно командной строки, благодаря чему будет прекращено выполнение процесса Testlimit и будут закрыты все открытые им дескрипторы.

Как показано на следующем рисунке, на системах x86 каждая запись дескриптора состоит из структуры с двумя 32-разрядными элементами: указателем на объект (с флагами) и маской предоставленных прав доступа. На 64-разрядных системах запись таблицы дескрипторов имеет длину 12 байт: 64-разрядный указатель на заголовок объекта и 32-разрядная маска доступа.

Просмотр таблицы дескрипторов с помощью отладчика ядра.

В команде !handle отладчика ядра используются три аргумента: !handle

Индекс дескриптора идентифицирует запись дескриптора в таблице дескрипторов. (Нуль означает «показать все дескрипторы».) Индекс первого дексритора имеет значение 4, второго — 8 и так далее. Например, после ввода команды !handle 4 будет показан первый дескриптор для текущего процесса.

Флаги можно указать в виде поразрядной маски, где разряд 0 означает «показать только информацию в записи дескриптора», разряд 1 означает «показать свободные (то есть неиспользуемые) дескрипторы, а разряд 2 означает «показать информацию об объекте, на который ссылается дескриптор». Следующая команда приводит к показу всех подробностей о таблице дескрипторов для процесса с идентификатором 0x62C:

lkd> !handle 0 7 62c

processor number 0, process 000000000000062c

Searching for Process with C >

SessionId: 1 Cid: 062c Peb: 7fffffdb000 ParentCid: 0558

DirBase: 7e401000 ObjectTable: fffff8a00381fc80 HandleCount: 111.

Handle table at fffff8a0038fa000 with 113 Entries in use

0000: free handle, Entry address fffff8a0038fa000, Next Entry 00000000fffffffe

0004: Object: fffff8a005022b70 GrantedAccess: 00000003 Entry: fffff8a0038fa010

Object: fffff8a005022b70 Type: (fffffa8002778f30) Directory

ObjectHeader: fffff8a005022b40fffff8a005022b40 (new version)

HandleCount: 25 PointerCount: 63

Directory Object: fffff8a000004980 Name: KnownDlls

0008: Object: fffffa8005226070 GrantedAccess: 00100020 Entry: fffff8a0038fa020

Object: fffffa8005226070 Type: (fffffa80027b3080) File

ObjectHeader: fffffa8005226040fffffa8005226040 (new version)

HandleCount: 1 PointerCount: 1

Directory Object: 00000000 Name: \Program Files\Debugging Tools for Windows (x64)

Первым флагом является бит блокировки, показывающий, что запись в настоящее время используется. Вторым флагом является указатель на возможность наследования, то есть он показывает, получат ли процессы, созданный данным процессом, копию этого дескриптора в свои таблицы дескрипторов. Как уже отмечалось, наследование дескрипторов может быть указано при создании дескриптора или после него с помощью функции SetHandleInformation.

Третий флаг показывает, должно ли закрытие объекта генерировать контрольное сообщение (флаг не показывается в Windows, диспетчер объектов использует его для внутренних нужд). Бит защиты от закрытия хранится в неиспользованной части маски доступа и показывает, разрешено ли вызывающей программе закрыть этот дескриптор (флаг может быть установлен с помощью системного вызова NtSetInformationObject).

Системным компонентам и драйверам устройств зачастую нужно открывать дескрипторы объектов, к которым не должны иметь доступ приложения пользовательского режима. Это делается путем создания дескрипторов в таблице дескрипторов ядра (внутренняя ссылка на которую осуществляется по имени ObpKernelHandleTable).

Дескрипторы в этой таблице доступны только из режима ядра и в контексте любого процесса. Это означает, что функция режима ядра может сослаться на дескриптор в контексте любого процесса, не оказывая отрицательного влияния на производительность системы. Диспетчер объектов распознает ссылки на дескрипторы из таблицы дескрипторов ядра, когда установлен старший бит дескриптора, то есть когда ссылки на дескрипторы из таблицы дескрипторов ядра имеют значение, больше чем 0x80000000.

Таблица дескрипторов ядра также служит в качестве таблицы дескрипторов для процесса System, и все дескрипторы, созданные процессом System (например, кодом, запущенным в системных потоках), автоматически помечаются как дескрипторы ядра, поскольку они размещаются в таблице дескрипторов ядра по определению.

Поиск открытых файлов с помощью отладчика ядра.

Хотя для поиска дескрипторов открытых файлов можно воспользоваться такими средствами, как Process Explorer, Handle и OpenFiles.exe, они недоступны при просмотре аварийного дампа или удаленном анализе системы.

Вместо них для поиска дескрипторов, отрытых для файлов на том или ином томе, можно воспользоваться командой !devhandles.

  1. Сначала нужно выбрать букву диска, представляющего интерес, и получить указатель на его объект Device. Для этого, как показано ниже, можно воспользоваться командой !object:

1: kd> !object \Global??\C:

Object: fffff8a00016ea40 Type: (fffffa8000c38bb0) SymbolicLink

ObjectHeader: fffff8a00016ea10 (new version)

HandleCount: 0 PointerCount: 1

Directory Object: fffff8a000008060 Name: C:

Target String is ‘\Device\HarddiskVolume1’

Drive Letter Index is 3 (C:)

  1. Затем нужно воспользоваться командой !object, чтобы получить объект

Device для нужного имени тома:

1: kd> !object \Device\HarddiskVolume1

Object: fffffa8001bd3cd0 Type: (fffffa8000ca0750) Device

  1. Теперь можно воспользоваться указателем на объект Device, вставив его в команду !devhandles. Каждый показанный объект указывает на файл:

Checking handle table for process 0xfffffa8000c819e0

Kernel handle table at fffff8a000001830 with 434 entries in use

SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000

DirBase: 00187000 ObjectTable: fffff8a000001830 HandleCount: 434.

0048: Object: fffffa8001d4f2a0 GrantedAccess: 0013008b Entry: fffff8a000003120

Object: fffffa8001d4f2a0 Type: (fffffa8000ca0360) File

ObjectHeader: fffffa8001d4f270 (new version)

HandleCount: 1 PointerCount: 19

Directory Object: 00000000 Name: \Windows\System32\LogFiles\WMI\

Решение задания с pwnable.kr 01 — fd. Файловые дескрипторы и процессы

Специально для тех, кто хочет узнавать что-то новое и развиваться в любой из сфер информационной и компьютерной безопасности, я буду писать и рассказывать о следующих категориях:

  • PWN;
  • криптография (Crypto);
  • cетевые технологии (Network);
  • реверс (Reverse Engineering);
  • стеганография (Stegano);
  • поиск и эксплуатация WEB-уязвимостей.

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

Чтобы вы могли узнавать о новых статьях, программном обеспечении и другой информации, я создал канал в Telegram и группу для обсуждения любых вопросов в области ИиКБ. Также ваши личные просьбы, вопросы, предложения и рекомендации рассмотрю лично и отвечу всем.

Вся информация представлена исключительно в образовательных целях. Автор этого документа не несёт никакой ответственности за любой ущерб, причиненный кому-либо в результате использования знаний и методов, полученных в результате изучения данного документа.

Илон Маск рекомендует:  Обмен ссылками

Файловые дескрипторы

Файловый дескриптор — это неотрицательное число, которое является идентификатором какого-либо потока ввода-вывода, который может быть связан с файлами, каталогами или сокетами.

В системной файловой таблице (SFT — System File Table) и таблице индексных дескрипторов (INode Table) содержится информация, необходимая для доступа процесса к данным файла. Если несколько процессов запрашивают доступ к одному и тому же файлу, то каждый из тих процессов получит собственный элемент системной файловой таблицы, несмотря на то что они будут работать с одним и тем же файлом.

Ядро предоставляет процессу файловый дескриптор, когда тот получает доступ к файлу. Можно сказать, что файловый дескриптор — это индекс массива открытых файлов, который является уникальным для каждого процесса. Но первые три индекса жестко закреплены:

  • 0 — стандартный ввод (stdin);
  • 1 — стандартным выводом (stdout);
  • 2 — стандартный поток ошибок (stderr).

Так функии gets() и printf() из стандартной библиотеки C используют stdin и stdout, что позволяет командным оболочкам правильно перенаправлять ввод и вывод процессов.

Решение задания fd

Нажимаем на первую иконку с подписью fd, и нам говорят, что нужно подключиться по SSH с паролем guest.

При подключении мы видим соотвтствующий баннер.

Давайте узнаем какие файлы есть на сервере, а также какие мы имеем права.

Таким образом мы можем можем прочитать исходный код программы, так как есть право читать для всех, и выполнить с правами владельца программу fd (установлен sticky-бит). Давай просмотрим исходный код.

Из кода следует, что программа принимает в качестве параметра число, отнимает от него 0x1234 и использует в качестве дескриптора для получения строки, которая должна быть равна «LETMEWIN».

Таким образом нам нужно послать программе строку «LETMEWIN» через стандартный поток ввода (stdin). Для этого дескриптор, который передается в функцию read(), должен быть равен 0. То есть в качестве параметра программы нужно использовать число 0х1234. Переведем его в десятичный вид.

Теперь запустим программу с параметром 4660, отпавим нужную строку и заберем флаг.

Структура каталога и дескриптора файла

Как мы уже говорили, любой каталог содержит 32-байтовые элементы – дескрипторы (Descriptor – дословно описатель, описательный элемент), описывающие файлы и другие каталоги. Поля дескриптора описывают различные характеристики файла (или каталога). Приведем формат дескриптора файла (Таблица 6):

Таблица 6 Формат дескриптора файла

Размер (байт) Поле
Имя файла или каталога
Расширение имени файла
Атрибуты файла.
Время создания файла или время его последней модификации
Дата создания файла или время его последней модификации
Номер первого кластера, распределённого файлу
Размер файла в байтах

Остановимся на понятии атрибутов файла. Атрибут – признак, дополнительно характеризующий некоторые свойства файла или каталога. В FAT атрибуты занимают один байт, каждый из атрибутов кодируется одним битом. Биты этого байта имеют следующие значения:

Таблица 7. Атрибуты файлов.

Бит Название атрибута Перевод Описание
R – READ ONLY только для чтения Файл предназначен только для чтения, в этот файл нельзя писать и его нельзя стирать.
Н–HIDDEN скрытый Файл скрывается от показа, пока явно не сказано обратное
S –SYSTEM системный Системный файл. Этот бит обычно установлен в файлах, являющихся составной частью операционной системы.
V–VOLUME том Данный дескриптор описывает метку диска. Для этого дескриптора поля имени файла и расширения имени файла должны рассматриваться как одно поле длиной 11 байтов. Это поле содержит метку диска.
D–DIRECTORY каталог Дескриптор описывает файл, являющийся подкаталогом данного каталога. Только операционная система может управлять этим атрибутом.
А–ARCHIVE Архивный (требующий архивации) Файл изменён после резервного копирования или не был скопирован программами резервного копирования (сейчас используется редко)

Информация, хранимая в атрибутах, используется операционной системой при выполнении файловых операций. Например, значение атрибута DIRECTORY позволяет отличать файл от подчиненного каталога, а по значению атрибута ARCHIVE отбираются файлы для резервного копирования. Атрибут READ ONLY запрещает изменять и удалять файл, а атрибут HIDDEN делает файл «невидимым». Биты атрибутов VOLUME и DIRECTORY может изменить только операционная система, остальные атрибуты могут изменяться пользователем.

Итак, мы видим, что в дескрипторе указывается имя и тип файла, длина, дата создания и некоторые его атрибуты, а также что важно, номер начального кластера этого файла. Если файл занимает один кластер мы имеем полную информацию о его размещении на диске, если файл не помещается в кластер для получении информации о его размещении нужно будет обратиться к таблице размещения файлов (FAT).

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Для студента самое главное не сдать экзамен, а вовремя вспомнить про него. 10034 — | 7498 — или читать все.

Базовые операции с файловой системой UNIX

Работа с каталогами

Утверждение все является файлом, составляющее философию UNIX®, означает, что работа с файлами и каталогами происходит постоянно, вне зависимости от того, с каким приложением в данный момент осуществляется работа. Все данные хранятся в файлах: от даты до конфигурационных файлов и данных об устройствах, и функции, которые содержатся в системном заголовочном файле stdio.h, станут вам знакомы уже через несколько часов программирования под UNIX.

Выбор способа, с помощью которого можно просматривать каталоги и обрабатывать файлы, каталоги и символические ссылки, найденные в нем, является типичной проблемой, с которой сталкиваются начинающие UNIX-программисты. Каким образом можно получить список содержимого каталога и определить, что оно означает?

В этой статье рассказывается, как использовать семейство функций, содержащихся в библиотечном файле dirent.h [ opendir()/readdir()/closedir() ] для просмотра записей каталога, и функцию stat() для интерпретации этой информации.

Учебный программный код, приведенный в этой статье (см. раздел Материалы для скачивания), был написан в среде Eclipse 3.1 при помощи расширения C/C++ Development Tools (CDT); проект readdir_demo project является проектом типа Managed Make, собранным с использованием правил генерации программ CDT. Makefile отсутствует в проекте, но он настолько простой, что если понадобится скомпилировать программу вне среды Eclipse, создать Makefile достаточно легко.

Среда Eclipse (см. раздел Ресурсы) – это отличная интегрированная среда разработки (integrated development environment, IDE), которая с каждой новой версией становится только лучше. Среда была создана разработчиками EMACS и Makefile. Если до сих пор вы не пользовались Eclipse, то обязательно попробуйте.

Получение содержимого каталога

Получив полный путь к каталогу, нужно просмотреть его записи. Каталог нельзя открыть подобно файлу при помощи функций open() или fopen() , а даже если и можно было бы открыть каталог таким образом, то представление полученных данных сильно зависело бы от используемой системы, и отличалось бы от того, с чем привык иметь дело обычный программист.

Функции из заголовочного файла dirent.h: opendir() , readdir() и closedir() – это то, что надо в подобной ситуации. Их применение очень схоже с использованием функций open/read/close при работе с файлами, но с одним исключением: функция readdir() возвращает указатель на специальную структуру (тип struct dirent ) для каждого элемента каталога. Пройти по содержимому каталога можно при помощи псевдокода из листинга 1.

Листинг 1. Чтение содержимого каталога

Функции opendir() и readdir() возвращают NULL , если возникла какая-то проблема, а в глобальную переменную errno записывается причина проблемы. Если readdir() возвращает NULL и errno равняется 0 (или, по-другому, EOK или ENOERROR ), это значит, что в каталоге больше нет записей.

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

Заметим, что readdir() не является многопоточной функцией, поскольку возвращаемая структура является статической переменной, которая хранится в библиотеке функции. Большинство современных UNIX-систем поддерживают многопоточную функцию readdir_r() , которую можно использовать вместо того чтобы писать свой многопоточный код.

Что находится в структуре struct dirent ?

Стандарт POSIX 1003.1 определяет только один необходимый элемент структуры struct dirent – массив элементов типа char с именем d_name . Это имя элемента каталога в виде стандартной NUL-завершенной строки. Все остальное в этой структуре зависит от конкретной UNIX-системы.

Все остальное, что находится в struct dirent , не является переносимым. Совместимые системы могут вообще не иметь других элементов в этой структуре. При создании программного кода, который использует дополнительные члены этой структуры, необходимо отмечать эти элементы как непереносимые, и в идеале включать в свой проект код, который делает те же самые операции, только без дополнительных элементов в struct dirent .

Например, многие UNIX-системы содержат поле d_type и несколько дополнительных констант, которые позволяют узнать тип элемента каталога без вызова функции stat() . Кроме избавления от необходимости лишний раз вызывать функцию это непереносимое расширение позволяет избежать занимающего много ресурсов запроса к файловой системе за подробными метаданными. Функция stat() на большинстве UNIX-систем работает медленно.

Получение информации о файле

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

Функция stat() заполняет структуру struct stat информацией об определенном файле; если вместо имени файла имеется файловый дескриптор, то можно использовать его совместно с fstat() . Если также необходимо обнаруживать символические ссылки, то вместе с именем файла следует использовать lstat() .

В отличие от struct dirent , которую возвращает readdir() , struct stat имеет довольно много обязательных стандартных полей:

  • st_mode – права доступа к файлу (пользователь, группа, остальные) и флаги.
  • st_ino – порядковый номер файла.
  • st_dev – устройство, на котором расположен файл.
  • st_nlink – счетчик числа связей.
  • st_uid – идентификатор пользователя-владельца файла.
  • st_gid – идентификатор группы-владельца.
  • st_size – размер файла в байтах (для файлов regular).
  • st_atime – время последнего доступа к файлу.
  • st_mtime – время последней модификации файла.
  • st_ctime – время создания файла.

Используя макрос S_*() для поля st_mode , можно определить тип файла:

  • S_ISBLK(mode) – специальный блочный файл? (обычно это блочное устройство).
  • S_ISCHR(mode) – специальный символьный файл? (обычно это символьное устройство).
  • S_ISDIR(mode) – каталог?
  • S_ISFIFO(mode) – UNIX-канал (pipe) или файл типа FIFO?
  • S_ISLNK(mode) – символическая ссылка?
  • S_ISREG(mode) – обычный файл?

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

Немного о символических ссылках

В обычной ситуации символические ссылки не заслуживают отдельного внимания. Результатом вызова stat() для символической ссылки будет информация о файле, на который эта ссылка указывает. Это соответствует привычным для пользователя приемам работы, так как права на доступ к целевому файлу, а не к самой символической ссылке, управляют взаимодействием с этим файлом.

Некоторые приложения, такие как ls и программы для резервного копирования, должны быть способны отобразить информацию о самой символической ссылке, например, на какой файл она указывает. Подобного результата можно добиться, используя lstat() вместо stat() ; этот способ пригодится на случай, если надо работать с самой символической ссылкой, а не с файлом, на который она указывает.

Совместное использование readdir() и stat()

Выше было показано, как при помощи readdir() и stat() получить информацию о содержимом каталога. Продемонстрируем программный код, который иллюстрирует применение этих функций.

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

Илон Маск рекомендует:  Тег ol

Как показано в листинге 2, в этом простом пробном приложении используются все заголовочные файлы. Наверху указаны стандартные файлы, которые используют все программы, а последние четыре файла необходимы для использования в этой программе readdir() и stat() .

Листинг 2. Заголовочные файлы

Функция process_directory() (которая начинает свою работу в листинге 3 и заканчивает в листинге 6) просматривает заданный каталог и выводит некоторую информацию о каждом элементе содержимого. Указатель DIR , возвращаемый функцией opendir() , идентичен указателю на файл ( FILE ), который возвращает функция fopen() ; это зависимый от типа ОС объект, который используется для прослеживания потока каталога, содержимое указателя DIR следует игнорировать.

Листинг 3. Обработка каталога

После открытия заданного каталога надо вызвать readdir_r() (листинг 4) для получения информации о первом элементе этого каталога; каждый последующий вызов readdir_r() возвращает следующий элемент до тех пор, пока не будет достигнут конец каталога и entryPtr не будет установлен в NULL . Также следует использовать strncmp() , чтобы игнорировать элементы . » и » .. «. Если нет необходимости пропускать обработку этих элементов, то обработка каталогов будет выполняться бесконечно (например, » theDir/./././././././././. » и так далее).

Листинг 4. Получение отдельного элемента

Теперь, когда получено имя элемента каталога, для него надо собрать абсолютный путь (листинг 5), а затем вызвать функцию lstat() для получения информации об этом элементе. Поскольку символическим ссылкам требуется особая обработка, в данном случае следует использовать lstat() . Целевой файл символической ссылки можно узнать при помощи функции readlink() .

Если элемент является каталогом, то для него выполняется рекурсивный вызов process_directory() и к общему числу обнаруженных элементов добавляются вновь найденные. Если элемент является файлом, выводятся его имя и размер (размер берется из поля st_size структуры struct stat ).

Листинг 5. Обработка отдельного элемента

В конце цикла while выполняются чтение и обработка еще одного элемента каталога (листинг 6). Если обработка элементов каталога закончена, то текущий рабочий каталог закрывается и возвращается число элементов, которые были обработаны.

Листинг 6. Чтение еще одного элемента

И, наконец, листинг 7 содержит функцию main() программы, которая вызывает функцию process_directory() для каждого аргумента, содержащегося в строке команды. В бизнес-приложении должен быть также предусмотрен вывод служебного сообщения на случай, если пользователь не задаст по крайней мере одного аргумента, но я оставлю этот аспект читателю для упражнения.

Листинг 7. Функция main

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

Заключение

Применяйте функции readdir() и stat() для просмотра содержимого каталога и определения дальнейших действий, которые необходимо выполнить над этими записями, и, возможно, для выполнения каких-то особенных, специфических задач во время обработки содержимого каталога. Хотя это весьма полезные функции, некоторые начинающие UNIX-разработчики считают их слишком сложными. Эта статья поможет таким UNIX-разработчикам быстро освоить readdir() и stat() .

Ресурсы для скачивания

  • этот контент в PDF
  • make проект для Eclipse 3.1 (au-readdir_demo.zip | 24KB)

Похожие темы

  • eclipse.org: сообщество разработчиков в Eclipse Platform.
  • C/C++ development with the Eclipse Platform (EN) (developerWorks, март 2006): статья об использовании C++ с Eclipse.(EN)
  • Open Group’s POSIX 1003.1: спецификация с подробной информацией о функциях readdir() и readdir_r() .(EN)
  • Спецификация функции stat() .(EN)
  • Спецификация функции lstat() .(EN)
  • Раздел developerWorks AIX and UNIX содержит сотни информативных статей для читателей начальной, средней и высокой квалификации.
  • Разделы библиотеки информации по темам AIX и UNIX:(EN)
    • Системное администрирование
    • Разработка приложений
    • Производительность
    • Переносимость
    • Безопасность
    • Подсказки
    • Инструментальные средства и утилиты
    • Java™-технологии
    • Linux®
    • Open source
  • IBM trial software: ознакомительные версии программного обеспечения для разработчиков, которые можно загрузить прямо со страницы сообщества developerWorks.(EN)
  • Podcasts: аудиозаписи презентаций экспертов IBM.(EN)

Комментарии

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

readdir — функция PHP

(PHP 3, PHP 4, PHP 5)

readdir — Получить элемент каталога по его дескриптору

Описание

Возвращает имя следующего по порядку элемента каталога. Имена элементов возвращаются в порядке, зависящем от файловой системы.

Обратите внимание на способ проверки значения, возвращаемого функцией readdir() в приведенном ниже примере. В этом примере осуществляется проверка значения на идентичность (выражения идентичны, когда они равны и являются значениями одного типа — за более подробной информацией обратитесь к главе Операторы сравнения) значению FALSE , поскольку в ином случае, любой элемент каталога, чье имя может быть выражено как FALSE , остановит цикл (например, элемент с именем «0»).

Пример 1. Вывести список всех файлов в каталоге

// Обратите внимание, что оператор !== не существовал до версии 4.0.0-RC2

if ( $handle = opendir ( ‘/path/to/files’ )) <
echo «Дескриптор каталога: $handle \n » ;
echo «Файлы:\n» ;

/* Именно этот способ чтения элементов каталога является правильным. */
while ( false !== ( $file = readdir ( $handle ))) <
echo «$file \n » ;
>

/* Этот способ НЕВЕРЕН. */
while ( $file = readdir ( $handle )) <
echo «$file \n » ;
>

closedir ( $handle );
>
?>

Обратите внимание, что функция readdir() также возвращает элементы с именами . и .. . Если вы не хотите получать эти значения, просто отбрасывайте их:

Пример 2. Получить список файлов в текущем каталоге и отбросить элементы с именами . и ..

if ( $handle = opendir ( ‘.’ )) <
while ( false !== ( $file = readdir ( $handle ))) <
if ( $file != «.» && $file != «..» ) <
echo «$file \n » ;
>
>
closedir ( $handle );
>
?>

См.также описания функций is_dir() и glob() .

Веб-библиотека

Поиск

Получение листинга каталога

Прежде чем выполнять операции с каталогом, необходимо создать его дескриптор. Дескриптор каталога напоминает дескриптор файла с тем лишь отличием, что при чтении считывается не файл, а содержимое каталога. Для открытия дескриптора каталога используется функция opendir:

В этом синтаксисе вместо имени_дескриптора следует указать дескриптор каталога, который вы хотите открыть, а вместо имени каталога — путь к каталогу, содержимое которого нужно прочитать. Если по какой-либо причине каталог нельзя открыть (например, у вас отсутствуют права на доступ к нему, либо просто указано имя несуществующего каталога), функция opendir возвращает значение false. При выборе имени дескриптора каталога следует руководствоваться теми же правилами, что и при выборе имени дескриптора файла (о них шла речь на 2-м занятии, «Строительные блоки Perl: числа и строки»). Всегда набирайте имя дескриптора прописными буквами, чтобы исключить возможный конфликт имен с ключевыми словами Perl, которые появятся в будущих версиях этого языка программирования. Вот пример использова-ния функции opendir: .

После открытия каталога доступ к его содержимому можно получить с помощью функции readdir:

В скалярном контексте функция readdir возвращает следующий по порядку элемент каталога или значение undef, если достигнут конец каталога. В контекстесписка функция readdir возвращает все оставшиеся элементы каталога. Имена, возвращаемые данной функцией, могут относиться как к файлам, так и к каталогам, а в системе UNIX — еще и к специальным файлам. Порядок их следования соответствует физическому расположению в каталоге. Другими словами, элементы каталога никак не сортируются. Кроме того, функция readdir возвращает еще два специальных элемента каталога: . и . которые соответствуют текущему и родительскому каталогам. В элементы каталога не включается путь.

После завершения работы с каталогом его дескриптор следует закрыть с помощью функции closedir:

В следующем примере продемонстрирована методика чтения каталога:

Здесь все содержимое каталога помещается в массив @FILES. Однако, чаще всего, из этого списка нужно исключить некоторые имена, например. И . поскольку для пользователя в них нет особого смысла. Для этого следует воспользоваться таким оператором чтения каталога:

В этом примере регулярное выражение /^\.\.?$/ соответствует строке текста, в которой находится как минимум одна точка. Функция grep отфильтровывает такие строки, поскольку перед регулярным выражением стоит оператор отрицания. Если нужно отобрать элементы каталога, содержащие заданное расширение, оператор чтения каталога будет выглядеть так:

Имена файлов, возвращаемые функцией readdir, не содержат путь, который мы указывали в функции opendir при открытии каталога. Поэтому следующий пример, скорее всего, не будет работать:

Кроме случаев, когда вы запускаете данную программу из каталога /tmp, при выполнении оператора open(FILEH, $file) будет возникать ошибка. Причина состоит в том, что программа читает список файлов каталога /tmp, а оператор open пытается открыть файл в текущем каталоге. Естественно, что если текущим является не каталог Дтр и имена файлов текущего каталога и каталога /tmp не совпадают, то функция open не будет находить файлы. Для решения проблемы в операторе open следует указать полный путь к файлу. Правильный код будет выглядеть так:

Отбор файлов заданного типа

Существует еще один метод получения списка нужных файлов заданного каталога, который называется отбором файлов (globbing). Если вы хоть немного работали с командной строкой DOS, то наверняка вам приходилось вводить команды наподобие dir *.txt. В данном случае команда dir выводит список всех файлов, имена которых имеют расширение *.txt. В UNIX понятие расширения файла отсутствует, однако отбор нужных файлов также можно осуществить с помощью командной оболочки. Например, аналог приведенной выше команды dir в UNIX выглядит так: Is *.txt. В результате будет получен список всех файлов, имена которых оканчиваются суффиксом .txt.

В Perl также предусмотрен специальный оператор glob, выполняющий описанные действия. Его синтаксис выглядит так:

Здесь параметр шаблон соответствует именам файлов, которые необходимо отобрать. Он может содержать путь, а также часть имени файла. Кроме того, в шаблоне может быть указано несколько специальных символов, описанных в табл. 10.1. В контексте списка оператор glob возвращает имена всех файлов и каталогов, имена которых соответствуют шаблону. В скалярном контексте при каждом вызове описываемый оператор возвращает имя следующего файла, соответствующего шаблону.

Ниже приведено несколько примеров отбора файлов.

Ниже приведен список основных отличий функции glob от opendir/readdir/closedir.

  • Функция glob может возвращать только ограниченное количество файлов. Если в каталоге будет находиться большое количество файлов, эта функция, скорее всего, аварийно завершит свое выполнение. Причина состоит в том, что в текущей версии Perl функция glob реализована с помощью сценария оболочки С, который может возвращать только ограниченное количество файлов. При использовании функций opendir/readdir/closedir подобная проблема не возникает.
  • Функция glob возвращает имя файла вместе с путем, который указан в шаблоне, тогда как функции opendir/readdir/closedir возвращают только имя файла. Например, оператор glob( ‘/usr/include/*.h’ ) к каждому возвращаемому имени файла добавляет путь /usr/include/.
  • Функция glob работает медленнее, чем opendir/readdir/closedir. Причина очевидна. Perl должен запустить внешнюю программу, которая выполнит отбор и сортировку файлов, а затем получить от нее данные и интерпретировать их.

Итак, исходя из этого, какими же средствами лучше всего воспользоваться для отбора файлов? Ответ один — теми, которыми вам удобнее. Однако стоит иметь в виду, что использование opendir/readdir/closedir позволяет создать более универсальный и гибкий код. Поэтому в большинстве примеров мы используем именно набор функций opendir/readdir/closedir.

Для полноты картины стоит упомянуть еще об одном способе отбора файлов. Просто поместите шаблон в угловые скобки (о); в результате угловой оператор превратится в некое подобие оператора glob, например:

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

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL