This is a programming assignment from a unit called Operating Systems programming its mainly like C programming. for writing codes: A virtual machine has been created that can be used to work on the Problem Case Studies. It is a Virtual Box Appliance, and can be imported into a Virtual Box installation. It is a stripped down 64-bit Ubuntu Linux 20.04 LTS, that has all the necessary tools and not much else. It is configured to use auto-configured NAT networking and thus should "Just Work!". If necessary, the pre-configured username is "user" and the password for that user is "password" (the worlds most popular password!). This user is capable of administrating the machine, so please don't connect it directly to the Internet as it isn't that secure, however the default network configuration is safe. It safe to use the web-browser on this virtual machine. If the virtual machine is too slow, shut it down and increase the memory allocation in virtual box. The Virtual Box Appliance is available for download here. It is a ~2Gb file, and has an SHA1 check sum of 3c265e4b5a8ef0d9d86f6d1fb226895ed3e7fdfc -- Virtual box version 6
Workshop D Operating Systems Programming – COMP 3015 1 Introduction In this workshop you will investigate file I/O and file copy operations. 2 Specification Following on from the demonstration program cp1.c presented in the lecture, we will make a series of modifi- cations to the program. Firstly, what happens when thecp1.cprogram is asked to copy a file onto itself, i.e. cp1 input input? Is this what you expect? Modify the program to do something more sensible! As a hint, two files are the same if they are on the same device and have the same i-node number (which stat() can give you), simply comparing the names is not enough. Secondly, a real copy program will assign the same file permissions to the destination as were on the source, modify your answer to the last part to do this. Thirdly, real copy programs allow the second argument to be a directory, i.e. you specify a directory for the second part and a copy of the source is placed in that directory with the same name as the source. Modify the answer to the last part to include this functionality. You should allocate the space for the new name dynamically. Fourthly, your program should rename the original version of the destination file to filename.bak (i.e. add an additional extension of .bak) if the destination file exists, or if the destination is a directory that a file with the same name exists in the directory. 1 3 Sample Code 3.1 cp1.c /* cp1.c -- simple copy program example * Dr Evan Crawford (
[email protected]) * COMP 30015 Operating Systems Programming * Practical Case Study D * This sample file was adapted from: * Molay, B. (2003). cp1.c. In Understanding unix/linux programming. * Source Code, Prentice Hall. */ #include
#include #include #define BUFFERSIZE 4096 #define COPYMODE 0644 void oops(char *, char *); int main(int ac, char *av[]) { int in_fd; int out_fd; int n_chars; char buf[BUFFERSIZE]; if (ac != 3) { fprintf(stderr, "usage: %s source destination\n", *av); exit(1); } if ((in_fd = open(av[1], O_RDONLY)) == -1) { oops("Cannot open ", av[1]); } if ((out_fd = creat(av[2], COPYMODE)) == -1) { oops("Cannot creat", av[2]); } while ((n_chars = read(in_fd, buf, BUFFERSIZE)) > 0) { if (write(out_fd, buf, n_chars) != n_chars) { oops("Write error to ", av[2]); } } 2 if (n_chars == -1) { oops("Read error from ", av[1]); } if (close(in_fd) == -1 || close(out_fd) == -1) { oops("Error closing files", ""); } return 0; } void oops(char *s1, char *s2) { fprintf(stderr, "Error: %s ", s1); perror(s2); exit(1); } 3 4 Supplementary Materials The material on the following pages is an extract of the linux system documentation and may prove useful in implementing this Workshop. These manual pages are taken from the Linux man-pages Project available at: http://www.kernel.org/doc/man-pages/. 4 http://www.kernel.org/doc/man-pages/ OPEN(2) Linux Programmer’s Manual OPEN(2) NAME open, openat, creat − open and possibly create a file SYNOPSIS #include int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); int creat(const char * pathname, mode_t mode); int openat(int dirfd , const char *pathname, int flags); int openat(int dirfd , const char *pathname, int flags, mode_t mode); /* Documented separately, in openat2(2): */ int openat2(int dirfd , const char *pathname, const struct open_how *how, size_t size); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): openat(): Since glibc 2.10: _POSIX_C_SOURCE >= 200809L Before glibc 2.10: _ATFILE_SOURCE DESCRIPTION The open() system call opens the file specified by pathname. If the specified file does not exist, it may op- tionally (if O_CREAT is specified in flags) be created by open(). The return value of open() is a file descriptor, a small, nonnegative integer that is an index to an entry in the process’s table of open file descriptors. The file descriptor is used in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.) to refer to the open file. The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process. By default, the new file descriptor is set to remain open across an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described in fcntl(2) is initially disabled); the O_CLOEXEC flag, described below, can be used to change this default. The file offset is set to the beginning of the file (see lseek(2)). A call to open() creates a new open file description, an entry in the system-wide table of open files. The open file description records the file offset and the file status flags (see below). A file descriptor is a refer- ence to an open file description; this reference is unaffected if pathname is subsequently removed or modi- fied to refer to a different file. For further details on open file descriptions, see NOTES. The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file read-only, write-only, or read/write, respectively. In addition, zero or more file creation flags and file status flags can be bitwise-or’d in flags. The file cre- ation flags are O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOL- LOW, O_TMPFILE, and O_TRUNC. The file status flags are all of the remaining flags listed below. The distinction between these two groups of flags is that the file creation flags affect the semantics of the open operation itself, while the file status flags affect the semantics of subsequent I/O operations. The file status flags can be retrieved and (in some cases) modified; see fcntl(2) for details. The full list of file creation flags and file status flags is as follows: O_APPEND The file is opened in append mode. Before each write(2), the file offset is positioned at the end of the file, as if with lseek(2). The modification of the file offset and the write operation are per- formed as a single atomic step. O_APPEND may lead to corrupted files on NFS filesystems if more than one process appends data to a file at once. This is because NFS does not support appending to a file, so the client kernel has to simulate it, which can’t be done without a race condition. Linux 2021-03-22 1 OPEN(2) Linux Programmer’s Manual OPEN(2) O_ASYNC Enable signal-driven I/O: generate a signal (SIGIO by default, but this can be changed via fc- ntl(2)) when input or output becomes possible on this file descriptor. This feature is available only for terminals, pseudoterminals, sockets, and (since Linux 2.6) pipes and FIFOs. See fcntl(2) for further details. See also BUGS, below. O_CLOEXEC (since Linux 2.6.23) Enable the close-on-exec flag for the new file descriptor. Specifying this flag permits a program to avoid additional fcntl(2) F_SETFD operations to set the FD_CLOEXEC flag. Note that the use of this flag is essential in some multithreaded programs, because using a separate fcntl(2) F_SETFD operation to set the FD_CLOEXEC flag does not suffice to avoid race condi- tions where one thread opens a file descriptor and attempts to set its close-on-exec flag using fc- ntl(2) at the same time as another thread does a fork(2) plus execve(2). Depending on the order of execution, the race may lead to the file descriptor returned by open() being unintentionally leaked to the program executed by the child process created by fork(2). (This kind of race is in principle possible for any system call that creates a file descriptor whose close-on-exec flag should be set, and various other Linux system calls provide an equivalent of the O_CLOEXEC flag to deal with this problem.) O_CREAT If pathname does not exist, create it as a regular file. The owner (user ID) of the new file is set to the effective user ID of the process. The group ownership (group ID) of the new file is set either to the effective group ID of the process (System V semantics) or to the group ID of the parent directory (BSD semantics). On Linux, the behavior depends on whether the set-group-ID mode bit is set on the parent directory: if that bit is set, then BSD semantics apply; otherwise, System V semantics apply. For some filesys- tems, the behavior also depends on the bsdgroups and sysvgroups mount options described in mount(8). The mode argument specifies the file mode bits to be applied when a new file is created. If neither O_CREAT nor O_TMPFILE is specified in flags, then mode is ignored (and can thus be speci- fied as 0, or simply omitted). The mode argument must be supplied if O_CREAT or O_TMP- FILE is specified in flags; if it is not supplied, some arbitrary bytes from the stack will be applied as the file mode. The effective mode is modified by the process’s umask in the usual way: in the absence of a de- fault ACL, the mode of the created file is (mode & ~umask). Note that mode applies only to future accesses of the newly created file; the open() call that cre- ates a read-only file may well return a read/write file descriptor. The following symbolic constants are provided for mode: S_IRWXU 00700 user (file owner) has read, write, and execute permission S_IRUSR 00400 user has read permission S_IWUSR 00200 user has write permission S_IXUSR 00100 user has execute permission S_IRWXG 00070 group has read, write, and execute permission Linux 2021-03-22 2 OPEN(2) Linux Programmer’s Manual OPEN(2) S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 others have read, write, and execute permission S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permission S_IXOTH 00001 others have execute permission According to POSIX, the effect when other bits are set in mode is unspecified. On Linux, the fol- lowing bits are also honored in mode: S_ISUID 0004000 set-user-ID bit S_ISGID 0002000 set-group-ID bit (see inode(7)). S_ISVTX 0001000 sticky bit (see inode(7)). O_DIRECT (since Linux 2.4.10) Try to minimize cache effects of the I/O to and from this file. In general this will degrade perfor- mance, but it is useful in special situations, such as when applications do their own caching. File I/O is done directly to/from user-space buffers. The O_DIRECT flag on its own makes an effort to transfer data synchronously, but does not give the guarantees of the O_SYNC flag that data and necessary metadata are transferred. To guarantee synchronous I/O, O_SYNC must be used in ad- dition to O_DIRECT. See NOTES below for further discussion. A semantically similar (but deprecated) interface for block devices is described in raw(8). O_DIRECTORY If pathname is not a directory, cause the open to fail. This flag was added in kernel version 2.1.126, to avoid denial-of-service problems if opendir(3) is called on a FIFO or tape device. O_DSYNC Write operations on the file will complete according to the requirements of synchronized