how to write to a directory C - c

I'm trying to copy directory contents to another directory
but I'm having a problem with writing to the second directory without using sprintf; Any suggestions?
void Copying(char *folder1, char *folder2) {
DIR *s1, *s2;
struct dirent *dep;
if ((s1 = opendir(folder1)) == NULL) {
printf("Error\n");
return;
}
if ((s2 = opendir(folder2)) == NULL) {
printf("Error \n");
return;
}
while ((dep = readdir(s1)) != NULL) {
//write(s2 , dep->d_name , sizeof(dep) ) ; // <-
}
closedir(s1);
closedir(s2);
return;
}

This approach won't work. Directory handles are not writable.
If you want to copy the contents of a directory, you will need to copy each file, directory, and link in the source directory individually. To copy each file, you will need to create a new file in the target directory and write the contents of the source file into it.

Related

C program for creating folders based on file extensions and copying files with the extensions into them

I am trying to create a c program that reads the extensions of the files in its current working directory.
The program then creates folders that correspond to the extensions of the files. It then copies each file
from its cwd into the corresponding folder.
e.g:
hello.txt into created .txt folder
The code successfully creates folders for all the file extensions in the current directory, but crashes when it begins to copy.
Here is the whole code.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <dir.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
FILE *input, *output; // Two files, input and output
char ch; // ch is used to assign characters from input file which will then be copied into the output file
char *exe = ".exe";
struct dirent *de;
DIR *dr = opendir("."); // Open directory for reading
printf("%s", dr->dd_name);
// If directory doesn't exist, quit
if(dr == NULL) {
printf("Can't open current directory.");
return 0;
}
// Loop first to create a directory corresponding to all
// extensions present in the current directory
while((de = readdir(dr)) != NULL) {
char *filename = de->d_name; // Get the filename
char *ext = strrchr(filename, '.'); // Get the extension
if(!(!ext || ext == filename)){ // Compare extension
int check = mkdir(ext);
if(!check)//Check if the directory was created
printf("Directory created successfully.\n");
else {
printf("Unable to create directory.\n");
}
}
}
// Close the directory so as to reset the pointer ready for the next read.
closedir(dr);
dr = opendir(".");
// Loop reading each file and checking which
// directory it corresponds to.
while((de = readdir(dr)) != NULL) {
char *filename = de->d_name; // Get the filename
char *ext = strrchr(filename, '.'); // Get the extension
if(!(!ext || ext == filename)){ // Check for a valid extension
DIR *file_ext_dir = opendir(ext); // Open the dir that corresponds to the extension of the file.
char *dir_name = file_ext_dir->dd_name; //Get the dir name of the opened directory
if(file_ext_dir && (strcmp(dir_name, "..") != 0)&& (strcmp(ext, exe) !=0) ) { //ignore .exe and the cwd
printf("Successfully opened: %s dir\n", file_ext_dir->dd_name);
char *output_path = strcat(dir_name, filename);
printf("Ready to copy files from %s to: %s\n", filename, output_path);
output = fopen(output_path, "a+"); // Open output.txt for appending, if doesn't exist, create it.
input = fopen(filename, "r"); // Open the input file ()'filename') for reading
while(1) { // Loop through the input file
ch = fgetc(input); // Get the current character
if(ch == EOF) break; // Stop if EOF is found
putc(ch, output); // Put current character from the input file into output.txt
}
fclose(input); // Close input file
fclose(output); // Close output file
closedir(file_ext_dir);
} else if(ENOENT == errno){ //Check if there is no such directory and handle the error
printf("Dir does not exist.");
}else {
continue; //Skip that file if for some reason the directory cannot be opened.
}
}
}
closedir(dr); // Close directory
printf("Created directories and copied all files to that correspond to them.");
return 0;
}

Recursively searching directories for a file

