I've been trying to find out why my tester is failing, it says that destination and source file don't match. link for testers: https://github.com/ShiraWolf/hwOP.git
Output Requirements & Testing:
It must output one of the following types of messages (precisely and case-sensitive):
Unable to open source file for reading
Unable to open destination file for writing
Unable to write to destination file
Unable to write buffer content to destination file
Unable to read source file
Unable to close source file
Unable to close destination file
File was successfully copied to
Or one of the various arguments parsing errors, as described in the examples above.
My code:
/*
* ex1.c
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_BUFFER_SIZE 65536
#define DESTINATION_FILE_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
extern int opterr, optind;
void exit_with_usage(const char *message) {
fprintf(stderr, "%s\n", message);
fprintf(stderr, "Usage:\n\tex1 [-f] BUFFER_SIZE SOURCE DEST\n");
exit(EXIT_FAILURE);
}
void copy_file(const char *source_file, const char *dest_file, int buffer_size, int force_flag) {
/*
* Copy source_file content to dest_file, buffer_size bytes at a time.
* If force_flag is true, then also overwrite dest_file. Otherwise print error, and exit.
*
* TODO:
* 1. Open source_file for reading
* 2. Open dest_file for writing (Hint: is force_flag true?)
* 3. Loop reading from source and writing to the destination buffer_size bytes each time
* 4. Close source_file and dest_file
*
* ALWAYS check the return values of syscalls for errors!
* If an error was found, use perror(3) to print it with a message, and then exit(EXIT_FAILURE)
*/
int c = 0;
int sourcef = 0;
int destf = 0;
sourcef = open(source_file, O_RDONLY);
if (sourcef == -1) {
perror("Unable to open source file for reading");
exit(EXIT_FAILURE);
}
destf = open(dest_file, O_WRONLY |O_CREAT | O_EXCL, 00700);
if (destf == -1) {
if (force_flag) {
destf = open(dest_file, O_WRONLY, 00700);
if (destf == -1) {
if (close(sourcef) == -1) {
perror("couldn't close source file");
exit(EXIT_FAILURE);
}
perror("Unable to open destination for writing");
exit(EXIT_FAILURE);
}
} else {
perror("Unable to open destination for writing");
exit(EXIT_FAILURE);
}
}
char *buffer = malloc(sizeof(char) * buffer_size);
while ((c = read(sourcef, buffer, buffer_size)) != 0) {
if (c == -1) {
perror("couldn't read from source file");
if (close(sourcef) == -1) {
perror("couldn't close source file after reading has failed");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("couldn't close dest file after reading has failed");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
c = write(destf, buffer, buffer_size);
if (c == -1) {
perror("couldn't write to source file");
if (close(sourcef) == -1) {
perror("couldn't close source file after writing has failed");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("couldn't close dest file after writing has failed");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
}
free(buffer);
if (close(sourcef) == -1) {
perror("couldn't close source file");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("couldn't close dest file");
exit(EXIT_FAILURE);
}
printf("File %s was copied to %s\n", source_file, dest_file);
exit(EXIT_SUCCESS);
}
void parse_arguments (
int argc, char **argv,
char **source_file, char **dest_file, int *buffer_size, int *force_flag) {
/*
* parses command line arguments and set the arguments required for copy_file
*/
int option_character;
opterr = 0; /* Prevent getopt() from printing an error message to stderr */
while ((option_character = getopt(argc, argv, "f")) != -1) {
switch (option_character) {
case 'f':
*force_flag = 1;
break;
default: /* '?' */
exit_with_usage("Unknown option specified");
}
}
if (argc - optind != 3) {
exit_with_usage("Invalid number of arguments");
} else {
*source_file = argv[argc - 2];
*dest_file = argv[argc - 1];
*buffer_size = atoi(argv[argc - 3]);
if (strlen(*source_file) == 0 || strlen(*dest_file) == 0) {
exit_with_usage("Invalid source / destination file name");
} else if (*buffer_size < 1 || *buffer_size > MAX_BUFFER_SIZE) {
exit_with_usage("Invalid buffer size");
}
}
}
int main(int argc, char **argv) {
int force_flag = 0; /* force flag default: false */
char *source_file = NULL;
char *dest_file = NULL;
int buffer_size = MAX_BUFFER_SIZE;
parse_arguments(argc, argv, &source_file, &dest_file, &buffer_size, &force_flag);
copy_file(source_file, dest_file, buffer_size, force_flag);
return EXIT_SUCCESS;
}
Can anybody see where my mistake is?
c = write(destf, buffer, buffer_size); does not use the correct size: you should write c bytes and store the written count into a separate variable nwritten and keep trying to write more bytes until c bytes have been written or write return 0 or -1.
Here is a modified version of the copying loop:
while ((c = read(sourcef, buffer, buffer_size)) != 0) {
if (c == -1) {
perror("Unable to read from source file");
if (close(sourcef) == -1) {
perror("Unable to close source file");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("Unable to close destination file");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
int towrite = c;
int pos = 0;
while (towrite > 0) {
int nwritten = write(destf, buffer + pos, towrite);
if (nwritten <= 0) {
perror("Unable to write to destination file");
if (close(sourcef) == -1) {
perror("Unable to close source file");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("Unable to close destination file");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
pos += nwritten;
towrite -= nwritten;
}
}
Also note that the other error messages are different from the specification.
Related
I'm getting a "too many arguments in function call" error in my C program. The error occurs at a line where I'm calling a function that has a fixed number of arguments. I'm not sure why I'm getting this error, as I'm not passing in more arguments than the function expects. Here's the code where the error occurs:
if (mkdir(path, 0777) == -1)
Here is full code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#define BUF_SIZE 1024
#define MAX_ARGS 10
// Print the usage message for the program
void print_usage() {
fprintf(stderr, "Usage: syscalls <command> [arguments]\n");
}
// Read the contents of a file and write them to stdout
int read_file(const char *path) {
static char buf[BUF_SIZE];
int fd = open(path, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
ssize_t num_read;
while ((num_read = read(fd, buf, BUF_SIZE)) > 0) {
if (write(STDOUT_FILENO, buf, num_read) != num_read) {
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
return 1;
}
}
if (num_read == -1) {
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
return 1;
}
return 0;
}
// Write a set of lines to a file
int write_file(const char *path, char *lines[], int num_lines) {
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
int total_bytes = 0;
for (int i = 0; i < num_lines; i++) {
const char *line = lines[i];
size_t len = strlen(line);
ssize_t num_written = pwrite(fd, line, len, total_bytes);
if (num_written == -1) {
fprintf(stderr, "Failed to write to %s: %s\n", path, strerror(errno));
return 1;
}
total_bytes += num_written;
}
printf("Wrote %d B\n", total_bytes);
return 0;
}
// Create a directory
int make_directory(const char *path) {
if (mkdir(path, 0777) == -1) {
if (errno == EEXIST) {
fprintf(stderr, "%s already exists\n", path);
} else {
fprintf(stderr, "Failed to create %s: %s\n", path, strerror(errno));
}
return 1;
}
return 0;
}
// List the contents of a directory
int list_directory(const char *path) {
DIR *dir = opendir(path);
if (dir == NULL) {
fprintf(stderr, "Failed to open directory %s: %s\n", path, strerror(errno));
return 1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
if (closedir(dir) == -1) {
fprintf(stderr, "Failed to close directory %s: %s\n", path, strerror(errno));
return 1;
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
print_usage();
return 1;
}
char *command = argv[1];
if (strcmp(command, "read") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return read_file(argv[2]);
} else if (strcmp(command, "write") == 0) {
if (argc < 4 || argc > MAX_ARGS + 2) {
print_usage();
return 1;
}
return write_file(argv[2], argv + 3, argc - 3);
} else if (strcmp(command, "mkdir") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return make_directory(argv[2]);
} else if (strcmp(command, "ls") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return list_directory(argv[2]);
} else {
print_usage();
return 1;
}
}
I am getting this error in terminal:
syscalls.c: In function 'write_file':
syscalls.c:54:31: warning: implicit declaration of function 'pwrite' [-Wimplicit-function-declaration]
ssize_t num_written = pwrite(fd, line, len, total_bytes);
^~~~~~
syscalls.c: In function 'make_directory':
syscalls.c:67:9: error: too many arguments to function 'mkdir'
if (mkdir(path, 0777) == -1) {
^~~~~
In file included from c:\mingw\include\unistd.h:56:0,
from syscalls.c:3:
c:\mingw\include\io.h:516:38: note: declared here
_CRTIMP __cdecl __MINGW_NOTHROW int mkdir (const char *);
Please help me to resolve this issue. Thank you
mkdir() is not specified in the C standard. It is specified in the POSIX standard, which is more or less a superset of the C standard.
This declaration of mkdir():
c:\mingw\include\io.h:516:38: note: declared here
_CRTIMP __cdecl __MINGW_NOTHROW int mkdir (const char *);
is the Microsoft version of the function, which takes a single argument, and does not conform to the POSIX standard.
From Microsoft's page:
The Microsoft-implemented POSIX function name mkdir is a deprecated
alias for the _mkdir function.
int _mkdir(
const char *dirname
);
Possible fix:
#ifdef _CRTIMP
#define mkdir(d,m) (mkdir)(d)
#endif
Credit: #chqrlie
This is my code
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 4) {
printf("Missing arguments\n");
return -1;
}
// Check if buffer is valid before reading anything
int bufferSize = atoi(argv[3]);
if (!bufferSize || bufferSize < 1) {
printf("Invalid buffer size\n");
return -1;
}
printf("*** Copying from '%s' to '%s' (Buffer size: %dB) ***\n",
argv[1], argv[2], bufferSize);
// READ SOURCE FILE
FILE *inputFile = fopen(argv[1], "r");
if (!inputFile) {
printf("Error opening source file\n");
return -1;
}
// READ DESTINATION FILE
FILE *outputFile = fopen(argv[2], "w");
if (!outputFile) {
printf("Error opening destination file\n");
return -1;
}
int buffer[bufferSize];
int bytes;
do {
bytes = fread(buffer, 1, bufferSize, inputFile);
if (fwrite(buffer, 1, bytes, outputFile) != bytes) {
printf("Error writing into destination file\n");
return -1;
}
} while (bytes > 0);
fclose(inputFile);
fclose(outputFile);
return 0;
}
But when I try to exe the file it doesn't work. What could be the problem?
Here's the command line:
/Users/jurajc/Documents/Program/C/L1\ 1/C_program/c_program file.txt fileCopy.txt 512
*** Copying from 'file.txt' to 'fileCopy.txt' (Buffer size: 512B) ***
Error opening source file
The input file file.txt cannot be opened: either because it is not present in the current directory or because you do not have read access to it.
You should output more informative error messages. Note also these problems:
if (!bufferSize || bufferSize < 1) is a redundant test. if (bufferSize < 1) is sufficient.
the error messages should be output to stderr
the files should be open in binary mode to reliably copy all file types on legacy systems.
the read/write loop is incorrect: you should stop when fread returns 0 before attempting to write 0 elements to the output file.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 4) {
fprintf(stderr, "Missing arguments\n");
return -1;
}
// Check if buffer is valid before reading anything
int bufferSize = atoi(argv[3]);
if (bufferSize < 1) {
fprintf(stderr, "Invalid buffer size: %s\n", argv[3]);
return -1;
}
printf("*** Copying from '%s' to '%s' (Buffer size: %dB) ***\n",
argv[1], argv[2], bufferSize);
// READ SOURCE FILE
FILE *inputFile = fopen(argv[1], "rb");
if (!inputFile) {
fprintf(stderr, "Error opening source file %s: %s\n",
argv[1], strerror(errno));
return -1;
}
// READ DESTINATION FILE
FILE *outputFile = fopen(argv[2], "wb");
if (!outputFile) {
fprintf(stderr, "Error opening destination file %s: %s\n",
argv[2], strerror(errno));
return -1;
}
int buffer[bufferSize];
int bytes;
while ((bytes = fread(buffer, 1, bufferSize, inputFile)) != 0) {
if (fwrite(buffer, 1, bytes, outputFile) != bytes) {
fprintf(stderr, "Error writing into destination file: %s\n", strerror(errno));
return -1;
}
}
fclose(inputFile);
fclose(outputFile);
return 0;
}
I created two programs, which will communicate via named pipe, one will be reading from it and another one will be writing to it. It works pretty fine now, except for the fact, that it opens and writes to the same fifo exactly 3 times. It's my first time with C and pipes, and I don't understand why is this writing three times. Can you see why is this writing three times?
writing.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void writing(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("writing to %s\n",s);
if ( (fd = open(s, O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, sizeof buf -1) ) > 0) {
buf[n-1] = '\0';
printf("Received: %s\n", buf);
if ( write(fd, buf, n) != n) {
err("write");
}
if(strcmp(buf,"END")==0){
printf("%s","exit");
break;
}
}
close(fd);
}
char* concat(const char *s1, const char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
int file_stat(char *argv){
int isfifo = 0;
struct stat sb;
printf("%s",argv);
if (stat(argv, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
if (sb.st_mode & S_IFMT == S_IFIFO) {
printf("FIFO/pipe\n");
isfifo = 1;
}
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
//exit(EXIT_SUCCESS);
return isfifo;
}
int main(int argc, char *argv[])
{
// READ ALL FILES IN DIRECTORY
if (argc != 2) {
fprintf(stderr, "Usage: %s /<pathname>/\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *d;
struct dirent *dir;
if ((d = opendir (argv[1])) != NULL) {
/* print all the files and directories within directory */
while ((dir = readdir (d)) != NULL) {
printf ("%s\n", dir->d_name);
char* s = concat(argv[1], dir->d_name);
if (file_stat(s) == 1) {
writing(s);
}
else {
mkfifo("fifo_x", 0666);
writing("fifo_x");
}
free(s);
}
closedir (d);
}
else {
/* could not open directory */
perror ("error: ");
return EXIT_FAILURE;
}
}
reading file is the same except for "reading" function and call to reading()
reading
void reading(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("%s",s);
if ( (fd = open(s, O_RDONLY)) < 0)
err("open");
while( (n = read(fd, buf, sizeof buf - 1) ) > 0) {
buf[n-1] = '\0';
if(strcmp(buf,"END")==0){
printf("%s\n", "exit");
break;
}
buf[n-1] = '\n';
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
the output
/home/..File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exitola
/home/olaFile type: Ownership: UID=1001 GID=1001
writing to fifo_x
END
Received: END
exit.
/home/.File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exit
You have three files in the directory with whose pathname you called your program. All three files are not fifo's so for each you write to fifo_x.
The file names are
.
..
olaFile
Maybe you should explicitly exclude the files
.
..
which happen to be in every directory in linux and represent the current directory . and the parent directory ...
I am using JaetBrains' Clion with MinGW 3.2.1 on windows. and I'm trying to build a project in c.
I keep getting the following linkage error:
undefined reference to `printf'
any Idea How to solve it?
this is my code:
#include <fcntl.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <libintl.h>
#define BUFFERSIZE 1
int main(int argc, char** argv) {
assert(argc == 3);
char* inputDirPath = argv[0];
char* keyFilePath = argv[1];
char* outputDirPath = argv[2];
// open key file
int key_fd = open(keyFilePath, O_RDONLY);
if (key_fd < 0) {
printf("Failed opening Key file %s. Error: %s\n", keyFilePath, strerror(errno));
return errno;
}
// making sure the file is not empty
char keyFirstChar;
if (read(key_fd, (void*)keyFirstChar, 1) == 0)
{
printf("Error. Key file is empty %s.", keyFilePath);
return errno;
}
else {
// go back to the begining of the file.
assert(!close(key_fd));
key_fd = open(keyFilePath, O_RDONLY);
if (key_fd < 0) {
printf("Failed opening Key file %s. Error: %s\n", keyFilePath,
strerror(errno)
);
return errno;
}
}
// Temp file name
char inputFilepath[200] ;
struct dirent *dirEntity;
DIR *inputDir_dfd;
// open directory stream
assert((inputDir_dfd = opendir(inputDirPath)) != NULL);
while ((dirEntity = readdir(inputDir_dfd)) != NULL)
{
// full path to input file
sprintf(inputFilepath, "%s/%s",inputDirPath, dirEntity->d_name) ;
// call stat to get file metadata
struct stat statbuf ;
assert( stat(inputFilepath,&statbuf ) != -1 );
// skip directories
if ( ( statbuf.st_mode & S_IFMT ) == S_IFDIR )
{
continue;
}
// open input file
int inputFile_fd = open(inputFilepath, O_RDONLY);
if (inputFile_fd < 0) {
printf("Failed opening file in input directory, %s. Error: %s\n", inputFilepath, strerror(errno));
return errno;
}
// Temp file name
char outputFilePath[200] ;
// full path to file
sprintf(outputFilePath, "%s/%s",outputDirPath, dirEntity->d_name) ;
// open input file
int outputFile_fd = open(outputFilePath, O_WRONLY | O_CREAT | O_TRUNC);
if (outputFile_fd < 0) {
printf("Failed opening file in output directory, %s. Error: %s\n", outputFilePath, strerror(errno));
return errno;
}
char inputFileBuf[BUFFERSIZE];
while (read(inputFile_fd, inputFileBuf, BUFFERSIZE) == BUFFERSIZE){
char keyFileBuf[BUFFERSIZE];
if (read(key_fd, keyFileBuf, BUFFERSIZE) == 0) {
assert(!close(key_fd));
key_fd = open(keyFilePath, O_RDONLY);
if (key_fd < 0) {
printf("Failed opening Key file %s. Error: %s\n", keyFilePath, strerror(errno));
return errno;
}
read(key_fd,keyFileBuf, BUFFERSIZE);
}
char outputToWrite[BUFFERSIZE];
int i;
for(i = 0; i < BUFFERSIZE; i++){
outputToWrite[i] = keyFileBuf[i] ^ inputFileBuf[1];
}
if( write(outputFile_fd, outputToWrite, BUFFERSIZE) == -1){
printf("Failed writing to output file, %s. Error: %s\n", outputFilePath, strerror(errno));
return errno;
};
}
if(close(inputFile_fd) ); // close key file
}
closedir(inputDir_dfd); // close Dir
assert(!close(key_fd)); // close key file
}
thanks.
In the example from, "Advance Programming in the Unix Environment" the following sample program creates a file, then uses lseek to move the file pointer to a further address thus placing a "hole" in the file. The author says the space in between is filled with "0's". I wanted to see if those "0's" would print out. So I modified the program slightly. However I noticed that only the valid characters were writen to the file.
My question is how does the Unix/Linux filesystem manager know not to print the bytes in between?
#include "apue.h"
#include <fcntl.h>
#include <unistd.h>
char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";
char buf3[10];
int
main(void)
{
int fd;
if ((fd = creat("file.hole", FILE_MODE)) < 0) {
err_sys("creat error");
}
if (write(fd, buf1, 10) != 10) { /* offset is now = 10 */
err_sys("buf1 write error");
}
if (lseek(fd, 16380, SEEK_SET) == -1) { /* offset now = 16380 */
err_sys("lseek error");
}
if (write(fd, buf2, 10) != 10) { /* offset now = 16390 */
err_sys("buf2 write error");
}
close(fd);
if ((fd = open("file.hole", O_RDWR)) == -1) {
err_sys("failed to re-open file");
}
ssize_t n;
ssize_t m;
while ((n = read(fd, buf3, 10)) > 0) {
if ((m = write(STDOUT_FILENO, buf3, 10)) != 10) {
err_sys("stdout write error");
}
}
if (n == -1) {
err_sys("buf3 read error");
}
exit(0);
}
The character \000 has a null-width display representation. It is printed, but its printing is invisible. Not every codepoint is a character. In the same way, \n is printed as a newline, not as a character.