I need to print all possible file attributes in a directory such as file size, type, ect. The code below uses the dirent structure and it doesnt have all the file information, like file size. The d_type returns some integer, but i can find a chart to look up the meaning of those numbers. I am printing the inode and the name of the file. Can i use the inode to get more information about the file with c commands?
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
int main(int ac, char *av[])
{
DIR *d;
struct dirent *dir;
d = opendir("/home/CS/user/unix/Project4/TestDirectory");
if (d) {
while ((dir = readdir(d)) != NULL) {
printf("Name: %s \n", dir->d_name);
printf("- Inode: %lu\n", dir->d_ino);
printf("- reclen: %u\n", dir->d_reclen);
printf("- type: %u\n", dir->d_type);
}
closedir(d);
}
return(0);
}
Related
this is my current code:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
int main(int argc, char *argv[]){
struct stat file_stat;
DIR *dirp;
struct dirent* dent;
long size = 0;
if(argc > 1){
dirp = opendir(argv[1]);
printf("%s",argv[1]);
}
if(argc == 1){
argv[1] = ".";
dirp = opendir(argv[1]);
printf("dir .\n");
do{
dent = readdir(dirp);
if(dent){
char* fileName = dent->d_name;
if(fileName[0] == '.'){
continue;
}
printf("\t%s\n",dent->d_name);
if(!lstat(dent->d_name, &file_stat)){
printf("\t%d:",(int) file_stat.st_size);
size += (int)
file_stat.st_size;
}
}
}while(dent);
printf("\n\nTotal file space used:%ld\n",size);
closedir(dirp);
}
}
As of right now I only have it printing the files of the current directory.
My output is printing all my correct file sizes and file names. But it's printing it out of order. Each line should have the "fileSize: fileName". Currently it prints the first filename and the prints the size on the next line. Making each Filename have the size of the file before it. My output is below
dir .
p7.c.save
564: p7.c.save.3
466: p7
8632: Makefile
44: n
0: p7.c
779: p7.c.save.4
384: p7.c.save.2
360: p7.c.save.1
559:
This is what my output should roughly look like. I am newer to C and have been struggling with fixing the format of my output. If anyone could help me out or point me in the right direction I would greatly appreciate it!!!
$ ./p7
dir .
17371:p8
170:Makefile
1715:p8.c
11416:p8.o
Total file space used:30672
I was wondering if someone could tell me what I'm doing wrong. This code is supposed to walk though all the directories and files and print them out exactly the same way the UNIX utility FIND does. But for some reason I cant get chdir to change the working directory. I'm trying to limit the number of file descriptors im using.
MAIN
#include <stdio.h>
#include "sfind.h"
#include <unistd.h>
#include <dirent.h>
int main(int argv, char *argc[]){
char cwd[1024]; /* current working directory limit*/
char *path = NULL;
DIR *dp = NULL;
if (getcwd(cwd, sizeof(cwd)) != NULL){ /*allow us to grab the current working directory*/
fprintf(stdout, "Current working dir: %s\n", cwd);
}
else{
perror("getcwd() error");
}
dp = opendir(cwd);
path = ".";
directoryList(dp,path);
return 0;
}
Directory Method Definition
#include <stdio.h>
#include <stdlib.h>
#include "sfind.h"
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
void directoryList(DIR *dp, char *path){
char newPath[PATH_MAX] = {0};/*To store new path*/
struct dirent *element; /*get file name*/
struct stat statbuf;/*determine type of file*/
int status = 0; /*My base case should be once the directory I'm in runs outs out of files I should return;*/
if(dp == NULL){
fprintf(stderr,"FILE DID NOT OPEN!");
exit(-1);
}
/*change the current file directory even if its the first one*/
if((status = chdir(path)) == -1){
printf("ERROOR!");
}/*change the current working directory whether that the same on or not*/
while((element = readdir(dp)) != NULL) /*while current file directory pointer is not equal to zero*/{
/* from here we only have two cases once were reading from the directory either is a file or directory!*/
/*using lstat*/
lstat(element->d_name,&statbuf);
if((S_ISDIR(statbuf.st_mode))) /*is of type directory*/{
if((strcmp(".",element->d_name) == 0) || (strcmp("..",element->d_name) == 0))
continue;
/*create new directory name*/
newPath[0] = '\0';
strcat(newPath,path);/* this will give us the "."*/
strcat(newPath,"/");
strcat(newPath,element->d_name);
printf("%s\n", newPath);
directoryList(dp,newPath); /*recursion*/
file*/
}
else /*Its a file!*/{
printf("%s/%s\n",path,element->d_name);
}
}
}
The issue seems to be with the call to readdir(dp)...
Even though you change the current working directory, you don't update the dp pointer to open the new folder.
Here's a poor-man's working example (I wouldn't do it this way, but it works for small trees).
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void directoryList(DIR *dp, char *path) {
char newPath[PATH_MAX] = {0}; /*To store new path*/
struct dirent *element; /*get file name*/
struct stat statbuf; /*determine type of file*/
int status = 0; /*My base case should be once the directory I'm in runs outs
out of files I should return;*/
DIR *dp_tmp;
if (dp == NULL) {
fprintf(stderr, "FILE DID NOT OPEN!");
exit(-1);
}
while ((element = readdir(dp)) !=
NULL) /*while current file directory pointer is not equal to zero*/ {
/* from here we only have two cases once were reading from the directory
* either is a file or directory!*/
/*using lstat*/
lstat(element->d_name, &statbuf);
if ((S_ISDIR(statbuf.st_mode))) /*is of type directory*/ {
if ((strcmp(".", element->d_name) == 0) ||
(strcmp("..", element->d_name) == 0))
continue;
/*create new directory name*/
newPath[0] = '\0';
strcat(newPath, path); /* this will give us the "."*/
strcat(newPath, "/");
strcat(newPath, element->d_name);
printf("%s\n", newPath);
if ((dp_tmp = opendir(newPath)) == NULL) {
perror("hmm?! ");
exit(1);
}
directoryList(dp_tmp, newPath); /*recursion*/
} else /*Its a file!*/ {
printf("* %s/%s\n", path, element->d_name);
}
}
closedir(dp);
}
int main(void) {
char cwd[1024]; /* current working directory limit*/
char *path = NULL;
DIR *dp = NULL;
if (getcwd(cwd, sizeof(cwd)) !=
NULL) { /*allow us to grab the current working directory*/
fprintf(stdout, "Current working dir: %s\n", cwd);
} else {
perror("getcwd() error");
}
dp = opendir(cwd);
path = ".";
directoryList(dp, path);
return 0;
}
EDIT:
To answer the question in the comment...
Open directories (that should be closed using closedir) are different (and quite unrelated) to the current working directory.
The current working directory is mostly used to resolve the path to any file/folder you're referencing.
Open directory pointers (DIR *) are just pointers to data in the memory. That data relates to a specific directory and you can open a number of directories at the same time.
EDIT2:
A few people in the comments recommended nftw (file tree walk) which is a great alternative to doing it yourself.
If this isn't a learning project, I would recommend it's use.
However, note that POSIX.1-2008 marks ftw as obsolete, so make sure to use the nftw flavor.
Is your goal to learn to implement this yourself, or do you just want results? Because you should take a look at fts.h if you want some very powerful stuff to implement something like find.
I have drafted a code snippet that is to emulate the operation of ls -all in a custom shell named My$HELL
The main shell process invokes this code(by calling its executable through execlp).
Following is the code of the executable myls which is to do the work:-
myls.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
void search_dir(const char * arg);
void main(int argc, char *argv[])
{
int i;
if (argc==1)
search_dir(".");
for(i=1;i<argc;i++)
search_dir(argv[i]);
}
void search_dir(const char *arg)//Function to read directories and file attributes//
{
DIR *dirp;
struct dirent *dp;//Dirent structure used to read and store directory attributes//
char file_name[256];
char time[50]={"\0"};
struct tm *timeinfo;
struct stat prop_file;//stat function for accessing file attributes//
char type;
if((dirp=opendir(arg))==NULL)
{
perror("opendir");
return;
}
printf("\n\nDirectory \tTime last Modified\tSize\t\t Name\n");
while((dp=readdir(dirp))!=NULL) // Navigates the directory structure
{
if ( stat(dp->d_name,&prop_file)!=0) //Reading file attributes//
{
printf("\n%s:Error in reading the file attributes", dp->d_name );
continue;
}
if ( dp->d_type==8 )
{
type = '-';
}
else
{
type = 'd';
}
timeinfo=localtime(&(prop_file.st_mtime));
strftime(time,20,"%b %d %H:%M", timeinfo);
printf("\n %c\t\t %s\t\t%d\t\t %s",type,time,(int)prop_file.st_size,dp->d_name); //Printing ile attributes//
}
printf("\n");
}
Irrespective of the contents in the directory, the process displays certain fields after which the calling process terminates with a segmentation fault.
A GDB run is also of a little help (for being vague) and search on the error yields little result. Following is the debugged output:-
[~pbox/working/trial]<My$HELL>myls
Executing myls
Directory Time last Modified Size Name
d Aug 14 19:22 4096 ..
d Aug 14 18:42 4096 .
[~pbox/working/trial]<My$HELL>
Program received signal SIGSEGV, Segmentation fault.
strlen () at ../sysdeps/x86_64/strlen.S:106
106 ../sysdeps/x86_64/strlen.S: No such file or directory.
(gdb) Quit
From what I could understand such error are results of illegal variable/pointer assignments. Any help in pointing out the bug is highly appreciated.
Am also appending code segment of the main process from where myls is being called
main.c
.
.
else if(strcmp(command[0],"myls")==0) //command of type char ** stores the user input command check if the first field is 'myls'//
{
printf("Executing myls\n");
strcat(path,"/myls"); //path stores the directory path
result=execvp(path,command); //result of type int
exit(0);
}
.
.
Cheers and thanks in anticipation!!
the following code :
1) cleanly compiles
2) handles errors in an appropriate manner
3) does the job correctly
4) does not follow symbolic links
5) does not display the proper file type for every file
6) when accessing directories that are (in any way) protected
from casual reading, will output an error message
7) properly builds the path+filename before calling stat()
8) properly declares main() function and proper return
9) does not handle any options that are passed in.
10)does not seg fault
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
void search_dir(const char * arg);
int main(int argc, char *argv[])
{
int i;
char dirBuf[128] = {'\0'};
char * newline = NULL;
if (argc==1)
search_dir(".");
else
{
for(i=1;i<argc;i++)
{
newline = strcpy( dirBuf, argv[i] );
if( strstr( dirBuf, "\n") )
{
*newline = '\0';
}
search_dir(dirBuf);
}
}
return 0;
}
void search_dir(const char *arg)//Function to read directories and file attributes//
{
DIR *dirp;
struct dirent *dp;//Dirent structure used to read and store directory attributes//
char fileName[256];
char fileTime[50]={"\0"};
struct tm *timeinfo;
struct stat prop_file;//stat function for accessing file attributes//
char type;
printf( "%s\n", arg);
if( NULL == (dirp=opendir(arg)) )
{
perror("opendir failed");
return;
}
// implied else, opendir successful
printf("\n\nDirectory \tTime last Modified\tSize\t\t Name\n");
while( NULL != (dp=readdir(dirp)) ) // gets next entry in current directory,
{
strcpy(fileName, arg);
strcat(fileName, "/");
strcat(fileName, dp->d_name);
printf( "\nfileName: %s", fileName);
if ( stat(fileName,&prop_file) ) //Reading file attributes//
{
perror( "stat failed" );
printf("\n%s:Error in reading the file attributes", dp->d_name );
continue;
}
#ifdef _DIRENT_HAVE_D_OFF
// following if/else needs expansion
if ( dp->d_type==8 )
{
type = '-';
}
else
{
type = 'd';
}
#else
type = '?';
#endif
timeinfo=localtime(&(prop_file.st_mtime));
strftime(fileTime, 49, "%b %d %H:%M", timeinfo);
printf("\n %c\t\t %s\t\t%d\t\t %s",
type,
fileTime,
(int)prop_file.st_size,
dp->d_name); //Printing file attributes//
}
printf("\n");
closedir( dirp );
}
I have been using access(file_name, 0) == -1 to check whether the user input file_name exists in the directory or not. But this method works in the current working directory.
I wonder if there is a way I could know whether the file_name exists in another directory or not so I can move it to that directory.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/param.h>
void MoveFile(void)
{
DIR *directory;
FILE *Temp_file;
struct dirent *read_direcory;
char inserted_file_name[25]="/", intro[3]="/";
char *file_name = malloc(sizeof(*file_name));
char Current_path[200], destination_path[1024],relocating_path[1024] = "/";
int counter;
directory = opendir("./");
if (directory != NULL && getcwd(Current_path, sizeof(Current_path)) !=NULL)
{
fprintf(stdout, "\nYour current working directory: %s \n", Current_path);
counter = 0;
while ((read_direcory = readdir(directory)) != NULL){
printf("%d %s\n",counter,read_direcory -> d_name);
counter++;
}
closedir(directory);
}else{
perror("\nUnable to find the directory!");
}
printf("\nEnter just the name of the file you wish to move from above (e.g) file.txt.\n");
scanf("%s",file_name);
strcat(inserted_file_name, file_name);
printf("\nWrite the directory where %s file is located (e.g) /Users/Sam\n", file_name);
scanf("%s", relocating_path);
strcat(relocating_path, inserted_file_name);
//I want to know here whether it exists in that directory or not.
printf("\nWrite the name of the directory where you want to move your file to (e.g) /Users/Sam/Pictures:\n");
scanf("%s", destination_path);//file_name
strcat(destination_path, inserted_file_name);
if (rename(relocating_path, destination_path)){
perror(NULL);
getchar();
}
printf("\nMoving %s file was successful!:D\n", file_name);
}
One way to see if a file exists is to use the stat system call:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
{
...
struct stat sb;
if (stat(destination_path, &sb) == -1) {
if (errno == ENOENT) {
// File does not exist
}
}
}
I write this code to print all files in /home/keep with absolution path:
#include <dirent.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
void catDIR(const char *re_path);
int main(int argc, char *argv[])
{
char *top_path = "/home/keep";
catDIR(top_path);
return 0;
}
void catDIR(const char *re_path)
{
DIR *dp;
struct stat file_info;
struct dirent *entry;
if ((dp = opendir(re_path)) == NULL)
{
perror("opendir");
return;
}
while (entry = readdir(dp))
{
if (entry->d_name[0] == '.')
continue;
//get Absolute path
char next_path[PATH_MAX];
strcpy(next_path, re_path);
strcat(next_path, "/");
strcat(next_path, entry->d_name);
lstat(next_path, &file_info);
if (S_ISDIR(file_info.st_mode))
{
catDIR(next_path);
}
else
{
printf("%s/%s\n", re_path, entry->d_name);
}
}
free(dp);
free(entry);
}
When I run it.
Not only print some file's path, but also print some error message:
opendir: Too many open files
I read man 3 opendir, then realize, I had opened too many files.
I do want to know, how to close it? and how to correct this program
You should probably use closedir when you finish iterating through a directory's contents.
Also, you might want to read the directory's listing into an array, close the directory, and then recurse on the array. This might help with traversing very deep directory structures.
Run
cat /proc/sys/fs/file-nr
what does it give ?
output format is : (number of allocated file handlers) - (number of allocated but unused file handlers) - (maximum number of file handlers)
If you get more number of allocated but unused file handlers, it means that you've to close directories as mentioned by #Matthew Iselin.
You can also change system limit.
More info about changing system limit Can be found here.