Operating Systems 2019F: Tutorial 4: Difference between revisions

From Soma-notes
Created page with "In this tutorial you will be experimenting with and extending [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut3/3000test.c 3000test.c] (listed below). ==Tasks/Ques..."
 
No edit summary
 
(One intermediate revision by the same user not shown)
(No difference)

Latest revision as of 20:34, 27 September 2019

In this tutorial you will be experimenting with and extending 3000test.c (listed below).

Tasks/Questions

  1. Compile and run 3000test.c. It takes a filename as an argument and reports information on the file. Try giving it the following and see what it reports:
    • a regular text file that exists
    • a directory
    • a symbolic link
    • a device file
  2. Change 3000test to use lstat rather than stat. How does its behavior change?
  3. Modify 3000test so when it is given a symbolic link it reports the name of the target. Use readlink(2).
  4. Are there files or directories that you cannot run 3000test on? Can you configure file/directory permissions so as to make something inaccessible to 3000test?
  5. How does the memory use of 3000test change as it runs? You may want to add calls to sleep(3) so you can observe its memory usage. You can create a 1 GB file of random data with the command dd if=/dev/urandom of=test bs=1024 count=1000000.
  6. Create a program 3000compare.c based on 3000test that compares the contents of two files and says whether or not they differ.
    • If given symbolic links it should report on where they point and only say they are equal if they refer to the same file.
    • If given two device files, it should say that they are equal if they are both the same kind of device file and have the same major and minor numbers.
    • If given two hard links to the same file, it should say that the files are identical because they refer to the same inode.
    • Other kinds of files (directories, pipes) should not be compared. Instead, it should report on the type of each file.

Code

/* 3000test.c */
/* v1 Oct. 1, 2017 */
/* Licenced under the GPLv3, copyright Anil Somayaji */
/* You really shouldn't be incorporating parts of this in any other code,
   it is meant for teaching, not production */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

void report_error(char *error)
{
        fprintf(stderr, "Error: %s\n", error);

        exit(-1);
}

int main(int argc, char *argv[])
{
        struct stat statbuf;
        char *fn;
        int fd;
        size_t len, i, count;
        
        char *data;

        if (argc < 2) {
                if (argc < 1) {
                        report_error("no command line");
                        fprintf(stderr, "Usage: %s <file>\n", argv[0]); 
                } else {
                        report_error("Not enough arguments");
                        fprintf(stderr, "Usage: %s <file>\n", argv[0]); 
                }
        }

        fn = argv[1];

        if (stat(fn, &statbuf)) {
                report_error(strerror(errno));
        }

        len = statbuf.st_size;
        printf("File %s: \n", fn);
        printf("   inode %ld\n", statbuf.st_ino);
        printf("  length %ld\n", len);        

        if (S_ISREG(statbuf.st_mode)) {
                fd = open(fn, O_RDONLY);
                if (fd == -1) {
                        report_error(strerror(errno));
                }
                data = (char *) mmap(NULL, len,
                                     PROT_READ, MAP_SHARED, fd, 0);
                if (data == MAP_FAILED) {
                        report_error(strerror(errno));
                }

                count = 0;
                for (i=0; i<len; i++) {
                        if (data[i] == 'a') {
                                count++;
                        }
                }

                printf(" a count %ld\n", count);

                if (munmap(data, len) == -1) {
                        report_error(strerror(errno));                        
                }
                close(fd);
        }

        return 0;
}