Implement LS command

Implement LS Command

Directories, Files and Timestamps

You are required to create a C program which works with command line
arguments. The arguments themselves may or may not be present on the command line.
Your code will have to adapt itself to accommodate for this.
You are essentially writing your own version of the lscommand. You need to customize your output to match the following specifications:

You program must accept the following parameters (if present):

-s: specifies the age of the oldest files (modification timestamp) to be listed from the
target directory. The -s argument will be followed by an integer (as a separate parameter
to make things easier if you wish). This integer will represent the maximum number of
days old the files can be in order for them to be included in your listing. You can think of
the -s to represent SINCE. As an example “-s 3” passed as arguments would mean: list
all files that have been modified since 3 days from the current system time.

-b: specifies the age of the newest files (modification timestamp) to be listed from the
target directory. The -b argument will be followed by an integer (as a separate parameter
to make things easier if you wish). This integer will represent the number of days old the
files need to be in order for them to show up in your listing. You can think of the -b to
represent BEFORE. As an example “-b 7” passed as arguments should represent list all
files whose modification timestamp is at least 7 days older than the current system time.
See examples below for how -s and -b work in practice.

directory_path: the last argument on the command line should be a directory
specification. Use this parameter to point your code to a specific directory whose content
you want to list. If this parameter is NOT there, the current working directory should be
assumed. You will be required to run your program against the /home/COIS/3380/lab3
directory on the loki.trentu.ca server. Test dates will be supplied in the examples below.
Your code however should work with any directory path. You can assume that any path
over 4096 characters can be rejected by your code as too long.
It is important to use modular programming techniques (i.e. functions) as the code from this lab
may be used in upcoming labs. It is strongly recommended that you work on a function to
generate the appropriate formatting of the information returned from the stat() function for a
single file before implementing it for the whole directory.
If you are not using the getopt() function, you need not implement logic to ensure that the -s/-b
options are followed by integers (when present). Your code can “assume” the argv[] elements
directly following the -s and -b are integers, just to make things simpler. When you run your
code, just make sure to put the proper values on the command line. The target directory for your
code must be the last parameter passed on the command line (if present. If not your code you
default back to the current directory).
Your code can be used for any directory. The output your code creates for the /home/COIS/3380/lab3 directory should contain the same information as and look similar to, the examples below.

Here is what is currently in /home/COIS/3380/lab3 on loki.trentu.ca:

[jacques@loki ~]$ ls /home/COIS/3380/lab3 -lt
total 32644
prw-r–r–. 1 root root 0 Jul 30 15:37 CHAT_FIFO
lrwxrwxrwx. 1 root root 22 Jul 30 15:30 info.php -> /var/www/html/info.php
-rw-r—–. 1 root root 16436089 Jul 30 11:44 lab3_dir.tar.gz
-rw-r–r–. 1 jacquesjacques 1921 Jul 30 11:17 small_world.txt
-rw-r–r–. 2 root root 616 Jul 25 11:23 lab2_textfile.txt
-rw-r–r–. 1 jacquesjacques 9043232 Feb 4 2017 WinSCP-5.9.3-Setup.exe
-rw-r–r–. 1 jacquesjacques 3093 Feb 1 2017 string_testing.c
-rw-r–r–. 1 jacquesjacques 6477803 Jan 20 2017 cities_all.csv
-rw-r–r–. 1 jacquesjacques 559 Jan 20 2017 cities_short.csv
-rw-r–r–. 1 jacquesjacques 531368 Jan 17 2017 putty.exe
-rwxr—–. 1 jacques COIS-3380H-A 213904 Dec 9 2016 visual_Studio_Community.exe
drwxr-xr-x. 2 jacquesjacques 4096 Feb 8 2016 gnuplot
-rw-r–r–. 1 jacquesjacques 6915 Jan 26 2016 3_range_random.c
-rw-r–r–. 1 jacquesjacques 1832 Jan 26 2016 1_test_random.c
-rw-r–r–. 1 jacquesjacques 2879 Jan 26 2016 2_seed_random.c
-rwxr—–. 1 jacques COIS-3380H-A 22434 Jan 21 2016 Shell_file_processing.pdf
-rw-r–r–. 1 jacquesjacques 46903 Jul 3 2005 jewel.jpg
-rw-r–r–. 1 jacquesjacques 408606 Nov 1 2001 poke1.jpg
-rw-r–r–. 1 jacquesjacques 20675 Feb 21 2000 arasaurolopus_baby.pdf
-rw-r–r–. 1 jacquesjacques 87489 Feb 21 2000 diplodocus.pdf
-rw-r–r–. 1 jacquesjacques 36019 Feb 21 2000 stegosau.pdf
-rwx——. 1 1005 1005 40102 Dec 6 1987 CALCOMP.ARC
-rw-r–r–. 1 jacquesjacques 1179 Jan 1 1980 C128.XTK
[jacques@loki ~]$
[jacques@loki ~]$ ls /home/COIS/3380/lab3/gnuplot/ -lt
total 3992
-rw-rw-r–. 1 jacquesjacques 2359473 Sep 2 2014 test_movie_1024x768.gif
-rw-rw-r–. 1 jacquesjacques 1591743 Aug 27 2014 video.gif
-rw-rw-r–. 1 jacquesjacques 117323 Aug 11 2014 sine.gif
-rw-rw-r–. 1 jacquesjacques 217 Aug 11 2014 sine.gp
-rw-rw-r–. 1 jacquesjacques 1107 Jun 28 2013 histo.gp
-rw-rw-r–. 1 jacquesjacques 62 Jun 28 2013 histo.dat
[jacques@loki ~]$ 

