Ignus Ignus - 5 months ago 9
Linux Question

system call "open" cannot create file with O_CREAT flag

I've got to complete an exercise using linux's system calls:


  1. open the file "testinput.txt" (already present in the working directory, not empty)

  2. open the file "testoutput.txt" (not present in the working directory)

  3. copy the content of testinput in testoutput

  4. close both files



I found that I can open the file with system call
open
can both open the input file (flag
O_RDONLY
) and the output file (flag
O_CREAT | O_WRONLY
).

The input file works correctly. The output file doesn't.

Errno says code 2 = "No such file or direcory" (obviously, I asked to create the file). What am I doing wrong?

P.S.: To highlight I'm using syscalls, I'm not calling function
open(...)
but
syscall(SYS_OPEN, ...)


outFileDesc = syscall(SYS_OPEN, "testoutput.txt", O_WRONLY | O_TRUNC | O_CREAT, 438);
if(outFileDesc == -1) {
int code = errno;

// gdb used here -> print code -> 2

char str[] = "Unable to open \"testoutput.txt\"\n";
syscall(SYS_WRITE, FILE_DESC_STDOUT, str, sizeof(str)/sizeof(char));
syscall(SYS_CLOSE, inFileDesc);
syscall(SYS_EXIT, 1);
return 1;
}


Whole code:

#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>

/* file flags fcntl.h */
#define O_RDONLY 0x0000 /* open for reading only */
#define O_WRONLY 0x0001 /* open for writing only */
#define O_CREAT 0x0200 /* create if nonexistant */
#define O_TRUNC 0x0400 /* truncate to zero length */

#define FILE_DESC_STDOUT 1

#define SYS_EXIT 1
#define SYS_READ 3
#define SYS_WRITE 4
#define SYS_OPEN 5
#define SYS_CLOSE 6

#define IN_MESSAGE_LEN 9
#define OUT_MESSAGE_LEN 9

char inBuffer[IN_MESSAGE_LEN];
char outBuffer[OUT_MESSAGE_LEN];

int main (int argc, char *argv[])
{
int inFileDesc, outFileDesc;

// Apertura fine di input
inFileDesc = syscall(SYS_OPEN, "testinput.txt", O_RDONLY, 438);
if(inFileDesc == -1) {
char str[] = "Unable to open \"testinput.txt\"\n";
syscall(SYS_WRITE, FILE_DESC_STDOUT, str, sizeof(str)/sizeof(char));
syscall(SYS_EXIT, 1);
return 1;
}

// Apertura fine di output
outFileDesc = syscall(SYS_OPEN, "testoutput.txt", O_WRONLY | O_TRUNC | O_CREAT, 438);
if(outFileDesc == -1) {
int code = errno;

char str[] = "Unable to open \"testoutput.txt\"\n";
syscall(SYS_WRITE, FILE_DESC_STDOUT, str, sizeof(str)/sizeof(char));
syscall(SYS_CLOSE, inFileDesc);
syscall(SYS_EXIT, 1);
return 1;
}

// Travaso contenuto file di input in file di output
int read, i;
while((read = syscall(SYS_READ, inFileDesc, inBuffer, IN_MESSAGE_LEN)) != 0) {

for(i = 0; i < IN_MESSAGE_LEN; i++) {
outBuffer[i] = inBuffer[i];
}

syscall(SYS_WRITE, outFileDesc, outBuffer, OUT_MESSAGE_LEN);
}

syscall(SYS_CLOSE, inFileDesc);
syscall(SYS_CLOSE, outFileDesc);

syscall(SYS_EXIT, 0);
return 0;
}


Screenshot of the execution

Answer

I ran your code under strace and got:

...
open("testinput.txt", O_RDONLY)         = 3
open("testoutput.txt", O_WRONLY|O_TRUNC|O_APPEND) = -1 ENOENT (No such file or directory)
//                                      ^^^^^^^^

I.e. your definition of the O_* flags is wrong.

As it turns out, there's more than one thing wrong: 0x0200 is actually O_TRUNC (not O_CREAT), and 0x0400 is actually O_APPEND (not O_TRUNC).

Changing it to

#define O_CREAT 0x0040
#define O_TRUNC 0x0200

makes it work.

Comments