转自:http://blog.csdn.net/cinmyheart/article/details/21740279
Files and directories
整个第四章都是围绕着三个stat函数展开的
- #include <sys/stat.h>
- int stat(const charchar *restrict pathname, struct stat *restrict buf);
- int fstat(int filedes, struct stat *buf);
- int lstat(const charchar *restrict pathname, struct stat *restrict buf);
对于给定的pathname,stat函数将返回关于文件的stat结构体的信息
而fstat函数和lstat有点不一样。
首先是参数:
fstat的结构体指针是struct stat * buf 而lstat的是struct stat * restrict buf
You see it。 restrict 这个关键字是C99新增加的。
In the C programming language, as of the C99 standard, restrict
is a keyword that can be used in pointer declarations. The restrict
keyword is a declaration of intent given by the programmer to the compiler. It says that for the lifetime of the pointer, only it or a value directly derived from it (such as pointer
) will be used to access the object to which it points. This limits the effects of pointer aliasing, aiding optimizations.
+ 1
--wikipedia
restrict是C99新增的关键字,作用于指针,几乎是用于编译器的优化作用,其实我觉得没什么大的作用吧。。。C已经很快了
In the above code, the pointers ptrA
, ptrB
, and val
might refer to the same memory location, so the compiler may generate less optimal code :
load R1 ← *val ; Load the value of val pointer
load R2 ← *ptrA ; Load the value of ptrA pointer
add R2 += R1 ; Perform Addition
set R2 → *ptrA ; Update the value of ptrA pointer
; Similarly for ptrB, note that val is loaded twice,
; because ptrA may be equal to val.
load R1 ← *val
load R2 ← *ptrB
add R2 += R1
set R2 → *ptrB
However if the restrict
keyword is used and the above function is declared as :
<span class="kw4" style="color: rgb(153, 51, 51);">void</span> updatePtrs<span class="br0" style="color: rgb(0, 153, 0);">(</span><span class="kw4" style="color: rgb(153, 51, 51);">size_t</span> <span class="sy0" style="color: rgb(51, 153, 51);">*</span>restrict ptrA<span class="sy0" style="color: rgb(51, 153, 51);">,</span> <span class="kw4" style="color: rgb(153, 51, 51);">size_t</span> <span class="sy0" style="color: rgb(51, 153, 51);">*</span>restrict ptrB<span class="sy0" style="color: rgb(51, 153, 51);">,</span> <span class="kw4" style="color: rgb(153, 51, 51);">size_t</span> <span class="sy0" style="color: rgb(51, 153, 51);">*</span>restrict val<span class="br0" style="color: rgb(0, 153, 0);">)</span><span class="sy0" style="color: rgb(51, 153, 51);">;</span>
then the compiler is allowed to assume that ptrA
, ptrB
, and val
point to different locations and updating one pointer will not affect the other pointers. The programmer, not the compiler, is responsible for ensuring that the pointers do not point to identical locations.
Now the compiler can generate better code as follows:
load R1 ← *val这样防止reload有点多此一举。C很快了。。。
load R2 ← *ptrA
add R2 += R1
set R2 → *ptrA
; Note that val is not reloaded,
; because the compiler knows it is unchanged
load R2 ← *ptrB
add R2 += R1
set R2 → *ptrB
fstat的第一个参数是file descriptor而lstat的参数是一个指向路径的const指针
此外,fstat和lstat的不同之初还在于,fstat函数获得关于filedes的信息,而如果pathname指向一个symbol link,那么就返回关于这个symbol link的信息,而不是symbol link指向的文件。
fstat test code:
- #include "apue.h"
- #include "sys/stat.h"
- #include "fcntl.h"
- #include "stdio.h"
- int main()
- {
- struct stat buf;
- int file_descriptor = 0;
- if((file_descriptor = open("./test.txt",O_RDWR)) < 0)
- {
- printf("open error\n");
- }
- if(fstat(file_descriptor,&buf) < 0)
- {
- printf("fstat error\n");
- }
- printf("The file mode is : %ld\n",buf.st_mode);
- printf("The i-node number is : %ld\n",buf.st_ino);
- printf("The device number is : %ld\n",buf.st_dev);
- printf("The device number for special files is : %d\n",buf.st_rdev);
- printf("The number of links is : %ld\n",buf.st_nlink);
- printf("The user ID of owner is : %ld\n",buf.st_uid);
- printf("The group ID of owner is : %ld\n",buf.st_gid);
- printf("The size in bytes for regular files is : %ld\n",buf.st_size);
- printf("The best I/O size is : %ld\n",buf.st_blksize);
- printf("The number of disk blocks allocated is : %ld\n",buf.st_blocks);
- return 0;
- }
lstat test code:
- /*********************************************************************
- code writer : EOF
- code date : 2014.03.21
- The lstat function is similar to stat, but when the named file
- is a symbolic link, lstat returns information about the symbolic
- link, not the file referenced by symbolic link.
- ***********************************************************************/
- #include "apue.h"
- #include "sys/stat.h"
- #include "fcntl.h"
- #include "stdio.h"
- int main()
- {
- struct stat buf;
- if(lstat("./test.txt",&buf) < 0)
- {
- printf("lstat error\n");
- }
- printf("The file mode is : %d\n",buf.st_mode);
- printf("The i-node number is : %ld\n",buf.st_ino);
- printf("The device number is : %ld\n",buf.st_dev);
- printf("The device number for special files is : %ld\n",buf.st_rdev);
- printf("The number of links is : %ld\n",buf.st_nlink);
- printf("The user ID of owner is : %d\n",buf.st_uid);
- printf("The group ID of owner is : %d\n",buf.st_gid);
- printf("The size in bytes for regular files is : %ld\n",buf.st_size);
- printf("The best I/O size is : %ld\n",buf.st_blksize);
- printf("The number of disk blocks allocated is : %ld\n",buf.st_blocks);
- return 0;
- }
stat test code:
- /*******************************************************************************
- code writer:liuzijian
- date : 2014.01.01
- e-mail: jasonleaster@gmail.com
- just test what is in the structure -- stat
- There would be some warnings during the code is complied,but it doesn't matter.
- Just ran the program that you complied is OK!
- ********************************************************************************/
- #include<apue.h>
- #include<stdio.h>
- int main(int argc,char* argv[])
- {
- struct stat buf;
- printf("please enter two parameter!\n");
- if(argc != 2)
- {
- printf("parameter is wrong!\nplease enter two parameter!\n");
- return 0;
- }
- else
- {
- if(lstat(argv[1],&buf) < 0 )
- {
- printf("lstat is wrong!\n");
- }
- else
- {
- printf("The file mode is : %ld\n",buf.st_mode);
- printf("The i-node number is : %ld\n",buf.st_ino);
- printf("The device number is : %ld\n",buf.st_dev);
- printf("The device number for special files is : %d\n",buf.st_rdev);
- printf("The number of links is : %ld\n",buf.st_nlink);
- printf("The user ID of owner is : %ld\n",buf.st_uid);
- printf("The group ID of owner is : %ld\n",buf.st_gid);
- printf("The size in bytes for regular files is : %ld\n",buf.st_size);
- printf("The best I/O size is : %ld\n",buf.st_blksize);
- printf("The number of disk blocks allocated is : %ld\n",buf.st_blocks);
- }
- }
- return 0;
- }
文件类型:
1.regular file 普通文件。对于Unix来说,没有所谓的data 或者file的区别。
2.Directory file 文件夹。嗯。文件夹也是个文件,这个特殊的文件包含了其他文件的信息。
3.Block special file 块文件。用于缓冲I/O的设备文件。
4.Character special file 字符文件。用于非缓冲I/O的设备文件
5.FIFO. 队列。用于进程间的通信
6.Socket. 用于网络进程通信的文件类型。
7.Symbolic link。链接。=_= A type of file that points to another file.
stat 结构体里面储存了很多关于文件的信息。
- struct stat {
- mode_t st_mode; /* file type & mode (permissions) */
- ino_t st_ino; /* i-node number (serial number) */
- dev_t st_dev; /* device number (file system) */
- dev_t st_rdev; /* device number for special files */
- nlink_t st_nlink; /* number of links */
- uid_t st_uid; /* user ID of owner */
- gid_t st_gid; /* group ID of owner */
- off_t st_size; /* size in bytes, for regular files */
- time_t st_atime; /* time of last access */
- time_t st_mtime; /* time of last modification */
- time_t st_ctime; /* time of last file status change */
- blksize_t st_blksize; /* best I/O block size */
- blkcnt_t st_blocks; /* number of disk blocks allocated */
- };
其中st_mode 这个变量可以用文件类型宏来确认文件类型。
Macro Type of file
S_ISREG() regular file
S_ISDIR() directory file
S_ISCHR() character special file
S_ISBLK() block special file
S_ISFIFO() pipe or FIFO
S_ISLNK() symbolic link
S_ISSOCK() socket
test code:
- #include"apue.h"
- #include"myerr.h"
- #include"stdio.h"
- int main(int argc,char* argv[])
- {
- int i =0;
- struct stat buf;
- charchar * ptr = NULL;
- for(i = 1;i < argc;i++)
- {
- printf("%s ",argv[i]);
- if(lstat(argv[i],&buf) < 0 )
- {
- err_ret("lstat error");
- continue;
- }
- if(S_ISREG(buf.st_mode))
- {
- ptr = "regular";
- }
- else if(S_ISDIR(buf.st_mode))
- {
- ptr = "directory";
- }
- else if(S_ISCHR(buf.st_mode))
- {
- ptr = "character special";
- }
- else if(S_ISBLK(buf.st_mode))
- {
- ptr = "block special";
- }
- else if(S_ISFIFO(buf.st_mode))
- {
- ptr = "fifo";
- }
- else if(S_ISLNK(buf.st_mode))
- {
- ptr = "symbolic link";
- }
- else if(S_ISSOCK(buf.st_mode))
- {
- ptr = "socket";
- }
- else
- {
- ptr = "** unknown mode **";
- }
- printf("%s\n",ptr);
- }
- return 0;
- }
./test.txt regular
类Unix里面大多是regular file,其次是directory,其余的百分比不足2.68。。。。
include <sys/stat.h>
这个stat.h 文件我找了半天都没找到。。。用 whereis 命令也没用
其实在这里
/usr/include/x86_64-linux-gnu/sys/stat.h
文件access权限
st_mode mask Meaning
S_IRUSR user-read
S_IWUSR user-write
S_IXUSR user-execute
S_IRGRP group-read
S_IWGRP group-write
S_IXGRP group-execute
S_IROTH other-read
S_IWOTH other-write
S_IXOTH other-execute
Note that read permission for a directory and execute permission for a directory
mean different things. Read permission lets us read the directory,obtaining a list of
all the filenames in the directory .Execute permission lets us pass through the
directory when it is a component of a pathname that we aretrying to access. (We
need to search the directory to look for a specific filename.)
特别要注意到,对于文件夹的权限问题。文件夹的可读和可执行完全是两码事。
对某个文件夹具有可执行的权限(x),表示可以进入这个这个这个文件夹
而对某个文件夹具有可读的权限,表示可以读取这个文件夹里所有文件的名字
•The read permission for a file determines whether we can open an existing file for
re ading: the O_RDONLY and O_RDWR flags for theopen function.
•The write permission for a file determines whether we can open an existing file for
writing: theO_WRONLY and O_RDWR flags for theopen function.
•We must have write permission for a file to specify the O_TRUNC flag in the open
function.// 打开O_TRUNC这个家伙如果原先文件里面有文件内容会被擦出。。。
•We cannot create a new file in a directory unless we have write permission and
execute permission in the directory.
•To delete an existing file, we need write permission and execute permission in the
directory containing the file. We do not need read permission or write permission
for the file itself.
•Execute permission for a file must be on if we want to execute the file using any of
the seven exec functions. The file also has to be a regular file.
access function:
- <span style="font-size:14px;"> #include <unistd.h>
- int access(const charchar * pathname ,int mode);
- int faccessat(int fd ,const charchar *pathname ,int mode,int flag); //这个是第三版的APUE加上去的。。。</span>
Both return: 0 if OK, −1 on error
mode Description
R_OK test for read permission
W_OK test for write permission
X_OK test for execute permission
- #include<apue.h>
- #include<fcntl.h>
- #include<myerr.h>
- int main(int argc ,char* argv[])
- {
- int file_descriptor = 0;
- if(argc != 2)
- {
- err_quit("usage : a.out <pathname>");
- }
- if(access(argv[1],R_OK) < 0)
- {
- err_ret("access error for %s",argv[1]);
- }
- else
- {
- printf("read access OK\n");
- }
- if(file_descriptor = open(argv[1],O_RDONLY) < 0)
- {
- err_ret("open error for %s",argv[1]);
- }
- else
- {
- printf("open for reading OK\n");
- }
- close(file_descriptor);
- return 0;
- }
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./c.out ./test.txt
read access OK
open for reading OK
之初创建Ad_Pro_in_Unix这个文件夹的时候就用的root权限,所以之后也一直没改,写的时候就用的root了,坏习惯,大家表和我一样。。。等APUE完了俺再也不轻易用root了。。。TT。保持良好的习惯
umask function:
- #include <sys/stat.h>
- mode_t umask(mode_t cmask );
Returns: previous file mode creation mask
返回值就这些种:
文件access权限,这里st_mode 是mode_t 类型的变量
st_mode mask Meaning
S_IRUSR user-read
S_IWUSR user-write
S_IXUSR user-execute
S_IRGRP group-read
S_IWGRP group-write
S_IXGRP group-execute
S_IROTH other-read
S_IWOTH other-write
S_IXOTH other-execute
- #include"apue.h"
- #include"stdio.h"
- #include"myerr.h"
- #include"fcntl.h"
- #define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
- int main()
- {
- umask(0);
- if(creat("foo",RWRWRW) < 0)
- {
- err_sys("creat error for foo");
- }
- umask(~(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
- if(creat("bar",RWRWRW) < 0)
- {
- err_sys("creat error for bar");
- }
- exit(0);
- }
If we want to ensure that anyone can read a file, we should set the umask to 0.
Otherwise, the umask value that is in effect when our process is
running can cause permission bits to be turned off.
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# umask
0022
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./a.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./bar ./foo
----rw-rw- 1 root root 0 3月 23 01:07 ./bar
-rw-rw-rw- 1 root root 0 3月 23 01:07 ./foo
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# umask
0022
This shows us that changing the file mode creation mask of a process doesn’t affect the mask of its
parent (often a shell).
bash 下面有个chmod 命令
NAME
chmod - change file mode bits
SYNOPSIS
chmod [OPTION]... MODE[,MODE]... FILE...
chmod [OPTION]... OCTAL-MODE FILE...
chmod [OPTION]... --reference=RFILE FILE...
DESCRIPTION
This manual page documents the GNU version of chmod. chmod changes the file mode bits of each given file according to mode, which can be either a symbolic representation of changes to make, or an octal number representing the bit pattern for the new mode bits.
类似的,有
chmod and fchmod function:
The chmod, fchmod,and fchmodat functions allow us to change the file access permissions for anexisting file.
- #include <sys/stat.h>
- int chmod(const charchar *pathname,mode_tmode);
- int fchmod(int fd ,mode_tmode);
- int fchmodat(int fd ,const char*pathname ,mode_tmode,int flag);//第三版加上去的...
- <span style="white-space:pre"> </span>All three return: 0 if OK, −1 onerror<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
mode Description
S_ISUID set-user-ID onexecution
S_ISGID set-group-ID onexecution
S_ISVTX saved-text(sticky bit)
S_IRWXU read, write, and execute byuser (owner)
S_IRUSR read by user (owner)
S_IWUSR write by user (owner)
S_IXUSR execute by user (owner)
S_IRWXG read, write, and execute bygroup
S_IRGRP read by group
S_IWGRP write by group
S_IXGRP execute by group
S_IRWXO read, write, and execute byother (world)
S_IROTH read by other (world)
S_IWOTH write by other (world)
S_IXOTH execute by other (world)
- #include "apue.h"
- #include "myerr.h"
- int main()
- {
- struct stat statbuf;
- if(stat("foo",&statbuf))
- {
- err_sys("stat error forfoo\n");
- }
- if(chmod("foo",(statbuf.st_mode & ~S_IXGRP | S_ISGID))< 0)
- {
- err_sys("chmod error forfoo");
- }
- if(chmod("bar",S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH) < 0)
- {
- err_sys("chmod error forbar");
- }
- return 0;
- }
test:
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./bar ./foo
----rw-rw- 1 root root 0 3月 23 01:07 ./bar
-rw-rw-rw- 1 root root 0 3月 23 01:07 ./foo
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./b.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./bar ./foo
-rw-r--r-- 1 root root 0 3月 23 01:07 ./bar
-rw-rwSrw- 1 root root 0 3月 23 01:07 ./foo
Note that the ls command lists the group-execute permissionas S to signify that the set-group-ID bit is set without the group-executebit being set.
原来木有S的,现在有S了哇。。。(⊙0⊙)
To prevent malicious users from setting the sticky bit and adversely affecting system performance,
only the superuser can set the sticky bit of a regular file.
If the process does not have superuser privileges, then theset-group-ID bit is automatically turned
off. This prevents a user from creating a set-group-ID file owned by agroup that the user doesn’t belong to
Sticky bit:sticky 位(以前的老技术,现在可以不用鸟,有virtual memory)
If it was set for an executable program file, then the first time the program was executed, a copy of the
program’s text was saved in the swap area when the process terminated. (The text portion of a program is the machine instructions.) The program would then load into memory more quickly the next time it was executed, because the swap area was handled as a contiguous file, as compared to the possibly random location of data blocks in a normal UNIX file system. The sticky bit was often set for common application programs, such as the text editor and the passes of the C compiler.
如果一个可执行程序文件的这个位被“激活”,当这个程序第一次执行的时候,当程序结束时,程序的文本副本就会被拷贝到swap里面去。当程序再次被执行的时候,程序就能更快的被载入内存,因为swap是用来把被处理对象当作连续文件来处理的。sticky bit常常被类似于文本编辑器和C编译器之类的程序使用。
With today’s newer UNIX systems, most of which have a virtual memory system and a faster file system, the need for this technique has disappeared.
chown functions:
- #include <unistd.h>
- int chown(const charchar *pathname,uid_t owner ,gid_t group);
- int fchown(int fd ,uid_t owner,gid_t group);
- int fchownat(int fd ,const char*pathname ,uid_t owner ,gid_t group,int flag);
- int lchown(const charchar * pathname,uid_t owner ,gid_t group);
- All four return: 0 if OK,−1 on error
These four functions operate similarly unless the referenced file is a symbolic link. In that case,lchown and fchownat (with the AT_SYMLINK_NOFOLLOW flag set) change the owners of the symbolic link itself, not the file pointedto by the symbolic link.
书上没有demo,我自己写的时候发现一个问题,fchown的 owner是用户ID。。。我去where调用个函数,找到我想要的用户ID额。。。。God ..=_=| 待解决。。要找到所有存在用户的ID并返回自己想设置的用户的ID。。。
File size:文件规格
For a regular file, a file size of 0 is allowed. We’ll get anend-of-file indication on the first read of the file.
For a directory ,t he file size is usually a multiple of a number, such as 16 or 512. (为什么是16 或者 512以后会讲)
For a symbolic link, the file size is the number of bytes in the filename.
For example, in the following case, the file size of 7 is thelength of the pathname usr/lib:
lrwxrwxrwx 1root 7 Sep 25 07:14 lib -> usr/lib
(Note that symbolic links do not contain the normal C null byte at the end ofthe name,
as the length is always specified by st_size.
File truncation:文件截断
Emptying a file, which we can do with the O_TRUNC flag to open, is a special case of truncation.
- #include <unistd.h>
- int truncate(const charchar *pathname,off_t length );
- int ftruncate(int fd ,off_t length);
- Bothreturn: 0 if OK, −1 on error
test code:
- #include "apue.h"
- #include "fcntl.h"
- #include "stdio.h"
- #include "unistd.h"
- #define BUFFSIZE 1024
- int main()
- {
- int file_descriptor = 0;
- char buffer[BUFFSIZE];
- if((file_descriptor =open("./test.txt",O_RDWR)) < 0)
- {
- printf("openerror\n");
- }
- memset(buffer,0,BUFFSIZE*sizeof(char));
- printf("beforetruncation\n");
- while(read(file_descriptor,buffer,BUFFSIZE-1) > 0)
- {
- if(write(STDIN_FILENO,buffer,BUFFSIZE-1) <=0)
- {
- printf("writeerror\n");
- }
- }
- ftruncate(file_descriptor,sizeof(char)*40);
- lseek(file_descriptor,0,SEEK_SET);
- memset(buffer,0,BUFFSIZE*sizeof(char));
- printf("after truncation\n");
- while(read(file_descriptor,buffer,BUFFSIZE-1) > 0)
- {
- if(write(STDIN_FILENO,buffer,BUFFSIZE-1) <=0)
- {
- printf("writeerror\n");
- }
- }
- close(file_descriptor);
- return 0;
- }
test.txt 里面是10行hello world。。。。
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./e.out
before truncation
1: hello world!
2: hello world!
3: hello world!
4: hello world!
5: hello world!
6: hello world!
7: hello world!
8: hello world!
9: hello world!
10:hello world!
after truncation
1: hello world!
2: hello world!
unlink function:
- #include <unistd.h>
- int unlink(const charchar * pathname );
- int unlinkat(int fd ,const charchar *pathname ,int flag);
- <span style="white-space:pre"> </span>Both return: 0 if OK, −1 on error
These functions remove the directory entry and decrement the link count of the file
re ferenced by pathname .Ifthereare o ther links to the file, the data in the file is still
accessible through the other links. The file is not changed if an error occurs.
test code:
- #include "apue.h"
- #include "stdio.h"
- #include <fcntl.h>
- #include "myerr.h"
- int main()
- {
- if(open("./test.txt",O_RDWR)< 0)
- {
- err_sys("openerror");
- }
- if(unlink("./test.txt") <0)
- {
- err_sys("unlinkerror");
- }
- printf("file unlinked");
- sleep(15);
- printf("done\n");
- return 0;
- }
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./test.txt
-rw-rw-r-- 1 liuzjian liuzjian 40 3月 23 02:19 ./test.txt
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# df ./
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 19478204 5621980 12860128 31% /
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./b.out &
[1] 6646
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./test.txt
ls: cannot access ./test.txt: No such file or directory
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# df ./
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 19478204 5621956 12860152 31% /
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# file unlinkeddone
df ./
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 19478204 5621952 12860156 31% /
[1]+ Done ./b.out
rename and renameat Functions:
A file or a directory is renamed with either the rename or renameat function.
- <span style="font-size:14px;">#include <stdio.h>
- int rename(const charchar * oldname,const charchar *newname );
- int renameat(int oldfd,const charchar *oldname,int newfd,const charchar *newname );
- <span style="white-space:pre"> </span>Both return: 0 if OK, −1 on error</span>
test code:
- #include "apue.h"
- #include "stdio.h"
- #include "unistd.h"
- int main()
- {
- if(rename("./test.txt","./hehe.txt") < 0)
- {
- printf("rename error\n");
- }
- return 0;
- }
Symbolic Links:
A symbolic link is an indirect pointer to a file, unlike the hard links described in the previous section, which pointed directly to the i-node of the file.Creating and Reading Symbolic Links
A symbolic link is created with either the symlink or symlinkat function.
- <span style="font-size:14px;">#include <unistd.h>
- int symlink(const charchar *actualpath,const charchar *sympath );
- int symlinkat(const charchar *actualpath,int fd ,const charchar *sympath );
- <span style="white-space:pre"> </span>Both return: 0 if OK, −1 on error</span>
test code:
- <span style="font-size:14px;">#include "apue.h"
- #include "stdio.h"
- #include "unistd.h"
- int main()
- {
- if(symlink("./test.txt","./symbolink_to_test") < 0)
- {
- printf("symlink error\n");
- }
- return 0;
- }</span><span style="font-size: 18px;">
- </span>
test result:
lrwxrwxrwx 1 root root 10 3月 23 11:34 symbolink_to_test -> ./test.txtA new directory entry, sympath , is created that points to actualpath.
It is not required that actualpath exist when the symbolic link is created. (We saw this in the example at
the end of the previous section.) Also, actualpath and sympath need not reside in the same file system.
The symlinkat function is similar to symlink,but the sympath argument is evaluated relative to the directory referenced by the open file descriptor for that directory (specified by the fd argument). If the sympath argument specifies an absolute pathname or if the fd argument has the special value AT_FDCWD ,then symlinkat
behaves the same way assymlink.
Because the open function follows a symbolic link, we need a way to open the link itself and read the name in the link. The readlink and readlinkat functions do this.
- #include <unistd.h>
- ssize_t readlink(const char* restrict pathname ,charchar *restrict buf,size_t bufsize );
- ssize_t readlinkat(int fd ,const char* restrict pathname ,charchar *restrict buf,size_tbufsize );
- Both return: number of bytes read if OK, −1 on error
*********************************
File time:文件时间(都在stat结构体里面的信息,用fstat函数读取即可)
Field Description Example ls(1) option
st_atim last-access time of file data read -u
st_mtim last-modification time of file data write default
st_ctim last-change time of i-node status chmod, chown -c
- <span style="font-size:14px;">#include "apue.h"
- #include "fcntl.h"
- #include "myerr.h"
- #include "unistd.h"
- #include "sys/times.h"
- #include "utime.h"
- int main(int argc,char* argv[])
- {
- int i,fd;
- struct stat statbuf;
- struct utimbuf timebuf;
- for(i = 1;i<argc ;i++)
- {
- if(stat(argv[i],&statbuf) < 0)
- {
- err_ret("%s stat error",argv[i]);
- continue;
- }
- if((fd = open(argv[i],O_RDWR |O_TRUNC)) < 0)
- {
- err_ret("%s open error");
- continue;
- }
- close(fd);
- timebuf.actime = statbuf.st_atime;
- timebuf.modtime = statbuf.st_mtime;
- if(utime(argv[i],&timebuf) < 0)
- {
- err_ret("%s : utime error",argv[i]);
- continue;
- }
- }
- return 0;
- }</span><span style="font-size: 18px;">
- </span>
下面是linux里面的stat定义:
- <span style="font-size:14px;">struct stat {
- unsigned long st_dev; /* Device. */
- unsigned long st_ino; /* File serial number. */
- unsigned int st_mode; /* File mode. */
- unsigned int st_nlink; /* Link count. */
- unsigned int st_uid; /* User ID of the file's owner. */
- unsigned int st_gid; /* Group ID of the file's group. */
- unsigned long st_rdev; /* Device number, if device. */
- unsigned long __pad1;
- long st_size; /* Size of file, in bytes. */
- int st_blksize; /* Optimal block size for I/O. */
- int __pad2;
- long st_blocks; /* Number 512-byte blocks allocated. */
- long st_atime; /* Time of last access. */
- unsigned long st_atime_nsec;
- long st_mtime; /* Time of last modification. */
- unsigned long st_mtime_nsec;
- long st_ctime; /* Time of last status change. */
- unsigned long st_ctime_nsec;
- unsigned int __unused4;
- unsigned int __unused5;
- };</span>
mkdir and rmdir function:
Directories are created with the mkdir and mkdirat functions, and deleted with the rmdir function.
- <span style="font-size:14px;">#include <sys/stat.h>
- int mkdir(const charchar *pathname ,mode_tmode);
- int mkdirat(intfd ,const charchar *pathname ,mode_tmode);
- <span style="white-space:pre"> </span>Both return: 0 if OK, −1 on error</span>
These functions create a new,empty directory.The entries for dot and dot-dot are created automatically .
The specified file access permissions,mode,are modified by the file mode creation mask of the process.
test code:
- #include "apue.h"
- #include "stdio.h"
- int main()
- {
- if(mkdir("./a_dir_made_from_mkdir",S_IRUSR|S_IWUSR|S_IXUSR) < 0)
- {
- printf("mkdir error\n");
- }
- return 0;
- }
a_dir_made_from_mkdir c.out fstat_test.c lstat_test.c pro_4_16.c pro_4_3.c rename_test.c truncation_test.c
a.out exercise_4_6.c hehe mkdir_test.c pro_4_21.c pro_4_8.c show_stat.c xixi
b.out file_permission.c link_test.c pro_4_12.c pro_4_22.c pro_4_9.c test.txt
这个时候可以看出,文件夹下面多出了一个a_dir_made_from_mkdir 的文件夹
A common mistake is to specify the same mode as for a file: read and write permissions only.
But for a directory, we normally want at least one of the execute bits enabled, to allow access to filenames within the
directory.
注意给文件夹权限的时候记得不仅仅要给RW还要给可执行(x)的权限
Reading directories: 读取文件信息
- <span style="font-size:14px;">#include <dirent.h>
- DIR *opendir(const charchar *pathname );
- DIR *fdopendir(int fd );
- <span style="white-space:pre"> </span>Both return: pointer if OK, NULL on error</span>
- struct dirent *readdir(DIR * dp);
- <span style="white-space:pre"> </span>eturns: pointer if OK,NULL at end of directory or error
- <span style="font-size:14px;">void rewinddir(DIR *dp);
- int closedir(DIR * dp);
- <span style="white-space:pre"> </span>Returns: 0 if OK,−1 on error</span>
- long telldir(DIR * dp);
- Returns: current location in directory associated with dp
- void seekdir(DIR * dp,long loc);
demo 来了。。。。:
- #include"apue.h"
- #include"dirent.h"
- #include"limits.h"
- #include"myerr.h"
- #include "/Ad_Pro_in_Unix/chapter_2/path_alloc.c"
- typedef int Myfunc(const char* ,const struct stat *,int);
- static Myfunc myfunc;
- static int myftw(char*,Myfunc *);
- static int dopath(Myfunc *);
- static long nreg ,ndir ,nblk,nchr,nfifo,nslink,nsock,ntot;
- int main(int argc,char* argv[])
- {
- int ret;
- if(argc != 2)
- {
- err_quit("usage: ftw <starting-pathname>");
- }
- ret = myftw(argv[1],myfunc);
- ntot = nreg+ndir+nblk+nchr+nfifo+nslink+nsock;
- if(ntot == 0)
- {
- ntot = 1;
- }
- printf("regular files = %7ld, %5.2f %%\n",nreg,nreg*100.0/ntot);
- printf("directories = %7ld, %5.2f %%\n",ndir,ndir*100.0/ntot);
- printf("block special = %7ld, %5.2f %%\n",nblk,nblk*100.0/ntot);
- printf("cha special = %7ld, %5.2f %%\n",nchr,nchr*100.0/ntot);
- printf("FIFOs = %7ld, %5.2f %%\n",nfifo,nfifo*100.0/ntot);
- printf("symbolic links = %7ld, %5.2f %%\n",nslink,nslink*100.0/ntot);
- printf("sockets = %7ld, %5.2f %%\n",nsock,nsock*100.0/ntot);
- exit(ret);
- }
- #define FTW_F 1
- #define FTW_D 2
- #define FTW_DNR 3
- #define FTW_NS 4
- static charchar *fullpath;
- static size_t pathlen;
- static int myftw(charchar *pathname,Myfunc* func)
- {
- fullpath = path_alloc(&pathlen);
- if(pathlen <= strlen(pathname))
- {
- pathlen = strlen(pathname)*2;
- if((fullpath = realloc(fullpath,pathlen)) == NULL)
- {
- err_sys("realloc failed");
- }
- }
- strcpy(fullpath,pathname);
- return(dopath(func));
- }
- static int dopath(Myfunc* func)
- {
- struct stat statbuf;
- struct dirent *dirp;
- DIR *dp;
- charchar *ptr;
- int ret,n;
- if(lstat(fullpath,&statbuf) < 0)
- {
- return (func(fullpath,&statbuf,FTW_NS));
- }
- if(S_ISDIR(statbuf.st_mode) == 0)
- {
- return (func(fullpath,&statbuf,FTW_NS));
- }
- if(S_ISDIR(statbuf.st_mode) == 0)
- {
- return (func(fullpath,&statbuf,FTW_F));
- }
- if((ret = func(fullpath,&statbuf,FTW_D)) != 0)
- {
- return (ret);
- }
- n = strlen(fullpath);
- if(n + NAME_MAX +2 >pathlen)
- {
- pathlen*=2;
- if((fullpath = realloc(fullpath,pathlen)) == NULL)
- {
- err_sys("realloc failed");
- }
- }
- fullpath[n++] = '/';
- fullpath[n] = 0;
- if((dp = opendir(fullpath)) == NULL)
- {
- return(func(fullpath,&statbuf,FTW_DNR));
- }
- while((dirp = readdir(dp)) != NULL)
- {
- if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0)
- {
- continue;
- }
- strcpy(&fullpath[n],dirp->d_name);
- if((ret = dopath(func)) != 0)
- {
- break;
- }
- }
- fullpath[n-1] = 0;
- if(closedir(dp) < 0)
- {
- err_ret("can't close directory %s",fullpath);
- }
- return (ret);
- }
- static int myfunc(const char* pathname,const struct stat* statptr,int type)
- {
- switch(type)
- {
- case FTW_F:
- {
- switch(statptr->st_mode & S_IFMT)
- {
- case S_IFREG: nreg++; break;
- case S_IFBLK: nblk++; break;
- case S_IFCHR: nchr++; break;
- case S_IFIFO: nfifo++; break;
- case S_IFLNK: nslink++; break;
- case S_IFSOCK: nsock++; break;
- case S_IFDIR: err_dump("for S_IFDIR for %s",pathname);
- }
- };
- break;
- case FTW_D:
- ndir++;
- break;
- case FTW_DNR:
- err_ret("can't read directory %s",pathname);
- break;
- case FTW_NS:
- err_ret("stat error for %s",pathname);
- break;
- default :
- err_dump("unknown type %d for pathname %s",type,pathname);
- }
- return 0;
- }
chdir fchdir function:
We can change the current working directory of the calling process by calling the chdir or fchdir function.- #include <unistd.h>
- int chdir(const charchar *pathname );
- int fchdir(int fd );
- <span style="white-space:pre"> </span>Both return: 0 if OK, −1 on error
demo:
- #include "apue.h"
- #include "unistd.h"
- #include "myerr.h"
- int main()
- {
- if(chdir("/tmp") < 0)
- {
- err_sys("chdir failed\n");
- }
- printf("chdir to /tmp succeeded\n");
- return 0;
- }
执行完程序,发现当前目录没有改变,还是程序运行前的目录。事情是这个样子的:
The current working directory for the shell that executed the my cd program didn’t change. This is a side effect of the way that the shell executes programs. Each program is run in a separate process, so the current working directory of the shell is unaffected by the call to chdir in the program. For this reason, the chdir function has to be called directly from the shell, so the cd command is built into the shells.
打印当前工作目录:
- #include <unistd.h>
- charchar *getcwd(charchar *buf,size_tsize );
- <span style="white-space:pre"> </span>Returns: buf if OK, NULL on error
We must pass to this function the address of a buffer, buf,and its size (in bytes).
- #include "apue.h"
- #include "stdio.h"
- #include "myerr.h"
- #include "/Ad_Pro_in_Unix/chapter_2/path_alloc.c"
- int main()
- {
- charchar *ptr;
- int size;
- if(chdir("/usr/") < 0)
- {
- err_sys("chdir failed\n");
- }
- ptr = path_alloc(&size);
- if(getcwd(ptr,size) == NULL)
- {
- err_sys("getcwd failed\n");
- }
- printf("pwd = %s\n",ptr);
- return 0;
- }
Device special file:设备文件
The major number identifies the device driver and sometimes encodes which peripheral board to communicate with; the minor number identifies the specific subdevice.
Each file system on the same disk drive would usually have the same major number ,but a different minor number.
• The st_dev value for every filename on a system is the device number of the file system containing that filename and its corresponding i-node.
• Only character special files and block special files have an st_rdev value. This value contains the device number for the actual device.
- <span style="font-size:14px;">#include "apue.h"
- #include "stdio.h"
- #include "myerr.h"
- #define _BSD_SOURCE
- #include "sys/sysmacros.h"
- #include "/usr/include/x86_64-linux-gnu/sys/types.h"
- #ifdef SOLARIS
- #include <sys/mkdev.h>
- #endif
- int main(int argc,char* argv[])
- {
- int i;
- struct stat buf;
- for(i = 0;i < argc;i++)
- {
- printf("%s\n",argv[i]);
- if(stat(argv[i],&buf) < 0)
- {
- err_ret("stat error\n");
- continue ;
- }
- printf("dev = %d/%d",major(buf.st_dev),minor(buf.st_dev));
- if(S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode))
- {
- printf("(%s) rdev = %d/%d",(S_ISCHR(buf.st_mode)) ? "character":"block",major(buf.st_rdev),minor(buf.st_rdev));
- }
- printf("\n");
- }
- return 0;
- }</span><span style="font-size:18px;">
- </span>
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# vim ./pro_4_25.c
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# gcc ./pro_4_25.c -o ./d.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./d.out /dev/tty
./d.out
dev = 8/1
/dev/tty
dev = 0/5(character) rdev = 5/0
TT。。。。。。。。。。终于summary了。。。。。。第四章太尼玛长了。。。吐槽一下。。。
当然第二次看,总结了还是很舒服。。。
Summary of File Access Permission Bits