Saturday, August 23, 2014

Unix Prog: Files -- Linking(2)

1. unlink open file
When user unlink a file which is still opened by some process, the i-node entry maybe removed but the data block's content will not be removed until closing the file.

When the kernel close the file, it will check the link count of the i-node, if reaching to 0, it will remove the data block's file content.

delay_ul.c:
After unlinking the given file, we use sleep command to pause for 15 seconds, during this period, the file content in data block should still be there, after the process is terminated, kernel will close open files, while checking the i-node link count and determine whether to remove the data block.
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<fcntl.h>  
   
 int main(int argc, char* argv[])  
 {  
  if(open(argv[1], O_RDWR) < 0) {  
   printf("open error!\n");  
   exit(1);  
  }  
   
  if(unlink(argv[1]) < 0) {  
   printf("unlink error!\n");  
   exit(2);  
  }  
   
  printf("file unlinked\n");  
  sleep(15);  
  printf("done\n");  
  exit(0);  
 }  

shell:
1) List temp file, which occupies about 13Mb space.
2) Use df command to list disk usage information at local directory. It indicates that we still have 6369392 units of blocks
3) Run the program against temp file, it will firstly unlink the temp(output file unlinked, and then starts to sleep)
4) At this time, we run "df .", the available disk space is still 6369392 units of blocks
5) After 15 seconds, the process get terminated, the kernel remove the file content.
6) We run "df ." command again, the available disk space increase to 6382744 units of blocks.
 ubuntu@ip-172-31-23-227:~$ ls -lrt temp  
 -rwx------ 1 ubuntu ubuntu 13631488 Aug 23 20:47 temp  
 ubuntu@ip-172-31-23-227:~$ df .  
 Filesystem   1K-blocks  Used Available Use% Mounted on  
 /dev/xvda1    8115168 1310500  6369392 18% /  
 ubuntu@ip-172-31-23-227:~$ ./delay_ul.out ./temp &  
 [1] 13436  
 ubuntu@ip-172-31-23-227:~$ file unlinked  
   
 ubuntu@ip-172-31-23-227:~$ df .  
 Filesystem   1K-blocks  Used Available Use% Mounted on  
 /dev/xvda1    8115168 1310500  6369392 18% /  
 ubuntu@ip-172-31-23-227:~$ done  
   
 [1]+ Done          ./delay_ul.out ./temp  
 ubuntu@ip-172-31-23-227:~$ df .  
 Filesystem   1K-blocks  Used Available Use% Mounted on  
 /dev/xvda1    8115168 1297148  6382744 17% /  

2. remove
remove system call can be used to remove the regular files and directories.
For regular files, it is identical to "unlink"
For directories, it is identical to "rmdir"

definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/stdio.h  
 ......  
 /* Remove file FILENAME. */  
 extern int remove (const char *__filename) __THROW;  
 ......  

fileio.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  if(remove(argv[1]) < 0) {  
   printf("remove error!\n");  
   exit(1);  
  }  
   
  exit(0);  
 }  

shell:
1) List all files
2) run the program against regular file tf1
3) run the program against directory td1
4) list all files, both files are already gone.

 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 24  
 -rw-rw-r-- 1 ubuntu ubuntu  96 Aug 23 21:26 fileio.c~  
 -rw-rw-r-- 1 ubuntu ubuntu 182 Aug 23 21:27 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:27 io.out  
 -rw-rw-r-- 1 ubuntu ubuntu  0 Aug 23 21:27 tf1  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:27 td1  
 ubuntu@ip-172-31-23-227:~$ ./io.out tf1  
 ubuntu@ip-172-31-23-227:~$ ./io.out td1  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu  96 Aug 23 21:26 fileio.c~  
 -rw-rw-r-- 1 ubuntu ubuntu 182 Aug 23 21:27 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:27 io.out  

3. rename
A file or one directory can be renamed by "rename" system call.
Actually it is trying to delete(unlink) new name entry(if it already exists), and then add the entry containing new name while also pointing to original file's i-node. Lastly remove the oldname's entry(reduce its i-node link count).

definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/stdio.h  
 ......  
 /* Rename file OLD to NEW. */  
 extern int rename (const char *__old, const char *__new) __THROW;  
 __END_NAMESPACE_STD  
 ......  

fileio.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
   
 int main(int argc, char* argv[])  
 {  
  if(rename(argv[1], argv[2]) < 0) {  
   printf("rename error!\n");  
   exit(1);  
  }  
   
  exit(0);  
 }  

shell:
1) List all files
2) Rename the directory from testd to testd1, which will point to the original testd's i-node
3) List all files
4) Rename the regular file tf1 to tf2, which will point to the original tf1's i-node
5) List all files
6) Rename the regular file tf2 to /testd1/tf2, which will add the new directory entry at testd1 which will point to the same i-node, original directory entry tf2 is removed.
7) List all files

In summary: rename doesn't touch the real file content in data block, it just change the directory entry pointing to the same i-node
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu 191 Aug 23 21:38 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:38 io.out  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:38 testd  
 -rw-rw-r-- 1 ubuntu ubuntu  0 Aug 23 21:39 tf1  
 ubuntu@ip-172-31-23-227:~$ ./io.out testd testd1  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu 191 Aug 23 21:38 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:38 io.out  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:38 testd1  
 -rw-rw-r-- 1 ubuntu ubuntu  0 Aug 23 21:39 tf1  
 ubuntu@ip-172-31-23-227:~$ ./io.out tf1 tf2  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu 191 Aug 23 21:38 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:38 io.out  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:38 testd1  
 -rw-rw-r-- 1 ubuntu ubuntu  0 Aug 23 21:39 tf2  
 ubuntu@ip-172-31-23-227:~$ ./io.out tf2 ./testd1/tf2  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu 191 Aug 23 21:38 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:38 io.out  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:39 testd1  
 ubuntu@ip-172-31-23-227:~$ ls -lrt ./testd1  
 total 0  
 -rw-rw-r-- 1 ubuntu ubuntu 0 Aug 23 21:39 tf2  

shell:(rename to existing file)
1 - 3) List all files, we have one directory testd1 containing one file tf2, another empty directory testd2
4) Rename the testd1 to testd2, it will remove existing testd2 directory entry, and rename testd1 to testd2, pointing to the same i-node
5 - 6) List all files
7) Rename fileio.c to testd2, failed. Since it need to remove the directory entry testd2, which is not empty. This case indicates that if new entry is one directory, that directory needs to be empty.
8) Rename testd2 to testd2/testd2, which is wrong. Rename needs that new name can't include old name as prefix.
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 24  
 -rw-rw-r-- 1 ubuntu ubuntu 191 Aug 23 21:38 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:38 io.out  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:39 testd1  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 24 13:00 testd2  
 ubuntu@ip-172-31-23-227:~$ ls testd1  
 tf2  
 ubuntu@ip-172-31-23-227:~$ ls testd2  
 ubuntu@ip-172-31-23-227:~$ ./io.out testd1 testd2  
 ubuntu@ip-172-31-23-227:~$ ls -lrt  
 total 20  
 -rw-rw-r-- 1 ubuntu ubuntu 191 Aug 23 21:38 fileio.c  
 -rwxrwxr-x 1 ubuntu ubuntu 9718 Aug 23 21:38 io.out  
 drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 23 21:39 testd2  
 ubuntu@ip-172-31-23-227:~$ ls testd2  
 tf2  
 ubuntu@ip-172-31-23-227:~$ ./io.out fileio.c testd2
 rename error!
 ubuntu@ip-172-31-23-227:~$ ./io.out testd2 ./testd2/testd2
 rename error!

Note: Since rename need to remove directory entry(new name and old name), and may need to create new directory entry(at new name place). So it needs process have the write and execute permission of both parent directory.

No comments:

Post a Comment