一.引言

  本章描述文件系统的其他特征和文件的性质。有些背景知识需要注意,例如用户ID与文件权限、文件系统等。

二.函数stat、fstat、fstatat和lstat

#include <sys/stat.h>
int stat( const char * restrict pathname, struct stat * restrict buf );
int fstat( int fd, struct stat * buf );
int lstat( const char * restrict pathname,struct stat * restrict buf );
int fstatat( int fd, const char * restrict pathname, struct stat *restrict buf,int flag ); 返回值:成功,0
    出错,-1

  以上四个函数都是为了获取文件的stat结构体,稍有差别:

  • stat和fstat:stat依据文件名,fstat依据fd
  • stat和lstat:对于符号链接,stat返回该符号链接指向的文件,lstat返回符号链接本身;
  • fstatat:相对当前打开的目录(fd)的目录经。pathname为相对路径且fd=AT_FDCWD,则会计算相对于当前目录的正真路径;如果pathname是绝对路径,fd参数被忽略。 flag控制是否跟随符号链接,默认跟随,AT_SYMLINK_NOFOLLOW时,不跟随。

  stat是很重要的结构体,如下。ls -l 时会显示很多stat的内容。后面很多函数会用到这个结构体。

struct stat
{
__dev_t st_dev; /* Device. 文件系统的设备号*/
unsigned short int __pad1;
#ifndef __USE_FILE_OFFSET64
__ino_t st_ino; /* File serial number. i-node number */
#else
__ino_t __st_ino; /* 32bit file serial number. */
#endif
__mode_t st_mode; /* File mode. */
__nlink_t st_nlink; /* Link count. */
__uid_t st_uid; /* User ID of the file's owner. */
__gid_t st_gid; /* Group ID of the file's group.*/
__dev_t st_rdev; /* Device number, if device. device设备的major和minor号 */
unsigned short int __pad2;
#ifndef __USE_FILE_OFFSET64
__off_t st_size; /* Size of file, in bytes. */
#else
__off64_t st_size; /* Size of file, in bytes. */
#endif
__blksize_t st_blksize; /* Optimal block size for I/O. 操作IO时的最优block大小 */ #ifndef __USE_FILE_OFFSET64
__blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
#else
__blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
#endif
#if defined __USE_MISC || defined __USE_XOPEN2K8
/* Nanosecond resolution timestamps are stored in a format
equivalent to 'struct timespec'. This is the type used
whenever possible but the Unix namespace rules do not allow the
identifier 'timespec' to appear in the <sys/stat.h> header.
Therefore we have to handle the use of this header in strictly
standard-compliant sources special. */
struct timespec st_atim; /* Time of last access. */
struct timespec st_mtim; /* Time of last modification. */
struct timespec st_ctim; /* Time of last status change. */
# define st_atime st_atim.tv_sec /* Backward compatibility. */
# define st_mtime st_mtim.tv_sec
# define st_ctime st_ctim.tv_sec
#else
__time_t st_atime; /* Time of last access. */
unsigned long int st_atimensec; /* Nscecs of last access. */
__time_t st_mtime; /* Time of last modification. */
unsigned long int st_mtimensec; /* Nsecs of last modification. */
__time_t st_ctime; /* Time of last status change. */
unsigned long int st_ctimensec; /* Nsecs of last status change. */
#endif
#ifndef __USE_FILE_OFFSET64
unsigned long int __unused4;
unsigned long int __unused5;
#else
__ino64_t st_ino; /* File serial number. */
#endif
};

三.文件类型  stat.st_mode

1.文件类型

(1) regular file,普通文件

(2) directory file,目录文件。目录文件中包含其他文件的名字和与这些文件有关的指针,也就是后面文件系统里说的“文件名”和“i-node”。对目录有度权限的进程可以读取目录内容,只要内核才能写,只能用系统调用才能更改目录

(3) block special file, 块特殊文件,例如磁盘,待缓冲

(4) char special file,字符特殊文件,不带缓冲。 系统中的设备,要么是块设备,要么是字符设备。

(5) FIFO,进程间通讯用

(6) socket,套接字,网络通信

(7) symbolic link,符号链接,指向另一个文件

2.相关宏定义

以下宏判断文件类型, 传入的参数是

