Reputation: 125
I need to implement ls
program in C language.
And I want to find a way to not use <dirent.h>
library.
Can I get list of files in directory using file descriptors in Linux C?
Thanks.
Upvotes: 1
Views: 12361
Reputation: 23
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include<stdlib.h>
#include<dirent.h>
#include<time.h>
#include<pwd.h>
#include <grp.h>
int main(int argc, char **argv)
{
struct passwd *pw;
struct group *gp;
DIR *mydir;
char *c;
int i;
struct dirent *myfile;
struct stat fileStat;
mydir=opendir(".");
stat(".",&fileStat);
while((myfile=readdir(mydir))!=NULL)
{
stat(myfile->d_name,&fileStat);
printf( (S_ISDIR(fileStat.st_mode)) ? "d" : "-");
printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-");
printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");
printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");
printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");
printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");
printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");
printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");
printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");
printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-");
printf(" ");
printf("%d ",fileStat.st_nlink);
pw=getpwuid(fileStat.st_uid);
printf("%s ",pw->pw_name);
gp=getgrgid(fileStat.st_gid);
printf("%s ",gp->gr_name);
printf("%4d ",fileStat.st_size);
c=ctime(&fileStat.st_mtime);
for(i=4;i<=15;i++)
printf("%c",c[i]);
printf(" ");
printf("%s\n",myfile->d_name);
}
closedir(mydir);
return 0;
}
Upvotes: 1
Reputation: 93
As a student I recently had to do quite the same job for my System Programming class at ECE Paris Engineering School.
Here's my piece of code. I haven't tested it but it should work fine, and it's well documented so you'll be able to understand each piece of it by reading the comments.
// This is the lsd function, yet another C implement of the classic ls, using UNIX functions
// Featuring "stat", "opendir", and "readdir"
// Credits: Jalil Benayachi, ECE PARIS - under MIT license
// contact [at] thejals.com
// Also thanks to some contributors on Stackoverflow
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
int main(int argc, char* argv[])
{
//Defining the different components of the program
//The directory: it's the folder we're browsing (we'll use an argument (argv) in order to identify it)
DIR *thedirectory;
//The file: when a file is found in the directory readdir loop, it's going to be called this way.
struct dirent *thefile;
//The stat: It's how we'll retrieve the stats associated to the file.
struct stat thestat;
//will be used to determine the file owner & group
struct passwd *tf;
struct group *gf;
//Creating a placeholder for the string.
//We create this so later it can be properly adressed.
//It's reasonnable here to consider a 512 maximum lenght, as we're just going to use it to display a path to a file,
//but we could have used a strlen/malloc combo and declared a simple buf[] at this moment
char buf[512];
//It's time to assign thedirectory to the argument: this way the user will be able to browse any folder simply by mentionning it
//when launching the lsd program.
thedirectory = opendir(argv[1]);
//If a file is found (readdir returns a NOT NULL value), the loop starts/keep going until it has listed all of them.
while((thefile = readdir(thedirectory)) != NULL)
{
//We sprint "thedirectory/thefile" which defines the path to our file
sprintf(buf, "%s/%s", argv[1], thefile->d_name);
//Then we use stat function in order to retrieve information about the file
stat(buf, &thestat);
//Now, we can print a few things !
// Here's the right order
// [file type] [permissions] [number of hard links] [owner] [group] [size in bytes] [time of last modification] [filename]
// [file type]
//Let's start with the file type
//The stat manual is pretty complete and gives details about st_mode and S_IFMT: http://manpagesfr.free.fr/man/man2/stat.2.html
//
switch (thestat.st_mode & S_IFMT) {
case S_IFBLK: printf("b "); break;
case S_IFCHR: printf("c "); break;
case S_IFDIR: printf("d "); break; //It's a (sub)directory
case S_IFIFO: printf("p "); break; //fifo
case S_IFLNK: printf("l "); break; //Sym link
case S_IFSOCK: printf("s "); break;
//Filetype isn't identified
default: printf("- "); break;
}
//[permissions]
//Same for the permissions, we have to test the different rights
//READ http://linux.die.net/man/2/chmod
printf( (thestat.st_mode & S_IRUSR) ? " r" : " -");
printf( (thestat.st_mode & S_IWUSR) ? "w" : "-");
printf( (thestat.st_mode & S_IXUSR) ? "x" : "-");
printf( (thestat.st_mode & S_IRGRP) ? "r" : "-");
printf( (thestat.st_mode & S_IWGRP) ? "w" : "-");
printf( (thestat.st_mode & S_IXGRP) ? "x" : "-");
printf( (thestat.st_mode & S_IROTH) ? "r" : "-");
printf( (thestat.st_mode & S_IWOTH) ? "w" : "-");
printf( (thestat.st_mode & S_IXOTH) ? "x" : "-");
// [number of hard links]
// Quoting: http://www.gnu.org/software/libc/manual/html_node/Attribute-Meanings.html
// "This count keeps track of how many directories have entries for this file.
// If the count is ever decremented to zero, then the file itself is discarded as soon as no process still holds it open."
printf("\t%d ", thestat.st_nlink);
//[owner]
// http://linux.die.net/man/3/getpwuid
tf = getpwuid(thestat.st_uid);
printf("\t%s ", tf->pw_name);
//[group]
// http://linux.die.net/man/3/getgrgid
gf = getgrgid(thestat.st_gid);
printf("\t%s ", gf->gr_name);
//And the easy-cheesy part
//[size in bytes] [time of last modification] [filename]
printf("%zu",thestat.st_size);
printf(" %s", thefile->d_name);
printf(" %s", ctime(&thestat.st_mtime));
}
closedir(thedirectory);
}
I hope this will help :) As well as a few other students browsing stackoverflow =)
Upvotes: 7
Reputation: 264
If I understand correctly you don't want to use the functions provided by the glibc and want to use the system calls provided by the kernel directly to read the contents of a directory. That means use the file descriptors directly. You can use the system call open() or openat() to open a directory as usual just like a regular file.
And to read the contents of the directory you can use the getdents() system call to read the entries of the directory. There is an example usage of these function in the man page of getdents.
Upvotes: 1
Reputation: 383718
It depends on what you mean by "without any library".
In the most hard sense, you could use assembly to read your disk manually, but this would be extremely hard and unportable.
Next, you could use assembly to make Linux system calls. But then, the kernel is just a big library.
What you may have meant was: without any library except the C stdlib. I believe that this is not possible.
Upvotes: 1