I've been trying to do c programming implementation of cp command in unix/linux by using system calls (read(), write(), open(), close()).
But when I run my program through terminal by copying my source code of this program to the same directory with name change (the source code is about 300 lines)
and when I open that output file , it has more character than the original file.
The extra line is the same as 200ish line. Where does it came from?
here's the screenshot when compile
argp.c
123.c
This is the source code near the end of the original file(argp.c). You will see how I use the read write method.
while (count - ind > 1) {
strcpy(cdir, argv[argc-1]);
if (!isFile(cdir)) {
strcat(cdir, basename(arguments.argv[ind]));
}
if (arguments.update) {
stat(cdir,&stDest);
stat(arguments.argv[ind],&stSrc);
if (difftime(stDest.st_mtim.tv_sec, stSrc.st_mtim.tv_sec) > 0 ) {
printf("Destination file is newer\n");
exit(EXIT_FAILURE);
}
}
//open source file
src = open(arguments.argv[ind],O_RDONLY);
//if source file can't be opened
if (src == -1) {
printf("\nError opening file %s errno = %d\n",arguments.argv[ind],errno);
exit(EXIT_FAILURE);
}
//open target file
if (arguments.force) {
//with -f option(default)
tgt = open(cdir, O_WRONLY | O_CREAT | O_TRUNC , S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
} else {
//with -n option
tgt = open(cdir, O_WRONLY | O_CREAT | O_EXCL , S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
}
//if the target file cannot be read or already exist(with -n option)
if (tgt == -1) {
printf("File exist or it's not a file.\nCan't copy.\n");
exit(EXIT_FAILURE);
}
//read source file
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, BUFFERSIZE) != pos) {
exit(EXIT_FAILURE);
}
}
//if the source file cannot be read
if (pos == -1) {
printf("\nError in reading data from %s\n",arguments.argv[ind]);
}
//close source file
if (close(src) == -1) {
printf("\nError in closing file %s\n",arguments.argv[ind]);
}
//close target file
if (close(tgt) == -1) {
printf("\nError in closing file %s\n",cdir);
}
ind++;
}
if (arguments.verbose) {
printf("Copy successfully!\n");
}
exit(EXIT_SUCCESS);
}
This is the source code near the end of the copy file(123.c)
while (count - ind > 1) {
strcpy(cdir, argv[argc-1]);
if (!isFile(cdir)) {
strcat(cdir, basename(arguments.argv[ind]));
}
if (arguments.update) {
stat(cdir,&stDest);
stat(arguments.argv[ind],&stSrc);
if (difftime(stDest.st_mtim.tv_sec, stSrc.st_mtim.tv_sec) > 0 ) {
printf("Destination file is newer\n");
exit(EXIT_FAILURE);
}
}
//open source file
src = open(arguments.argv[ind],O_RDONLY);
//if source file can't be opened
if (src == -1) {
printf("\nError opening file %s errno = %d\n",arguments.argv[ind],errno);
exit(EXIT_FAILURE);
}
//open target file
if (arguments.force) {
//with -f option(default)
tgt = open(cdir, O_WRONLY | O_CREAT | O_TRUNC , S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
} else {
//with -n option
tgt = open(cdir, O_WRONLY | O_CREAT | O_EXCL , S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
}
//if the target file cannot be read or already exist(with -n option)
if (tgt == -1) {
printf("File exist or it's not a file.\nCan't copy.\n");
exit(EXIT_FAILURE);
}
//read source file
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, BUFFERSIZE) != pos) {
exit(EXIT_FAILURE);
}
}
//if the source file cannot be read
if (pos == -1) {
printf("\nError in reading data from %s\n",arguments.argv[ind]);
}
//close source file
if (close(src) == -1) {
printf("\nError in closing file %s\n",arguments.argv[ind]);
}
//close target file
if (close(tgt) == -1) {
printf("\nError in closing file %s\n",cdir);
}
ind++;
}
if (arguments.verbose) {
printf("Copy successfully!\n");
}
exit(EXIT_SUCCESS);
}
it(EXIT_FAILURE);
}
//read source file
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, BUFFERSIZE) != pos) {
exit(EXIT_FAILURE);
}
}
//if the source file cannot be read
if (pos == -1) {
printf("\nError in reading data from %s\n",arguments.argv[ind]);
}
//close source file
if (close(src) == -1) {
printf("\nError in closing file %s\n",arguments.argv[ind]);
}
//close target file
if (close(tgt) == -1) {
printf("\nError in closing file %s\n",cdir);
}
ind++;
}
if (arguments.verbose) {
printf("Copy successfully!\n");
}
exit(EXIT_SUCCESS);
}
You always try to read/write BUFFERSIZE bytes. But what happens if the file you want to copy has a size multiple of BUFFERSIZE? You write what have been read last time.
read return the number of bytes read, so each write should try to write this number of bytes:
Instead of:
pos = read(src, buffer, BUFFERSIZE);
//write target file
while (pos > 0) {
write(tgt, buffer, BUFFERSIZE);
pos = read(src, buffer, BUFFERSIZE);
}
Use:
pos = read(src, buffer, BUFFERSIZE);
//write target file
while (pos > 0) {
write(tgt, buffer, pos);
pos = read(src, buffer, BUFFERSIZE);
}
Same here, instead of:
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, BUFFERSIZE) != pos) {
exit(EXIT_FAILURE);
}
}
Use:
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, pos) != pos) {
exit(EXIT_FAILURE);
}
}
You unconditionally write a full buffer, regardless of how much was read:
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, BUFFERSIZE) != pos) {
exit(EXIT_FAILURE);
}
}
should be:
//write target file
while ((pos = read(src, buffer, BUFFERSIZE)) > 0) {
if (write(tgt, buffer, pos) != pos) {
exit(EXIT_FAILURE);
}
}
Related
I'm trying to create a function that duplicates a file given a file descriptor and a file name:
int filedup(int fd1, char *cpyfile)
{
int fd;
size_t rd;
char buff;
if (fd1 < 0 || fd1 > OPEN_MAX)
return (-1);
if (!validfname(fname))
return (-1);
fd = open(cpyfile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
return (-1);
rd = read(fd1, &buff, 1);
while (rd > 0)
{
write(fd, &buff, 1);
rd = read(fd1, &buff, 1);
}
close(fd);
return (0);
}
int main(void)
{
int fd;
fd = open("/tmp/cpyfromfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
return (-1);
putstr_fd(strdup("hello world\n"), fd);
filedup(fd, "cpyfile");
close(fd);
return (0);
}
I tried to debug it, and the problem was rd == 0 even though the file contains data.
$ cat ./cpyfile
$ (nothing)
I'm not sure what's the problem ? what am i doing wrong ?
when I input "./test test.c /home/user1/Desktop/" it doesnt work anything.
I want to make copy file from (now_path) to (other_path).
But, I dont know why it does not work I think it is perfect code. Is it has error or need some more other codes??
char ch;
int src, dst;
if( argc != 3 )
{
printf("argument error\n");
printf("usage: ./a.out src dest\n");
}
src = open( argv[1], O_RDONLY );
dst = open( argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644 );
while( read( src, &ch, 1 ))
write( dst, &ch, 1 );
close( src );
close( dst );
return 0;
It's impossible to figure out unless you start to check return values. The open function returns a negative value on failure, and errno is set to indicate what went wrong.
Same goes for read and write. They returns the number of bytes read/written and a negative value on failure. errno is also set by these functions.
You could use constructs like this:
if ((src = open( argv[1], O_RDONLY )) < 0) {
fprintf(stderr, "Error accessing source file.\n");
fprintf(stderr, "errno: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
Your code is ok but you might want to ensure that the source file is readable before trying to copy it's content. Also you may want to terminate the program if an error occurs.
char ch;
int src, dst;
if( argc != 3 )
{
printf("argument error\n");
printf("usage: ./a.out src dest\n");
exit(1); // Terminate the program
}
if ((src = open( argv[1], O_RDONLY )) == -1)
{
printf("Error accessing source file.\n");
exit(1);
}
if (dst = open( argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644 )) == -1)
{
printf("Error accessing destination file.\n");
exit(1);
}
while( read( src, &ch, 1 ) > 0 )
write( dst, &ch, 1 );
close( src );
close( dst );
return 0;
Also, if the second argument will always be a directory, you'll need to set the open command for the destination file to the combination of the second and first arguments (argv[2] joined with argv[1]).
For this you can use the strcat function which copies the content of the second string into the first. Start by adding #include <string.h> to the header of your program:
char* buffer[BUF_SIZE];
int src, dst;
int bytesRead;
char dstFile[1024];
if (argc != 3)
{
printf("argument error\n");
printf("usage: ./a.out src dest\n");
}
if ((src = open(argv[1], O_RDONLY)) == -1)
{
printf("Error accessing source file.\n");
exit(1);
}
strcat(dstFile, argv[2]);
strcat(dstFile, argv[1]);
if ((dst = open(dstFile, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1)
{
printf("Error accessing destination file. %s\n", dstFile);
exit(1);
}
while ((bytesRead = read(src, buffer, BUF_SIZE)) > 0)
{
write(dst, buffer, bytesRead);
}
close(src);
close(dst);
return 0;
I am trying to create an empty file if it does not exists. And than map it using mmap() so, that i can pass it to my other program for writing. I am not sure which arguments for mmap are suitable for an empty file. My code works for non empty files but gives error "Invalid argument" if file is empty
Code program1 (only creates an empty file if not exists)
int i;
int fd = open("/home/sungmin/dummy_programs/dummy.txt", O_RDONLY | O_CREAT, 0777);
char *pmap;
pid_t child;
if (fd == -1)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
struct stat fileInfo = {0};
if (fstat(fd, &fileInfo) == -1)
{
perror("Error getting the file size");
exit(EXIT_FAILURE);
}
/*if (fileInfo.st_size == 0)
{
fprintf(stderr, "Error: File is empty, nothing to do\n");
exit(EXIT_FAILURE);
}*/
pmap = mmap(0, fileInfo.st_size, PROT_READ | PROT_EXEC , MAP_ANONYMOUS, fd, 0);
if (pmap == MAP_FAILED)
{
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/* Calling fork function */
if((child=fork())==0){
printf("Iam Child process\n\n");
static char *argv[]={"This is some sample text. I need to write this text in my dummy file.","/home/sungmin/dummy_programs/dummy.txt",NULL};
execv("/home/sungmin/dummy_programs/pro2",argv);
exit(127);
}
else {
printf("Iam parent, waiting for child process to exit\n\n");
waitpid(child,0,0);
printf("Existing parent\n\n");
}
/* Don't forget to free the mmapped memory*/
if (munmap(pmap, fileInfo.st_size) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
/* Un-mmaping doesn't close the file, so we still need to do that.*/
close(fd);
Code program2 (opens same file as program1 and writes text passed by program1)
size_t i;
int fd;
char *pmap;
pid_t child;
struct stat fileInfo = {0};
const char *text = argv[0];
fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
if (fd == -1)
{
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
size_t textsize = strlen(text) + 1; // + \0 null character
if (lseek(fd, textsize-1, SEEK_SET) == -1)
{
close(fd);
perror("Error calling lseek() to 'stretch' the file");
exit(EXIT_FAILURE);
}
if (write(fd, "", 1) == -1)
{
close(fd);
perror("Error writing last byte of the file");
exit(EXIT_FAILURE);
}
pmap = mmap(0, textsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pmap == MAP_FAILED)
{
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/* Writting users text to file */
for (i = 0; i < textsize; i++)
{
pmap[i] = text[i];
}
// Write it now to disk
if (msync(pmap, textsize, MS_SYNC) == -1)
{
perror("Could not sync the file to disk");
}
/* Don't forget to free the mmapped memory*/
if (munmap(pmap, textsize) == -1)
{
close(fd);
perror("Error un-mmapping the file");
exit(EXIT_FAILURE);
}
/* Un-mmaping doesn't close the file, so we still need to do that.*/
close(fd);
You need to use truncate to extend the file length after creating it before mapping it.
Yes, the function name sounds wrong, but truncate can actually set the file length to any number. Be sure to use a multiple of 4K for best results.
Then, if you want to keep the mapping open to see data between Program 1 and 2, you need to get rid of ANONYMOUS and map with MAP_SHARED in Program 1. A mapping that isn't shared will not show changes made by other programs. Or it might, if it has to reload from disk. It's weird, don't mix SHARED and not-SHARED mappings.
Once you've changed Program 1 to use truncate, take that lseek and write code out of Program 2. The file will already have been created and extended by Program 1.
So I was following a little outdated book (2010) and I'm trying to copy a file with Linux system calls. This is what i have:
NOTE: Ignore the tlpi_hdr.h and error_functions.h, they define errExit() and fatal() and some otheres, they just print the error and exit.
#include <stdio.h>
#include <fcntl.h>
#include "lib/tlpi_hdr.h"
#include "lib/error_functions.h"
#ifndef BUF_SIZE
#define BUF_SIZE 1024
#endif
int main(int argc, char *argv[])
{
int inputFd, outputFd, openFlags;
mode_t filePerms;
ssize_t numRead;
char buf[BUF_SIZE];
if (argc != 3 || strcmp(argv[1], "--help") == 0) {
usageErr("%s old-file new-file\n", argv[0]);
}
inputFd = open(argv[1], O_RDONLY);
if (inputFd == -1) {
errExit("Opening file %s", argv[1]);
}
openFlags = O_CREAT | O_WRONLY | O_TRUNC;
filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
outputFd = open(argv[2], openFlags, filePerms);
if (outputFd == -1) {
errExit("Opening file for writing %s", argv[1]);
}
while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0) {
if (write(outputFd, buf, numRead) != numRead))
fatal("I/O Error");
if (numRead == -1)
fatal("Reading error");
}
if (close(outputFd == -1))
errExit("close input");
if (close(inputFd == -1))
errExit("close output");
return EXIT_SUCCESS;
}
I'm failing on closing of the output file descriptor with EBADF Bad file descriptor:
thinkpad :: ~/.tlpi % ./cp.o a b
ERROR [EBADF Bad file descriptor] close output
The file copies fine tho:
thinkpad :: ~/.tlpi % sha1sum a
40a925a93e149ac53d2630cde8adeb63b8134b29 a
thinkpad :: ~/.tlpi % sha1sum b
40a925a93e149ac53d2630cde8adeb63b8134b29 b
thinkpad :: ~/.tlpi %
Why?
Let's take a closer look at your close call:
close(outputFd == -1)
Here you are comparing outputFd to the value -1. The result of that is a boolean value, which in C will be either 0 or 1. This happens to be either standard input or standard output, depending on the result. Not a file you descriptor you should close.
My guess is that you meant
if (close(outputFd) == -1)
I try to create a copy of a source file but the target file is always empty.
The algorithm is: read from STDIN and write to source file, then read on this file and write the text in target file.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFFSIZE 8192
int main(){
int fdsource, fdtarget;
int n, nr;
char buff[BUFFSIZE];
fdsource = open("source.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // Create and open a source file in read/write
if (fdsource < 0){
printf("Source file open error!\n");
exit(1);
}
fdtarget = open("target.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); // Create and open a source file in write only
if (fdtarget < 0){
printf("Target file open error!\n");
exit(1);
}
printf("\nInsert text:\n");
while ((n = read(STDIN_FILENO, buff, BUFFSIZE)) > 0){ // Read from STDIN and write to source file
if ((write(fdsource, buff, n)) != n){
printf("Source file write error!\n");
exit(1);
}
}
while ((read(fdsource, buff, n)) > 0){ // Read from source file and write to target file
if ((write(fdtarget, buff, n)) != n){
printf("Source file open error!\n");
exit(1);
}
}
close(fdsource);
close(fdtarget);
exit(0);
return 0;
}
The problem with your code is "You have opened both the file in initial stage". To solve the problem just open the source file in the write mode and write all the data, then close and reopen the source file in read mode, Then open the target file in the write mode.
The modified code is given below and it was not tested
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFFSIZE 8192
int main(){
int fdsource, fdtarget;
int n;
char buff[BUFFSIZE];
fdsource = open("source.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // Create and open a source file in read/write
if (fdsource < 0){
printf("Source file open error!\n");
exit(1);
}
printf("\nInsert text:\n");
while ((n = read(STDIN_FILENO, buff, BUFFSIZE)) > 0){ // Read from STDIN and write to source file
if ((write(fdsource, buff, n)) != n){
printf("Source file write error!\n");
exit(1);
}
}
close(fdsource);
fdsource = open("source.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // Create and open a source file in read/write
if (fdsource < 0){
printf("Source file open error!\n");
exit(1);
}
fdtarget = open("target.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); // Create and open a source file in write only
if (fdtarget < 0){
printf("Target file open error!\n");
exit(1);
}
while ((read(fdsource, buff, n)) > 0){ // Read from source file and write to target file
if ((write(fdtarget, buff, n)) != n){
printf("Source file open error!\n");
exit(1);
}
}
close(fdsource);
close(fdtarget);
exit(0);
return 0;
}
If am wrong anywhere use the logic mentioned above.