Solution 

#include <stdio.h>

#include <unistd.h>

#include <sys/stat.h>

#include <time.h>

#include <stdlib.h>

#include <string.h>

#include <dirent.h>

#include <errno.h>

#include <limits.h>

#include <pwd.h>

#include <grp.h>

/* parse the arguments.

* (1) get the range of allowed modification time.

* (2) get the directory to list. */

const char *parse_args(intargc, const char *argv[], time_t *since, time_t *before);

/* list the content in the dir. */

voidlist_directory(const char *dir, consttime_t since, consttime_t before);

/* use stat to print the detail of this entry. */

voidstat_entry(const char *name, const char *path, consttime_t since, consttime_t before);

/* format the time into yyyy-mm-dd HH:MM:SS for printing. */

const char *format_time(consttime_t t, char buf[], constsize_t size);

/* parse the name for the user or group id */

const char *parse_uid(constuid_tuid, char *buf, constsize_t size);

const char *parse_gid(constgid_tgid, char *buf, constsize_t size);

/**

* ./myls [-s days] [-b days] [path]

* As suggested in the project, there is no parameter format checking

* in this implementation.

*/

int main(intargc, const char *argv[]) {

const char *dir;

time_t since;

time_t before;

dir = parse_args(argc, argv, &since, &before);

list_directory(dir, since, before);

return 0;

}

/** ———————- function implementation —————— */

const char *parse_args(intargc, const char *argv[], time_t *since, time_t *before) {

const char *dir = “.”;

time_t now = time(NULL);

unsignedint i;

int gap;

charbuf[128]; /* store timestamp to display */

*since = 0;

*before = now;

for (i = 1; i <argc; i++) {

if (strcmp(argv[i], “-s”) == 0) {

gap = atoi(argv[i + 1]);

i ++;

/* recalculate the since time (accurate in second) */

*since = now – gap * 24 * 3600;

printf(“The newer than timestamp is %lu which equates to: %s\n”,

*since, format_time(*since, buf, sizeof(buf)));

} else if (strcmp(argv[i], “-b”) == 0) {

gap = atoi(argv[i + 1]);

i ++;

/* recalculate the before time */

*before = now – gap * 24 * 3600;

printf(“The newer than timestamp is %lu which equates to: %s\n”,

*before, format_time(*before, buf, sizeof(buf)));

} else {

/* must be the directory to list */

dir = argv[i];

}

}

returndir;

}

const char *format_time(consttime_t t, char buf[], constsize_t size) {

strftime(buf, size, “%Y-%m-%d %H:%M:%S”, localtime(&t));

returnbuf;

}

