Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
практична робота 7.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
253 Кб
Скачать
☆

Системні виклики і команди для виконання операцій над файлами і директоріями

В матеріалах попередніх практичних занять вже мовилося про деякі команди і системні виклики, що дозволяють виконувати операції над файлами в операційній системі UNIX.

Вся інформація про атрибути файлу і його розташовують на фізичному носії міститься у відповідному файлу індексному вузлі і, можливо, в декількох пов'язаних з ним логічних блоках. Для того, щоб при кожній операції над файлом не прочитувати цю інформацію з фізичного носія наново, представляється логічним, прочитавши інформацію один раз при першому зверненні до файлу, берегти її в адресному просторі процесу або в частині адресного простору ядра, що характеризує даний процес. Саме тому в лекції 2 дані про файли, що використовуються процесом, були віднесено до складу системного контексту процесу, що міститься в його PCB.

З погляду призначеного для користувача процесу кожний файл є лінійним набором байт, забезпечений покажчиком поточної позиції процесу в цьому наборі. Всі операції читання з файлу і запису у файл проводяться в цьому наборі з того місця, на яке показує покажчик поточної позиції. Після закінчення операції читання або запису покажчик поточної позиції поміщається після кінця прочитаної або записаної ділянки файлу. Значення цього покажчика є динамічною характеристикою файлу для використовуючого його процесу і також повинне зберігатися в PCB.

Насправді організація інформації, що описує відкриті файли в адресному просторі ядра операційної системи UNIX, є складнішою.

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

Незалежне використовування одного і того ж файлу декількома процесами в операційній системі UNIX припускає можливість для кожного процесу скоювати операції читання і запису у файл на свій розсуд. При цьому для коректної роботи з інформацією необхідно організовувати ті, що взаємовиключають для операцій уведення-виведення. Сумісне використовування одного і того ж файлу в операційній системі UNIX можливе для близько споріднених процесів, тобто процесів, один з яких є нащадком іншого або які мають загального батька. При сумісному використовуванні файлу процеси розділяють деякі дані, необхідні для роботи з файлом, зокрема, покажчик поточної позиції. Операції читання або запису, виконані в одному процесі, змінюють значення покажчика поточної позиції у всіх близько споріднених процесах, одночасно використовуючих цей файл.

Як ми бачимо, вся інформація про файл, необхідна процесу для роботи з ним, може бути розбита на три частини:

  • дані, специфічні для цього процесу;

  • дані, загальні для близько споріднених процесів, сумісно використовуючих файл, наприклад, покажчик поточної позиції;

  • дані, що є загальними для всіх процесів, що використовують файл, – атрибути і розташовують файлу.

Мал. 11-12.2.  Взаємозв'язки між таблицями, що містять дані про відкриті файли в системі

Природно, що для зберігання цієї інформації застосовуються три різні зв'язані структури даних, лежачі, як правило, в адресному просторі ядра операційної системи, – таблиця відкритих файлів процесу, системна таблиця відкритих файлів і таблиця індексних вузлів відкритих файлів. Для доступу до цієї інформації в управляючому блоці процесу заводиться таблиця відкритих файлів, кожний непорожній елемент якої містить посилання на відповідний елемент системної таблиці відкритих файлів, що містить дані, необхідні для сумісного використовування файлу близько спорідненими процесами. З системної таблиці відкритих файлів ми, у свою чергу, можемо по посиланню дістатися до загальних даних про файл, що містяться в таблиці індексних вузлів відкритих файлів (див. рис. 11–12.2). Тільки таблиця відкритих файлів процесу входить до складу нього PCB і, відповідно, успадковується при народженні нового процесу. Індекс елемента в цій таблиці (невелике ціле ненегативне число) або файловий дескриптор є тією величиною, що характеризує файл, яку може оперувати процес при роботі на рівні користувача. В цю ж таблицю відкритих файлів поміщаються і посилання на дані, що описують інші потоки уведення-виведення, такі як pipe і FIFO.

