Ako zistíte čas vytvorenia súboru?

01.09.2016 20:11 | Články | mirek biňas
Jednou zo zaujímavých otázok, s ktorými sa dá stretnúť na linuxových pohovoroch, je práve táto: "Povedzte nám, ako zistíte, kedy bol súbor s názvom filename vytvorený?". Potenciálny uchádzač si pomyslí, že ľahšiu otázku už dostať nemohol a bez hlbšieho rozmýšľania odpovie, že "Zadaním príkazu ls s prepínačom -l pre dlhý výpis. Dátum a čas, ktorý sa v tomto výstupe nachádza, je čas vytvorenia súboru". Aké však bude jeho zdesenie, keď sa dozvie, že odpovedal nesprávne, už opisovať nebudem. V čom sa však tento uchádzač pomýlil, keď si bol odpoveďou tak istý?

Tak trochu o súboroch

Ešte predtým, ako prejdeme k odpovedi na pôvodnú otázku, si o súboroch niečo málo povieme. V princípe potrebujeme vedieť, že každý súbor je definovaný:

  • svojim obsahom, a
  • svojimi vlastnosťami.

Ak je súbor nositeľom údajov istého druhu, tak tieto údaje tvoria práve obsah súboru. Ak sa jedná o textový súbor, bude to text, ktorý bude možné zobraziť alebo upraviť v ľubovoľnom textovom editore. Ak súbor reprezentuje fotografiu, bude sa jednať o binárne údaje, ktoré je možné zobraziť v prehliadači obrázkov.

Vlastnosti zasa nesú doplnkové údaje o celom súbore. Môžeme ich priamo nazvať metaúdajmi - teda údajmi (vlastnosťami) o údajoch (obsahu súboru). Medzi tieto údaje patria informácie ako názov súboru, veľkosť súboru, vlastník súboru, prístupové práva k súboru a podobne.

Pre zistenie odpovede na pôvodnú otázku sa pozrieme bližšie práve na vlastnosti súboru. Tie sa nachádzajú v štruktúre, ktorá sa volá inode a môžeme si ich zobraziť pomocou príkazu stat.

Príkaz stat

Ak sa pozrieme do manuálovej stránky tohto príkazu, dozvieme sa, že príkaz zobrazuje stav súboru (z orig. file status). Vyskúšajme si teda, ako bude vyzerať jeho výstup:

$ touch subor.txt
$ stat subor.txt
 File: 'subor.txt'
  Size: 0             Blocks: 0          IO Block: 4096   regular empty file
Device: fd02h/64770d    Inode: 1588088     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/   mirek)   Gid: ( 1000/   mirek)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2016-08-31 19:26:30.021906753 +0200
Modify: 2016-08-31 19:26:30.021906753 +0200
Change: 2016-08-31 19:26:30.021906753 +0200
 Birth: -

Okrem už spomenutých vlastností súboru sa tu nachádzajú aj tri časy nazvané ako Access (Time), Modify (Time) a Change (Time). Ak teda hľadáme odpoveď na otázku, kedy bol súbor vytvorený, bude sa nachádzať zrejme tu.

Modification Time alebo čas poslednej zmeny obsahu súboru

Modification time (skrátene mtime) je čas poslednej zmeny obsahu súboru. Kedykoľvek súbor otvoríte a vykonáte v ňom akúkoľvek zmenu alebo ho proste len uložíte, dôjde k aktualizácii tohto času. K aktualizácii tohto času však nedôjde vtedy, ak zmeníte niektorú z vlastností súboru.

Access Time alebo čas posledného prístupu k súboru

Access time (skrátene atime) je čas posledného prístupu k súboru. Tento čas sa aktualizuje zakaždým, keď dôjde k otvoreniu súboru. K aktulizácii však dôjde rovnako aj v prípade, ak so súborom pracujete s nástrojmi ako napr. cat, sed, tr, grep a podobne.

Change Time alebo čas poslednej zmeny vlastností súboru

Change time (skrátene ctime) predstavuje čas poslednej zmeny niektorej z vlastností súboru, ktoré sú uložené v inode. Napr. ak zmeníte vlastníka súboru, prístupové práva súboru, ale rovnako dôjde k aktualizácii aj vtedy, ak sa zmení veľkosť súboru.

Niekoľko príkladov

Na niekoľkých príkladoch si teraz ukážeme, ako je to s jednotlivými časmi súboru v praxi. Začneme tým, že vytvoríme nový (prázdny) súbor (opäť) pomocou príkazu touch:

$ touch experiment.txt
$ stat experiment.txt
 File: 'experiment.txt'
  Size: 0             Blocks: 0          IO Block: 4096   regular empty file
