Related
This mmap tutorial from 15 years ago ranks high in Google searches, but it actually runs subtly incorrectly on my Linux system.
mmap_write.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define FILEPATH "/tmp/mmapped.bin"
#define NUMINTS (1000)
#define FILESIZE (NUMINTS * sizeof(int))
int main(int argc, char *argv[])
{
int i;
int fd;
int result;
int *map; /* mmapped array of int's */
/* Open a file for writing.
* - Creating the file if it doesn't exist.
* - Truncating it to 0 size if it already exists. (not really needed)
*
* Note: "O_WRONLY" mode is not sufficient when mmaping.
*/
fd = open(FILEPATH, O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
if (fd == -1) {
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
/* Stretch the file size to the size of the (mmapped) array of ints
*/
result = lseek(fd, FILESIZE-1, SEEK_SET);
if (result == -1) {
close(fd);
perror("Error calling lseek() to 'stretch' the file");
exit(EXIT_FAILURE);
}
/* Something needs to be written at the end of the file to
* have the file actually have the new size.
* Just writing an empty string at the current file position will do.
*
* Note:
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - An empty string is actually a single '\0' character, so a zero-byte
* will be written at the last byte of the file.
*/
result = write(fd, "", 1);
if (result != 1) {
close(fd);
perror("Error writing last byte of the file");
exit(EXIT_FAILURE);
}
/* Now the file is ready to be mmapped.
*/
map = mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/* Now write int's to the file as if it were memory (an array of ints).
*/
for (i = 1; i <=NUMINTS; ++i) {
map[i] = 2 * i;
}
/* Don't forget to free the mmapped memory
*/
if (munmap(map, FILESIZE) == -1) {
perror("Error un-mmapping the file");
/* Decide here whether to close(fd) and exit() or not. Depends... */
}
/* Un-mmaping doesn't close the file, so we still need to do that.
*/
close(fd);
return 0;
}
mmap_read.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define FILEPATH "/tmp/mmapped.bin"
#define NUMINTS (1000)
#define FILESIZE (NUMINTS * sizeof(int))
int main(int argc, char *argv[])
{
int i;
int fd;
int *map; /* mmapped array of int's */
fd = open(FILEPATH, O_RDONLY);
if (fd == -1) {
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
map = mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
/* Read the file int-by-int from the mmap
*/
for (i = 1; i <=NUMINTS; ++i) {
printf("%d: %d\n", i, map[i]);
}
if (munmap(map, FILESIZE) == -1) {
perror("Error un-mmapping the file");
}
close(fd);
return 0;
}
If the file does not already exist, the output of mmap_read is
...
998: 1996
999: 1998
1000: 2000
But if it does, the output is
...
998: 1996
999: 1998
1000: 0
Should the author have flushed the write? Or is GCC miscompiling the code?
Edit: I noticed that it's the prior existence or non-existence of the file that makes a difference, not the compilation flag.
You are starting at the second element, and writing 2000 after the end of the map.
for (i = 1; i <=NUMINTS; ++i) {
map[i] = 2 * i;
}
should be
for (i = 0; i < NUMINTS; ++i) {
map[i] = 2 * ( i + 1 );
}
Demo
It's not a buffering issue. write is a system call, so the data passed to the OS directly. It doesn't mean the data has been written to disk when write returns, but it is in the OS's hands, so it's as if it was on disk as far as OS functions are concerned, including its memory-mapping functionality.
In C indexes are from zero. Writing and reading index 1000 you invoke undefined behaviour
Change to in the write.:
for (i = 1; i <=NUMINTS; ++i) {
map[i - 1] = 2 * i;
}
and reading to:
for (i = 1; i <=NUMINTS; ++i) {
printf("%d: %d\n", i, map[i-1]);
}
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.
update 20-12-2014: This problem has been solved, see the bottom of the question for working code.
Design
There are four clients that process some data and then passes it to a server process over a named pipe (FIFO).
Problem
When running the server outside of gdb (not stepping in gdb also gives the same problem) only one pipe is read. Select returns 1 and FD_ISSET only reacts to one pipe (and it stays the same pipe during execution).
Looking into /proc/[PID]/{fd,fdinfo} shows that the other pipes are still open and haven't been read. The pos field in fdinfo is 0).
The Question
What do I need to change to read from all the four pipes in an interleaved fashion?
Test
To simulate the client I use a 12MByte random file that is catted onto the named pipe.
The random file is generated with:
dd if=/dev/urandom of=test.bin bs=1024 count=$((1024*12))
And then executed as (each in a separate terminal and in the following order)
terminal 1:
./server.out
terminal 2:
cat test.bin > d0
terminal 3:
cat test.bin > d1
terminal 4:
cat test.bin > d2
terminal 5:
cat test.bin > d3
Makefile
server:
gcc server.c -o server.out -g -D _DEFAULT_SOURCE -Wall --std=c11
Source
The clients are called dongles.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define NR_OF_DONGLES 4
int do_something(int fd);
int main()
{
fd_set read_fd_set;
FD_ZERO(&read_fd_set);
int dongles[NR_OF_DONGLES];
/*Create FIFO */
for(int i = 0; i < NR_OF_DONGLES; i++)
{
char name[255];
snprintf(name, sizeof(name), "d%d", i);
if(mkfifo(name, 0666) == -1)
{
fprintf(stderr, "Failed to create fifo %s \t Error: %s", name, name);
exit(EXIT_FAILURE);
}
int dongle = open(name, O_RDONLY);
if(dongle > 0)
{
fprintf(stderr,"set dongle %s\n", name);
FD_SET(dongle, &read_fd_set);
dongles[i] = dongle;
}
else
{
fprintf(stderr, "failed to open: %s\nerror: %s\n", name, strerror(errno));
exit(EXIT_FAILURE);
}
}
int closed = 0;
int isset[NR_OF_DONGLES];
memset(isset, 0, sizeof(isset));
while(closed < NR_OF_DONGLES)
{
int active;
if((active = select (FD_SETSIZE , &read_fd_set, NULL,NULL,NULL)) < 0)
{
fprintf(stderr, "select failed\n errno: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stderr, "active devices %i\n", active);
for(int i = 0; i < NR_OF_DONGLES; ++i)
{
int dongle = dongles[i];
if(FD_ISSET(dongle, &read_fd_set))
{
isset[i] += 1;
int size = do_something(dongle);
fprintf(stderr, "round %i \tdongle %i \tread %i bytes\n", isset[i],i, size);
if(size == 0)
{
if(close(dongle) == -1)
{
fprintf(stderr,"Could not close dongle %i\nError: %s\n",
i,strerror(errno));
}
closed += 1;
fprintf(stderr, "closed dongle %i \t number of closed dongles %i\n",
i, closed);
FD_CLR(dongle, &read_fd_set);
}
}
}
}
exit(EXIT_SUCCESS);
}
#define BLOCK_SIZE (8*1024)
/*
* If the size is zero we reached the end of the file and it can be closed
*/
int do_something(int fd)
{
int8_t buffer[BLOCK_SIZE];
ssize_t size = read(fd, buffer, sizeof(buffer));
if(size > 0)
{
//Process read data
}
else if(size == -1)
{
fprintf(stderr, "reading dongle failed\nerrno: %s", strerror(errno));
return -1;
}
return size;
}
The Solution
kestasx's solution worked for me. The watchlist (read_fd_set) needs to be reinitialized before a call to select.
Source code
while(closed < number_of_dongles)
{
/*Reinitialize watchlist of file descriptors.*/
FD_ZERO(&read_fd_set);
for(int i = 0; i < number_of_dongles; i++)
{
int dongle = dongles[i];
/*if fd == -1 the pipe has been closed*/
if(dongle != -1)
{
FD_SET(dongle, &read_fd_set);
}
}
int active = select (FD_SETSIZE , &read_fd_set, NULL,NULL,NULL);
if(active < 0)
{
fprintf(stderr, "select failed\n errno: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
//fprintf(stderr, "active devices %i\n", active);
for(int i = 0; i < number_of_dongles; ++i)
{
int dongle = dongles[i];
/*Check if the current dongle fd has data in the FIFO*/
if(FD_ISSET(dongle, &read_fd_set))
{
isset[i] += 1;
int size = transfer_dongle_data(dongle);
// fprintf(stderr, "round %i \tdongle %i \tread %i bytes\n", isset[i],i, size);
if(size == 0)
{
if(close(dongle) == -1)
{
fprintf(stderr,"Could not close dongle %i\nError: %s\n",
i,strerror(errno));
}
closed += 1;
fprintf(stderr, "closed dongle %i \t number of closed dongles %i\n",
i, closed);
FD_CLR(dongle, &read_fd_set); //could be removed
/*notify that the pipe is closed*/
dongles[i] = -1;
}
}
}
}
You can try to run Your code via strace (truss on Solaris, ktrace/kdump on FreeBSD). For me it stalls on open("d0", O_RDONLY). So the server dosn't create all pipes before (other pipes most likely are created by cat).
if(dongle)... after open is incorrect: in case of failure open() returns -1, not 0.
Because of this, I think Your program is not working with files You expect (only one pipe is openned correctly).
One more issue ir related to select() use. You should reinitialize read_fd_set before each call to select(), because after each select() call only descriptors, which have data are left marked, others are cleared.
After some tinkering, I got it. On my MacOSX open(...) would block until there was actually something on the FIFO. Consider the program below; it worked as soon as you start feeding data into d0, d1 and so on. But until then, the output of the program was only:
Creating dongle d0
Creating dongle d1
Creating dongle d2
Creating dongle d3
Opening dongle d0
So I pulled up the manpage for open() and lo and behold - there's a flag O_NONBLOCK. With that added in, the following code works like a charm. FYI, POSIX doesn't say that opening a FIFO should block, but I found comments that some implementations do.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/select.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define NR_OF_DONGLES 4
#define BLOCK_SIZE (8*1024)
// Prints error and stops program
int error(char const *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
exit(1);
}
// Alternative for printf() that flushes stdout
void msg(char const *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
fflush(stdout);
}
// Reads an open readable fd
int do_something(int fd) {
int8_t buffer[BLOCK_SIZE];
ssize_t size = read(fd, buffer, sizeof(buffer));
if(size > 0)
msg("Got data from fd %d, length %ld\n", fd, size);
else if (size == -1)
error("Reading dongle fd %d failed: %s\n", fd, strerror(errno));
else
msg("Dongle with fd %d signals EOF\n", fd);
return size;
}
int main() {
int dongles[NR_OF_DONGLES];
// Create the dongles, open, add to list of open fd's
for (int i = 0; i < NR_OF_DONGLES; i++) {
char name[255];
snprintf(name, sizeof(name), "d%d", i);
msg("Creating dongle %s\n", name);
if (mkfifo(name, 0666) == -1 && errno != EEXIST)
error("Failed to create fifo %s: %s\n", name, strerror(errno));
}
for (int i = 0; i < NR_OF_DONGLES; i++) {
char name[255];
snprintf(name, sizeof(name), "d%d", i);
msg("Opening dongle %s\n", name);
/* ****************************************
* Here it is, first test was with
* int fd = open(name, O_RDONLY);
* which blocked at the open() call
*******************************************/
int fd = open(name, O_RDONLY | O_NONBLOCK);
if (fd < 0)
error("Cannot open dongle %s: %s\n", name, strerror(errno));
dongles[i] = fd;
}
int closed = 0;
while (closed < NR_OF_DONGLES) {
msg("Closed dongles so far: %d\n", closed);
// Add dongle fd's to select set, unless the fd is already closed
// which is indicated by fd == -1
fd_set read_fd_set;
FD_ZERO(&read_fd_set);
for (int i = 0; i < NR_OF_DONGLES; i++)
if (dongles[i] > 0)
FD_SET(dongles[i], &read_fd_set);
// Wait for readable fd's
int active;
if ( (active = select (FD_SETSIZE , &read_fd_set, 0, 0, 0)) < 0 )
error("Select failure: %s\n", strerror(errno));
msg("Active dongles: %d\n", active);
for (int fd = 0; fd < FD_SETSIZE; fd++)
if (FD_ISSET(fd, &read_fd_set)) {
msg("Fd %d is readable\n", fd);
int size = do_something(fd);
if (!size) {
// Fd signals EOF. Close dongle, remove from array
// of open fd's by setting to -1
msg("Fd %d signals EOF\n", fd);
if (close(fd) < 0)
error("Failure to close fd %d: %s\n",
fd, strerror(errno));
for (int i = 0; i < NR_OF_DONGLES; i++)
if (dongles[i] == fd)
dongles[i] = 0;
// Update closed fd counter
closed++;
}
}
}
exit(0);
}
im trying to read a file and write the content in other file, but the finish file is empty after program execution.
this is the code:
char buf[80];
int main(int argc, char *argv[])
{
int fd;
int fs;
if( (fd=open("salida.txt",O_CREAT|O_TRUNC|O_WRONLY,S_IRUSR|S_IWUSR))<0) {
printf("\nError %d en open",errno);
perror("\nError en open");
exit(EXIT_FAILURE);
}
if( (fs=open(argv[1],O_CREAT|O_TRUNC|O_RDONLY,S_IRUSR|S_IWUSR))<0) {
printf("\nError %d en open",errno);
perror("\nError en open");
exit(EXIT_FAILURE);
}
int cont = 1;
if(fs=read(fd,&buf,80) < 0){
cont++;
if(write(fd,&buf,80) != 80) {
perror("\nError en el write");
exit(EXIT_FAILURE);
}
}
The condition
if (fs=read(fd,&buf,80) < 0)
doesn't mean
if ((fs = read(fd,&buf,80)) < 0)
it means
if (fs = (read(fd,&buf,80) < 0))
and has the effect of overwriting the file descriptor fs with 0 if the read succeeds, and with 1 if it fails. (read returns the number of bytes read, or -1 on failure.)
You don't want to assign the result to fs in any case, as it means that you're destroying any possibility of writing to the file you opened.
Also, fd is apparently your output file, so it's slightly strange to read from it.
If you want to copy (up to) 80 bytes, you could say something like
int size = 0;
if((size = read(fs, buf, 80)) > 0){
if (write(fd, buf, size) != size) {
perror("\nError en el write");
exit(EXIT_FAILURE);
}
}
Also, truncating the input file (O_TRUNC) may not be the best idea.
You seem to be reading and writing from and to fd. Your code is not very clear, you may want to clean it up. As other answers have pointed out, there are multiple errors in your code and your intentions are not entirely clear.
You should comment your code and indent properly.
int main()
{
char ch;
FILE *source, *target;
source = fopen(source_file, "r");
if( source == NULL )
{
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
target = fopen(target_file, "w");
if( target == NULL )
{
fclose(source);
printf("Press any key to exit...\n");
exit(EXIT_FAILURE);
}
while( ( ch = fgetc(source) ) != EOF )
fputc(ch, target);
printf("File copied successfully.\n");
fclose(source);
fclose(target);
return 0;
}
You never closed the files. Most operating systems don't actually make changes to the files until you close them. Until then your changes are only visible in RAM and not on the hard drive. Just add:
close(fd);
close(fs);
To the end of your code.
There seem to be some other problems too (why are you reading from a write-only file and seemingly attempting to write the same data back to it), and it's very much unclear what you're trying to accomplish.
// the following compiles, but the #include statements do expect linux
// so if your using a different OS, you may have to update them.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#define BUFFER_SIZE (80)
static char buf[ BUFFER_SIZE ]; // static so only visible in this file
// note: file scope variables are set to 0 by the startup code
int main( int argc, char *argv[])
{
int fd = -1; // destination file descriptor
int fs = -1; // source file descriptor
int statusRd = 0; // returned value from read
int statusWr = 0; // returned value from write
if( 2 > argc )
{ // then, file name parameter missing
printf( "\ncalling format: %s <filenametoread>\n", argv[0]);
exit( EXIT_FAILURE );
}
// implied else, proper number of parameters
// note: there should be a call to 'stat()'
// to assure input file exists placed here
// open destination file, uses fixed name
if( (fd = open("salida.txt", O_TRUNC | O_CREAT | O_WRONLY, S_IWRITE) ) <0)
{
printf("\nError %d en open",errno);
perror("open for write failed");
exit(EXIT_FAILURE);
}
// implied else, open of destination file successful
if( (fs=open(argv[1],O_RDONLY,S_IREAD))<0)
{
printf("\nError %d en open",errno);
perror("open for read failed");
close(fd); // cleanup
exit(EXIT_FAILURE);
}
// implied else, open of source file successful
do
{
if( (statusRd = read(fs,&buf, BUFFER_SIZE)) < 0)
{ // then read failed
perror( "read failed" );
close(fs); // cleanup
close(fd); // cleanup
exit( EXIT_FAILURE );
}
// implied else, read successful
if( 0 < statusRd )
{ // then some bytes read
if( ( statusWr = write(fd, buf, statusRd)) < 0)
{ // then, write failed
perror("\nwrite failed");
close(fs); // cleanup
close(fd); // cleanup
exit(EXIT_FAILURE);
}
}
} while( statusRd > 0 ); // exit loop when reach end of file
close(fs);
close(fd);
return(0);
}