I'm trying to recursively search a directory for a file and output the file if it matches the given:
static int *search(char *path, const char *request, int depth, bool verbose)
{
DIR *dir;
struct dirent *ent;
char *start_dir = strcmp(path, "/") == 0 ? "root" : path;
printf("\nStarting in '%s' directory..\n\n", start_dir);
if ((dir = opendir(path)) != NULL)
{
while ((ent = readdir(dir)) != NULL)
{
if (verbose == true)
{
printf("Searching directory %s for file %s\n", ent->d_name, request);
}
if (ent->d_type == DT_DIR)
{
if ((strlen(path) + strlen(ent->d_name) + 1) > PATH_MAX)
{
puts("Path to long, cannot continue..");
}
else
{
if (ent->d_name == DT_DIR && strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0 )
{
printf("%s\n", ent->d_name);
}
}
}
}
}
return 0;
}
This will work but it will not output the files or directories inside of the directory. Example:
#ubuntu:~/bin/c/find-files$ ./utilis test / -V
Initialized to search for file: 'test'..
Starting in 'root' directory..
Searching directory vmlinuz.old for file test
Searching directory boot for file test
Searching directory home for file test
Searching directory libx32 for file test
Searching directory lib32 for file test
Searching directory lib64 for file test
Searching directory initrd.img for file test
Searching directory srv for file test
Searching directory usr for file test
Searching directory . for file test
Searching directory cdrom for file test
Searching directory tmp for file test
Searching directory initrd.img.old for file test
Searching directory bin for file test
Searching directory .. for file test
Searching directory proc for file test
Searching directory lib for file test
Searching directory var for file test
Searching directory dev for file test
Searching directory sys for file test
Searching directory media for file test
Searching directory root for file test
Searching directory snap for file test
Searching directory run for file test
Searching directory sbin for file test
Searching directory opt for file test
Searching directory lost+found for file test
Searching directory mnt for file test
Searching directory vmlinuz for file test
Searching directory etc for file test
How can I refactor this function in order to recursively search for the given filename in all directories and sub directories?
As already point out in the comments by many. Your code is not recursive with the missing recursive call (function calling itself). You have a lot of mistake. Not checking for errors with various system calls and forgetting to close the directory stream. I don't know what you want to achieve with your various parameters int depth, bool verbose. But this is another way of looking for a specific file and returning 0 --> EXIT_SUCCESS on success and 1 -->EXIT_FAILURE on failure.
The are various ways things can go wrong when using system calls and some them set errnos, which is important to look at them and print to STDERR
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#define DEBUG 1
static int search(char *path,const char *file){
DIR *dir;
char *slash = "/";
int ret = 1;
struct dirent *entry;
//checking if it failed to open and report errors to STDERR
if((dir = opendir(path)) == NULL){
fprintf(stderr,"opendir: %s\n",strerror(errno));
return EXIT_FAILURE;
}
while ((entry = readdir(dir))){
//if is . or .. we continue to prevent winging back and forth
if(strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0)
continue;
//we check if the path has already a / if not we add one
int length = strlen(path);
if(path[length-1] != '/'){
slash = "/";
}
length += strlen(entry->d_name)+2;
char *newpath = malloc(length);
if (!newpath){
fprintf(stderr,"malloc: %s\n",strerror(errno));
break;
}
snprintf(newpath,length,"%s%s%s",path,slash,entry->d_name);
if(strcmp(entry->d_name,file) ==0){
#if DEBUG
printf("Was found here %s\n",newpath);
#endif
ret = EXIT_SUCCESS;
break;
}
//checking if is a directory to do a recursive call
// using DT_DIR to avoid the use of lstat or stat
// if not directory we free the memory and move on
if(entry->d_type == DT_DIR)
search(newpath,file);
else{
free(newpath);
continue;
}
free(newpath);
}
if(closedir(dir) != 0){
fprintf(stderr,"closedir: %s\n",strerror(errno));
return EXIT_FAILURE;
}
return ret;
}
int main() {
char *file = "algo.c";
int ret = search("/",file);
printf("%d The file %s was %s\n",ret,file,(ret == 0 ? "found":"not found"));
return 0;
}
With DEBUG set to 1
Was found here /Users/addodennis/CLionProjects/BluePrint/algo.c
The file algo.c was found
With DEBUG set to 0
file algo.c was found

How to open a file in a subdirectory in c

