logoISU  

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;

}