Device: 29h/41d    Inode: 1500352     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/   mirek)   Gid: ( 1000/   mirek)
Context: unconfined_u:object_r:user_tmp_t:s0
Access: 2016-09-01 17:09:03.212380264 +0200
Modify: 2016-09-01 17:09:03.212380264 +0200
Change: 2016-09-01 17:09:03.212380264 +0200
 Birth: -

Priamo po vytvorení sú samozrejme všetky časy nastavené na rovnakú hodnotu - v tomto prípade je to dátum a čas 2016-09-01 17:09:03.212380264 +0200.

Teraz sa však pozrime na to, ako sa zmení hodnota atime, ak si necháme zobraziť obsah súboru:

$ cat experiment.txt
$ stat experiment.txt 
  File: 'experiment.txt'
  Size: 0             Blocks: 0          IO Block: 4096   regular empty file
Device: 29h/41d    Inode: 1500352     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/   mirek)   Gid: ( 1000/   mirek)
Context: unconfined_u:object_r:user_tmp_t:s0
Access: 2016-09-01 17:11:46.342097172 +0200
Modify: 2016-09-01 17:09:03.212380264 +0200
Change: 2016-09-01 17:09:03.212380264 +0200
 Birth: -

Ako je vidieť z výpisu príkazu stat, došlo k zmene len hodnoty času posledného prístupu k súboru, pretože nedošlo ani k zmene jeho obsahu a ani k zmene jeho vlastností.

Skúsme teraz opäť zobraziť obsah súboru pomocou rovnakého príkazu, aby sme si overili správanie, že opäť dôjde k aktualizácii hodnoty času posledného prístupu k súboru:

$ cat experiment.txt
$ stat experiment.txt --format="atime: %x
mtime: %y
ctime: %z"
atime: 2016-09-01 17:11:46.342097172 +0200
mtime: 2016-09-01 17:09:03.212380264 +0200
ctime: 2016-09-01 17:09:03.212380264 +0200

Tentokrát som použil formátovaný výpis a nechal som vypísať len uvedené časy. Ak však porovnáte predchádzajúci výstup s aktuálnym, všimnete si, že ku žiadnej aktualizácii času poslednej zmeny nedošlo aj napriek tomu, že by k jeho aktualizácii dôjsť malo. Kde je teda chyba?

V tomto prípade sa nejedná o žiadnu chybu, ako by sa na prvý pohľad mohlo zdať. Aby sme však porozumeli tomuto správaniu, musíme si uvedomiť jednu veľmi dôležitú vec, ktorá sa deje na pozadí súborového systému. Ak dochádza k zápisu súboru, jedná sa o aktualizáciu hodnôt ctime a mtime. Ak však dochádza k čítaniu súboru, jedná sa o aktualizáciu hodnoty atime. Dôsledkom tohto správania v POSIX-ových systémoch však súčasne s čítaním údajov zo súboru (napr. pomocou príkazu cat) dochádza aj k zápisu údajov (aktualizácia času poslednej zmeny - atime). Toto správanie bolo dlhodobo kritizované a vývojár jadra Ingo Molnár dokonca o hodnote atime povedal, že sa jedná "pravdepodobne o najhlúpejší nápad v rámci dizajnu Unix-u všetkých čias" dodávajúc: "Len si to predstavte: Pri každom jednom čítaní súboru z disku urobme... zápis na disk! A pre každý súbor, ktorý sa už nachádza v cache, a ktorý budeme z chace čítať, urobme... zápis na disk!". Aktualizácia hodnoty atime predstavuje jeden z najväčších nedostatkov výkonu IO, ktoré Linux v súčasnosti má.

Toto správanie je však možné zmeniť, čím ale dôjde k porušeniu POSIX-u a niektoré aplikácie kvôli tomu nemusia pracovať správne. Jadro ponúka niekoľko možností, ktorými je možné ovplyvniť toto správanie a je možné ho nastaviť pri pripájaní súborového systému alebo priamo v súbore /etc/fstab.

Teraz sa však pozrime na to, ako môžeme ovplyvniť hodnotu ctime a teda čas, kedy došlo k aktualizácii niektorej z vlastností nachádzajúcich sa v metaúdajoch súboru (v inode). Ilustrujeme si teda aktualizáciu tejto hodnoty pomocou zmeny prístupového práva k súboru:

$ chmod o+w experiment.txt
$ stat experiment.txt --format="atime: %x
mtime: %y
ctime: %z"
atime: 2016-09-01 17:11:46.342097172 +0200
mtime: 2016-09-01 17:09:03.212380264 +0200
ctime: 2016-09-01 17:44:23.739689080 +0200