Системний виклик open(). Для виконання більшості операцій над файлами через системні виклики призначений для користувача процес звичайно повинен вказати як один з параметрів системного виклику дескриптор файлу, над яким потрібно вчинити операцію. Тому, перш ніж скоювати операції, ми повинні помістити інформацію про файл в наші таблиці файлів і визначити відповідний файловий дескриптор. Для цього, як вже мовилося в попередніх заняттях, застосовується процедура відкриття файлу, здійснювана системним викликом open(). При відкритті файлу операційна система перевіряє, чи відповідають права, які запитав процес для операцій над файлом, правам доступу, встановленим для цього файлу. У разі відповідності вона поміщає необхідну інформацію в системну таблицю файлів і, якщо цей файл не був раніше відкритий іншим процесом, в таблицю індексних дескрипторів відкритих файлів. Далі операційна система знаходить порожній елемент в таблиці відкритих файлів процесу, встановлює необхідний зв'язок між всіма трьома таблицями і повертає на призначений для користувача рівень дескриптор цього файлу.

По суті справи, за допомогою операції відкриття файлу операційна система здійснює відображення з простору імен файлів в дисковий простір файлової системи, готуючи грунт для виконання інших операцій.

Системний виклик close(). Зворотним системним викликом по відношенню до системного виклику open() є системний виклик close(), з яким ми вже познайомилися. Після завершення роботи з файлом процес звільняє виділені ресурси операційної системи і, можливо, синхронізує інформацію про файл, що міститься в таблиці індексних вузлів відкритих файлів, з інформацією на диску, використовуючи цей системний виклик. Треба відзначити, що місце в таблиці індексних вузлів відкритих файлів не звільняється по системному виклику close() до тих пір, поки в системі існує хоча б один процес, що використовує цей файл. Для забезпечення такої поведінки в ній для кожного індексного вузла заводиться лічильник числа відкриттів, що збільшується на 1 при кожному системному виклику open() для даного файлу і що зменшується на 1 при кожному його закритті. Очищення елемента таблиці індексних вузлів відкритих файлів з остаточною синхронізацією даних в пам'яті і на диску відбувається тільки в тому випадку, якщо при черговому закритті файлу цей лічильник стає рівним 0.

Поведінка таблиці відкритих файлів процесу і пов'язаних з нею таблиць при системних викликах exit(), exec() і fork() розглядалося в матеріалах практичного заняття 5.

Операція створення файлу. Системний виклик creat(). При обговоренні системного виклику open() детально розказувалося про його використовування для створення нового файлу. Для цих же цілей можна використовувати системний виклик creat(), є, по суті, урізаним варіантом виклику open() (про значення прапора O_TRUNC для системного виклику open() буде сказано трохи нижче).

Системний виклик creat()

#include <fcntl.h>

int creat(char *path, int mode);

Опис системного виклику

Системний виклик creat еквівалентний системному виклику open() з параметром flags, встановленим в значення O_CREAT | O_WRONLY | O_TRUNC.

Параметр path є покажчиком на рядок, що містить повне або відносне ім'я файлу.

Якщо файлу з вказаним ім'ям не існувало до моменту системного виклику, він буде створений і відкритий тільки для виконання операцій запису. Якщо файл вже існував, то він відкривається також тільки для операції запису, при цьому його довжина зменшується до 0 з одночасним збереженням всіх інших атрибутів файлу.

Параметр mode встановлює атрибути прав доступу різних категорій користувачів до нового файлу при його створенні. Цей параметр задається як сума наступних вісімкових значень:

  • 0400 – дозволено читання для користувача, що створив файл.

  • 0200 – дозволений запис для користувача, що створив файл.

  • 0100 – дозволено виконання для користувача, що створив файл.

  • 0040 – дозволено читання для групи користувача, що створив файл.

  • 0020 – дозволений запис для групи користувача, що створив файл.

  • 0010 – дозволено виконання для групи користувача, що створив файл.

  • 0004 – дозволено читання для всієї решти користувачів

  • 0002 – дозволений запис для всієї решти користувачів

  • 0001 – дозволено виконання для всієї решти користувачів

При створенні файлу реально встановлювані права доступу виходять із стандартної комбінації параметра mode і маски створення файлів поточного процесу umask, а саме – вони рівні mode & ~umask.

Значення, що повертається

Системний виклик повертає значення файлового дескриптора для відкритого файлу при нормальному завершенні і значення -1 при виникненні помилки.

Операція читання атрибутів файлу. Системні виклики stat(), fstat() і lstat(). Для читання всіх атрибутів файлу в спеціальну структуру можуть застосовуватися системні виклики stat(), fstat() і lstat(). Роз'яснення понять жорсткого і м'якого (символічної) зв'язку, що зустрічаються в описі системних викликів, буде дано пізніше при розгляді операцій скріплення файлів.

