Když se říká, že v Linuxu je všechno soubor, pak to opravdu platí. Většinu operací, které můžeme provádět se soubory, lze provádět na jiných entitách, jako je soket, potrubí, adresáře atd.
Existují určité situace, kdy může softwarový nástroj cestovat přes adresáře v systému Linux najít nebo porovnat něco. Toto je případ použití, kdy se programátor tohoto nástroje musí zabývat programováním adresářů. V tomto článku tedy probereme následující základy programování adresářů na příkladu.
- Vytváření adresářů.
- Čtení adresářů.
- Odebírání adresářů.
- Zavření adresáře.
- Získání aktuálního pracovního adresáře.
Projdeme si funkce, které se používají pro každý výše uvedený krok, a nakonec uvidíme příklad, který shrne všechny operace s adresáři.
1. Vytváření adresářů
Systém Linux poskytuje následující systémové volání pro vytvoření adresářů:
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
Argument ‚cesta‘ se používá pro název adresáře.
Z manuálové stránky :
Režim argumentů určuje oprávnění k použití. Umask procesu jej upravuje obvyklým způsobem:oprávnění vytvořeného adresáře jsou (režim &~umask &0777). Další bity režimu vytvořeného adresáře závisí na operačním systému. Pro Linux viz níže.
Nově vytvořený adresář bude vlastnit skutečné ID uživatele procesu. Pokud má adresář obsahující soubor nastavený bit set-group-ID nebo pokud je souborový systém připojen se sémantikou skupiny BSD (mount -o bsdgroups nebo synonymně mount -o grpid), nový adresář zdědí vlastnictví skupiny od jeho rodič; jinak bude ve vlastnictví efektivní skupiny ID procesu. Pokud má nadřazený adresář nastaven bit set-group-ID, pak bude nastaven i nově vytvořený adresář.
2. Čtení adresářů
Pro čtení obsahu adresáře se používá rodina funkcí.
1. Nejprve je třeba otevřít adresářový proud. To se provádí následujícím systémovým voláním :
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);
Z manuálové stránky :
Funkce opendir() otevře adresářový proud odpovídající názvu adresáře a vrátí ukazatel na adresářový proud. Proud je umístěn na první položce v adresáři.
2. Dále, ke čtení položek v adresáři, použije výše otevřený proud následující systémové volání:
#include struct dirent *readdir(DIR *dirp);
Z manuálové stránky :
Funkce readdir() vrací ukazatel na direntovou strukturu představující další položku adresáře v adresářovém proudu, na který ukazuje dirp. Vrací NULL při dosažení konce adresářového proudu nebo pokud došlo k chybě.
V Linuxu je struktura direntu definována následovně:
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ };
3. Odebírání adresářů
Systém Linux poskytuje následující systémové volání pro odstranění adresářů:
#include <unistd.h> int rmdir(const char *pathname);
Z manuálové stránky :
rmdir() odstraní adresář reprezentovaný ‚cestou‘, pokud je prázdný. POKUD adresář není prázdný, tato funkce nebude úspěšná.
4. Zavírání adresářů
Systém Linux poskytuje následující systémové volání pro uzavření adresářů:
#include <sys/types.h> #include <dirent.h> int closedir(DIR *dirp);
Z manuálové stránky :
Funkce closedir() zavře adresářový proud spojený s dirp. Úspěšné volání closedir() také zavře základní deskriptor souboru spojený s dirp. Po tomto volání není popisovač toku adresáře dostupný.
5. Získání aktuálního pracovního adresáře
Systém Linux poskytuje následující systémové volání pro získání CWD:
#include <unistd.h> char *getcwd(char *buf, size_t size);
Z manuálové stránky :
Funkce getcwd() zkopíruje absolutní název cesty k aktuálnímu pracovnímu adresáři do pole, na které ukazuje buf, které má velikost délky. Tato funkce vrací řetězec zakončený nulou obsahující absolutní název cesty, který je aktuálním pracovním adresářem proces volání. Název cesty je vrácen jako výsledek funkce a prostřednictvím argumentu buf, pokud je přítomen. Pokud délka názvu absolutní cesty aktuálního pracovního adresáře, včetně ukončovacího null bajtu, překročí velikost bajtů, vrátí se NULL a errno se nastaví na ERANGE; aplikace by měla tuto chybu zkontrolovat a v případě potřeby přidělit větší vyrovnávací paměť.
6. Příklad
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<dirent.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main (int argc, char *argv[]) { if(2 != argc) { printf("\n Please pass in the directory name \n"); return 1; } DIR *dp = NULL; struct dirent *dptr = NULL; // Buffer for storing the directory path char buff[128]; memset(buff,0,sizeof(buff)); //copy the path set by the user strcpy(buff,argv[1]); // Open the directory stream if(NULL == (dp = opendir(argv[1])) ) { printf("\n Cannot open Input directory [%s]\n",argv[1]); exit(1); } else { // Check if user supplied '/' at the end of directory name. // Based on it create a buffer containing path to new directory name 'newDir' if(buff[strlen(buff)-1]=='/') { strncpy(buff+strlen(buff),"newDir/",7); } else { strncpy(buff+strlen(buff),"/newDir/",8); } printf("\n Creating a new directory [%s]\n",buff); // create a new directory mkdir(buff,S_IRWXU|S_IRWXG|S_IRWXO); printf("\n The contents of directory [%s] are as follows \n",argv[1]); // Read the directory contents while(NULL != (dptr = readdir(dp)) ) { printf(" [%s] ",dptr->d_name); } // Close the directory stream closedir(dp); // Remove the new directory created by us rmdir(buff); printf("\n"); } return 0; }
Výše uvedený příklad by nyní měl být samozřejmý.
Výstup výše uvedeného příkladu je:
# ./direntry /home/himanshu/practice/linux Creating a new directory [/home/himanshu/practice/linux/newDir/] The contents of directory [/home/himanshu/practice/linux] are as follows [redhat] [newDir] [linuxKernel] [..] [ubuntu] [.]