Ak teda porovnáme predposledný výpis príkazu stat s posledným, došlo k zmene len hodnoty ctime.

Nakoniec sa pozrime na to, ako dôjde k aktualizácii hodnoty mtime, ku ktorej dôjde v prípade zmeny obsahu súboru:

$ echo "This is a test" > experiment.txt
$ stat experiment.txt
 File: 'experiment.txt'
  Size: 15            Blocks: 8          IO Block: 4096   regular file
Device: 29h/41d    Inode: 1500352     Links: 1
Access: (0666/-rw-rw-rw-)  Uid: ( 1000/   mirek)   Gid: ( 1000/   mirek)
Context: unconfined_u:object_r:user_tmp_t:s0
Access: 2016-09-01 17:11:46.342097172 +0200
Modify: 2016-09-01 17:47:26.985383553 +0200
Change: 2016-09-01 17:47:26.985383553 +0200
 Birth: -

Pri porovnaní týchto dvoch posledných výstupov príkazu stat si môžeme všimnúť, že nedošlo len k aktualizácii času hodnoty mtime, ale rovnako aj k aktualizácii hodnoty ctime. Ak si však uvedomíme, že hodnota ctime sa aktualizuje vtedy, ak dôjde k aktualizácii niektorej z vlastností súboru v inode, tak nemôžeme byť prekvapení - tým, že sme do súboru zapísali údaje, došlo k aktualizácii jeho dĺžky. Nutne sa teda aktualizovala aj hodnota ctime. Prakticky to znamená, že ak vykonáte akúkoľvek operáciu zápisu alebo prepisu údajov v súbore, dôjde okrem aktualizácie hodnoty mtime aj k aktualizácii hodnoty ctime.

Príkaz ls

Ako je to teda s príkazom ls? Ktorý čas vlastne pri voľbe dlhého výpisu (-l) zobrazí?

Ak sa pozrieme do manuálovej stránky príkazu ls podrobnejšie, nájdeme v nej prepínač --time, pomocou ktorého môžeme určiť, aký čas sa bude v dlhom výstupe príkazu zobrazovať. Táto voľba má dve možnosti:

  1. atime (skrátene prepínač -u) pre zobrazovanie času posledného prístupu, alebo
  2. ctime (skrátene prepínač -c) pre zobrazovanie času poslednej zmeny vlastností súboru

Pokiaľ nevyužijeme ani jednu možnosť, predvolene sa zobrazuje hodnota mtime a teda čas poslednej zmeny obsahu súboru.

Creation Time alebo dátum vytvorenia súboru?

Ak sa teda vrátime k pôvodnej otázke, jedná sa o chyták. Dalo by sa síce polemizovať, že za istých okolností je možné považovať hodnotu mtime za čas vytvorenia súboru, ale to rozhodne nebude platiť vždy.

Ak sa však pozrieme do histórie, hodnota ctime naozaj reprezentovala čas a dátum vytvorenia súboru (z angl. Creation Time). Postupne sa však z tejto hodnoty stala hodnoty času poslednej zmeny vlastností súboru tak, ako ho poznáme dnes.

Použité zdroje

    • RE: Ako zistíte čas vytvorenia súboru? 01.09.2016 | 21:19
      Avatar bedňa LegacyIce-antiX  Administrátor

      Jj, pamätám si ako pred pár rokmi bola veľká diskusia medzi jadrákmi, že v Linuxe neexistuje možnosť ako zistiť kedy súbor vznikol.

      No moderné FS mimo štandard už tento údaj poskytujú.

      Táto správa neobsahuje vírus, pretože nepoužívam MS Windows. http://kernelultras.org
      • RE: Ako zistíte čas vytvorenia súboru? 02.09.2016 | 17:16
        Avatar mirek biňas Fedora 35  Administrátor

        hmm... diky za tip - rad sa na to kuknem, ako to vyzera v jednotlivych systemoch.

        • RE: Ako zistíte čas vytvorenia súboru? 02.09.2016 | 20:24
          Avatar bedňa LegacyIce-antiX  Administrátor

          Hoď do vyhľadávača "Linux xstat".

          Win na uchovávanie času vytvorenia používa Hack nazvaný "File System Tunneling" (z diskusie o xstat).

          Linus ako obyčajne v diskusií zabodoval, či je potrebné vôbec takú vec riešiť, keď sa nevedia dohodnúť ani na jej názve.

          Táto správa neobsahuje vírus, pretože nepoužívam MS Windows. http://kernelultras.org