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 Assignment 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


you will also modify extras.h to get the printType function to work. That will 
handle files other than regular files or directories. 


*/

// header files
#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>

//our custom header file
#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
		// feel free to use the "check Permissions function I wrote in extras.h"
		// hint: you'll be passing in the mode and the mask value for "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
			// make sure this doesn't try to run it's own executable
			// hint use the fileMatchStr function in extras.h to determine this: 
			if(fileMatchStr(argv[0], argv[1])){
				printf("Looks like you're tryimg to run this very program through this one\n");
				exit(2);
			}
	

			//inform user what program they're executing

				 //call fork, store in pid

				 //check return value of pid

				//if pid > 0 we are in the parent process
					//we'll have a child, so get the exit code

			    // if pid == 0 we are in the child process
					//use a variant of exec to execute the program
		
		} else {
            // if it's  not executable, so we're just printing the contents
				// essentally implementing the cat command here

			//declare char buffer for content

			//open file for reading
			
			//checking return value of open

			
			//setting up read/write loop


			//close file once done
		}
	} 

	//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);


	} 

	return 0;

}