Unix环境高级编程学习笔记(二)

第四章 文件和目录

本章将描述文件系统特征和文件性质
1、stat、fstat和lstat函数
原型:#include<sys/stat.h>
int stat(const char* restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char* restrict pathname, struct stat *restrict buf);          若成功返回0,出错返回-1
注:lstat与stat的不同,当命名文件是一个符号链接时,lstat返回符号链接的有关信息,而stat返回引用文件的信息。
struct stat{
mode_t st_mode;
ino_t st_ino;
dev_t st_dev;
dev_t st_rdev;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
blksize_t st_blksize;
blkcnt_t st_blocks;
};

2、文件类型:包括普通文件、目录文件、块特殊文件、字符特殊文件、FIFO、套接字、符号链接。     文件类型信息包括在stat结构的st_mode字段,可用以下宏检测文件类型:
S_ISREG():普通文件;S_ISDIR():目录文件;S_ISCHR():字符特殊文件;S_ISBLK():块特殊文件;S_ISFIFO():管道或FIFO;S_ISLNK():符号链接;S_ISSOCK():套接字。 注:头文件:<sys/stat.h> 参数是st_mode
 由于POSIX.1允许实现将进程间通信对象(如消息队列和信号量等)表示为文件,所以有一些对应宏用于测是:S_TYPEISMQ():消息队列;S_TYPEISSEM():信号量;S_TYPEISSHM():共享存储对象。注:Linux没有把他们实现为文件,所以没啥用。

3、设置用户Id和组ID
与进程相关的id:实际用户id、实际组id(我们实际上是谁)、有效用户id、有效组id、附加组id(用于文件访问权限检查)、保存的设置用户id、保存的设置组id(由exec函数保存),通常:有效用户id等于实际用户id,有效组id等于实际组id。
每个文件都有所有者(st_uid)和组所有者(st_gid)。可以在st_mode中设置一个特殊标志,使“当执行这个文件时,将进程的有效用户id设置为所有者id”,这叫做设置用户id,同理有设置组id。例如:passwd程序就使用了设置用户id。。。可用S_ISUID和S_ISGID宏测试设置用户id和设置组id。

4、文件访问权限
9个访问权限位:S_IRUSR:用户读;S_IWUER:用户写;S_IXUSR:用户执行;   S_IRGRP:组读;S_IWGRP:组写;S_IXGRP:组执行;     S_IROTH:其他读   S_IWOTH:其他写   S_IXOTH:其他执行。(注:关于文件访问权限的意义,在之前的博客已写过,在此不再赘述。)

5、新文件和目录的所有权:新文件的用户id设置为进程的有效用户id,组id设置为:(1)进程的有效组id;(2)所在目录的组id。

6、access函数:按实际用户id和实际组id进行访问权限测试。用于验证实际用户能否访问1个文件。
原型:#include<unistd.h>   int access(const char* pathname, int mode);   mode:R_OK(测试读权限),W_OK(测试写权限),X_OK(测试执行权限),F_OK(测试文件是否存在)   注:这些标志可以进行或运算,来自头文件<unistd.h>

7、umask函数:为进程设置文件模式创建屏蔽字,并返回以前的值,无出错函数。
原型:#include<sys/stat.h>     mode_t umask(mode_t cmask) 返回以前的文件模式创建屏蔽字,其中参数cmask是S_IRUSR等9个常量之一或按位或的结果。
说明:任何在文件模式创建屏蔽字中为1的位,在文件mode中的对应位一定被关闭。

8、chmod和fchmod函数:更改现有文件的访问权限
原型:#include<sys/stat.h>
int chmod(const char* pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);        成功返回0,失败返回-1
mode可以使用的参数:1、上文的9个文件访问常量   2、S_IRWXU、S_IRWXG、S_IRWXO、S_ISUID(设置用户id)、S_ISGID(设置组id)、S_ISVTX(保存正位(粘住位))

9、粘住位:如果对一个目录设置了粘住位,则要更名和或删除该目录下的文件必须满足以下条件之一:拥有此文件;拥有此目录;是超级用户。   一般来说,/temp目录就设置了粘住位。

10、chown、fchown和lchown函数:可用于更改文件的用户id或组id
原型:#include <unistd.h>
int chown(const char* pathname, uid_t owner, gid_t group);
int fchown(int filedes, uid_t owner, gid_t group);
int lchown(const char* pathname, uid_t owner, gid_t group);         成功返回0,失败返回-1    lchown:当是符号链接时,lchown改变符号链接本身的所有者,而不是该符号链接指向的文件。
若owner或 group参数的值为-1,则对应的值不变。