Системні виклики для читання атрибутів файлу

#include <sys/stat.h>

#include <unistd.h>

int stat(char *filename

struct stat *buf);

int fstat(int fd, struct stat *buf);

int lstat(char *filename

struct stat *buf);

Справжній опис не є повним описом цих системних викликів, а пристосовано для цілей даного курсу. Для отримання повного опису звертайтеся в UNIX Manual.

Системні виклики stat, fstat і lstat служать для отримання інформації про атрибути файлу.

Системний виклик stat читає інформацію про атрибути файлу, на ім'я якого указує параметр filename, і заповнює ними структуру, розташовану за адресою buf. Помітимо, що ім'я файлу повинне бути повним, або повинне будуватися щодо тієї директорії, яка є поточною для процесу, що вчинив виклик. Якщо ім'я файлу відноситься до файлу типу "зв'язок", то читається інформація (рекурсивно!) про атрибути файлу, на який указує символічний зв'язок.

Системний виклик lstat ідентичний системному виклику stat за одним виключенням: якщо ім'я файлу відноситься до файлу типу "зв'язок", то читається інформація про самий файл типу "зв'язок".

Системний виклик fstat ідентичний системному виклику stat, тільки файл задається не ім'ям, а своїм файловим дескриптором (природно, файл до цього моменту повинен бути відкритий).

Для системних викликів stat і lstat процесу не потрібні ніякі права доступу до вказаного файлу, але можуть знадобитися права для пошуку у всіх директоріях, що входять в специфіковане ім'я файлу.

Структура stat в різних версіях UNIX може бути описана по-різному. В Linux вона містить наступні поля:

struct stat {

dev_t st_dev;

/* пристрій, на якому розташований файл */

ino_t st_ino;

/* номер індексного вузла для файлу */

mode_t st_mode;

/* тип файлу і права доступу до нього */

nlink_t st_nlink;

/* лічильник числа жорстких зв'язків */

uid_t st_uid;

/* ідентифікатор користувача власника */

gid_t st_gid;

/* ідентифікатор групи власника */

dev_t st_rdev;

/*тип пристрої для спеціальних файлів

устройств*/

off_t st_size;

/* розмір файлу в байтах (якщо визначений для даного типу файлів) */

unsigned long st_blksize;

/* розмір блоку для файлової системи */

unsigned long st_blocks;

/* число виділених блоків */

time_t st_atime;

/* час останнього доступу до файлу */

time_t st_mtime;

/* час останньої модифікації файлу */

time_t st_ctime;

/* час створення файлу */

}

Для визначення типу файлу можна використовувати наступні логічні макроси, застосовуючи їх до значення поля st_mode:

  • S_ISLNK(m) – файл типу "зв'язок"?

  • S_ISREG(m) – регулярний файл?

  • S_ISDIR(m) – директорія?

  • S_ISCHR(m) – спеціальний файл символьного пристрою?

  • S_ISBLK(m) – спеціальний файл блокового пристрою?

  • S_ISFIFO(m) – файл типа FIFO?

  • S_ISSOCK(m) – файл типу "socket"?

Молодші 9 біт поля st_mode визначають права доступу до файлу подібно тому, як це робиться в масці створення файлів поточного процесу.

Значення, що повертається

Системні виклики повертають значення 0 при нормальному завершенні і значення -1 при виникненні помилки.

Операції зміни атрибутів файлу. Більшість операцій зміни атрибутів файлу звичайно виконується користувачем в інтерактивному режимі за допомогою команд операційної системи. Про них вже йшла мова в матеріалах практичних занять 1–2, і ми не повертатимемося до них знов. Відзначимо тільки операцію зміни розмірів файлу, а точніше операцію його обрізання, без зміни всіх інших атрибутів, окрім, мабуть, часу останнього доступу до файлу і його останньої модифікації. Для того, щоб зменшити розміри існуючого файлу до 0, не зачіпаючи решти його характеристик (прав доступу, дати створення, облікової інформації і т.д.), можна при відкритті файлу використовувати в комбінації прапорів системного виклику open() прапор O_TRUNC. Для зміни розмірів файлу до будь-якої бажаної величини (навіть для його збільшення в багатьох варіантах UNIX, хоча спочатку цього не передбачалося!) може використовуватися системний виклик ftruncate(). При цьому, якщо розмір файлу ми зменшуємо, то вся інформація в кінці файлу, що не влізає в новий розмір, буде втрачена. Якщо ж розмір файлу ми збільшуємо, то це виглядатиме так, як ніби ми доповнили його до бракуючого розміру нульовими байтами.

