Home > Net >  I need help getting file info in C
I need help getting file info in C

Time:10-09

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

// This program is pretty much a simulation of the ls command. Find out how to scan all of the files
// in the directory it's being run in and print out all the file names. Has to be in order.

int main(int argc, char* argv[])
{   
    // Don't worry about the else if, this is just a second part of my code that does not work entirely.
    else if (strstr(argv[1], "-i")) // Long output
    {
        char **words = calloc(1000, sizeof(*words));
        
        DIR *d;
        struct dirent *dir;  // Pointer for directory entry 
        d = opendir(".");
        char* a = ".";
        char* b = "..";
        char* c = "ls";
        int ret1, ret2, ret3, count = 0;
        
        
        if (d)  // opendir returns NULL if couldn't open directory
        {
            while ((dir = readdir(d)) != NULL)
            {
                ret1 = strcmp(dir->d_name, a); // Compare with the parent directory.
                ret2 = strcmp(dir->d_name, b); // Compare with the parent directory.
                ret3 = strcmp(dir->d_name, c); // Compare with the ls
                
                if (ret1 == 0 || ret2 == 0 || ret3 == 0)
                {
                    // Skip the ., .., and ls
                }
                else
                {
                    words[count] = strdup(dir->d_name); // Put the file name in the array.
                    count  ;
                }
            }
            
            for (int i = 0; i < count;   i) // Start readjusting the array in alphabetical order.
            {
                int imin = i;
                for (int j = i   1; j < count;   j)
                {
                    char word1[1000], word2[1000];
                    strcpy(word1, words[j]);
                    strcpy(word2, words[imin]);
                    for(int p = 0; word1[p]; p  )
                    {
                        word1[p] = tolower(word1[p]);
                    }
                    for(int p = 0; word2[p]; p  )
                    {
                        word2[p] = tolower(word2[p]);
                    }
                    if (strcmp(word1, word2) < 0)
                    {
                        imin = j;
                    }
                }
                char *tmp = words[i];
                words[i] = words[imin];
                words[imin] = tmp;
            }
            
            // Print every word in the array, but this time with metadata!
            struct stat meta;
            for (int i = 0; i < count;   i)
            {
                stat(words[i], &meta);
                int size = meta.st_size;
                
                // How am I supposed to get read, write, execute info???
                
                struct passwd *p;
                struct group *grp;
                uid_t uid = 0;
                gid_t gid = 0;
                
                if ((p = getpwuid(uid)) == NULL) // If username doesn't exist
                {
                    printf("%d ", meta.st_uid); // User id
                }
                else
                {
                    printf("%s ", p->pw_name); // User Name
                }
                
                if ((grp = getgrgid(gid)) == NULL) // If group name doesn't exist
                {
                    printf("%d ", meta.st_gid); // Group id
                }
                else
                {
                    printf("%s ", grp->gr_name); // Group Name
                }
                
                printf("%d ", size); // File Size
                
                printf("%s ", ctime(&meta.st_mtime)); // bad date format
                
                // I don't want the file name moving down. 
                
                printf("%s \n", words[i]); // File name
            }
            
        }   
        // Closing and freeing
        closedir(d);
        for (int a = 0; a < 1000;   a)
        {
            free(words[a]);
        }
        free(words);
        
        return 0;
    }
}

Currently my code gives this output.

root root 435 Tue Oct  5 23:52:59 2021
 find.c 
root root 4562 Fri Oct  8 15:31:23 2021
 ls.c 
root root 58 Wed Oct  6 00:14:25 2021
 Makefile 
root root 296 Wed Oct  6 00:04:37 2021
 tree.c 

My problem is that it's supposed to be in this format. -rwxrw-r-- tim users 1252 Sep 28 14:00 find.c

The first "-" is supposed to be an indicator for a file(-) or directory(d), then check, read, write, execute permissions for user, group, and others, then username(or user id), groupname(or group id), then file size, then modification time, then file name.

  1. I don't know how to check if something is a file or directory.
  2. I've tried looking up methods for reading permissions and none have worked.
  3. The date format from my output does not match the output I'm trying to get and I don't know how to fix it.
  4. With the date format I'm using currently, the file name gets put down a line and I don't want that.

Can anyone help me out with this?

CodePudding user response:

The line break before the filename is because ctime() returns a string that ends with newline. So you should remove this.

char *time = ctime(&meta.st_mtime);
time[strlen(time)-1] = '\0'; // remove newline
printf("%s ", time);

To determine the file type, see Checking if a file is a directory or just a file

To convert the permissions to symbolic form, see Printing file permissions like 'ls -l' using stat(2) in C

  • Related