Search code examples
clinuxfile-type

c S_ISDIR and S_ISREG not working


I need to make an app in linux using C, I need to enter a folder path and copy all the files and subdirectories in a new folder. The problem is when I try to check if the path is to a folder or a file, the program always take the path like a folder, even if it's a file. I don't know what am i doing wrong. Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <assert.h>

int main()
{
    CopyFile("test3","test4");
    return (0);
}

void mkdirRecursive(const char *path, mode_t mode) {
    char opath[PATH_MAX];
    char *p;
    size_t len;

    strncpy(opath, path, sizeof(opath));
    opath[sizeof(opath) - 1] = '\0';
    len = strlen(opath);
    if (len == 0)
        return;
    else if (opath[len - 1] == '/')
        opath[len - 1] = '\0';
    for(p = opath; *p; p++)
        if (*p == '/') {
            *p = '\0';
            if (access(opath, F_OK))
                mkdir(opath, mode);
            *p = '/';
        }
    if (access(opath, F_OK))         
        mkdir(opath, mode);
}

void CopyFile(char* NumeFisOld, char* NumeFisNew)
{


    DIR *dp;
    struct dirent *dirp;
    struct stat info;
    char OldDirPath[255];
    char NewDirPath[255];
    stat(NumeFisOld,&info);
    int status = stat (NumeFisOld, &info);
    if (status != 0) 
    {
        fprintf (stderr, "Error, errno = %d\n", errno);
        perror("stat error: ");
        return;
    }
    fprintf (stderr, "Error, errno = %d\n", errno);
    perror("stat error: ");
    if(S_ISREG(info.st_mode))
    {
        printf("File: File location: %s \n",NumeFisOld);
        printf("File: New file location: %s \n",NumeFisNew);
        char buffer[65];
        int fhRead;
        int fhWrite;
        unsigned int nbytes=65;
        int bytesread;
        int byteswritten;
        if((fhRead=open(NumeFisOld, O_RDONLY)) ==-1)
        {
            perror("Eroare la deschiderea fisierului");
            exit(1);
        }

        if((bytesread=read(fhRead,buffer,nbytes))<=0)
            perror("Probleme la citirea fisierului");
        else
            printf("Citeste %u bytes din fisier\n", bytesread);

        close(fhRead);
        if((fhWrite=open(NumeFisNew,O_WRONLY | O_CREAT,S_IREAD | S_IWRITE)) !=-1) 
        {
            if((byteswritten=write(fhWrite, buffer, sizeof(buffer))) == -1)
                perror("Eroare la scriere");
            else
                printf("A scris %u bytes in fisier\n",byteswritten);
            close(fhWrite);
        }

    }
    else if(S_ISDIR(info.st_mode))
    {
        printf("Folder: File location: %s \n",NumeFisOld);
        printf("Folder: New file location: %s \n",NumeFisNew);
        dp=opendir(NumeFisOld);
        while((dirp=readdir(dp)) != NULL)
        {

            strcpy(OldDirPath, NumeFisOld);
            strcat(OldDirPath,"/");
            strcat(OldDirPath,dirp->d_name);
            strcpy(NewDirPath, NumeFisNew);
            strcat(NewDirPath, "/");
            strcat(NewDirPath,dirp->d_name);
            DIR* dir = opendir(NewDirPath);
            if(dirp->d_name[0]!='.') 
            {
                if (dir)
                {
                    /* Directonry exists. */
                    CopyFile (OldDirPath,NewDirPath);
                    printf("Directorul %s exista deja \n",NewDirPath);
                    closedir(dir);
                }
                else if (ENOENT == errno)
                {

                    printf("Directorul %s nu exista \n",NewDirPath);
                    mkdirRecursive(NewDirPath,0755);
                    CopyFile (OldDirPath,NewDirPath);
                    /* Directory does not exist. */
                }
                else
                {
                    printf("Directorul %s nu s-a putut deschide \n",NewDirPath);
                    /* opendir() failed for some other reason. */
                }
            }

        }


    }

}

My logic is that: First I check if the path is a directory, if it is, create it in my new folder(NumeFisNew) and then enter it(NumeFisOld) and repeat for each subdirectory or file in it. If the path is a file, then it should enter in else and copy the file in the path(NumeFisNew).

Edit: Ok, here is the result:

Error, errno = 0
stat error: : Success
Folder: File location: test3 
Folder: New file location: test4 
Error, errno = 0
stat error: : Success
Folder: File location: test3/test5 
Folder: New file location: test4/test5 
Directorul test4/test5 exista deja 
Error, errno = 0
stat error: : Success
Folder: File location: test3/test4 
Folder: New file location: test4/test4 
Error, errno = 0
stat error: : Success
File: File location: test3/test4/test2 
File: New file location: test4/test4/test2 
Citeste 42 bytes din fisier
Directorul test4/test4/test2 exista deja 
Directorul test4/test4 exista deja 
Error, errno = 21
stat error: : Is a directory
File: File location: test3/test1 
File: New file location: test4/test1 
Citeste 42 bytes din fisier
Directorul test4/test1 exista deja 

If it has File in front, it means it was used from if(S_ISREG) and if it has Folder, it means it was used from if(S_ISDIR). So at least now it recognized that test1 and test2 are files, but it still copied them as folders.


Solution

  • You must switch you control statement: first look if it's a file and after check if it is a dir

    if (S_ISREG (info.st_mode)) 
    {
        printf ("It's a file\n");
    }
    else if (S_ISDIR (info.st_mode)) 
    {
        printf ("It's a dir\n");
    }
    

    Moreover you should take care of stat return value

    int status = stat (NumeFisOld, &info);
    if (status != 0) 
    {
        fprintf (stderr, "Error, errno = %d\n", errno);
        perror("stat error: ");
        return;
    }