GNU/Linux >> Znalost Linux >  >> Linux

Co se v Linuxu stane, když se 1000 souborů v adresáři přesune do jiného umístění, zatímco dalších 300 souborů bylo přidáno do zdrojového adresáře?

To závisí na tom, jaké nástroje používáte:Podívejme se na několik případů:

Pokud spustíte něco ve smyslu mv /path/to/source/* /path/to/dest/ v shellu skončíte s přesunem původních 1000 souborů, přičemž nových 300 zůstane nedotčeno. To vychází ze skutečnosti, že shell rozšíří * před zahájením operace přesunu, takže když přesun probíhá, seznam je již opraven.

Pokud používáte Nautilus (a další přátele s GUI), skončíte stejným způsobem:Spustí operaci přesunu podle toho, které soubory byly vybrány - to se nezmění, když se objeví nové soubory.

Pokud používáte svůj vlastní program pomocí systémových volání podél linie smyčky přes glob a pouze jeden mv do glob zůstane prázdná, skončíte se všemi 1300 soubory v novém adresáři. Je to proto, že každý nový glob vybere nové soubory, které se mezitím objevily.


Když systému řeknete, aby přesunul všechny soubory z adresáře, zobrazí seznam všech souborů a poté je začne přesouvat. Pokud se v adresáři objeví nové soubory, nepřidají se do seznamu souborů k přesunu, takže zůstanou v původním umístění.

Můžete samozřejmě naprogramovat jiný způsob přesouvání souborů než mv který bude pravidelně kontrolovat nové soubory ve zdrojovém adresáři.


Samotné jádro nemůže být „uprostřed“ operace „přesunout 1000 souborů“. Musíte být mnohem konkrétnější v tom, jakou operaci navrhujete.

Jedno vlákno může přesunout pouze jeden soubor najednou pomocí rename(*oldpath, const char *newpath) nebo renameat systémová volání (a pouze v rámci stejného souborového systému). Nebo Linux renameat2 který má příznaky jako RENAME_EXCHANGE k atomické výměně dvou cest nebo RENAME_NOREPLACE ne nahradit cíl, pokud existuje. (např. povolení mv -i implementace, která se vyhýbá sporu stat a poté rename , což by stále přepisovalo soubor vytvořený po stat .link + unlink by to také mohlo vyřešit, protože link selže, pokud nový název existuje.)

Ale každé z těchto systémových volání přejmenuje pouze jednu položku adresáře na systémové volání . Pomocí POSIX renameat s olddirfd a newdirfd (otevřeno open(O_DIRECTORY) ) by vám umožnilo opakovat soubory v adresáři, i když je zdrojový nebo cílový adresář sám byl přejmenován. (Použití relativních cest by to také mohlo umožnit s běžným rename() .)

Každopádně, jak říkají ostatní odpovědi, většina programů, které používají systémové volání přejmenování, zjistí seznam názvů souborů, než provede první rename . (Obvykle pomocí readdir(3) Knihovna POSIX funguje jako obal pro systémová volání specifická pro platformu, jako je Linux getdents ).

Ale pokud mluvíte o find -exec ... {} \; spustit jeden příkaz na soubor nebo efektivnější -exec {} + s tolika soubory, že se nevejdou na jeden příkazový řádek, pak jistě může dojít k přejmenování během skenování. např.

find . -name '*.txt' -exec mv -t ../txtfiles {} \;   # Intentionally inefficient

Pokud jste vytvořili nějaké nové .txt souborů, když to bylo spuštěno, možná některé z nich naleznete v ../txtfiles . Ale interně find(1) použije open(O_DIRECTORY) a getdents na . .

Pokud k návratu všech stačilo jedno systémové volání položky adresáře v . (který nález se bude opakovat jeden po druhém, pouze v případě potřeby provede další systémová volání pro -type nebo rekurzovat nebo fork+exec při shodě), pak je seznam snímkem položek adresáře v jednom okamžiku. Další změny v adresáři nemohou ovlivnit to, co find ano, protože již má kopii adresáře se seznamem toho, co bude opakovat. (Pravděpodobně interně používá readdir(3) , který vrací jeden záznam po druhém, ale uvnitř glibc víme z použití strace find . že to dělá getdents64 systémové volání s velikostí vyrovnávací paměti count=32768 záznamy.)

Ale pokud je adresář velký a/nebo jádro nezaplňuje find 's buffer, bude muset provést 2. systémové volání getdents poté, co projde smyčkou, co získal poprvé. Takže by možná mohl vidět nové položky po provedení některých přejmenování.

Ale podívejte se na diskusi v komentářích pod jinými odpověďmi:jádro nám možná udělalo snímek, protože (myslím) getdents nemá povoleno vracet stejný název souboru dvakrát. Různé souborové systémy používají různé mechanismy řazení/indexování, aby byl přístup k záznamu v obrovském adresáři efektivnější než lineární vyhledávání. Přidání nebo odebrání adresáře tedy může mít další vliv na pořadí zbývajících položek. Hmm, pravděpodobně je pravděpodobnější, že souborové systémy udržují stabilní pořadí a pouze aktualizují skutečný index (jako EXT4 dir_index funkce), takže pozice FD v adresáři může být pouze záznam v adresáři, ze kterého lze pokračovat? Opravdu nevím, jak telldir(3) rozhraní knihovny mapuje na lseek , nebo pokud je to čistě věc uživatelského prostoru pro smyčkování přes vyrovnávací paměť získanou uživatelským prostorem. Ale více getdents může být potřeba k získání všech záznamů z velkého adresáře, takže i když hledání není podporováno, jádro musí být schopné zaznamenat aktuální pozici.

Poznámka 1:

Chcete-li se "přesunout" mezi souborovými systémy, je na uživatelském prostoru, aby zkopíroval a odpojil. (např. s open a buď read+write , mmap+write nebo sendfile(2) nebo copy_file_range(2) , poslední dva se zcela vyhýbají poskakování dat souboru uživatelským prostorem.)


Linux
  1. Co se stane s popisovačem otevřeného souboru v systému Linux, pokud se označený soubor přesune nebo odstraní

  2. Jaké jsou nevýhody linuxových front zpráv?

  3. Jaký je aktuální zdrojový kód jádra Linuxu?

  1. Jaké jsou rozdíly mezi lsof a netstat na linuxu?

  2. Jaká by měla být ideální oprávnění k domovskému adresáři v linuxu

  3. Co je ekvivalentem Active Directory v Linuxu

  1. Co přesně jsou hlavičky linuxového jádra?

  2. Hierarchie souborů Linux – jaké je nejlepší umístění pro ukládání souborů zámků?

  3. Jaké jsou důsledky pro výkon milionů souborů v moderním souborovém systému?