Sunday, August 24, 2014

Unix Prog: Files -- Linking(3)

1. Symbolic Links

Hard link disadvantage:
1) Need the link and file pointed reside in the same file system
2) Only super user is allowed to create the hard link pointing to the directory

Symbolic Link is pointing to the separate i-node, who points to the data block which only contains the path name of destination file.

For many system calls, we need to if it follows symbolic links.

fileio.c:
stat system call will follow the symbolic link.
lstat system call will not follow the symbolic link.
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<sys/stat.h>  
   
 int main(int argc, char* argv[])  
 {  
  struct stat buff;  
  if(stat(argv[1], &buff) < 0) {  
   printf("stat error!\n");  
   exit(1);  
  }  
   
  printf("file size: %d\n", (int)buff.st_size);  
   
  if(lstat(argv[1], &buff) < 0) {  
   printf("lstat error!\n");  
   exit(2);  
  }  
   
  printf("file size: %d\n", (int)buff.st_size);  
   
  exit(0);  
 }  

shell:
1) Given regular file, both stat and lstat give the file size information of itself
2) Make one symbolic link pointing to fileio.c
3) Given one symbolic link, stat system call will follow the link to give the file size of fileio.c. But lstat system call will only give the file size of link itself.
 ubuntu@ip-172-31-23-227:~$ ./io.out fileio.c  
 file size: 406  
 file size: 406  
 ubuntu@ip-172-31-23-227:~$ ln -s fileio.c slink  
 ubuntu@ip-172-31-23-227:~$ ./io.out slink  
 file size: 406  
 file size: 8  

2. Symbolic Link Loop
We may introduce loops into the file system by creating the symbolic links.
1) Create directory foo
2) Create the symbolic link flink under foo which points to the parent directory
3) Enter foo directory
4) List all files
5) do the "find" with -L option, but it tells us that it detects one infinite loop. If following this link to do the search, it will be endless
./
./flink
./flink/flink
./flink/flink/flink
......
 ubuntu@ip-172-31-23-227:~$ mkdir foo  
 ubuntu@ip-172-31-23-227:~$ ln -s ../foo foo/flink  
 ubuntu@ip-172-31-23-227:~$ cd foo  
 ubuntu@ip-172-31-23-227:~/foo$ ls -lrt  
 total 0  
 lrwxrwxrwx 1 ubuntu ubuntu 6 Aug 24 13:53 flink -> ../foo  
 ubuntu@ip-172-31-23-227:~/foo$ find -L  
 .  
 find: File system loop detected; `./flink' is part of the same file system loop as `.'.  

3. Symbolic Link to non-existing file
symbolic link can point to non-existing file.
But when doing the "read" on such symbolic link, it will follow the link to output the file content of file pointed to.
In following case, it tells us that the file doesn't exist.
 ubuntu@ip-172-31-23-227:~$ ln -s no-such-file flink  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 0  
 lrwxrwxrwx 1 ubuntu ubuntu 12 Aug 24 13:56 flink -> no-such-file  
 ubuntu@ip-172-31-23-227:~$ cat flink  
 cat: flink: No such file or directory  

4. symlink and readlink
symlink system call is used to create the symbolic link.
readlink system call is used to read the symbolic link itself's content. Note: readlink doesn't get any information of the i-node, like file size, permission etc., it is the job of "lstat". Instead, readlink is just the combination of system calls "open", "read" and "close". It open the link file itself, and read the content of link file, which is the path string of destination file.

definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/unistd.h  
 ......  
 /* Make a symbolic link to FROM named TO. */  
 extern int symlink (const char *__from, const char *__to)  
    __THROW __nonnull ((1, 2)) __wur;  
   
 /* Read the contents of the symbolic link PATH into no more than  
   LEN bytes of BUF. The contents are not null-terminated.  
   Returns the number of characters read, or -1 for errors. */  
 extern ssize_t readlink (const char *__restrict __path,  
              char *__restrict __buf, size_t __len)  
    __THROW __nonnull ((1, 2)) __wur;  
 ......  

fileio.c:
It creates the symbolic link "flink", pointing to "no-such-file". This case tells us that symbolic link doesn't need to point to existing file.
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  if(symlink("no-such-file", "flink") < 0) {  
   printf("symlink error!\n");  
   exit(1);  
  }  
   
  char buff[12];  
  if(readlink("flink", buff, 12) < 0) {  
   printf("readlink error!\n");  
   exit(2);  
  }  
   
  printf("link content read: %s\n", buff);  
   
  exit(0);  
 }  

shell:
1) Run the program, it creates the flink, and output the link content from "readlink", which is just path name string.
2) Run the program again, failed. since flink is already existed, we can't create the symbolic link which is already existed.
3) List all files, including the symbolic link.
 ubuntu@ip-172-31-23-227:~$ ./io.out  
 link content read: no-such-file  
 ubuntu@ip-172-31-23-227:~$ ./io.out  
 symlink error!  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu 308 Aug 24 14:07 fileio.c~  
 -rw-rw-r-- 1 ubuntu ubuntu 352 Aug 24 14:07 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9889 Aug 24 14:07 io.out  
 lrwxrwxrwx 1 ubuntu ubuntu  12 Aug 24 14:08 flink -> no-such-file  

No comments:

Post a Comment