Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

1- Write a utility like cp(1) that copies a file containing holes, without writi

ID: 3563889 • Letter: 1

Question

1- Write a utility like cp(1) that copies a file containing holes, without writing the bytes of 0 to the output file. Also, add logic that will cause cp to not copy to the target file if it already exists. Add a "-f" option on the commandline that will force the copy even if the file exists.

2- The tee command reads its standard input until end-of-file, writing a copy of the input to standard output and to the file named in its command-line argument. (We show an example of the use of this command when we discuss FIFOs in Section 44.7.) Implement tee using I/O system calls. By default, tee overwrites any existing file with the given name. Implement the –a command-line option (tee –a file), which causes tee to append text to the end of a file if it already exists. (Refer to Appendix B for a description of the getopt() function, which can be used to parse command-line options.)

Explanation / Answer

Please rate:

1- Write a utility like cp(1) that copies a file containing holes, without writing the bytes of 0 to the output file. Also, add logic that will cause cp to not copy to the target file if it already exists. Add a "-f" option on the commandline that will force the copy even if the file exists.

#include <stdio.h>

#include <fcntl.h>

#include <string.h>

#include <errno.h>

#ifndef BUF_SIZE /* Allow "cc -D" to override */

#define BUF_SIZE 1024

#endif

void print_usage()

{

printf("Usage: ./prog_cpholes <src> <dst> ");

}

int main(int argc, char *argv[])

{

int inputFd, outputFd, openFlags;

mode_t filePerms;

ssize_t numRead;

char buf[BUF_SIZE];

/* parse argv

* ./prog_cpholes src dst

*/

if (argc != 3 || strcmp(argv[1], "--help") == 0) {

print_usage();

return 1;

}

/* Open input and output files */

openFlags = (O_CREAT | O_WRONLY | O_TRUNC);

filePerms = (S_IRUSR | S_IWUSR | S_IRGRP |

S_IROTH | S_IWOTH);

inputFd = open(argv[1], O_RDONLY);

if (inputFd < 0) {

printf("Failed to open input file: %s ", strerror(errno));

print_usage();

return 1;

}

outputFd = open(argv[2], openFlags, filePerms);

if (outputFd < 0) {

printf("Failed to open output file: %s ", strerror(errno));

print_usage();

return 1;

}

/*

* For copying, we read-and-copy from source to destination

*/          

int i, err;

unsigned long holeSize = 0;

while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0) {

for (i = 0; i < numRead; i++) {

if (buf[i] == '') {

holeSize++;

} else if (holeSize > 0) {

lseek(outputFd, holeSize, SEEK_CUR);

write(outputFd, &buf[i], 1);

holeSize = 0;

} else {

write(outputFd, &buf[i], 1);

}

}

}

/* close fds */

close(inputFd);

close(outputFd);

return 0;

}

2- The tee command reads its standard input until end-of-file, writing a copy of the input to standard output and to the file named in its command-line argument. (We show an example of the use of this command when we discuss FIFOs in Section 44.7.) Implement tee using I/O system calls. By default, tee overwrites any existing file with the given name. Implement the –a command-line option (tee –a file), which causes tee to append text to the end of a file if it already exists. (Refer to Appendix B for a description of the getopt() function, which can be used to parse command-line options.)

#include <stdio.h>

#include <stdlib.h>

#include <getopt.h>

static int append_mode = 0;

int parse_args(int argc, char *argv[])

{

char c;

while ((c = getopt(argc, argv, "a")) != -1) {

switch (c) {

case 'a':

append_mode = 1;

break;

case '?':

if (isprint(optopt))

fprintf(stderr, "Unkonw option `-%c'. ", optopt);

else

fprintf(stderr,

"Unknown option character `\x%x'. ", optopt);

return 1;

default:

abort();

break;

}

}

return 0;

}

int main(int argc, char *argv[])

{

char buf[100];

size_t len;

char *file_mode;

int i;

FILE *files[20];

int num_files;

if (parse_args(argc, argv)) {

return 1;

}

file_mode = (append_mode ? "a" : "w");

num_files = argc - optind;

if (num_files > 0) {

if (files == NULL) {

fprintf(stderr, "Unable to allocate file buffer space ");

return 1;

}

/* go through file arguments and either open for writing

or append based on the -a flag */

for (i = optind; i < argc; i++) {

FILE *pFile = fopen(argv[i], file_mode);

if (pFile == NULL)

{

fprintf(stderr, "Unable to open file %s for mode %s",

argv[i], file_mode);

goto main_cleanup;

}

files[i - optind] = pFile; /* mind the offset */

}

}

FILE *not_stdin = fopen("tee.c", "r");

while ((len = fread(&buf[0], 1, sizeof(buf), not_stdin)) > 0) {

fwrite(&buf[0], 1, len, stdout);

for (i = 0; i < num_files; i++) {

fwrite(&buf[0], 1, len, files[i]);

}

}

main_cleanup:

if (num_files > 0) {

for (i = 0; i < num_files; i++) {

fclose(files[i]);

}

}

return 0;

}