Philip Withnall
philip.withnall@collabora.co.uk 2015
Jak přistupovat k souborovému systému

# Přístup k souborovému systému

#

        Shrnutí

        Při přístupu k souborovému systému byste měli mít na paměti několik negativních návrhových vzorů. Tento článek předpokládá znalost standardních API GFile, GInputStream a GOutputStream.

          Pro přístup k souborům používejte asynchronní V/V. ()
          Vždy používejte vhodné funkce k vytvoření názvů souborů a cest. ()
          Než použijete cestu k souboru, ověřte, že se nachází v očekávané složce. ()
          Používejte povinné profily pro řízení přístupu, aby se zaručily omezení v přístupu k souborům. ()

# Asynchronní V/V

Většina V/V operací by měla být prováděna asynchronně. Což znamená bez blokování hlavního kontextu GLib. Toho lze dosáhnout důsledným používáním variant `*_async()` a `*_finish()` jednotlivých V/V funkcí.

Například použijte `g_input_stream_read_async()` a ne `g_input_stream_read()`.

Synchronní V/V operace blokují hlavní smyčku, což znamená, že ostatní události, jako je vstup od uživatele, příchozí síťový paket, vypršení časového limitu a zpětné volání při nečinnosti, nejsou obsluhovány, dokud nedojde k návratu z blokující funkce.

Synchronní V/V je přijatelný za určitých okolností, kdy náklady na plánování asynchronní operace převýší cenu místního synchronního V/V v Linuxu. Například provedení drobného čtení z místního souborového systému nebo z virtuálního souborového systému, jako je /proc. Při takovém čtení by měly být použity raději nízkoúrovňové funkce `g_open()`, `read()` a `g_close()` místo GIO.

Soubory v uživatelově domovské složce se nepočítají jako místní, protože mohou být na síťovém souborovém systému.

Upozorňujeme, že alternativa – běh synchronního V/V v odděleném vlákně – je silně nedoporučován. Více informací viz pokyny k vláknům.

# Sestavení cesty k souboru

Názvy souborů a cesty nejsou běžné řetězce: na některých systémech mohou používat jiné kódování znaků, než UTF-8, zatímco u normálních řetězců je v GLib vždy zaručeno použití UTF-8. Z tohoto důvodu by pro sestavení a zpracování názvů souborů a cest měly používat speciální funkce. (Moderní linuxové systémy povětšinou pro kódování názvů souborů jednotně používají UTF-8, takže to v praxi není problém, ale tyto funkce by měly být přesto používány kvůli kompatibilitě s jinými systéme, jako jsou Windows používající v názvech souborů UTF-16.)

Například cesta k souboru by se měla sestavit pomocí `g_build_filename()` namísto běžného `g_strconcat()`.

Když se to dělá takto, je v kódu jasnější, co se tím míní a také se tím zamezí zdvojení oddělovačů cest a vrácená cesta je kanonická (i když ne nutně absolutně).

Jiným příkladem by mohlo být rozložení cesty pomocí `g_path_get_basename()` a `g_path_get_dirname()` namísto běžného `g_strrstr()` nebo jiných ručních vyhledávacích funkcí.

# Ověřování cest a pískoviště

Když název souboru nebo cesta pochází z externího vstupu, jako je webová stránka nebo uživatelský vstup, měly by být ověřeny, aby se zajistilo, že jejich vložení do cesty nevytvoří jen tak nějakou cestu. Například, když je název souboru sestavován z řetězce ~/ plus uživatelského vstupu a uživatel zadá ../../etc/passwd, mohl by (potenciálně) získat přístup k citlivým informacím o účtech, v závislosti na tom, pod jakým účtem program běží a co dělá s daty načtenými ze sestavené cesty.

Tomu se dá předejít ověřováním sestavené cesty před tím, než ji použijete, pomocí funkce `g_file_resolve_relative_path()`, která převede relativní cesty na absolutní a následně ověří, že cesta je pod danou kořenovou složku pískoviště příslušejícího operaci. Například, když kód stahuje soubor, mohl by pomocí `g_file_has_parent()` ověřovat, že jsou všechny cesty pod ~/Downloads.

Jako druhou linii obrany by všechny projekty, které přistupují k souborovému systému, měly zvážit poskytnutí povinného profilu pro řízení přístupu za použití systému jako jsou AppArmor nebo SELinux, čímž se omezí složky a soubory, které lze číst a zapisovat do nich.