Sunday, August 17, 2014

Unix Prog: File Sharing(3)

1. fcntl -- F_GETFL, F_SETFL
F_GETFL and F_SETFL commands can be used to get and set the file status flags.
fileio.c:
It get the file status flags and do the bit operation with O_ACCMODE and other flags to get the real flag name.
 #include<unistd.h>  
 #include<fcntl.h>  
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<errno.h>  
   
 int main(int argc, char *argv[])  
 {  
  int val;  
   
  // Convert the first argument to int, which is the file descriptor  
  if((val = fcntl(atoi(argv[1]), F_GETFL)) < 0) {  
   printf("fcntl error!\n");  
   exit(1);  
  }  
   
  // Map val with O_ACCMODE, to check what is the mode  
  switch(val & O_ACCMODE) {  
  case O_RDONLY:  
   printf("read only!\n");  
   break;  
  case O_WRONLY:  
   printf("write only!\n");  
   break;  
  case O_RDWR:  
   printf("read write!\n");  
   break;  
  default:  
   printf("unknown mode!\n");  
   break;  
  }  
   
  // Map with O_APPEND, O_NONBLOCK, O_SYNC and O_FSYNCx  
   
  if(val & O_APPEND)  
   printf(" append!\n");  
  if(val & O_NONBLOCK)  
   printf(" nonblock!\n");  
  if(val & O_SYNC)  
   printf(" synchronos writes!\n");  
  if(val & O_FSYNC)  
   printf(" file synchronos writes!\n");  
   
  exit(0);  
 }  

shell:
1) Open the file /dev/tty as the standard input, and program detect it as read only
2) Open the file /dev/tty as the standard output, and program detect it as write only
3) Open the file test.txt as the standard error, and also specify ">>" to indicate that program will append to the file. So finally it is write only and append
4) Open the file test.txt as the file descriptor 5, and also specify "<>" to indicate that program can read or write to the file. So finally it is read write
 ubuntu@ip-172-31-23-227:~$ ./io.out 0 </dev/tty  
 read only!  
 ubuntu@ip-172-31-23-227:~$ ./io.out 1 >/dev/tty  
 write only!  
 ubuntu@ip-172-31-23-227:~$ ./io.out 2 2>>test.txt  
 write only!  
  append!  
 ubuntu@ip-172-31-23-227:~$ ./io.out 5 5<>test.txt  
 read write!  

bit operation explanation:
O_ACCMODE is defined as 3, binary format: 11.
O_RDONLY: 0, O_WRONLY: 1, O_RDWR: 2(binary format: 10)
So using O_ACCMODE to "&" with flag, will turn off all other bits but only leaving one of above 3 bits.

Similar for O_APPEND, O_SYNC, O_NONBLOCK, only one bit is 1, all others are 0. By "& with" the flag, it will test if the bit is on.
 ubuntu@ip-172-31-23-227:~$ sudo find /usr/include -name *.h | xargs grep O_ACCMODE  
 /usr/include/asm-generic/fcntl.h:#define O_ACCMODE   00000003  
 /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h:#define O_ACCMODE     0003  

2. Change the file status flag
fileio.c:
Retrieve the file status flag and then turn on another bit: O_SYNC.
 #include<unistd.h>  
 #include<fcntl.h>  
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<errno.h>  
   
 int main(int argc, char *argv[])  
 {  
  int val;  
  int flag = O_SYNC;  
   
  // Convert the first argument to int, which is the file descriptor  
  // Get the flag of specified file descriptor  
  if((val = fcntl(atoi(argv[1]), F_GETFL)) < 0) {  
   printf("fcntl error!\n");  
   exit(1);  
  }  
   
  // Turn on the O_SYNC bit on existing flag  
  val |= flag;  
   
  // Set up the flag on specified file descriptor  
  if((val = fcntl(atoi(argv[1]), F_SETFL, flag)) < 0) {  
   printf("fcntl error!\n");  
   exit(2);  
  }  
   
  exit(0);  
 }  

O_SYNC and system calls: fsync, fdatasync, sync are very similar. But for some system, it doesn't respect the O_SYNC flag, but only those system calls.

No comments:

Post a Comment