How to write a file with C in Linux? - c

I want to rewrite the "cp" command of Linux. So this program will work like #./a.out originalfile copiedfile. I can open the file, create new file but can't write the new file. Nothing is written. What could be the reason?
The current C code is:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *aa[]){
int fd,fd1;
char buffer[100];
if(argc!=3){
printf("Usage : ./a.out <original> <copy> \n");
return -1;
}
fd=open(aa[1],O_RDONLY,S_IRUSR);
if(fd==-1){
printf("file not found.\n");
return -1;
}
fd1=open(aa[2],O_CREAT | O_WRONLY,S_IRUSR);
if(fd1!=-1){
printf("file is created.\n");
}
ssize_t n;
while(n=read(fd,buffer,50)){
write(fd1,buffer,n);
printf("..writing..\n");
}
close(fd);
close(fd1);
}

You need to write() the read() data into the new file:
ssize_t nrd;
int fd;
int fd1;
fd = open(aa[1], O_RDONLY);
fd1 = open(aa[2], O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
while (nrd = read(fd,buffer,50)) {
write(fd1,buffer,nrd);
}
close(fd);
close(fd1);
Update: added the proper opens...
Btw, the O_CREAT can be OR'd (O_CREAT | O_WRONLY). You are actually opening too many file handles. Just do the open once.

First of all, the code you wrote isn't portable, even if you get it to work. Why use OS-specific functions when there is a perfectly platform-independent way of doing it? Here's a version that uses just a single header file and is portable to any platform that implements the C standard library.
#include <stdio.h>
int main(int argc, char **argv)
{
FILE* sourceFile;
FILE* destFile;
char buf[50];
int numBytes;
if(argc!=3)
{
printf("Usage: fcopy source destination\n");
return 1;
}
sourceFile = fopen(argv[1], "rb");
destFile = fopen(argv[2], "wb");
if(sourceFile==NULL)
{
printf("Could not open source file\n");
return 2;
}
if(destFile==NULL)
{
printf("Could not open destination file\n");
return 3;
}
while(numBytes=fread(buf, 1, 50, sourceFile))
{
fwrite(buf, 1, numBytes, destFile);
}
fclose(sourceFile);
fclose(destFile);
return 0;
}
EDIT: The glibc reference has this to say:
In general, you should stick with
using streams rather than file
descriptors, unless there is some
specific operation you want to do that
can only be done on a file descriptor.
If you are a beginning programmer and
aren't sure what functions to use, we
suggest that you concentrate on the
formatted input functions (see
Formatted Input) and formatted output
functions (see Formatted Output).
If you are concerned about portability
of your programs to systems other than
GNU, you should also be aware that
file descriptors are not as portable
as streams. You can expect any system
running ISO C to support streams, but
non-GNU systems may not support file
descriptors at all, or may only
implement a subset of the GNU
functions that operate on file
descriptors. Most of the file
descriptor functions in the GNU
library are included in the POSIX.1
standard, however.

You have to do write in the same loop as read.

You have to allocate the buffer with mallock, and give the read write the pointer to it.
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
ssize_t nrd;
int fd;
int fd1;
char* buffer = malloc(100*sizeof(char));
fd = open("bli.txt", O_RDONLY);
fd1 = open("bla.txt", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
while (nrd = read(fd,buffer,sizeof(buffer))) {
write(fd1,buffer,nrd);
}
close(fd);
close(fd1);
free(buffer);
return 0;
}
Make sure that the rad file exists and contains something.
It's not perfect but it works.

Related

Implementing the cp command using read/write system calls [duplicate]

This question already has an answer here:
Using open(), read() and write() system calls to copy a file
(1 answer)
Closed last year.
I am trying to implement the cp command only using read/write system calls.
Here is my code:
/**
* cp file1 file 2
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int errsv;
char contents[1024];
int fd_read, fd_write;
fd_read = open(argv[1], O_RDONLY);
if (fd_read == -1)
{
errsv = errno;
printf("Error occured: %d\n", errsv);
}
read(fd_read, contents, sizeof(contents));
fd_write = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0744);
if (fd_write == -1)
{
errsv = errno;
printf("Error occured: %d\n", errsv);
}
write(fd_write, contents, sizeof(contents));
close(fd_read);
close(fd_write);
return 0;
}
I tested the code using the commands:
cc test.c
./a.out file1 file2
Here is my file1:
dummy text
dummy text
After running the code, although file2 contains the text from file1, it also has some gibberish characters. [not keeping this here.]
Why is this so?
You need to call read() and write() in a loop to copy the entire file. read() returns 0 when you reach EOF, or a negative result if there's an error, then you can end the loop.
read() returns the number of bytes that were read, which may be less than the size of the buffer. You need to use that number when calling write(), otherwise you'll write extra characters to the output file. These will be unitialized characters on the first iteration, and on other iterations they'll be left over characters from previous iterations.
int main(int argc, char *argv[])
{
char contents[1024];
int fd_read, fd_write;
fd_read = open(argv[1], O_RDONLY);
if (fd_read == -1)
{
perror("open input file");
exit(1);
}
fd_write = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0744);
if (fd_write == -1)
{
perror("open output file");
exit(1)
}
int n_read;
while ((n_read = read(fd_read, contents, sizeof(contents))) > 0) {
write(fd_write, contents, n_read);
}
close(fd_read);
close(fd_write);
return 0;
}
write(fd_write, contents, strlen(contents));
Strlen returns the filled entries number but sizeof returns the buffer size which is 1024

C - Declare a file in function parameters

so here is my problem :
int isopen()
{
int fd;
fd = open("myfile", O_RDONLY);
if (fd == 0)
printf("file opening error");
if (fd > 0)
printf("file opening success");
return(0);
}
int main(void)
{
isopen();
return(0);
}
Is use this code to check if this the open command worked, as i'm just starting to lurn how to use it.
Basically this code is working just fine, but I would like to declare the file I would like to open directly in the parameters of my function isopen.
I saw some other posts using main's argc and argv, but I really need to declare my file in the parameters of my function isopen, not using argc & argv.
Is it even possible ?
Thank you for your help, I'm quite lost here.
Your question is unclear, but maybe you want this:
int isopen(const char *filename)
{
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0) //BTW <<<<<<<<<<<< fd < 0 here !!
printf("file opening error");
else // else here
printf("file opening success");
return(0);
}
int main(void)
{
isopen("myfile");
return(0);
}
BTW, the isopen function as it stands here is still pretty useless as it just opens the file and throwing away fd.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int isOpen(char *filename)
{
return open(filename, O_RDONLY);
}
int main()
{
printf("%d\n", isOpen("/home/viswesn/file1.txt"));
printf("%d\n", isOpen("file2.txt"));
return 0;
}
Output
viswesn#viswesn:~$ cat /home/viswesn/file1.txt
hello
viswesn#viswesn:~$
viswesn#viswesn:~$ cat /home/viswesn/file2.txt
cat: /home/viswesn/file2.txt: No such file or directory
viswesn#viswesn:~$
viswesn#viswesn:~$ ./a.out
3 <---------- File exist and it give file descriptor number '3'
STDIN-0, STDOUT-1, STDERR-2 are reserved and
next file opened will start with 3 and it keeps going
-1 <--------- File not found; so open gives -1 as error

How not to open a file twice in linux?

I have a linked list with an fd and a string I used to open this file in each entry. I want to open and add files to this list only if this file is not already opened, because I open and parse this files and do not want to do it twice. My idea was to compare the filename with every single name in this list, but my program do it multiple times and one file in Linux can have multiple names (soft/hard links). I think it should not be so complicated, because its easy for the OS to check, whether I already used a inode or not, r?
I already tried to open the same file with and without flock, but I always get a new fd.
When you successfully open a file use fstat on the file. Check to see if the st_ino and st_dev of the struct stat filed in by fstat have already been recorded in your linked list. If so then close the file descriptor and move on to the next file. Otherwise add the file descriptor, the file name and st_ino and st_dev values to the list.
You can instead use stat to check before opening the file, but using fstat after will be slightly faster if the usual case is that file hasn't already been opened.
In situations like this, it's often useful to consider your data structures. Change to a data structure which does not allow duplicates, such as a hash table.
Maintain a set of which data you've seen before. I've used a hash table for this set. As per #RossRidge's answer, use the inode and device as the key. This allows duplicates to be discovered in O(1) time.
Here is an example implementation.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
static int get_fd(GHashTable *fds, const char *filename, int mode) {
int fd;
struct stat stat;
int keysize = 33;
char key[keysize]; /* Two 64 bit numbers as hex and a separator */
/* Resolve any symlinks */
char *real_filename = realpath(filename, NULL);
if( real_filename == NULL ) {
printf("%s could not be resolved.\n", filename);
return -1;
}
/* Open and stat */
fd = open( real_filename, mode );
if( fd < 0 ) {
printf("Could not open %s: %s.\n", real_filename, strerror(errno));
return -1;
}
if( fstat(fd, &stat) != 0 ) {
printf("Could not stat %s: %s.\n", real_filename, strerror(errno));
return -1;
}
/* Make a key for tracking which data we've processed.
This uses both the inode and the device it's on.
It could be done more efficiently as a bit field.
*/
snprintf(key, keysize, "%lx|%lx", (long int)stat.st_ino, (long int)stat.st_dev);
/* See if we've already processed that */
if( g_hash_table_contains(fds, key) ) {
return 0;
}
else {
/* Note that we've processed it */
g_hash_table_add(fds, key);
return fd;
}
}
int main(int argc, char** argv) {
int mode = O_RDONLY;
int fd;
GHashTable *fds = g_hash_table_new(&g_str_hash, &g_str_equal);
for(int i = 1; i < argc; i++) {
char *filename = argv[i];
fd = get_fd(fds, filename, mode);
if( fd == 0 ) {
printf("%s has already been processed.\n", filename);
}
else if( fd < 0 ) {
printf("%s could not be processed.\n", filename);
}
else {
printf("%s: %d\n", filename, fd);
}
}
}
And here's a sample result.
$ touch one two three
$ ln one one_link
$ ln -s two two_sym
$ ./test one* two* three*
one: 3
one_link has already been processed.
two: 5
two_sym has already been processed.
three: 7
As long as you don't close the successfully and intentionally opened files, you can use nonblocking flock to prevent another lock on the same file:
#include <unistd.h>
#include <sys/file.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <assert.h>
int openAndLock(const char* fn){
int fd = -1;
if(((fd = open(fn, O_RDONLY)) >= 0) && (flock(fd, LOCK_EX|LOCK_NB) == 0)){
fprintf(stderr, "Successfully opened and locked %s\n", fn);
return fd;
}else{
fprintf(stderr, "Failed to open or lock %s\n", fn);
close(fd);
return -1;
}
}
int main(int argc, char** argv){
for(int i=1; i<argc; i++){
openAndLock(argv[i]);
}
return 0;
}
Example:
$ touch foo
$ ln foo bar
$ ./a.out foo foo
Successfully opened and locked foo
Failed to open or lock foo
$ ./a.out foo bar
Successfully opened and locked foo
Failed to open or lock bar

