Reputation: 361
Hello I want to read from and write to a directory just like reading from and writing to files. I always use the open
, read
, write
and close
functions, which means I use descriptors. But doing this on a directory doesn't work, the open
call works, but read
returns -1 and errno
is EISDIR. Am I forced to use streams to read a directory?
Upvotes: 2
Views: 4401
Reputation: 145
As @caf pointed out, you should use readdir
for this purpose. Indeed, one uses a sequence of opendir
, readdir
, closedir
for reading directory files. Futhermore, directories are read only and cannot be written. However, if you are curious about using getdents
system call to read a directory, here is a minimal example without error checking. Here, the function read_dirent
takes the file descriptor corresponding to your directory and returns a directory entry on each call. The directory name can be passed as a command line argument. The default behavior prints the content of the current working directory. You can read more about getdents
in here or here.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#define BUF_SIZE 1024
typedef struct linux_dirent
{
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
} LinuxDirEnt;
LinuxDirEnt *read_dirent(int fd);
int main(int argc, char *argv[])
{
int fd;
LinuxDirEnt *d;
fd = open(argc > 1 ? argv[1] : ".", O_RDONLY);
printf("inode# d_reclen d_name\n");
while(d = read_dirent(fd))
printf("%8ld %4d %s\n", d->d_ino, d->d_reclen, d->d_name);
exit(EXIT_SUCCESS);
}
LinuxDirEnt *read_dirent(int fd)
{
static int nread = 0;
static int bpos = 0;
static char buf[BUF_SIZE];
static LinuxDirEnt *d;
if (nread == 0)
{
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == 0)
return NULL;
bpos = 0;
}
else
bpos += d->d_reclen;
d = (LinuxDirEnt *)(buf + bpos);
nread -= d->d_reclen;
return d;
}
Upvotes: 1
Reputation: 239321
The read()
and write()
system calls cannot be used on directories. Instead, the getdents()
/ getdents64()
system calls are used to read a directory. Directories cannot be directly written at all.
Futhermore, glibc does not provide a wrapper for the getdents()
/ getdents64()
system calls - instead it provides the POSIX-conforming readdir()
function, which is implemented using those system calls. Most programs should use readdir()
, but it is possible to call the system calls directly using syscall()
.
Upvotes: 3
Reputation: 892
I found this code here in Stack Overflow (How can I get the list of files in a directory using C or C++?), that helped me a lot in understanding how it works:
#include <dirent.h>
#include <stdio.h>
#include <string.h>
int main(){
DIR* dirFile = opendir( "." );
struct dirent* hFile;
if ( dirFile )
{
while (( hFile = readdir( dirFile )) != NULL )
{
if ( !strcmp( hFile->d_name, "." )) continue;
if ( !strcmp( hFile->d_name, ".." )) continue;
// in linux hidden files all start with '.'
if ( gIgnoreHidden && ( hFile->d_name[0] == '.' )) continue;
// dirFile.name is the name of the file. Do whatever string comparison
// you want here. Something like:
if ( strstr( hFile->d_name, ".c" ))
printf( "found an .txt file: %s", hFile->d_name );
}
closedir( dirFile );
}
}
Upvotes: 1