Системний виклик ftruncate()

#include <sys/types.h>

#include <unistd.h>

int ftruncate(int fd, size_t length);

Опис системного виклику

Системний виклик ftruncate призначений для зміни довжини відкритого регулярного файлу.

Параметр fd є дескриптором відповідного файлу, тобто значенням, яке повернув системний виклик open().

Параметр length – значення нової довжини для цього файлу. Якщо параметр length менше ніж поточна довжина файлу, то вся інформація в кінці файлу, що не влізає в новий розмір, буде втрачена. Якщо ж він більше, ніж поточна довжина, то файл виглядатиме так, як ніби ми доповнили його до бракуючого розміру нульовими байтами.

Значення, що повертається

Системний виклик повертає значення 0 при нормальному завершенні і значення -1 при виникненні помилки.

Операції читання з файлу і запису у файл. Для операцій читання з файлу і запису у файл застосовуються системні виклики read() і write(), які ми вже обговорювали раніше.

Треба відзначити, що їх поведінка при роботі з файлами має певні особливості, пов'язані з поняттям покажчика поточної позиції у файлі.

При роботі з файлами інформація записується у файл або читається з нього, починаючи з місцем, визначуваним покажчиком поточної позиції у файлі. Значення покажчика збільшується на кількість реально прочитаних або записаних байт. При читанні інформації з файлу вона не пропадає з нього. Якщо системний виклик read повертає значення 0, то це означає, що досягнутий кінець файлу.

Операція зміни покажчика поточної позиції. Системний виклик lseek(). З погляду процесу всі регулярні файли є файлами прямого доступу. У будь-який момент процес може змінити положення покажчика поточної позиції у відкритому файлі за допомогою системного виклику lseek().

Особливістю цього системного виклику є можливість приміщення покажчика поточної позиції у файлі за кінець файлу (тобто можливість встановлення значення покажчика більшого, ніж довжина файлу).

При будь-якій подальшій операції запису в такому положенні покажчика файл виглядатиме так, як ніби виниклий проміжок від кінця файлу до поточної позиції, де починається запис, був заповнений нульовими байтами. Якщо операції запису в такому положенні покажчика не проводиться, то ніякої зміни файлу, пов'язаного з незвичайним значенням покажчика, не відбудеться (наприклад, операція читання повертатиме нульове значення для кількості прочитаних байтів).

Системний виклик lseek()

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset

int whence);

Опис системного виклику

Системний виклик lseek призначений для зміни положення покажчика поточної позиції у відкритому регулярному файлі.

Параметр fd є дескриптором відповідного файлу, тобто значенням, яке повернув системний виклик open().

Параметр offset спільно з параметром whence визначають нове положення покажчика поточної позиції таким чином:

  • Якщо значення параметра whence рівне SEEK_SET, то нове значення покажчика складатиме offset байт від початку файлу. Природно, що значення offset в цьому випадку повинне бути не негативним.

  • значення параметра whence рівне SEEK_CUR, те нове значення покажчика складатиме старе значення покажчика + offset байт. При цьому нове значення покажчика не повинне стати негативним.

  • Якщо значення параметра whence рівне SEEK_END, то нове значення покажчика складатиме довжина файлу + offset байт. При цьому нове значення покажчика не повинне стати негативним.

Системний виклик lseek дозволяє виставити поточне значення покажчика за кінець файлу (тобто зробити його перевищуючим розмір файлу). При будь-якій подальшій операції запису в цьому положенні покажчика файл виглядатиме так, як ніби виниклий проміжок був заповнений нульовими бітами.

Тип даних off_t звичайно є синонімом типу long.

Значення, що повертається

Системний виклик повертає нове положення покажчика поточної позиції в байтах від початку файлу при нормальному завершенні і значення -1 при виникненні помилки.

Операції створення зв'язків. Команда ln, системні виклики link() і symlink(). З операціями, що дозволяють змінювати логічну структуру файлової системи, такими як створення файлу, ми вже стикалися в цьому розділі. Проте операції створення зв'язку служать для проведення нових іменованих ребер у вужі існуючій структурі без додавання нових вузлів або для опосередкованого проведення іменованого ребра до вже існуючого вузла через файл типу "зв'язок" і неіменоване ребро. Такі операції ми дотепер не розглядали, тому давайте зупинимося на них докладніше.

