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