Checking the file existence in other directories - c

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

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.

Can I get all file attributes in a directory using Inodes?

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

Printing directory: chdir not working

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.

How to code my own version of mv (rename/move) unix command in C language?

I want to write my own code for move(mv) Unix command. I am completely new to C language and apparently lost on how to fix my code. I want to perform actions like renaming a file if both the inputs are file names. If the the dest_folder is a directory I would like to move the file into the directory.
But I am unable to fix code for the particular problem as I am not much familiar with directories and C in particular. The program takes 2 inputs source and destination after which it performs necessary functions. I am apparently able to rename my files but I am unable to move the file to a particular folder for some reason I don't know?
Need help with moving file to a particular directory.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define SBUF 256
#define DBUF 256
int main(int ac, char *argv[])
{
DIR* dir_ptr; // the directory
struct dirent* direntp;
if( ac == 1 )
{
printf("Usage: %s MOVE\n", argv[0] );
exit(0);
}
if(ac>1 && ac<3)
{
printf("Error! few arguments provided " );
exit(0);
}
char src_folder[SBUF];
char dest_folder[DBUF];
strcpy(src_folder, argv[1]);
strcpy(dest_folder, argv[2]);
dir_ptr = opendir("."); //open directory
if ( dir_ptr == NULL )
{
perror( "." );
exit( 1 );
}
while( (direntp = readdir( dir_ptr )) != NULL )
{
if ( strcmp(direntp->d_name, dest_folder) !=0) //search file or directory
{
printf("found the file %s", dest_folder);
break;
}else
printf("not found");
break;
}
rename(src_folder, dest_folder);
closedir( dir_ptr );
return 0;
}
rename(3) does not work the way you want it to work (I don't know why, ask the committee). You cannot do a rename(some_file, some_directory), just as the man-page says.
Just use stat(2) (or lstat(2) if necessary) and check what you have been given. Here is a short, runnable sketch.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
// check if it is the same inode on the same device
#define SAME_INODE(a, b) ((a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)
// ALL CHECKS OMMITTED!
int main(int argc, char **argv)
{
struct stat statbuf_src, statbuf_dest;
char *src, *dest, *new_src, *new_dest;
char *current_directory;
if (argc != 3) {
fprintf(stderr, "usage: %s src dest\n", argv[0]);
exit(EXIT_FAILURE);
}
// work on copy
src = malloc(strlen(argv[1]) + 1);
dest = malloc(strlen(argv[2]) + 1);
strcpy(src, argv[1]);
strcpy(dest, argv[2]);
stat(src, &statbuf_src);
stat(dest, &statbuf_dest);
// there are many more, of course
printf("\"%s\" is a ", src);
if (S_ISREG(statbuf_src.st_mode)) {
puts("a regular file");
}
if (S_ISDIR(statbuf_src.st_mode)) {
puts("a directory");
}
printf("\"%s\" is a ", dest);
if (S_ISREG(statbuf_dest.st_mode)) {
puts("a regular file");
}
if (S_ISDIR(statbuf_dest.st_mode)) {
puts("a directory");
}
if (SAME_INODE(statbuf_dest, statbuf_src)) {
printf("%s and %s are the identical\n", src, dest);
}
// if that is not set you have to do it by hand:
// climb up the tree, concatenating names until the inodes are the same
current_directory = getenv("PWD");
printf("current directory is \"%s\"\n", current_directory);
// I'm pretty sure it can be done in a much more elegant way
new_src = malloc(strlen(src) + 1 + strlen(current_directory) + 1);
strcpy(new_src,current_directory);
strcat(new_src,"/");
strcat(new_src,src);
printf("new_src = %s\n",new_src);
new_dest = malloc(strlen(dest) + 1 + strlen(current_directory) + 1 + strlen(src) + 1);
strcpy(new_dest,current_directory);
strcat(new_dest,"/");
strcat(new_dest,dest);
strcat(new_dest,"/");
strcat(new_dest,src);
printf("new_dest = %s\n",new_dest);
if(rename(new_src,new_dest) != 0){
fprintf(stderr,"rename failed with error %s\n",strerror(errno));
}
free(new_src);
free(new_dest);
free(src);
free(dest);
exit(EXIT_SUCCESS);
}
Edit: added code for the desciption below
At the end you have a the path where you are, the information if the arguments given are directories or regular files and the path. If the source is a regular file and the destination a directory, you concatenate the path with the name of the regular file, the path with the name of the directory and the name of the regular file (your source)
Out of
Path = /home/foo
src = bar
dest = coffee
build
new_src = /home/foo/bar
new_dest = /home/foo/coffee/bar
Such that the call to rename() is
rename(new_src, new_dest);
That way you rename a regular file to a regular file which rename() accepts.
Please be aware that rename() does not work across every filesystem, but most.
Like you know, mv is implemented by rename. rename is a atomic system call that can rename a file to a file , an emtpy directory to an empty directory or a directory to a directory(the dest must be nonentity). So there are following situation to deal with:
mv file1 file2 - use rename function
mv dir1 dir2(nonentity or empty) - use rename function
mv dir1 dir2(not empty) - rename dir1 to dir2/dir1
mv file dir(exist) - rename file to dir/file
mv dir file - illegal operation
can you understand?

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.

Resources