#include <sys/stat.h>
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask)) #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR)
#define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK)
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
#ifdef __S_IFIFO
# define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)
#endif
#ifdef __S_IFLNK
# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
#endif #if defined __USE_BSD && !defined __S_IFLNK
# define S_ISLNK(mode)
#endif #if (defined __USE_BSD || defined __USE_UNIX98 || defined __USE_XOPEN2K) \
&& defined __S_IFSOCK
# define S_ISSOCK(mode) __S_ISTYPE((mode), __S_IFSOCK)
#elif defined __USE_XOPEN2K
# define S_ISSOCK(mode)
#endif

进程间通信(IPC)对象,如消息队列和信号灯,也可以说明为文件,如下宏可以判断这列文件的类型。注意,传入的参数是stat结构体指针

/* These are from POSIX.1b.  If the objects are not implemented using separate
distinct file types, the macros always will evaluate to zero. Unlike the
other S_* macros the following three take a pointer to a `struct stat'
object as the argument. */
#ifdef __USE_POSIX199309
# define S_TYPEISMQ(buf) __S_TYPEISMQ(buf)    // 消息队列
# define S_TYPEISSEM(buf) __S_TYPEISSEM(buf)   // 信号量
# define S_TYPEISSHM(buf) __S_TYPEISSHM(buf) // 共享存储对象
#endif

3.例程

判断文件类型,并打印

/* lseek test */
#include <stdio.h> // printf
#include <stdlib.h> // exit
#include <unistd.h>
#include <fcntl.h>
#include <errno.h> // errno
#include <string.h> // strerror
#include <sys/stat.h> // mode,stat函数 int main(int args, char *argv[])
{
int i;
struct stat fl_stat; if( args< ){
printf("args error.\r\n");
exit();
} for( i=;i<args;i++ ){
printf("%s:",argv[i]);
if( lstat(argv[i],&fl_stat) != ){
printf("lstat error.\r\n");
exit(); } if( S_ISREG(fl_stat.st_mode) )
printf("reguler file.\r\n");
else if( S_ISDIR(fl_stat.st_mode) )
printf("directory file.\r\n");
else if( S_ISCHR(fl_stat.st_mode) )
printf("char special file.\r\n");
else if( S_ISBLK(fl_stat.st_mode) )
printf("BLOCK special file.\r\n");
else if( S_ISFIFO(fl_stat.st_mode) )
printf("FIFO file.\r\n");
else if( S_ISLNK(fl_stat.st_mode) )
printf("symble link file.\r\n");
else if( S_ISSOCK(fl_stat.st_mode) )
printf("socket file.\r\n");
else
printf("unknow file.\r\n");
} exit();
} $./example * /dev/cdrom /dev
example:reguler file.
example.c:reguler file.
example.o:reguler file.
Makefile:reguler file.
result:reguler file.
/dev/cdrom:symble link file.
/dev:directory file.

四.SUID(设置用户ID)和SGID(设置组ID) stat.st_mode

1. 进程相关的ID

    

  • 实际用户ID/实际组ID,系统登录者,登录期间一般不变;
  • 有效用户ID/组ID/附属组ID, 用于文件访问权限检查。一般情况下  实际用户ID=有效用户ID,也有特例,后面说明。
  • 保存的设置用户ID/组ID,执行一个程序时,包含有效用户ID/组ID的副本。

2. 文件所有者和组所有者

  文件有所有者和组所有者,用stat结构的st_uid/st_gid表示。

3. 执行程序文件时的ID

   程序文件——执行——>变成进程,进程就有有效用户ID。

  情况1(通常情况):有效用户ID/组ID = 实际用户ID/组ID;例如登录者是login_name, 则程序文件执行以后,该进程的有效用户ID就是login_name;

   情况2(设置SUID/SGID):SUID/SGID包含在文件的stat的st_mode字段中,如果程序文件的属性里,设置了SUID/SGID,则该程序文件执行以后,该进程的有效用户ID/组ID=该程序文件的用户ID/组ID。可用S_ISUID/S_ISGID宏测试是否设置了这两个bit。

  举例说明,以用户ID为例,组ID也类似, 为便于说明,uid使用用户名代替数字:

