Wenn gesagt wird, dass unter Linux alles eine Datei ist, dann ist das wirklich wahr. Die meisten Operationen, die wir mit Dateien durchführen können, können auch mit anderen Entitäten wie Sockets, Pipes, Verzeichnissen usw. durchgeführt werden.
Es gibt bestimmte Situationen, in denen ein Software-Dienstprogramm möglicherweise Verzeichnisse im Linux-System durchqueren muss um etwas zu finden oder zuzuordnen. Dies ist der Anwendungsfall, bei dem sich der Programmierer dieses Dienstprogramms mit der Verzeichnisprogrammierung befassen muss. Daher behandeln wir in diesem Artikel die folgenden Grundlagen der Verzeichnisprogrammierung anhand eines Beispiels.
- Verzeichnisse erstellen.
- Leseverzeichnisse.
- Entfernen von Verzeichnissen.
- Schließen des Verzeichnisses.
- Das aktuelle Arbeitsverzeichnis abrufen.
Wir werden die Funktionen durchgehen, die für jeden obigen Schritt verwendet werden, und schließlich sehen wir ein Beispiel, das alle Verzeichnisoperationen zusammenfasst.
1. Verzeichnisse erstellen
Das Linux-System bietet den folgenden Systemaufruf zum Erstellen von Verzeichnissen:
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
Das Argument „Pfadname“ wird für den Namen des Verzeichnisses verwendet.
Aus der Manpage :
Das Argument mode gibt die zu verwendenden Berechtigungen an. Es wird auf die übliche Weise von der umask des Prozesses modifiziert:Die Berechtigungen des erstellten Verzeichnisses sind (mode &~umask &0777). Andere Modusbits des erstellten Verzeichnisses hängen vom Betriebssystem ab. Für Linux siehe unten.
Das neu erstellte Verzeichnis gehört der effektiven Benutzer-ID des Prozesses. Wenn das Verzeichnis, das die Datei enthält, das set-group-ID-Bit gesetzt hat oder wenn das Dateisystem mit BSD-Gruppensemantik gemountet ist (mount -o bsdgroups oder synonym mount -o grpid), erbt das neue Verzeichnis den Gruppenbesitz von sein Elternteil; andernfalls gehört es der effektiven Gruppen-ID des Prozesses. Wenn im übergeordneten Verzeichnis das set-group-ID-Bit gesetzt ist, wird dies auch im neu erstellten Verzeichnis der Fall sein.
2. Verzeichnisse lesen
Eine Familie von Funktionen wird verwendet, um den Inhalt des Verzeichnisses zu lesen.
1. Zuerst muss ein Verzeichnisstream geöffnet werden. Dies geschieht durch den folgenden Systemaufruf:
#include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name);
Aus der Manpage :
Die Funktion opendir() öffnet einen Verzeichnisstrom, der dem Verzeichnisnamen entspricht, und gibt einen Zeiger auf den Verzeichnisstrom zurück. Der Stream wird am ersten Eintrag im Verzeichnis positioniert.
2. Um als nächstes die Einträge im Verzeichnis zu lesen, wird der oben geöffnete Stream durch den folgenden Systemaufruf verwendet:
#include struct dirent *readdir(DIR *dirp);
Aus der Manpage :
Die Funktion readdir() gibt einen Zeiger auf eine dirent-Struktur zurück, die den nächsten Verzeichniseintrag im Verzeichnisstrom darstellt, auf den dirp zeigt. Es gibt NULL zurück, wenn das Ende des Verzeichnisstroms erreicht wird oder wenn ein Fehler aufgetreten ist.
Unter Linux ist die dirent-Struktur wie folgt definiert:
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. Verzeichnisse entfernen
Das Linux-System bietet den folgenden Systemaufruf zum Entfernen von Verzeichnissen:
#include <unistd.h> int rmdir(const char *pathname);
Aus der Manpage :
rmdir() entfernt das durch „Pfadname“ dargestellte Verzeichnis, wenn es leer ist. Wenn das Verzeichnis nicht leer ist, wird diese Funktion nicht erfolgreich sein.
4. Verzeichnisse schließen
Das Linux-System stellt den folgenden Systemaufruf bereit, um die Verzeichnisse zu schließen:
#include <sys/types.h> #include <dirent.h> int closedir(DIR *dirp);
Aus der Manpage :
Die Funktion closedir() schließt den dirp zugeordneten Verzeichnisstrom. Ein erfolgreicher Aufruf von closedir() schließt auch den zugrunde liegenden Dateideskriptor, der dirp zugeordnet ist. Der Verzeichnis-Stream-Deskriptor dirp ist nach diesem Aufruf nicht verfügbar.
5. Abrufen des aktuellen Arbeitsverzeichnisses
Das Linux-System stellt den folgenden Systemaufruf bereit, um die CWD abzurufen:
#include <unistd.h> char *getcwd(char *buf, size_t size);
Aus der Manpage :
Die Funktion getcwd() kopiert einen absoluten Pfadnamen des aktuellen Arbeitsverzeichnisses in das Array, auf das buf zeigt, das die Länge size hat. Diese Funktion gibt einen nullterminierten String zurück, der einen absoluten Pfadnamen enthält, der das aktuelle Arbeitsverzeichnis von ist Aufrufprozess. Der Pfadname wird als Funktionsergebnis und über das Argument buf, falls vorhanden, zurückgegeben. Wenn die Länge des absoluten Pfadnamens des aktuellen Arbeitsverzeichnisses einschließlich des abschließenden Nullbytes size bytes überschreitet, wird NULL zurückgegeben und errno auf ERANGE gesetzt; eine Anwendung sollte auf diesen Fehler prüfen und gegebenenfalls einen größeren Puffer zuweisen.
6. Ein Beispiel
#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; }
Das obige Beispiel sollte nun selbsterklärend sein.
Die Ausgabe des obigen Beispiels ist:
# ./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] [.]