#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.
- I don't know how to check if something is a file or directory.
- I've tried looking up methods for reading permissions and none have worked.
- 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.
- 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