Программа в листинге 18.1 демонстрирует, что, даже когда удалена последняя ссылка на файл, сам он удаляется только после закрытия всех файловых дескрипторов, соотнесенных с ним.
Листинг 18.1. Удаление ссылки с помощью системного вызова unlink()
dirs_links/t_unlink.c
#include
#include
#include "tlpi_hdr.h"
#define CMD_SIZE 200
#define BUF_SIZE 1024
int
main(int argc, char *argv[])
{
int fd, j, numBlocks;
char shellCmd[CMD_SIZE]; /* Команда, передаваемая вызову system() */
char buf[BUF_SIZE]; /* Случайные байты для записи в файл */
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s temp-file [num-1kB-blocks] \n", argv[0]);
numBlocks = (argc > 2)? getInt(argv[2], GN_GT_0, "num-1kB-blocks")
: 100000;
fd = open(argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd == -1)
errExit("open");
if (unlink(argv[1]) == -1) /* Удаляем имя файла */
errExit("unlink");
for (j = 0; j < numBlocks; j++) /* Заполняем файл мусором */
if (write(fd, buf, BUF_SIZE)!= BUF_SIZE)
fatal("partial/failed write");
snprintf(shellCmd, CMD_SIZE, "df — k `dirname %s`", argv[1]);
system(shellCmd); /* Просмотр пространства,
занятого в файловой системе */
if (close(fd) == -1) /* Теперь файл удален */
errExit("close");
printf("********** Closed file descriptor\n");
system(shellCmd); /* Повторный просмотр пространства,
занятого в файловой системе */
exit(EXIT_SUCCESS);
}
dirs_links/t_unlink.c
Программа в листинге 18.1 принимает через командную строку два аргумента. Первый идентифицирует имя файла, который следует создать. Программа открывает этот файл, а затем немедленно разрывает связь с его именем. И хотя оно пропадает, сам файл продолжает существовать. Затем программа записывает произвольные блоки данных в этот файл. Количество их указано в необязательном втором аргументе командной строки. Здесь программа применяет команду df(1) для отображения величины занятого пространства в файловой системе.
Затем программа закрывает файловый дескриптор, и в этот момент происходит удаление файла. Далее она еще раз применяет команду df(1), чтобы показать уменьшение величины использованного дискового пространства. Следующий сеанс работы в оболочке демонстрирует применение программы из листинга 18.1:
$ ./t_unlink /tmp/tfile 1000000
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda10 5245020 3204044 2040976 62 % /
********** Closed file descriptor
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda10 5245020 2201128 3043892 42 % /
В листинге 18.1 задействована функция system() для выполнения команды оболочки. Мы подробно опишем эту функцию в разделе 27.6.
Системный вызов rename() можно использовать как для переименования файла, так и для его перемещения в другой каталог той же файловой системы.
#include
int rename(const char *
Возвращает 0 при успешном завершении или –1 при ошибке
Аргумент oldpath — существующее имя пути, которое будет переименовано на указанное в аргументе newpath.
Системный вызов rename() оперирует записями каталога; он не перемещает данные файла. Переименование не отражается на других жестких ссылках, связанных с этим файлом, оно не влияет также ни на какие процессы, удерживающие открытыми дескрипторы для данного файла, поскольку такие дескрипторы соотносятся с открытыми файловыми дескрипторами, которые (после вызова open()) не связаны с именами файлов.
С применением системного вызова rename() связаны следующие правила.
• Если файл по адресу newpath уже существует, то перезаписывается.
• Если аргументы newpath и oldpath ссылаются на один и тот же файл, то никаких изменений не производится (и вызов завершается успешно). Данное правило противоречит здравому смыслу. Если отталкиваться от предыдущего пункта, то можно было бы ожидать, что при наличии двух имен файлов x и y системный вызов rename("x", "y") удалил бы имя x. Но это не так, если x и y являются ссылками на один и тот же файл.
Разумным объяснением этого правила, восходящим к реализации BSD, является, вероятно, желание упростить проверки, которые должно было выполнять ядро, чтобы такие системные вызовы, как rename("x", "x"), rename("x", "./x") и rename("x", "somedir/../x"), не удаляли файл.
• Системный вызов rename() не разыменовывает символические ссылки в обоих аргументах. Если аргумент oldpath является символической ссылкой, она переименовывается. Если аргумент newpath является символической ссылкой, то она обрабатывается как обычное имя пути, на которое следует переименовать имя oldpath (то есть существующая символическая ссылка newpath удаляется).