I am trying to open a file in a subdirectory called "Files". I know how to open a file in a subdirectory if I know the name:
fopen("./Files/file.txt", "r");
However, I am trying to create a file that will open any and all files in the subdirectory without having to know the file names ahead of time. I am using the reaaddir() function to be able to locate the file name, however, I am not sure how to plug it into fopen to open and read the file. The readdir() function automatically saves the file name in dp_>d_name. Then If I do this:
fopen("./Files/dp->d_name", "r");
the program is going to try to open the file named "dp->d_name" rather than the file name stored at that location.
IF there is not a way to do this, is there a way to change the current working directory from within the program? Every file I want to open is within the same subdirectory, so that would be an acceptable solution.
Here is my code, for reference:
#include <stdio.h>
#include <dirent.h>
#include <string.h>
void readFile(int)
{
DIR *dir;
struct dirent *dp;
char * file_name;
char buffer[100];
FILE *out;
FILE *in;
char outName[] = "filenames.txt";
if (( out = fopen(outName, "w+")) == NULL )
{
printf("Can't open %s for writing.\n", outName);
return 2;
}
dir = opendir("./Files/");
while ((dp=readdir(dir)) != NULL)
{
if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
{
//do nothing...
}
else
{
if (( in = fopen( dp->d_name, "r")) == NULL)
{
printf("Can't open %s for writing.\n", dp->d_name);
return 2;
}
fgets(buffer, 100, in);
printf("\"%s\"\n", buffer);
}
}
closedir(dir);
fclose(out);
return 0;
}
you can create the full file location in another variable by joining "./Files/" before dp->d_name. you can either use strcat() for it or use create char* with enough size to store the entire location and then fill it using a for loop, and then use this variable in fopen. eg.
if dp->d_name = "f1.txt" then create a variable,
newFileName = "./Files/f1.txt" and then fopen(newFileName, "r");

writing ls from scratch recursively

I am working on a simple project to implement "ls -R" from scratch. Whenever I run what I have, my program just keeps searching the root directory over and over again. What am I doing wrong?
void lsR(char dirName[]) {
/*
The recursive function call.
*/
DIR *dir;
struct dirent *directory;
struct stat fileStat;
char type;
char **nameList[MAX_RECURSIVE_FILES];
struct passwd *user;
int count = 0;
int i = 0;
printf("\n");
printf("./%s :\n", dirName);
printf("\n");
if ((dir = opendir(dirName)) == NULL) {
perror("opendir error:");
return;
}
while ((directory = readdir(dir)) != NULL) {
if (stat(directory->d_name, &fileStat) < 0) {
perror("fstat error:");
return;
}
if (fileStat.st_uid == 1) {
continue;
}
user = getpwuid(fileStat.st_uid);
printf("%s ", directory->d_name);
fileType(&fileStat, &type);
if ((type == 'd') && (count < MAX_RECURSIVE_FILES)) {
nameList[count] = malloc(sizeof(char)*MAX_STRING_LENGTH);
strncpy(nameList[count++], directory->d_name, MAX_STRING_LENGTH);
}
}
closedir(dir);
printf("\n");
for (i=0; i<count; i++) {
printf("Calling lsR on: %s\n", nameList[i]);
lsR(nameList[i]);
}
}
When it executes, I get the following output:
"./. :
., .., ... all other files in my current working directory ....
./. :
., .., ... all other files in my current working directory...
"
Among the list of files in the current directory you've noticed . and .. The first one is a hardlink to the current directory and the second one to the parent directory. So when you recurse through your dir entries you will want to skip those two. Otherwise the first directory you will recurse into will be ., in other words the directory you've just gone through.
This is the reason of your program current behavior, but once you fix that you will run into the issue lurker mentioned in his answer.
Additional notes :
Are you sure about the char **nameList[MAX_RECURSIVE_FILES]; variable? Seems to me you want an array of char * not an array of char **.
Are you aware you can use the S_ISDIR macro on the st_mode field of your stat struct, in order to check that the current file is not a directory instead of your custom function?
You need to include the path relative to your program's current directory. Each nameList element will need to be dirName + "/" + directory->d_name.
If you started out calling lsR on the local directory, ./foo and foo has directory named bar under it, then to open bar you need to open ./foo/bar since your program is running from the directory represented by ..

Delete files from a specific folder in C

I'm trying to delete files from a specifc folder. My deleteFile() function only deletes on its home folder, not on /tmp folder which is what I need. I tried the same approach as my displayDIR() function to change directory but I can't figure out how to make it work. I use cygwin as compiler.
void deleteFile() {
int status;
char filetodelete[25];
printf("\n \t **Delete File**\n");
displayDIR();
printf("\n\tChoose the name of the file to delete:\t");
scanf("%s", filetodelete);
status = remove(filetodelete);
if( status == 0 )
printf("%s file deleted successfully.\n", filetodelete);
else {
printf("\n\tUnable to delete the file");
perror("\n\tError");
}
}
void displayDIR() {
DIR *d;
struct dirent *dir;
d = opendir("C:/cygwin/tmp");
if (d) {
while ((dir = readdir(d)) != NULL)
printf("\t\t\t%s\n", dir->d_name);
closedir(d);
}
}
You need to include the folder path in the argument to remove():
char fullpath[40] = "C:/cygwin/tmp/";
strcat(fullpath, filetodelete);
status = remove(fullpath);

Resources