C Write() Error in Mac

I'm trying to write characters in a text file on my Macbook Air, but it seems not to be working.
I tried compiling both via Xcode and Terminal.
But the results are same:
File Descripter: 3
write() Error!
Here is the code.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void Error_handling(char* message);
int main() {
int fd;
char buf[] = "Let's go! \n";
fd = open("data.txt", O_CREAT|O_RDONLY|O_TRUNC);
if (fd == -1)
Error_handling("open() Error! \n");
printf("File Descripter: %d \n", fd);
if(write(fd, buf, sizeof(buf))==-1)
Error_handling("write() Error! \n");
close(fd);
return 0;
}
void Error_handling(char* message)
{
fputs(message, stderr);
exit(1);
}
You open file with O_RDONLY and then try to write, of course it reports error.
And as comments suggested the right open variant should be:
fd = open("data.txt", O_CREAT|O_WRONLY|O_TRUNC, 0600);
Your file is opened in read only mode, which naturally prevents you from writing to it.
fd = open("data.txt", O_CREAT|O_RDONLY|O_TRUNC);
// ^ <- Your problem is here
Fix it by using
fd = open("data.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IWRITE);

C program to use Unix System call for I/O [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
My professor asked me to write a simple C program, then asked me to convert using Unix system calls. I have try changing the values around but nothing is working.
Requirement:
Write a new C program newcat, which performs exactly as oldcat, but uses the following UNIX system calls for I/O.
int read(int fd, char *buf, int n);
int write(int fd, char *buf, int n);
int open(char *name, int accessmode, int permission);
int close(int fd);
To open a file for read, you can use the symbolic constant O_RDONLY defined in fcntl.h header file to specify the accessmode. Simply pass 0 for permission. That is, the code will appear as follows:
fd = open (filename, O_RDONLY, 0);
You will need the following header files: sys/types.h, unistd.h and fcntl.h
#include <stdio.h>
/* oldcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(FILE *, FILE *); /* prototype for function */
int fd = open(*fp, O_RDONLy,0)
char *prog = argv[0]; /* program name for errors */
if (argc == 1) /* no args; copy standard input */
filecopy(0, 1);
else
while (--argc > 0)
if (fd == -1) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(fp, 1);
fclose(fp);
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(FILE *ifp, FILE *ofp)
{
int c;
while ((c = getc(ifp)) != EOF)
putc(c, ofp);
}
Is this the write idea? It still won't compile:
#include <stdio.h>
/* oldcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(int ifp, int ifo);
int fd = open(*File,O_RDONLY,0); //is this correct?
char *prog = argv[0];
if (argc == 1) /* no args; copy standard input */
filecopy(0, 1); //is this correct?
else
while (--argc > 0)
if ((fd == -1) //is this correct?{
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(*FILE, 1);//is this correct?
close(*FILE);//is this correct?
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(FILE *ifp, FILE *ofp)//NO CLUE HOW THIS SHOULD BE
{
int c;
while (c = read(fd ,&something,1)//What is &ch/&something?
putc(c, ofp);
}
Assuming your oldcat uses the C standard library calls (like fopen), it's a simple matter of mapping those to the UNIX calls.
At a high level:
fopen -> open
fread -> read
fwrite -> write
fclose -> close
For example, when opening your input file with:
FILE *fIn = fopen ("jargon.txt", "r");
you could instead use:
int inFd = open ("jargon.txt", O_RDONLY, 0);
The other calls are very similar, with similar functionality at the C standard library and UNIX system call levels. Details on those calls can usually be obtained from the manpages by entering something like man 2 open into your shell, or by plugging man open into your favourite search engine.
The only "tricky" mapping is if you've used getchar/putchar-style calls to do the actual reading and writing but that too becomes easy when you realise that (for example) reading a character is functionally identical to reading a block of size one:
int c = getc (fIn);
or:
char c;
int numread = read (inFd, &c, 1);
For your added question:
So to open a file: if (fd = open (fp, O_RDONLY, 0); ) == NULL)
Not quite. The fopen function returns NULL on error because it returns a pointer to a FILE structure.
The lower level calls use file descriptors rather than file handles, the former being a small integer value. So, instead of:
FILE *fp = fopen ("nosuchfile", "r");
if (fp == NULL) doSomethingIntelligent();
you would do something like:
int fd = open ("nosuchfile", O_RDONLY, 0);
if (fd == -1) doSomethingIntelligentUsing (errno);
In terms of what you need to change, the following comes off the top of my head (so may not be totally exhaustive but should be a very good start):
Add the required headers.
Stop using FILE* totally, using int instead.
Translate the fopen/fclose calls to open/close. This includes the function name, different parameters and different return types.
Modify filecopy to use file descriptors rather than file handles.
use 1 instead of stdout when calling filecopy (the latter is a FILE *).
As an example of how to do this, the following program testprog.c will read itself and echo each character to standard output:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
int main (void) {
int num, ch, inFd;
// Open as read only.
inFd = open ("testprog.c", O_RDONLY, 0);
if (inFd == -1)
printf ("\n**Error %d opening file\n", errno);
// Get and output esach char until EOF/error.
while ((num = read (inFd, &ch, 1) != 0) == 1)
putchar (ch);
// Detect error.
if (num != 0)
printf ("\n**Error %d reading file\n", errno);
// Close file and exit.
close (inFd);
return 0;
}
Please note that documentation of linux sys calls is present in manual called man pages which you can access by using man command in bash shell in a linux system. As UNIX and Linux are quite similar (maybe equivalent) for the syscalls you are interested in you can check the man page for those syscalls in Linux.
All the four read, write, open and close linux syscalls are explained in man pages. You can access the manual page for these syscalls by typing below commands in shell:
man 2 read
man 2 write
man 2 open
man 2 close
These should probably guide you to right direction.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
/* newcat: Concatenate files */
int main(int argc, char *argv[])
{
void filecopy(int ifp, int ofp); /* prototype for function */
int fd;
char *prog = argv[0]; /* program name for errors */
if (argc == 1) /* no args; copy standard input */
filecopy(0,1);
else
while (--argc > 0)
fd = open(*++argv , O_RDONLY,0);
if ( fd == -1) {
fprintf(stderr, "%s: can't open %s\n", prog, *argv);
return(-1);
} else {
filecopy(fd, 1);
close(fd);
}
return(0);
}
/* filecopy: copy file ifp to ofp */
void filecopy(int ifp, int ofp)
{
int c;
while (read(ifp,&c,ofp ) != 0)
write(ofp,&c,ofp);
}

Resources