登录者ID = login_name
可执行文件exe_file的用户ID,uid = file_owner_name
1.如果没有设置文件exe_file的SUID属性,则文件执行后,该进程的有效用户ID = 登录者ID(实际用户ID) = login_name,
文件权限校验时用login_name校验。如果exe_file的other权限里没有x,则不能执行。
2.如果设置文件exe_file的SUID属性,则文件执行后,该进程的有效用户ID = 该文件的UID = file_owner_name,
 文件权限校验时用file_owner_name,如果exe_file的所有者权限里没有x,则不能执行 另一个典型的例子是 /etc/passed,该文件所有者是root,且设置了SUID,则其他用户执行时,有效进程ID=文件所有者ID=root,所以能够执行。

五.文件访问权限 stat.st_mode

1. 文件访问权限

【注意】chmod 777 file,其中777是八进制,在编写程序时,应使用八进制。

2. 权限与文件操作

(1)打开文件对目录的权限要求

open一个文件时,需要搜索目录,需要对目录具有执行权限。例如 /path/file,对/path必须有执行权限。

【扩展】目录读权限与执行权限不同, 读权限允许读目录,获取所有的文件列表;执行权限允许对目录进行搜索,寻找特定文件。

(2)读权限

决定是否可以打开文件进行读操作,open的O_RDONLY和O_RDWR

(3)写权限

决定是否可以打开文件进行写操作,open的O_WRONLY和O_RDWR

(4)O_TRUNC

需写权限

(5)创建新文件对目录的权限要求

创建文件时,需要写目录,在目录中增加文件名和对应的i-node,所以对目录要有写权限

(6)删除文件对目录的权限要求

只删除目录里的文件信息,对目录有写+执行权限即可。对文件权限没有要求。

(7)exec执行文件

需执行权限。

3. 文件访问权限测试

每次打开、创建、删除文件时,内核都进行文件权限测试,是否具有权限决定于文件ID/组ID和进程有效ID/组ID。

(1)root,有效用户ID=0,允许访问系统中所有文件

(2)有效用户ID=文件所有者ID,则允许操作,具体是否有RWX全下, 要看对应的权限位是否设置。

(3)有效组ID或附属组ID之一=文件组ID,允许

(4)若其他用户的适当权限位被设置,则允许访问,否则不允许。

以上4点按顺序检查,上一条不满足才检查下一条。

六.新文件和目录的所有权

open和creat新建函数时,没有指定各种ID,有默认的分配规则,linux的规则为:

(1)新文件用户ID = 进程有效用户ID

(2) 新文件组ID规则:

if( 目录的SGID )
新文件的GID=所在目录的GID
else
新文件的GID=进程的有效GID

七.函数access和faccessat

前面提到权限测试都是按照进程的有效用户ID和有效组ID进行的,这两个函数用实际用户ID进行权限测试。

#include <unistd.h>
int access( const char * pathname, int mode );
int faccessat( int fd, const char * pathname, int mode, int flag);
返回值:
成功,0
失败,-1 mode参数(可以按位或):
F_OK:测试文件是否存在
W_OK:测试写权限
R_OK:测试读权限
X_OK:测试执行权限
faccessat的fd和pathname:
pathname绝对路径,fd忽略
fd为AT_FDCWD,pathname是相对路径
其他:计算相对于打开目录fd的pathname
faccessat的flag:
可改变faccessat的行为,如果AT_EACCESS,则检查进程的有效用户ID和有效组ID,而不是实际用户ID和实际组ID。

 

八.函数umask

九.函数chmod、fchmod和fchmodat

十.粘着位

十一.函数chown、fchown、fchownat和lchown

十二.文件长度

十三.文件截断

十四.文件系统

十五.函数link、linkat、unlink、unlinkat和remove

十六.函数rename和renameat

十七.符号链接

十八.创建和读取符号链接

十九.文件的时间

二十.函数futimens、utimensat、utimes

二十一.函数mkdir、mkdirat和rmdir

二十二.读目录

二十三.函数chdir、fchdir和getcwd

二十四.特殊设备文件

二十五.文件访问权限位小结

二十六.总结

