Initial commit.
This commit is contained in:
commit
6e3e702a88
|
@ -0,0 +1,249 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
/**************************************************************************
|
||||
* Authors: Gary Fleming, Amber McCloughan
|
||||
* Class: CIS452 - Operating Systems Concepts
|
||||
* Professor: Dr. Greg Wolffe
|
||||
* Date: 4/18/2019
|
||||
*
|
||||
* Program that mimics basic ls functionality. Depending on the flags
|
||||
* passed into the program, we display information about a directory's
|
||||
* files. We try and ensure that the output is human readable, so a
|
||||
* user can easily summarize the contents of a directory.
|
||||
*
|
||||
* Arguments
|
||||
* -------------------------------------------------------------------------
|
||||
* -i : Displays the inode number along with basic output.
|
||||
* -n : Displays user and group ID for each file, along with
|
||||
* some other basic information.
|
||||
* [directory] : Input a directory name as an argument to display
|
||||
* information about a directory other than the one
|
||||
* you're currently in.
|
||||
***************************************************************************/
|
||||
|
||||
// Max size of a timestamp.
|
||||
#define MAX_TIMESTAMP_LEN 255
|
||||
|
||||
// Max size of a character buffer.
|
||||
#define MAX_BUF_LEN 1024
|
||||
|
||||
/**
|
||||
* Main function of the program. Takes in
|
||||
* three possible arguments: -i, -n, and
|
||||
* the name of a directory.
|
||||
*
|
||||
* @param argc, number of arguments.
|
||||
* @param argv, the actual arguments.
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Integer used in for loop.
|
||||
int i;
|
||||
|
||||
// Flag that is set to 1 if -n is used.
|
||||
int nFlag = 0;
|
||||
|
||||
// Flag that is set to 1 if -i is used.
|
||||
int iFlag = 0;
|
||||
|
||||
// For use with symbolic links.
|
||||
char *linkName;
|
||||
|
||||
// Buffer for formatting time information.
|
||||
char *timeBuf = malloc(MAX_TIMESTAMP_LEN * sizeof(char));
|
||||
|
||||
// Buffer for holding the directory we're concerned with.
|
||||
char *direct = malloc(MAX_BUF_LEN * sizeof(char));
|
||||
|
||||
// File name buffer.
|
||||
char *fileName = malloc(MAX_BUF_LEN * sizeof(char));
|
||||
|
||||
// For the fully-qualified path.
|
||||
char *fulQual;
|
||||
|
||||
// Used in getting the fully-qualified path.
|
||||
char actualPath[PATH_MAX + 1];
|
||||
|
||||
// Copying initial value into directory.
|
||||
strcpy(direct, ".");
|
||||
|
||||
// Reading the program arguments.
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
// If we found the -i flag.
|
||||
if (!strcmp(argv[i], "-i"))
|
||||
{
|
||||
iFlag = 1;
|
||||
}
|
||||
// If we found the -n flag.
|
||||
else if (!strcmp(argv[i], "-n"))
|
||||
{
|
||||
nFlag = 1;
|
||||
}
|
||||
// If we found a combination of flags.
|
||||
else if (!strcmp(argv[i], "-in") || !strcmp(argv[i], "-ni"))
|
||||
{
|
||||
nFlag = 1;
|
||||
iFlag = 1;
|
||||
}
|
||||
// Anything else must be the directory.
|
||||
else
|
||||
{
|
||||
strcpy(direct, argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer for file statistics.
|
||||
struct stat statBuf;
|
||||
|
||||
// Directory pointer.
|
||||
DIR *dirPtr;
|
||||
|
||||
// Directory stream pointer.
|
||||
struct dirent *entryPtr;
|
||||
|
||||
// Opening directory stream.
|
||||
dirPtr = opendir(direct);
|
||||
|
||||
// If the directory could not be read (not found or improperly formatted).
|
||||
if (dirPtr == NULL)
|
||||
{
|
||||
// Error message.
|
||||
printf("An error occured while attempting to open directory.\n");
|
||||
|
||||
// Freeing resources.
|
||||
free(timeBuf);
|
||||
free(direct);
|
||||
free(fileName);
|
||||
|
||||
// Goodbye.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Iterating over the directory's files.
|
||||
while ((entryPtr = readdir(dirPtr)))
|
||||
{
|
||||
// Creating the full relative path.
|
||||
strcpy(fileName, direct);
|
||||
strcat(fileName, "/");
|
||||
strcat(fileName, entryPtr->d_name);
|
||||
|
||||
/*
|
||||
* Getting the fully-qualified path name. I learned how to do
|
||||
* this using the following link:
|
||||
* https://stackoverflow.com/questions/229012/
|
||||
*/
|
||||
fulQual = realpath(fileName, actualPath);
|
||||
|
||||
// Checking if the file is a soft link.
|
||||
if (entryPtr->d_type == DT_LNK)
|
||||
{
|
||||
// Getting link statistics.
|
||||
if (lstat(fileName, &statBuf) < 0)
|
||||
{
|
||||
free(timeBuf);
|
||||
free(direct);
|
||||
free(fileName);
|
||||
perror("huh? there is ");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Allocating buffer for where the link leads.
|
||||
linkName = malloc(statBuf.st_size + 1);
|
||||
|
||||
// Getting where the link leads.
|
||||
if (readlink(fileName, linkName, statBuf.st_size + 1) < 0)
|
||||
{
|
||||
free(timeBuf);
|
||||
free(direct);
|
||||
free(fileName);
|
||||
free(linkName);
|
||||
perror("huh? there is ");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Adding a null-terminating character.
|
||||
linkName[statBuf.st_size] = '\0';
|
||||
|
||||
// Creating a special link name for -n.
|
||||
strcpy(fileName, entryPtr->d_name);
|
||||
strcat(fileName, " -> ");
|
||||
strcat(fileName, linkName);
|
||||
|
||||
free(linkName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Name for non-link files.
|
||||
strcpy(fileName, entryPtr->d_name);
|
||||
|
||||
// Grabbing stats for non-link files.
|
||||
if (stat(fulQual, &statBuf) < 0)
|
||||
{
|
||||
free(timeBuf);
|
||||
free(direct);
|
||||
free(fileName);
|
||||
perror("huh? there is ");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't display the current directory or previous directory files.
|
||||
if (!strcmp(entryPtr->d_name, ".") || !strcmp(entryPtr->d_name, ".."))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We figured out how to format time using the article below.
|
||||
* We have to convert the time_t type into a tm, which takes
|
||||
* a few steps. Then, we utilize the strftime() function to
|
||||
* format the time into a user-readable string.
|
||||
* https://stackoverflow.com/questions/13542345
|
||||
*/
|
||||
time_t t = statBuf.st_mtime;
|
||||
struct tm lt;
|
||||
localtime_r(&t, <);
|
||||
strftime(timeBuf, MAX_TIMESTAMP_LEN * sizeof(char), "%b %d, %Y %X", <);
|
||||
|
||||
// Changing name if we aren't using -n.
|
||||
if (nFlag == 0)
|
||||
{
|
||||
strcpy(fileName, entryPtr->d_name);
|
||||
}
|
||||
|
||||
// For no flags.
|
||||
if (iFlag == 0 && nFlag == 0)
|
||||
printf("%s\n", fileName);
|
||||
// For only the -i flag.
|
||||
else if (iFlag == 1 && nFlag == 0)
|
||||
printf("%lu %s\n", entryPtr->d_ino, fileName);
|
||||
// For only the -n flag.
|
||||
else if (iFlag == 0 && nFlag == 1)
|
||||
printf("%o | %lu | %d | %d | %ld | %s | %s\n", statBuf.st_mode, statBuf.st_nlink, statBuf.st_uid, statBuf.st_gid, statBuf.st_size, timeBuf, fileName);
|
||||
// For both flags.
|
||||
else if (iFlag == 1 && nFlag == 1)
|
||||
printf("%lu | %o | %lu | %d | %d | %ld | %s | %s\n", entryPtr->d_ino, statBuf.st_mode, statBuf.st_nlink, statBuf.st_uid, statBuf.st_gid, statBuf.st_size, timeBuf, fileName);
|
||||
}
|
||||
|
||||
// Closing stream.
|
||||
closedir(dirPtr);
|
||||
|
||||
// Freeing resources.
|
||||
free(timeBuf);
|
||||
free(direct);
|
||||
free(fileName);
|
||||
|
||||
// Goodbye.
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue