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
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.
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.
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.
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.
How this is interpreted by the compiler
Not differently than any other bitwise OR operation. Consider the following #define
s 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 */
}
...
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 (&&
).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With