《UNIX环境高级编程》笔记——4.文件和目录的更多相关文章

  1. (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  2. UNIX环境高级编程笔记之文件I/O

    一.总结 在写之前,先唠几句,<UNIX环境高级编程>,简称APUE,这本书简直是本神书,像我这种小白,基本上每看完一章都是“哇”这种很吃惊的表情.其实大概三年前,那会大三,我就买了这本书 ...

  3. (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  4. UNIX环境高级编程笔记 目录

    每一章的重点会使用加粗字体 第一章:UNIX基础知识:UNIX体系结构:文件和目录:输入和输出:程序和进程:出错处理:信号:时间值:系统调用和库函数 第三章:文件I/O:文件描述符:文件操作函数:文件 ...

  5. UNIX环境高级编程笔记之高级I/O

    本章说明了很多高级I/O功能: 非阻塞I/O——发一个I/O操作,不使其阻塞,记录锁,STREAMS机制 I/O多路转接——select和poll函数 readv和writev函数,以及存储映射I/O ...

  6. UNIX环境高级编程笔记之标准I/O库

    一.总结 文件I/O一章讲了不带缓冲的I/O,本章讲的是带缓冲的I/O.不带缓冲针对的是内核的系统调用,而带缓冲针对的是用户空间的标准库函数,是基于带缓冲的I/O实现的.不带缓冲的I/O通过文件描述符 ...

  7. UNIX环境高级编程笔记之线程

    本章涉及到线程的一些基本知识点,讨论了现有的创建线程和销毁线程的POSIX.1原语,此外,重点介绍了线程同步问题,讨论了三种基本的同步机制:互斥量.读写锁.条件变量.

  8. UNIX环境高级编程笔记之进程控制

    本章重点介绍了进程控制的几个函数:fork.exec族._exit.wait和waitpid等,主要需要掌握的是父进程和子进程之间的运行机制,怎么处理进程的正常和异常终止.以及怎么让进程执行不同的程序 ...

  9. UNIX环境高级编程笔记之进程环境

    本章讲的都是一些非常基础的知识,目的是为了下一章讲进程控制做铺垫,所以,本章就不做过多的总结了,直接看图吧.

  10. (四) 一起学 Unix 环境高级编程(APUE) 之 系统数据文件和信息

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

随机推荐

  1. 关于 js中的arguments 对象

    arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推.这个对象只有在函数体内部,才可以使用. var f = fu ...

  2. JAVA 7新特性——在单个catch代码块中捕获多个异常,以及用升级版的类型检查重新抛出异常

    在Java 7中,catch代码块得到了升级,用以在单个catch块中处理多个异常.如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度.下面用一个例子来理解. Java 7之前 ...

  3. struts2与struts1的比较

    struts2相对于struts1来说简单了很多,并且功能强大了很多,我们可以从几个方面来看: 从体系结构来看:struts2大量使用拦截器来出来请求,从而允许与业务逻辑控制器 与 servlet-a ...

  4. java数据结构----带权图

    1.带权图:要引入带权图,首先要引入最小生成树,当所有的边拥有相同的权值时.问题变得简单了,算法可以选择任意一条边加入最小生成树.但是当边有不同的权值时,需要用一些算法决策来选择正确的边. 2.带权图 ...

  5. Virtual Judge使用指南

    https://cn.vjudge.net/ Virtual Judge并不是常规的Online Judge平台,他通过爬取其他OJ的题目,让我们可以直接在VJ上查找并提交各种OJ的题目,然后将我们的 ...

  6. [POI2011]Plot

    https://szkopul.edu.pl/problemset/problem/mzrTn1kzVBOAwVYn55LUeAai/site/?key=statement 既卡常又卡精度...真的A ...

  7. Promise.then(a, b)与Promise.then(a).catch(b)问题详解

    原文: When is .then(success, fail) considered an antipattern for promises? 问题 我在bluebrid promise FAQ上面 ...

  8. oracle tps

    http://blog.csdn.net/nilxin/article/details/5812480 sample 1: 定义 TPS:Transactions Per Second(每秒传输的事物 ...

  9. (转载)Unity 优化总结

    Unity 优化总结 2017-03-10 | 发布 大海明月  zengfeng75@qq.com  | 分类 Unity  | 标签 Unity  优化 相关文档 UGUI 降低填充率技巧两则 U ...

  10. 表单辅助函数-form_open()

    使用from_open()之前需要装载本辅助函数: $this->load->helper('form'); php===> echo form_open('email/send') ...