Припустимо, що декілька програмістів спільно ведуть роботу над одним і тим же проектом. Файли, що відносяться до цього проекту, цілком природно можуть бути виділені в окрему директорію так, щоб не змішуватися з файлами інших користувачів і іншими файлами програмістів, що беруть участь в проекті. Для зручності кожний з розробників, звичайно, хотів би, щоб ці файли знаходилися в його власній директорії. Цього можна б було добитися, копіюючи у міру зміни нові версії відповідних файлів з директорії одного виконавця в директорію іншого виконавця. Проте тоді, по-перше, виникне непотрібне дублювання інформації на диску. По-друге, з'явиться необхідність рішення важкої задачі: синхронізації оновлення заміни всіх копій цих файлів новими версіями.

Існує інше рішення проблеми. Достатньо дозволити файлам мати декілька імен. Тоді одному фізичному екземпляру даних на диску можуть відповідати різні імена файлу, що знаходяться в одній або в різних директоріях. Подібна операція привласнення нового імені файлу (без знищення раніше існуючого імені) одержала назву операції створення зв'язку.

В операційній системі UNIX зв'язок може бути створена двома різними способами.

Перший спосіб, найбільш точно наступний описаній вище процедурі, одержав назву способу створення жорсткого зв'язку (hard link). З погляду логічної структури файлової системи цьому способу відповідає проведення нового іменованого ребра з вузла, відповідного деякій директорії, до вузла, відповідному файлу будь-якого типу, одержуючому додаткове ім'я. З погляду структур даних, що описують будову файлової системи, в цю директорію додається запис, що містить додаткове ім'я файлу і номер його індексного вузла (вже існуючий!). При такому підході і нове ім'я файлу, і його старе ім'я або імена абсолютне рівноправні для операційної системи і можуть взаємозамінний використовуватися для здійснення всіх операцій.

Використовування жорстких зв'язків приводить до виникнення двох проблем.

Перша проблема пов'язана з операцією видалення файлу. Якщо ми хочемо видалити файл з деякої директорії, то після видалення з її вмісту запису, відповідного цьому файлу, ми не можемо звільнити логічні блоки, займані файлом, і його індексний вузол, не переконавшися, що у файлу немає додаткових імен (до його індексного вузла не ведуть посилання з інших директорій), інакше ми порушимо цілісність файлової системи. Для вирішення цієї проблеми файли одержують додатковий атрибут – лічильник жорстких зв'язків (або іменованих ребер), що ведуть до них, який, як і інші атрибути, розташовується в їх індексних вузлах. При створенні файлу цей лічильник набуває значення 1. При створенні кожного нового жорсткого зв'язку, що веде до файлу, він збільшується на 1. Коли ми видаляємо файл з деякої директорії, то з її вмісту віддаляється запис про цей файл, і лічильник жорстких зв'язків зменшується на 1. Якщо його значення стає рівним 0, відбувається звільнення логічних блоків і індексного вузла, виділеного цьому файлу.

Друга проблема пов'язана з небезпекою перетворення логічної структури файлової системи з ациклічного графа в циклічного і з можливою невизначеністю тлумачення запису з ім'ям ".." у вмісті директорій. Для їх запобігання у всіх існуючих варіантах операційної системи UNIX заборонено створення жорстких зв'язків, що ведуть до вже існуючих директорій (не дивлячись на те, що POSIX-стандарт для операційної системи UNIX дозволяє подібну операцію для користувача root). Тому ми і говорили про те, що у вузол, відповідний файлу типу "директорія", не може вести більш одного іменованого ребра. (В операційній системі Linux з незрозумілої причини додатково заборонено створення жорстких зв'язків, ведучих до спеціальних файлів пристроїв.)

Команда ln

ln [options] source [dest]

ln [options] source ... directory

Опис команди

Справжній опис не є повним описом команди ln, а описує тільки її опції, що використовуються в даному курсі. Для отримання повного опису звертайтеся до UNIX Manual

Команда ln призначена для реалізації операції створення зв'язку у файловій системі. В нашому курсі ми використовуватимемо дві форми цієї команди.