voidlist_directory(const char *dir, consttime_t since, consttime_t before) {

DIR *d;

structdirent *ent;

char path[PATH_MAX];

/* open the directory */

if ((d = opendir(dir)) == NULL) {

fprintf(stderr, “%s: No such directory\n”, dir);

exit(errno);

}

printf(“%10s  %-4s    %-10s  %-12s  %-12s  %-20s  %8s   %s\n”,

“inode”, “Type”, “Permission”, “UID”, “GID”, “Modification Date”, “Size”, “Filename”);

/* traverse the directory and collect all entries */

while ((ent = readdir(d)) != NULL) {

if (strcmp(ent->d_name, “.”) == 0 || strcmp(ent->d_name, “..”) == 0) {

continue;

}

/* construct the full path for this entry */

snprintf(path, sizeof(path), “%s/%s”, dir, ent->d_name);

stat_entry(ent->d_name, path, since, before);

}

/* assume the end of directory has reached.

* anyerrno is ignored here. */

/* close the directory */

if (closedir(d) == -1) {

fprintf(stderr, “could not close directory: %d\n”, errno);

exit(errno);

}

}

voidstat_entry(const char *name, const char *path, consttime_t since, consttime_t before) {

struct stat s;

char type[16];

char perm[16];

charuid[128], gid[128];

charmtime[128];

char link[PATH_MAX + 4] = ” -> “;

if (lstat(path, &s) == -1) {

return; /* cannot get the detail of this entry, silently ignored */

}

/* filter by the time range */

if (s.st_mtime< since || s.st_mtime> before) {

return;

}

/* collect information about this path from stat. */

if (S_ISREG(s.st_mode)) {

strncpy(type, “REG”, sizeof(type));

} else if (S_ISDIR(s.st_mode)) {

strncpy(type, “DIR”, sizeof(type));

} else if (S_ISFIFO(s.st_mode)) {

strncpy(type, “FIFO”, sizeof(type));

} else if (S_ISLNK(s.st_mode)) {

strncpy(type, “LINK”, sizeof(type));

readlink(path, &link[4], PATH_MAX);

} else if (S_ISSOCK(s.st_mode)) {

strncpy(type, “SOCK”, sizeof(type));

} else { /* unknown type, should not happen */

strncpy(type, “”, sizeof(type));

}

/* not a link, clear the link field so no extra information is printed. */

if (strcmp(link, ” -> “) == 0) {

strncpy(link, “”, sizeof(link));

}

/* construct the permission from st_mode */

perm[0] = (s.st_mode& S_IRUSR) ? ‘r’ : ‘-‘;

perm[1] = (s.st_mode& S_IWUSR) ? ‘w’ : ‘-‘;

perm[2] = (s.st_mode& S_IXUSR) ? ‘x’ : ‘-‘;

perm[3] = (s.st_mode& S_IRGRP) ? ‘r’ : ‘-‘;

perm[4] = (s.st_mode& S_IWGRP) ? ‘w’ : ‘-‘;

perm[5] = (s.st_mode& S_IXGRP) ? ‘x’ : ‘-‘;

perm[6] = (s.st_mode& S_IROTH) ? ‘r’ : ‘-‘;

perm[7] = (s.st_mode& S_IWOTH) ? ‘w’ : ‘-‘;

perm[8] = (s.st_mode& S_IXOTH) ? ‘x’ : ‘-‘;

perm[9] = 0;

printf(“%10lu  %-4s    %-10s  %-12s  %-12s  %-20s  %8lu   %s%s\n”,

(unsigned long)s.st_ino,

type,

perm,

parse_uid(s.st_uid, uid, sizeof(uid)),

parse_gid(s.st_gid, gid, sizeof(gid)),

format_time(s.st_mtime, mtime, sizeof(mtime)),

(unsigned long)s.st_size,

name,

link);

}

const char *parse_uid(constuid_tuid, char *buf, constsize_t size) {

structpasswd *p;

if ((p = getpwuid(uid)) == NULL) {

/* ignore the error and use the number uid as the name directly */

errno = 0;

snprintf(buf, size, “%d”, uid);

} else {

snprintf(buf, size, “%s”, p->pw_name);

}

returnbuf;

}

const char *parse_gid(constgid_tgid, char *buf, constsize_t size) {

struct group *p;

if ((p = getgrgid(gid)) == NULL) {

/* ignore the error and use the number uid as the name directly */

errno = 0;

snprintf(buf, size, “%d”, gid);

} else {

snprintf(buf, size, “%s”, p->gr_name);

}

returnbuf;

}