Hlavní navigace

Programování pod Linuxem pro všechny (3)

Jakub Matys 6. 2. 2004

V dnešním dílu si konečně povíme o vytváření dočasných souborů, bude se jednat o funkce využívající k zápisu a čtení dat deskriptor souboru i proměnnou typu *FILE.

V minulém dílu jsem pasáž o systémových proměnných napsal trochu stroze. Úplným začátečníkům se omlouvám. Napíšu zde ještě pár doplňujících informací.

Proměnné se dědí z procesu na proces, tzn. rodičovský proces předá spouštěnému procesu všechny své proměnné. Všechny proměnné, které jsou součástí prostředí (environment) procesu si můžete prohlédnout v souboru /proc/cislo-procesu/environ. Přidávat proměnné do prostředí (bashe nebo vašeho programu) můžete pomocí metod napsaných v minulém dílu. Proč musíte proměnnou předávanou z bashe exportovat? Bash funguje také jako programovací jazyk (snad všechny systémové skripty jsou napsány v něm). Jak určitě víte, programovací jazyky používají proměnné k uchovávání hodnot a bylo by krajně nepraktické ukládat proměnné do prostředí bashe, dokonce by mohly vznikat kolapsy se spouštěnými programy. Proto se proměnné ukládají interně v bashi, a pokud je chcete použít v prostředí, musíte je exportovat.

Vytváření dočasných souborů

Občas je potřeba zapsat data do dočasného (temporary) souboru, přečíst je nebo pomocí tohoto souboru předat data jinému procesu. V Linuxu se dočasné soubory ukládají v adresáři /tmp. Měli byste si však dát při používání dočasných souborů pozor na několik záludností:

  • V první řadě mějte na paměti, že na počítači může běžet v jeden moment několik instancí vašeho programu. Pokud budete používat neměnný název dočasného souboru, všechny instance tohoto programu budou zapisovat jen do jednoho souboru. A může se stát, že budou číst data, která nejsou jejich. Každá instance by měla používat jiný název dočasného souboru.
  • Práva souboru by měla být nastavena tak, aby případný útočník nemohl měnit jeho obsah a tím i chod celého programu.
  • Jméno dočasného souboru by mělo být generováno tak, aby nemohlo být externě předpovězeno. Jinak by mohl útočník využít prodlevy mezi testem, zda se již dané jméno používá, a mezi otevřením nového dočasného souboru.

Tyto problémy vám pomohou řešit dvě funkce: 1) Funkce mkstemp(), která je definována v hlavičkovém souboru stdlib.h. Tato funkce využívá deskriptor souboru pro práci se souborem. 2) Funkce tmpfile() je obsažena v hlavičkovém souborustdio.h a využívá pro práci se soubory ukazatel typu FILE. Ve stejném hlavičkovém souboru jsou také definovány funkce jako mktemp(), tempnam() nebo tmpnam(). Tyto funkce slouží také k práci s dočasnými soubory, ale v tomto článku se jimi zabývat nebudu. Zájemce mohu odkázat na manuálové stránky jmenovaných funkcí. Nyní si povíme něco o funkcích mkstemp() a tmpfile().

Funkce mkstemp()

Funkce mkstemp() vytváří dočasný soubor s jedinečným jménem. Toto jméno se generuje pomocí šablony. Funkci se předává jako parametr znakový řetězec obsahující jméno souboru s šablonou. Šablona je „XXXXXX“ a funkce tato X nahradí jinými znaky, aby se vytvořilo jedinečné jméno. Funkce otevře nový soubor s právy číst a zapisovat do souboru pro vlastníka procesu.

Pokud nebudete chtít pomocí dočasného souboru předávat data jinému procesu, pravděpodobně budete chtít soubor zrušit, až nebude potřeba. Soubory vytvořené funkcí mkstemp() se neruší automaticky. Proto použijte po zavolání mkstemp() funkci unlink(), která zruší jméno souboru v souborovém systému. Se souborem bude možné nadále pracovat a po uzavření deskriptoru souboru se odstraní. Snad bych ještě měl upozornit na to, že k zápisu a čtení dat pomocí deskriptoru souboru se používají funkce write() a read(), pokud nevíte, jak se funkce používají, prohlédněte si manuálové stránky, případně se poohlédněte po nějakém článku na Internetu.

V příkladu jsou použity funkce demonstrující použití mkstemp(). První funkce slouží k vytvoření a zápisu dat do dočasného souboru. Vrací deskriptor souboru pro případný další zápis dat a čtení pomocí druhé funkce.

#include <stdlib.h>
#include <unistd.h>

/* Novy datovy typ file_decriptor pro deskriptor souboru */
typedef int file_descriptor;

/* Funkce zapise LENGTH bytu z BUFFER do docasneho souboru.
 * Pote je jmeno souboru zruseno v filesystemu(unlink).
 * Vraci deskriptor souboru. */

