Printing directory: chdir not working - c

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.

Related

How to Find number and folder of files in a directory

I need to find number of files and folders in a directory. I'm using MinGW compiler before this I tried to use d_type but I couldn't compile my code.
And I don't care about "." and" .. " directory. I don't wanna calculate them.
So I write a program like this. This program can easily find how many files and folders in a directory.
But When I give a new Name a folder instead of New Folder, New Folder(1). This programs calculate that folders as a file.
What can I do? I really stuck. I have to find how many files and how many folders...
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
int
main(int argc, char *argv[])
{
int file_count = 0;
int dir_count = 0;
struct dirent * entry;
struct stat filestat;
size_t nfiles = 0, ndirs = 0;
DIR *dp;
if (argc != 2)
{
printf("usage: put directory_name\n");
exit(-1);
}
if ((dp = opendir(argv[1])) == NULL)
{
printf("Error: can't open %s\n", argv[1]);
exit(-2);
}
while ((entry= readdir(dp)) != NULL){
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
stat(entry->d_name,&filestat);
if( S_ISDIR(filestat.st_mode) ){
ndirs++;
}
else
nfiles++;
}
closedir(dp);
printf("%lu Files, %lu Directories\n", nfiles, ndirs);
return(0);
}
entry->d_name will contain the filename only, not the full path, so if call stat() it will fail unless that file happens to exist in the current directory.
Also note that your code is not recursive, so it won't count stuff in the subfolders.

Searching Through a Directory to see if a File Exists in C

I'm trying to search for a file in a directory which are both specififed by the user on the command line when executing my program. It should look into the directory specified, and also check in sub-directories within that directory and recursively search for the file.
I have print statements in here trying to analyze the variables being passed around and how they're changing. Within my while loop, it's never reaching the checks for if it's a file or just the else statement saying it wasn't found. The check for if it's a directory is true every time, which is obviously not the case.
Thank you for any help. I'm not very familiar/comfortable with dirent and stat so I've been trying to review and make sure I'm using them correctly in the meantime.
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
void traverse(char *dir, char *file) {
DIR *directory;
struct dirent *structure;
struct stat info;
printf("Current directory to search through is: %s\n", dir);
printf("Current file to search for is: %s\n", file);
printf("\n");
printf("\n");
// make sure the directory can be opened
if((directory = opendir(dir)) == NULL) {
fprintf(stderr, "The directory could not be opened. %s\n", strerror(errno));
return;
}
chdir(dir); // change to the directory
while((structure = readdir(directory)) != NULL) { // loop through it
fprintf(stderr, "before the change it is: %s\n", dir);
lstat(structure->d_name, &info); // get the name of the next item
if(S_ISDIR(info.st_mode)) { // is it a directory?
printf("checking if it's a directory\n");
if(strcmp(".", structure->d_name) == 0 ||
strcmp("..", structure->d_name) == 0)
continue; // ignore the . and .. directories
dir = structure->d_name;
fprintf(stderr, "after the change it is: %s\n", dir);
printf("About to recurse...\n");
printf("\n");
traverse(structure->d_name, file); // recursively traverse through that directory as well
}
else if(S_ISREG(info.st_mode)) { // is it a file?
printf("checking if it's a file\n");
if(strcmp(file, structure->d_name) == 0) { // is it what they're searching for?
printf("The file was found.\n");
}
}
else {
printf("The file was nout found.\n");
}
}
closedir(directory);
}
int main(int argc, char *argv[]) {
// make sure they entered enough arguments
if (argc < 3) {
fprintf(stderr, "You didn't enter enough arguments on the command line!\n");
return 3;
}
traverse(argv[2], argv[1]);
}
There is a POSIX function for tree walking like this. It's called nftw().
It provides a callback mechanism and it also detects links caused by badly constructed symbolic link chaining.
So I'd recommend you use that rather than the way you're doing it.
As usual man nftw will explain it's operation in detail. The standard Linux/Unix include file is ftw.h.
Note their was a function called ftw() which is apparently obsolete now.
As Andrew Medico noted: You chdir down into directories but never go back up. Thus, just insert
chdir(".."); // change back to upper directory
between the end of the while loop and the end of the traverse() function.

Checking the file existence in other directories

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
}
}
}

In C, is there a way to get the size of multiple files with names matching a string?

I have files something like this:
file1_a_etc.txt,
file1_b_etc.txt
file2_a_z.txt
file2_b_z.txt
I want to get the size of files with "a" i.e. file2_a_z.txt & file1_a_etc.txt
I have got a large number of files this way, so cant specify each name individually.
I am a beginner at C.
I know how to read the size of a single file. And I am working on windows.
#include <stdio.h>
#include <sys/stat.h> // For struct stat and stat()
struct stat attr;
void main()
{
if(stat("filename.txt", &attr) == 0)
{
float x;
x=(attr.st_size)/1048576.0; //1MB=1048576 bytes
printf("Filesize: %.2f MB", x);
}
else
{
// couldn't open the file
printf("Couldn't get file attributes...");
}
}
For Windows console there is function _findfirst. For first parameter put *a*.txt.
You need to iterate over the files in a given directory while searching for the substring in each file name.
This answer, under the section (Unix/Linux), specifies how to iterate over each filename while comparing for an exact match, you can modify the strcmp function call to strstr to look for a substring.
You could make an Array of strings to store all filenames. Then you can use the strchr function to test, if an 'a' or other character is the name. The use of this function is explained e.g at http://www.tutorialspoint.com/ansi_c/c_strchr.htm
Reading directories programmatically can be done with readdir.
You could do something like this:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
static void lookup(const char *dir)
{
DIR *dirp;
struct dirent *dp;
if ((dirp = opendir(dir)) == NULL) {
perror("couldn't open '.'");
return;
}
do {
errno = 0;
if ((dp = readdir(dirp)) != NULL) {
if (strstr(dp->d_name, "_a_") == NULL)
continue;
(void) printf("found %s\n", dp->d_name);
// Add code to handle the file
}
} while (dp != NULL);
if (errno != 0)
perror("error reading directory");
(void) closedir(dirp);
return;
}
readdir is part of POSIX.1-2001, which is supported by unix/linux-type systems (including OS/X) but only some windows compilers. If you are programming in windows you may have to use another solution.

opendir: Too many open files

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.

Resources