|
CS456 - Systems Programming
Spring 2026
|
Displaying ./code/h4/filetypev2.c
/*
This takes a file, and depending on it's attributes, something happens
We're going to take what we did in Assignme3nt h3 and make some changes
Here, we're going to do stuff with regular files
- regular files:
- what this does depends on whether or not you have execute permission
- if you do, execute the program using the fork and exec functions (but if someone passes
in this very program as an argument, do NOT let it execute!)
- if you don't, print the file's contents to stdout
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include "extras.h"
int main(int argc, char **argv){
//prints usage statement if file not provided
if(argc < 2){
fprintf(stderr, "Usage %s file\n", argv[0]);
exit(1);
}
// call stat on the file we're passing in
struct stat st;
int rt = lstat(argv[1], &st);
if (rt < 0){
perror("Error: stat failed");
exit(-1);
}
//check what type of file we have here
//if it's a regular file, we're going to do something based on permission values
if(S_ISREG(st.st_mode)){
//check if owner has execute permission
int perm = checkPermissions(st.st_mode, S_IXUSR);
//if it does, try to execute it, but don't let it execute itself
// otherwise just print contents to stdout
if(perm == 1){
//need to compare device and inode values of this executable and the one passed in
if(fileMatchStr(argv[0], argv[1])){
printf("Looks like you're trying to run this very program through this one\n");
exit(2);
}
printf("Running %s:\n", argv[1]); //inform user what program they're executing
pid_t pid = fork(); //call fork, store in pid
if(pid == -1){ //check return value of pid
perror("fork failed");
exit(-1);
}
if(pid){ //we are in the parent process
//we have a child, so get the exit code
int status;
waitpid(pid, &status, 0);
return 0;
} else {
//we are in the child process
//use a variant of exec to execute the program
// using execv, as we have arguments coming in through the command line
execv(argv[1], &argv[1]);
// first arg: string containing pathname to program
// second arg: array of strings containing all command line arguments being passed in
// need that ampersand in front of that to access all args, otherwise it'd
// ony get the first string
}
} else { // not executable, so we're just printing the contents
// essentially doing the cat command
char content[st.st_size+1]; //buffer for content
int fd = open(argv[1], O_RDONLY); //open file for reading
//checking return value
if(fd == -1){
perror("error");
exit(-1);
}
//setting up read/write loop
int stuff;
while(( stuff = read(fd, content, st.st_size)) > 0) {
write(1, content, stuff);
}
//close file
close(fd);
}
//if it's a directory,
// print the contents but not hidden files
// print the count of total files as well as hidden files
} else if(S_ISDIR(st.st_mode)){
DIR *mydir; //defining pointer to directory
struct dirent *file; //accessing the dirent struct, defined in dirent.h
mydir = opendir(argv[1]); //opening a directory
//check return value of opendir
if(mydir == NULL){
perror("opendir failed");
exit(-2);
}
//keep counts of files
int count = 0;
int hidden = 0;
//reading through directory
while((file = readdir(mydir)) != NULL){
count++;
// checking if this is a hidden file ,
// denoted by a '.' period character in the first chaacter of filename
if(file->d_name[0] == '.'){
hidden++;
continue;
}
printf("%s\n", file->d_name);
}
printf("The directory %s has %d files, of which %d are hidden\n", argv[1], count, hidden);
closedir(mydir);
//anything else, just print the name along with it's type in octal
} else {
//get what filetype this file is
int type = getType(st.st_mode);
//print filename
printf("Name: %s\n", argv[1]);
//print the filetype
printType(type);//printType is defined in extras.h
}
return 0;
}
|