file_descriptor write_tmp(char *buffer, size_t length)
{
  /* Vytvori nazev souboru a samotny soubor. XXXXXX bude
   * prepsano nejakymi znaky, aby bylo jmeno unikatni. */
  char temp_filename[] = "/tmp/temp_file.XXXXXX";
  int fd = mkstemp(temp_filename);
  /* Zrusi jmeno souboru v filesystemu, az se
   * uzavre deskriptor souboru soubor se smaze. */
  unlink(temp_filename);
  /* Zapise velikost zapisovanych dat v bytech. */
  write(fd, &length, sizeof(length));
  /* Nyni zapise samotna data. */
  write(fd, buffer, length);
  /* Vrati deskriptor souboru docasneho souboru */
  return(fd);
}

/* Precte data z docasneho souboru, jehoz deskriptor
 * souboru je ji predan jako 1. parametr(TEMP_FILE).
 * Vraci nove alokovany buffer s prectenymi daty, po
 * pouziti musi byt manualne dealokovany pomoci free().
 * Pomoci *LENGTH se vraci velikost bufferu v bytech.
 * Funkce nakonec uzavre deskriptor souboru a tim se
 * pri ukonceni souboru odstrani docasny soubor. */

char *read_tmp(file_descriptor temp_file, size_t *length)
{
  char *buffer;
  /* Vrati se na zacatek souboru. */
  lseek(temp_file, 0, SEEK_SET);
  /* Precte velikost zapsanych dat v souboru. */
  read(temp_file, length, sizeof(*length));
  /* Alokuje pamet pro buffer a cte data. */
  buffer = (char *) malloc (*length);
  read(temp_file, buffer, *length);
  /* Zavre deskriptor souboru */
  close(temp_file);
  return(buffer);
} 

Funkce tmpfile()

Pokud budete chtít použít k zápisu a čtení dat knihovní funkce fwrite() a fread(), můžete použít funkci tmpfile(). Funkce vygeneruje unikátní jméno a použije cestu uloženou v symbolické konstantě P_tmpdir definované vstdio.h. Soubor je otevřen v binárním módu pro čtení i zápis (w+b). Dočasný soubor je již odpojen, jako v předcházejícím příkladě, proto je automaticky odstraněn, jakmile se soubor uzavře, nebo po skončení programu. Následující příklad je pouze přepsaným příkladem funkce mkstemp():

#include <stdio.h>

FILE *write_tmp(char *buffer, size_t length)
{
  /* Vytvori ukazatel pro praci se souborem */
  FILE *temp_file;

  /* Vytvori novy docasny soubor */
  temp_file = tmpfile();
  fwrite(&length, sizeof(length), 1, temp_file);
  fwrite(buffer, length, 1, temp_file);
  return(temp_file);
}

char *read_tmp(FILE *temp_file, size_t *length)
{
  char *buffer;
  fseek(temp_file, 0, SEEK_SET);
  fread(length, sizeof(*length), 1, temp_file);
  buffer = (char *) malloc(*length);
  fread(buffer, *length, 1, temp_file);
  fclose(temp_file);
  return(buffer);
}

Tak to by bylo pro dnešní díl vše, doufám, že si nových znalostí užijete. Příště se podíváme na knihovny. Nejdříve probereme statické knihovny, a jestli zbyde nějaké místo, nakousneme knihovny dynamické.

Našli jste v článku chybu?

21. 12. 2009 18:33

me (neregistrovaný)

Docasny soubor se vytvori pomoci mkstemp() a hned se smaze pomoci unlink(). Lze vytvoreny docasny soubor ulozit pozdeji (pred zavrenim a definitivnim smazanim) pod novym jmenem (pokud se treba vypocet dokonci)? Mam na mysli hodne velky docasny soubor, takze copy() do finalniho souboru by nebylo efektivni a zbytecne by pozadovalo dalsi diskovu kapacitu. Rekneme, ze se jedna o ISO obraz CD.

9. 2. 2004 22:20

Jirka Kosina (neregistrovaný)

> pak si musite zkontrolovat, jestli ten soubor uz
> neexistuje, napriklad ho utocnik muze predvytvorit
> jako symlink nekam k sobe a data si pak precist

Testovani existence/neexistence souboru samo o sobe smrdi race condition, pokud se neudela spravne.

Tzn naivni reseni, ktere lze jeste dnes najit skutecne v leckterych programech (a ktere nefunguje), je (v pseudokodu):

stat(filename, &st);
if (!S_ISREG(st.st_mode)) return(-1);
fd = open(filename, ...)

mezi radky 2 a…











Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

DigiZone.cz: Česká televize mění schéma ČT :D

Česká televize mění schéma ČT :D

DigiZone.cz: NG natáčí v Praze seriál o Einsteinovi

NG natáčí v Praze seriál o Einsteinovi

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Vitalia.cz: To není kašel! Správná diagnóza zachrání život

To není kašel! Správná diagnóza zachrání život

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Lupa.cz: Babiš: E-shopů se EET možná nebude týkat

Babiš: E-shopů se EET možná nebude týkat

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Podnikatel.cz: EET zvládneme, budou horší zákony

EET zvládneme, budou horší zákony

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

Měšec.cz: Finančním poradcům hrozí vracení provizí

Finančním poradcům hrozí vracení provizí