Перша форма команди, коли як параметр source задається ім'я тільки одного файлу, а параметр dest відсутній, або коли як параметр dest задається ім'я файлу, не існуючого у файловій системі, створює зв'язок до файлу, вказаного як параметр source, в поточній директорії з його ім'ям (якщо параметр dest відсутній) або з ім'ям dest (повним або відносним) у разі наявності параметра dest.

Друга форма команди, коли як параметр source задаються імена одного або декількох файлів, розділені між собою пропусками, а як параметр directory задається ім'я вже існуючої у файловій системі директорії, створює зв'язки до кожного з файлів, перерахованих в параметрі source, в директорії directory з іменами, співпадаючими з іменами перерахованих файлів.

Команда ln без опцій служить для створення жорстких зв'язків (hard link), а команда ln з опцією –s – для створення м'яких (soft link) або символічних (symbolic) зв'язків.

Примітка: у всіх існуючих версіях UNIX (не дивлячись на стандарт POSIX) заборонено створення жорстких зв'язків до директорій. Операційна система Linux забороняє також, з незрозумілих причин, створення жорстких зв'язків до спеціальних файлів пристроїв.

Для створення жорстких зв'язків застосовуються команда операційної системи ln без опцій і системний виклик link().

Треба відзначити, що системний виклик link() є одним з небагатьох системних викликів, що скоюють операції над файлами, які не вимагають попереднього відкриття файлу, оскільки він має на увазі виконання одиничної дії тільки над вмістом індексного вузла, виділеного зв'язуваному файлу.

Системний виклик link()

#include <unistd.h>

int link(char *pathname

char *linkpathname);

Опис системного виклику

Системний виклик link служить для створення жорсткого зв'язку до файлу з ім'ям, на яке указує параметр pathname. Покажчик на ім'я створюваного зв'язку задається параметром linkpathname (повне або відносне ім'я зв'язку). У всіх існуючих реалізаціях операційної системи UNIX заборонено створювати жорсткі зв'язки до директорій. В операційній системі Linux (з незрозумілої причини) додатково заборонено створювати жорсткі зв'язки до спеціальних файлів пристроїв.

Значення, що повертається

Системний виклик повертає значення 0 при нормальному завершенні і значення -1 при виникненні помилки.

Другий спосіб створення зв'язку одержав назву способу створення м'якого (soft) або символічного (symbolic) зв'язку (link). Тоді як жорсткий зв'язок файлів є аналогом використовування прямих посилань (покажчиків) в сучасних мовах програмування, символічний зв'язок, до деякої міри, нагадує непрямі посилання (покажчик на покажчик). При створенні м'якого зв'язку з ім'ям symlink з деякої директорії до файлу, заданого повним або відносним ім'ям linkpath, в цій директорії дійсно створюється новий файл типу "зв'язок" з ім'ям symlink з своїми власними індексним вузлом і логічними блоками. При ретельному розгляді можна знайти, що весь його вміст складає тільки символьний запис імені linkpath. Операція відкриття файлу типу "зв'язок" влаштована таким чином, що насправді відкривається не сам цей файл, а той файл, чиє ім'я міститься в ньому (при необхідності рекурсивно!). Тому операції над файлами, що вимагають попереднього відкриття файлу (як, втім, і більшість команд операційної системи, що скоюють дії над файлами, де операція відкриття файлу присутня, але прихована від користувача), в реальності скоюватимуться не над файлом типу "зв'язок", а над тим файлом, ім'я якого міститься в ньому (або над тим файлом, який, врешті-решт, відкриється при рекурсивних посиланнях). Звідси, зокрема, витікає, що спроби прочитати реальний вміст файлів типу "зв'язок" за допомогою системного виклику read() приречені на невдачу. Як видно, створення м'якого зв'язку, з погляду зміни логічної структури файлової системи, еквівалентно опосередкованому проведенню іменованого ребра до вже існуючого вузла через файл типу "зв'язок" і неіменоване ребро.

Створення символічного зв'язку не приводить до проблеми, пов'язаної з видаленням файлів. Якщо файл, на який посилається м'який зв'язок, віддаляється з фізичного носія, то спроба відкриття файлу м'якого зв'язку (а, отже, і видаленого файлу) приведе до помилки "Файлу з таким ім'ям не існує", яка може бути акуратно оброблена додатком. Таким чином, видалення зв'язаного об'єкту, як згадувалося раніше, лише частково і не фатально порушить цілісність файлової системи.

