Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bitwise OR in linux open flags

Tags:

c

linux

In the linux open system call, what is the meaning of bitwise OR in flags. How this is interpreted by the compiler. Here's an example:

fd = open("myfile", O_RDONLY | O_CREAT | O_TRUNC, S_IRUSR);

Also, what does comma operator do in flags?

Update: What is the effect of using other operators like if we do && operator

like image 216
Ashish Rawat Avatar asked Feb 25 '14 08:02

Ashish Rawat


People also ask

What does open () return in C?

The normal return value from open is a non-negative integer file descriptor. In the case of an error, a value of -1 is returned instead. In addition to the usual file name errors (see File Name Errors), the following errno error conditions are defined for this function: EACCES.

What is O_nonblock?

O_NONBLOCK is a property of the open file description, not of the file descriptor, nor of the underlying file. Yes, you could have separate file descriptors open for the same file, one of which is blocking and the other of which is non-blocking.

What does the open () return on success?

On success, open(), openat(), and creat() return the new file descriptor (a nonnegative integer). On error, -1 is returned and errno is set to indicate the error.

What is O_rdwr?

Open for writing only. O_RDWR. Open for reading and writing. The result is undefined if this flag is applied to a FIFO. Any combination of the following may be used: O_APPEND.


3 Answers

How this is interpreted by the compiler

Not differently than any other bitwise OR operation. Consider the following #defines as found for example in /usr/include/asm-generic/fcntl.h (note that values are in octal):

#define O_RDONLY        00000000
#define O_CREAT         00000100
#define O_TRUNC         00001000

Then, in your example, the value passed to the function is 00000000 | 00000100 | 00001000 which is 00001100. By evaluating the various bit positions, open() can reconstruct which of the flags had been set by the caller:

if (oflag & O_CREAT) {
   /* caller wants the file to be created */
}

if (oflag & O_TRUNC) {
   /* caller wants the file to be truncated */
}
...
like image 90
Andreas Fester Avatar answered Oct 04 '22 04:10

Andreas Fester


This is the prototype of the function:

int open(const char *pathname, int flags, mode_t mode);

This is the way you are calling it:

fd = open("myfile", O_RDONLY | O_CREAT | O_TRUNC, S_IRUSR);

So you are passing the following arguments:

  • pathname = "myfile"
  • flags = O_RDONLY | O_CREAT | O_TRUNC
  • mode = S_IRUSR (user has read permission)

The argument flags must include exactly one of the following access modes: O_RDONLY or O_WRONLY or O_RDWR. These requests will open the file read-only or write-only or read/write, respectively.

When combined with O_CREAT, if the file does not exist then it will be created.

When combined with O_TRUNC, if the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) then it will be truncated to length 0.

Please note that the (undefined) effect of O_RDONLY | O_TRUNC varies among implementations. On many systems the file is actually truncated.

Update:

These flags are typically meant to be used only with the bit-wise OR operator (|).

If you want to use all possible flags except for a few, then you can use the bit-wise FLIP operator (~). For example: ~(O_RDONLY | O_CREAT | O_TRUNC)... but don't try this one in specific at home...

It is pretty pointless to use any other bit-wise operator in this case, and it is most certainly pointless to use any other non-bit-wise operator, such as logical AND (&&).

like image 32
barak manos Avatar answered Oct 04 '22 05:10

barak manos


The bitwise OR is applying a logical OR to the specified values. The flags are defined as a bitmask or individual bits, and with the OR operation you can set the specified bits in the target, without changing other bits.

A: 1 1 0 0
B: 1 0 1 0
-----------
 = 1 1 1 0

So what happens in this call is that all the flags that you specified are set in the resulting value and passed to the function

#define _O_RDONLY       0    <- Bit 0
#define _O_WRONLY       1    <- Bit 0
#define _O_RDWR         2    <- Bit 1

#define _O_CREAT    0x0100  /* Create the file if it does not exist. */
#define _O_TRUNC    0x0200  /* Truncate the file if it does exist. */

O_RDONLY | O_CREAT | O_TRUNC = 0x0000 + 0x0100 + 0x0200 = 0x0300

0000 0000 0000 0000 O_RDONLY
0000 0001 0000 0000 O_CREAT
0000 0010 0000 0000 O_TRUNC
---------------------------
0000 0011 0000 0000 = 0x0300

So the compiler passes 0x0300 to the open call.

As to your second question:

The open call is defined as int open(const char *pathname, int flags, mode_t mode);

So the comma is simply separating the individual arguments and is not part of the flags. Just like in any other function call.

like image 33
Devolus Avatar answered Oct 04 '22 06:10

Devolus