Operating Systems 2017F: Tutorial 3: Difference between revisions
No edit summary |
No edit summary |
||
(4 intermediate revisions by one other user not shown) | |||
Line 2: | Line 2: | ||
==Tasks/Questions== | ==Tasks/Questions== | ||
# Compile and run [http://homeostasis.scs.carleton.ca/~soma/os-2017f/code/tut3/3000test.c 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 | |||
# Change 3000test to use lstat rather than stat. How does its behavior change? | |||
# Modify 3000test so when it is given a symbolic link it reports the name of the target. Use readlink(2). | |||
# 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 <tt>dd if=/dev/urandom of=test bs=1024 count=1000000</tt>. | |||
# 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== | ==Code== | ||
Line 66: | Line 80: | ||
data = (char *) mmap(NULL, len, | data = (char *) mmap(NULL, len, | ||
PROT_READ, MAP_SHARED, fd, 0); | PROT_READ, MAP_SHARED, fd, 0); | ||
if (data == | if (data == MAP_FAILED) { | ||
report_error(strerror(errno)); | report_error(strerror(errno)); | ||
} | } | ||
Line 76: | Line 90: | ||
} | } | ||
} | } | ||
printf(" a count %ld\n", count); | printf(" a count %ld\n", count); | ||
if (munmap(data, len) == -1) { | |||
report_error(strerror(errno)); | |||
} | |||
close(fd); | |||
} | } | ||
Latest revision as of 17:47, 1 October 2017
In this tutorial you will be experimenting with and extending 3000test.c (listed below).
Tasks/Questions
- 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
- Change 3000test to use lstat rather than stat. How does its behavior change?
- Modify 3000test so when it is given a symbolic link it reports the name of the target. Use readlink(2).
- 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.
- 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;
}