::Главная страница :: С++/Си :: Статьи

Функции link, unlink, remove и rename

Как мы говорили ранее, любой файл может иметь несколько записей в директории, ука-зывающие на его I-node. Способ, которым мы создаем ссылку на существующий файл - по-средством функции link().

#include <unistd.h>
int link(const char *existingpath, const char *newpath);
    Return: 0 если OK, -1 при ошибке

Эта функция создает новый элемент каталога, newpath, который ссылается на сущест-вующий файл existingpath. Создание нового элемента каталога и увеличение счетчика ссылок должно быть элементарной операцией. Только процесс суперпользователя может создать ссыл-ку, которая указывает на директорию. Причина состоит в том, что при этом возможно зацикли-вание в файловой системе. При этом, большинство утилит, завязанных в работе файловой сис-темы, неспособны функционировать. Мы рассмотрим зацикливание на примере символических ссылок чуть позже.

Чтобы удалить существующий элемент директория, мы вызываем функцию unlink().

#include <unistd.h>
int unlink(const char *pathname);
    Return: 0 если OK, -1 при ошибке

Эта функция удаляет элемент директория и уменьшает количество ссылок на файл, ука-зываемый pathname.

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

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

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

Пример 3.5


/* Файл test_unlink.c
*/
#include 
#include 
#include 
#include "errorx.h"
int main()
{
   if(open("tempfile",O_RDWR")
 err_sys("open error");
  if(unlink("tempfile") <0)
 err_sys("unlink error");

  printf("file unlinked\n");
  sleep(15);
  printf("done\n");

  exit(0);
 }
Программа 3.5 открывает файл и затем удаляет его. Затем она засыпает на 15 секунд пе-ред завершением.

Запуск этой программы дает нам:


$ ls -l tempfile  смотрим насколько большой этот файл
-rw-r--r--   1 aster 9240990 Jul 31 13:42   tempfile

$ df /home   сколько доступно свободного места
Filesystem     Kbytes      used       avail     capacity   Mounted on
/dev/hda1      282908    181979   72368       71%      /home

$ ./test_unlink &  Запускаем программу в фоновом режиме
1364    Шелл выдает ID процесса
$ file unlinked   Файл удален

ls -l tempfile   Смотрим на месте ли файл
tempfile not found  Элемента директория уже нет

$ df /home   сколько доступно свободного места
Filesystem     Kbytes      used       avail     capacity   Mounted on
/dev/hda1      282908    181979   72368       71%      /home

$ done    программа завершена, все открытые файлы закрываются
df /home   теперь дисковое пространство должно быть свободно
Filesystem     Kbytes      used       avail     capacity   Mounted on
/dev/hda1      282908    172939   81678       68%      /home
    теперь 9.2 Мб свободно

Свойство функции unlink() часто используется программой для гарантии того, что вре-менный файл, который она создает не будет оставлен, в случае, если программа аварийно за-вершит работу. Процесс создает файл, используя либо open() или crate() и сразу же вызывает unlink(). Файл не удаляется, поскольку все еще открыт. Только когда процесс либо закроет файл или завершиться (в этом случае ядро само закроет все открытые файлы) файл будет удален.

Если pathname это символическая ссылка, unlink() ссылается на символическую ссылку, а не на файл на который та указывает.

Суперпользователь может вызвать unlink() с pathname, указывающим на директорию, но для удаления директории должна быть использована функция rmdir().

Мы также можем удалить файл или директорию, вызвав функцию remove(). Для файла remove() идентична unlink(), а для директории - rmdir().

#include <stdio.h>
int remove(const char *pathname);
    Return: 0 если OK, -1 при ошибке

Файл или директорий переименовываются с помощью функции rename().

#include <stdio.h>
int rename(const char *oldname, const char *newname);
    Return: 0 если OK, -1 при ошибке

Рассмотрим два условия, в зависимости от того ссылается ли oldname на файл или на ди-ректорий. Мы опишем также, что произойдет, если newname уже существует.

  1. Если oldname специфицирует файл, который не является директорием, тогда мы переименовываем файл. В этом случае, если newname существует, он не может ссылаться на директорий. Если newname существует (и это не директо-рий), он удаляется и oldname переименовывается в newname. Мы должны обла-дать правами записи на диреторий, содержащей oldname и для директория, со-держащего newname.
  2. Если oldname специфицирует директорий, тогда мы переименовываем директо-рию. Если newname существует, он должен ссылаться на директорий и этот ди-ректорий должен быть пуст. (Когда мы говорим, что директорий пуст - это оз-начает, что там имеются только два элемента: точка, точка-точка). Если new-name существует (и это пустой директорий), он удаляется и oldname переиме-новывается в newname. Дополнительно, когда мы переименовываем директо-рий, newname не может содержать путевой префикс, который именует oldname. Например, мы не можем переименовать /usr/foo в /usr/foo/testdir, так как старое имя (/usr/foo) это путевой префикс для нового имени и не может быть удален.
  3. Как специальный случай, если oldname и newname ссылаются на один и тот же файл, функция возвращает OK без изменения чего-либо.

Если newname уже существует, нам необходимы права доступа, как если бы мы его уда-ляли. Поскольку мы удаляем элемент директория для oldname и возможно создаем элемент ди-ректория для newname, нам нужны права записи и выполнения в директории, содержащие old-name и newname.

Символические ссылки

Символическая ссылка это косвенный указатель на файл, в отличие от жестких ссылок, которые указывали прямо на I-node файла. Символические ссылки были введены для обхода ограничений, связанных с жесткими ссылками: (a) жесткие ссылки обычно требуют, чтобы ссылка и файл размещались в одной файловой системе, и (b) только суперпользователь может создать жесткую ссылку на директорию. Символические ссылки не накладывают никаких огра-ничений на файловую систему и на что они указывают, и любой пользователь может создать символическую ссылку на директорий. Символические ссылки типично используются, чтобы переместить файл или целую иерархию директория в другое местоположение в системе.

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

Используя символические ссылки возможно ввести файловую систему в состояние за-цикливания. Большинство функций которые просматривают путевое имя возвращают перемен-ную errno установленную в ELOOP, когда это происходит. Рассмотрим следующие команды:


$ mkdir foo   создаем новый директорий
$ touch foo/a   создаем файл нулевой длины
$ ln -s ./foo  foo/testdir создаем символическую ссылку

$ ls -l foo
taotal 1
-rw-rw-r--     1   aster   0  Dec 6  06:06  a
lrwxrwxrwx  1   aster  6  Dec 6  06:06  testdir->./foo

Этот набор команд создает директорий foo который содержит файл a и символическую ссылку, которая указывает на foo. Мы показали такое расположение на рис 3.4, рисуя директо-рий как кружок, а файл как квадратик.

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


foo
foo/a
foo/testdir
foo/testdir/a
foo/testdir/testdir/
foo/testdir/testdir/a
foo/testdir/testdir/testdir
foo/testdir/testdir/testdir/a
(many more lines)
ftw return -1: Too many levels of symbolic links

Мы предоставим, нашу собственную версию функции ftw(), которая использует функ-цию lstat взамен stat, чтобы предупредить следование за символическими ссылками.

Цикл такой формы легко удалить - мы способны удалить файл foo/testdir, поскольку unlink() не следит за символической ссылкой. Но если мы создадим жесткую ссылку которая формирует цикл такого типа, его удаление гораздо сложнее. Вот почему функция link не фор-мирует жесткие ссылки на директории, до тех пор пока процесс не имеет привилегий супер-пользователя.

Когда мы открываем файл, если путевое имя передаваемое функции open() специфици-рует символическую ссылку, open() следует за ссылкой к указанному файлу. Если файл, указы-ваемый символической ссылкой не существует, open() возвращает ошибку, говоря, что она не может открыть файл. Это может запутать пользователей, что не привык к ссылкам. Например:


$ ln -s /no/such/file myfile  создаем символическую ссылку
$ ls myfile
myfile     ls говорит, что файл там
$ cat myfile   поэтому мы пытаемся открыть его
cat: myfile: No such file or directory
$ ls -l myfile
lrwxrwxrwx   1   aster   13 Dec 6 07:00  myfile->/no/such/file

Файл myfile не существует, и cat говорит, что нет такого файла, поскольку myfile - это символическая ссылка и файл на который она указывает - не существует. Опция -l к команде ls дает нам две подсказки: первый символ - l, который означает символическую ссылку, и после-довательность -> также указывающая на символическую ссылку.
Тематические ссылки
Ваша ссылка Ваша ссылка

Обмен кнопками, ведение статистики, реклама.