Неакуратне вживання символічних зв'язків користувачами операційної системи може привести до перетворення логічної структури файлової системи з ациклічного графа в циклічний граф. Це, звичайно, небажано, але не носить такого руйнівного характеру, як цикли, які могли б бути створені жорстким зв'язком, якби не була введена заборона на організацію жорстких зв'язків до директорій. Оскільки м'які зв'язки принципово відрізняється від жорстких зв'язків і зв'язків, що виникають між директорією і файлом при його створенні, м'який зв'язок легко може бути ідентифікована операційною системою або програмою користувача. Для запобігання зациклення програм, що виконують операції над файлами, звичайно обмежується глибина рекурсії по проходженню м'яких зв'язків. Перевищення цієї глибини приводить до виникнення помилки дуже Багато м'яких зв'язків", яка може бути легко оброблена додатком. Тому обмеження на тип файлів, до яких може вести м'який зв'язок, в операційній системі UNIX не вводяться.

Для створення м'яких зв'язків застосовуються вже знайома нам команда операційної системи ln з опцією -s і системний виклик symlink(). Треба відзначити, що системний виклик symlink() також не вимагає попереднього відкриття зв'язуваного файлу, оскільки він взагалі не розглядає його вміст.

Системний виклик symlink()

#include <unistd.h>

int symlink(char *pathname

char *linkpathname);

Опис системного виклику

Системний виклик symlink служить для створення символічного (м'якої) зв'язку до файлу з ім'ям, на яке указує параметр pathname. Покажчик на ім'я створюваного зв'язку задається параметром linkpathname (повне або відносне ім'я зв'язку).

Ніякої перевірки реального існування файлу з ім'ям pathname системний виклик не проводить.

Значення, що повертається

Системний виклик повертає значення 0 при нормальному завершенні і значення -1 при виникненні помилки.

Операція видалення зв'язків і файлів. Системний виклик unlink(). При розгляді операції скріплення файлів ми вже майже повністю розглянули, як проводиться операція видалення жорстких зв'язків і файлів. При видаленні м'якого зв'язку, тобто фактично файлу типу "зв'язок", все відбувається, як і для звичайних файлів. Єдиною зміною, з погляду логічної структури файлової системи, є те, що при дійсному видаленні вузла, відповідного файлу типу "зв'язок", разом з ним віддаляється і неіменоване ребро, що виходить з нього.

Додатково необхідно відзначити, що умовою реального видалення регулярного файлу з диска є не тільки рівність 0 значення його лічильника жорстких зв'язків, але і відсутність процесів, які тримають цей файл відкритим. Якщо такі процеси є, то видалення регулярного файлу буде виконано при його повному закритті останнім використовуючим файл процесом.

Для здійснення операції видалення Для здійснення операції видалення жорстких зв'язків и/или файлів можна задіювати вже відому вам з семінарів 1–2 команду операційної системи rm або системний виклик unlink().

Помітимо, що системний виклик unlink() також не вимагає попереднього відкриття файлу, що видаляється, оскільки після його видалення скоювати над ним операції безглуздо.

Системний виклик unlink()

#include <unistd.h>

int unlink(char *pathname);

Опис системного виклику

Системний виклик unlink служить для видалення імені, на яке указує параметр pathname, з файлової системи.

Якщо після видалення імені лічильник числа жорстких зв'язків у даного файлу став рівним 0, то можливі наступні ситуації.

  • Якщо в операційній системі немає процесів, які тримають даний файл відкритим, то файл повністю віддаляється з фізичного носія.

  • Якщо ім'я, що видаляється, було останнім жорстким зв'язком для регулярного файлу, але який-небудь процес тримає його відкритим, то файл продовжує існувати до тих пір, поки не буде закритий останній файловий дескриптор, що посилається на даний файл.

  • Якщо ім'я відноситься до файлу типу socket, FIFO або до спеціального файлу пристрою, то файл віддаляється незалежно від наявності процесів, що тримають його відкритим, але процеси, що відкрили даний об'єкт, можуть продовжувати користуватися ним.

  • Якщо ім'я відноситься до файлу типу "зв'язок", то він віддаляється, і м'який зв'язок виявляється розірваним.

Значення, що повертається

Системний виклик повертає значення 0 при нормальному завершенні і значення -1 при виникненні помилки.