11、文件长度:stat结构成员st_size表示以字节为单位的文件长度。此字段只对普通文件、目录文件和符号链接有意义。     stat的st_blksize字段:文件IO较合适的块长度  st_blocks:实际512字节数量。
  du   -s   core : 报告该文件的st_blocks值       wc  -c core:用于统计文件中的字节数     (这一段讲述了关于文件空洞问题)

12、文件截短:
原型:#include<unistd.h>     int truncate(const char* pathname, off_t length);
     int ftruncate(int filedes, off_t length);    成功返回0,失败返回-1
将现有的文件长度截短为length长度,若length长于原来长度,则会产生空洞。

13、文件系统:i节点记录了文件的大部分信息:链接计数(stat的st_nlink成员)、文件类型、文件访问权限等等。只有两项信息放在目录项中:文件名和i节点编号。
两个目录想指向同一个i节点叫做硬链接(nlink_t)、符号链接(S_IFLNK)

14、link、unlink、remove和rename函数
创建一个指向现有文件的链接的方法是使用link函数:#include<unistd.h>     int link(const char* existingpath, const char* newpath);   成功返回0,失败返回-1
此函数创建一个新目录项newpath,它引用现有的文件exitingpath(若已存在则报错)。   硬链接
为了删除一个目录项,可以调用unlink函数:#include<unistd.h>    int unlink(const char* pathname);         成功返回0,失败返回-1
如果pathname是符号链接,unlink删除符号链接,不会删除引用文件。
我们可以用remove函数解除对一个文件或目录的链接:#include<stdio.h>      int remove(const char* pathname);   (对文件remove等价于unlink,对目录remove等价于rmdir,这个函数是ISO C指定的)
文件或目录用rename函数更名:#include<stdio.h>    int rename(const char* oldname, const char* newname);        成功返回0,失败返回-1

15、符号链接:    硬链接的不足:1)链接和文件必须位于同一文件系统中;2)只有超级用户才能创建指向目录的硬链接     当使用以名字引用文件的函数时,应当了解该函数是否处理符号链接。

16、symlink和readlink函数:
symlink函数创建一个符号链接:#include<unistd.h>     int symlink(const char* actualpath, const char* sympath);   创建指向actualpath的新目录项sympath,并不要求actualpath已经存在。
因为open函数跟随符号链接,所以要有一种方法打开该链接本身:#include<unistd.h>     ssize_t readlink(const char* restrict pathname, char* restrict buf, size_t bufsize);

17、文件时间:st_atime:文件数据最后访问时间;  st_mtime:文件数据最后修改时间;     st_ctime:i节点状态最后更改时间。

18、utime函数:更改一个文件的访问和修改时间。
原型:#include<utime>     int utime(const char* pathname, const struct utimbuf *times);
struct utimbuf{
    time_t actime;
    time_t modtime;
}   times是NULL则设置当前时间。

19、mkdir和rmdir函数:创建目录和删除目录
原型:#include<sys/stat.h> int mkdir(const char* pathname, mode_t mode);
     #include<unistd.h>   int rmdir(const char* pathname);   用于删除一个空目录。

20、读目录:
#include<dirent.h>
DIR *opendir(const char* pathname);    返回值:若成功返回指针,若出错返回null
struct dirent *readdir(DIR* dp);       返回值:若成功返回指针,若出错返回null
void rewinddir(DIR* dp);        
int closedir(DIR* dp);                 返回值:若成功返回0,若出错返回-1
long telldir(DIR *dp);         返回值:与dp关联的目录中的当前位置
void seekdir(DIR* dp, long loc);
struct dirent{
    ino_t d_ino;
    char d_name[NAME_MAX + 1];     
DIR结构是内部结构,上述6个函数用这个内部结构保存当前正被读的目录的有关信息。
}
注意:程序清单4-7用到了函数path_alloc(),但是程序中没定义,编译无法通过。我的解决方法是自己定义一个path_alloc(),简单方便。
char*path_alloc(int* size)
{
char *p = NULL;
if(!size) return NULL;
p = malloc(256);
if(p)
*size = 256;
else
*size = 0;
return p;
}                 程序清单4-7用到了opendir,readdir,closedir。

21、chdir、fchdir和getcwd函数
进程通过调用chdir和fchdir函数可以更改当前工作目录:#include<unistd.h>      int chdir(const char* pathname);       int fchdir(int filedes);   这两个函数分别用pathname或打开的文件描述符来指定新的当前工作目录。         注意:当前工作目录是进程的一个属性,所以chdir函数不会影响别的进程。
#include<unistd.h>     char*  getcwd(char* buf, size_t size);                  得到完整路径名。

22、设备特殊文件:(1)、系统中与每个文件名关联的st_dev值是文件系统的设备号,只有字符特殊文件和块特殊文件才有st_rdev值。 

posted @ 2011-07-30 13:54  name_110  阅读(700)  评论(0编辑  收藏  举报