文件和目录

start fstart lstart函数

一旦给出pathname, start函数就返回了与此命名文件有关的信息结构

  1. #include <sys/start>
  2. int stat(const char *pathname, struct stat *buf);
  3. int fstat(int fd, struct stat *buf);
  4. int lstat(const char *pathname, struct stat *buf);/*能观察到符号链接*/

参数:

pathname:文件路径

fd:文件描述符

buf:存放每天与此命名文件有关信息结构的地址

返回值:

成功返回0 失败返回1

  1. struct stat {
  2. mode_t st_mode; // 文件类型和访问权限
  3. ino_t st_ino; // 指向数据块的i节点的编号
  4. dev_t st_dev; // 设备号
  5. dev_t st_rdev;
  6. nlink_t st_nlink; // 硬链接数
  7. uid_t st_uid; // 用户ID
  8. gid_t st_gid; // 用户组ID
  9. off_t st_size;
  10. struct timespec st_atim; // 数据访问时间
  11. struct timespec st_mtim; // 数据修改时间
  12. struct timespec st_ctim; // 属性修改时间
  13. blksize_t st_blksize; // 合适的IO块大小
  14. blkcnt_t st_blocks; //分配了多少block
  15. };

文件类型

普通文件(regular file):包含数据的常规文件,数据可以是文本类型的,也可以是二进制的。

目录文件(directory file):它是一个目录,保存目录相关的信息。

块设备文件(block special file):这种文件提供对硬件(如磁盘)带缓冲的访问。

字符设备文件(regular file):这种文件提供对硬件(如磁盘)不带缓冲的访问。

FIFO:这种文件用于进程间通信。有时也被称为命名管道。

套接字文件(regular file):这种文件用于网络间通信。也可以用在一台宿主机进程上的非网络通信。

符号连接(regular file):类似Windows系统的快捷方式,指向另外一个文件。

文件类型的信息包含在start中的st_mode中,可以用以下的宏函数来判断文件类型。

  1. S_ISREG() /* 普通文件 */
  2. S_ISDIR() /* 目录 */
  3. S_ISCHR() /* 字符文件 */
  4. S_ISBLK() /* 块文件 */
  5. S_ISFIFO() /* 管道文件 */
  6. S_ISLINK() /* 链接文件 */
  7. S_ISSOCK() /* 网络套接字 */

如果要确定IPC对象的类型用以下宏函数,但是参数改为指向start结构体的指针。

  1. S_TYPEISMQ() /*消息队列*/
  2. S_TYPEISSEM() /*信号量*/
  3. S_TYPEISSHM() /*共享存储对象*/

简单用法:

  1. #include "apue.h"
  2. int
  3. main(int argc, char *argv[])
  4. {
  5. int i;
  6. struct stat buf;
  7. char *ptr;
  8. for (i = 1;i < argc; i++) {
  9. printf("%s: ", argv[i]);
  10. if (lstat(argv[i], &buf) < 0) {
  11. err_ret("lstat error");
  12. continue;
  13. }
  14. if (S_ISREG(buf.st_mode))
  15. ptr = "regular";
  16. else if (S_ISDIR(buf.st_mode))
  17. ptr = "directory";
  18. else if (S_ISCHR(buf.st_mode))
  19. ptr = "character special";
  20. else if (S_ISBLK(buf.st_mode))
  21. ptr = "block special";
  22. else if (S_ISFIFO(buf.st_mode))
  23. ptr = "fifo";
  24. else if (S_ISLNK(buf.st_mode))
  25. ptr = "symbolic link";
  26. else if (S_ISSOCK(buf.st_mode))
  27. ptr = "socket";
  28. else
  29. ptr = "** unknown mode **";
  30. printf("%s\n", ptr);
  31. }
  32. exit(0);
  33. }

输入:./a.out pathname1 pathname2

文件访问权限

所有文件类型都有文件访问权限,每个文件有九个文件访问权限位,可将其分为三类。分别表示用户u 组g 其他o的读写执行权限

我们用名字来打开任意类型的文件时,对该名字所包含的每一个目录包括当前目录,都必须具有执行权限

读权限用于目录可以读取目录包含的文件,例如ls,对以一个普通文件的读权限决定了我们打开文件后能否进行读操作

在目录中创建一个文件,必须对该目录具有写权限和执行权限,在目录中删除一个文件时不需要对该文件的读写权限

想要打开一个文件必须对该文件具有可执行权限,想要对该文件修改内容(对目录来说是创建或者删除文件),必须在打开该文件

或目录的基础上(具有执行权限)具有写权限才可以,而想要读取文件则只需要对该文件有执行权限和读权限。

进程每次操作一个文件时,内核就会进行文件权限测试,即把文件的所有者(st_uid st_gid)和进程的有效ID(有效用户ID和有效组ID)对比

  • 如果进程的有效用户id为0(超级用户)则允许访问
  • 进程的有效ID等于文件所有者的ID(进程拥有这个文件),如果文件所有者适当的访问权限被设置(读写执行权限)则允许访问
  • 进程有效组ID等于文件的组ID,判断方法同上
  • 其他用户适当的访问权限被设置,也允许访问

新文件和目录的所有权

创建新文件时,新文件的组id可以是进程的有效组id也可以是他所在目录的id,取决于设置

access函数

判断当前用户是否具有以某种模式访问某个文件的权限

  1. #include<unistd.h>
  2. int access(const char *pathname, int mode);

参数:

mode可取值如下R_OK、W_OK、X_OK、F_OK(测试文件是否存在)

返回值:

能访问则返回0,不能访问则返回-1

umask函数

umask为进程创建新文件时对文件模式创建屏蔽字,修改文件权限时没有效果,并返回以前的值

  1. #include<sys_start.h>
  2. mode_t umask(mode_t cmask);

返回值:

以前的文件模式屏蔽字

  1. /* 例子 */
  2. mode_t mode = umask(0111);
  3. if(creat("a.txt",0777)<0)/* 原来设置的权限是0777,那么最终的结果是0777 - 0111 = 0666*/
  4. err_sys("creat error");
  5. umask(mode); /* 恢复修改之前的umask数值 */

chmod和fchmod函数

可以更改现有文件的访问权限 chmod修改指定文件的访问权限,fchmod修改已经打开的文件的访问权限(打开文件返回文件描述符)

  1. #include <sys_start.h>
  2. int chmod(const char* pathname ,mode_t mode);
  3. int fchmod(int fd,mode_t mode);

返回值:

修改成功返回0,失败返回-1

想要修改一个文件的权限位,进程的有效id必须等于文件所有者的id,或者该进程拥有超级用户权限

mode 说明
S_ISUID 执行时设置用户id
S_ISGID 执行时设置组id
S_ISVTX 保存正文
---- ----
S_IRWXU 用户读写执行
S_IRUSR 用户读
S_IWUSR 用户写
S_IXUSR 用户执行
---- ----
S_IRWXG 组读写执行
S_IWGRP 组写
S_IXGRP 组执行
S_IRGRP 组读
---- ----
S_IRWXO 其他读写执行
S_IWOTH 其他写
S_IXOTH 其他执行
S_IROTH 其他读

保存正文:

该程序第一次执行并结束时,正文部分的一个副本仍然被保留在交换区,这使得下次执行时该程序能较快的装入内存区

现在已经不需要这项技术

对一个目录设置了粘住位,你只有在拥有此文件,拥有此目录,是超级用户才能删除或者更名该目录下的文件

chown fchown lchown 函数

修改文件的用户id和组id

  1. #include<unistd>
  2. int chown(const char* pathname,uid_t owner,gid_t group);
  3. int fchown(int fd , uid_t owner ,gid_t group);
  4. /*lchown更改符号链接本身的所有者,而不是符号链接指向的文件*/
  5. int lchown(const char* pathname, uid_t owner , gid_t group);

返回值:

成功返回0,失败返回-1

只有超级用户进程才能修改文件的用户id

进程拥有此文件,可以修改文件的组id,但只能该到自己所属的组

文件长度

start结构体中的st_size 表示以字节为单位的文件长度且只对普通文件目录文件和符号链接有意义

普通文件:文件长度可以是0

目录:文件长度通常是一个数(16或者512的整数倍)

符号链接:文件长度是文件名的实际字节数,如usr/lib文件长度为7(并不包含c语言最后的null)

大部分unix系统提st_blksize(对文件较合适的块长度)和st_blocks(所分配实际的块的个数)

文件系统

我们可以把一个磁盘分为多个分区,每一个分区都有一个文件系统

i节点是固定长度的记录项,他包含了文件的大部分信息,并指向该文件要包含的数据块

图示为硬链接

每个目录块都包含了一个以文件名和它i节点号为表项的表

每个i节点都有一个链接计数,表示有多少指向该i节点的目录项数,当这个记数减少到0的时候文件才会彻底删除(解除对一个文件的链接)

link,unlink,remove和rename函数

任何一个文件可以有多个目录项指向其i节点,创建一个指向现有文件的链接:link

  1. #include<unistd.h>
  2. int link(const char *existingpath ,const char* newpath );

引用现有的文件existingpath创建一个新的文件newpath,如果newpath已经存在返回出错

返回值:

成功返回0,失败返回-1

删除一个现有的目录项使用ulink

  1. #include <unistd.h>
  2. int ulink(const char * pathname);

删除目录项,并将pathname引用的文件链接计数-1(如果其它地方还是有链接还是能访问此文件)

如果设置了粘住位只有在拥有该文件,具有超级管理员权限才可以删除

返回值:

成功返回0,失败返回-1

remove函数

解除该路径对一个文件或者一个目录的链接

  1. #include <stdio.h>
  2. int remove (const char *pathname);

返回值:

成功返回0,失败返回-1

rename函数

文件或者目录更名

  1. #include<stdio.h>
  2. int rename (const char* oldname,const char new name);

返回值:

成功返回0,失败返回-1

符号链接

符号链接就是一个指向文件的间接指针

  1. # include <unistd.h>
  2. int symlink(const char * path ,const char * sympath);

创建一个指向path的新目录项sympath,创建时并不要求path存在,path和sympath不一定在一个文件系统中

  1. /*读取符号链接*/
  2. #include <unist.h>
  3. size_t readlink(const char * restrict pathname , char restrict buf,size_t bufsize );

返回值:

成功则返回读到的字节数,失败则返回-1

文件的时间

st_atime、文件数据的最后访问时间

st_mtime、文件数据的最后修改时间

st_ctime、i节点状态的最后修改时间

目录相关函数

  1. /*dirent至少有如下两个成员*/
  2. struct dirent{
  3. ino_t d_ino;/*节点*/
  4. char d_name [NAME_MAX+1];/*文件名*/
  5. }
  6. #include <dirent.h>
  7. /* 打开一个目录 */
  8. DIR *opendir(const char *name); // 成功返回指针,失败返回NULL
  9. DIR *fdopendir(int fd); // 成功返回指针,失败返回NULL
  10. /* 读取目录中的内容,如文件、子目录 */
  11. struct dirent *readdir(DIR *dirp); // 成功返回指针,失败返回NULL
  12. /* 让目前的读取位置还原到开头的读取位置 */
  13. void rewinddir(DIR *dirp);
  14. /* 设置相对于开头偏移值为pos的读取位置 */
  15. void seekdir(DIR *dirp, long int pos);
  16. /* 关闭目录 */
  17. int closedir(DIR *dirp); // 成功时返回0,失败返回-1
  18. /* 例子 */
  19. DIR* dir = opendir("../");
  20. struct dirent* ent;
  21. while(ent=readdir(dir)) // 1 读, 2 =,3 判断ent是否为0
  22. {
  23. printf("%d, %s\n", ent->d_type, ent->d_name);
  24. } // d_tpye == 4 的是目录
  25. closedir(dir);

chdir、fchdir、getcwd函数

用以下两个函数可以改变当前工作目录

  1. #include<unist.h>
  2. int chdir(const char * pathname);
  3. int fchdir(int fd);

getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buf的空间大小。

缓冲区必须有足够大的空间足以容纳下绝对路径加上一个null ,否则返回出错

#include<unist.h>

char *getcwd(char * buf, size_t size );

unix环境高级编程第四章笔记的更多相关文章

  1. unix环境高级编程第六章笔记

    口令文件 阴影口令 组文件 附属组ID 登录账户记录 系统标识 口令文件<\h2> /etc/passwd文件是UNIX安全的关键文件之一.该文件用于用户登录时校验用户的口令,文件中每行的 ...

  2. unix环境高级编程第三章笔记

    文件描述符 1.文件描述符的概念 对于内核而言,所有打开的文件都会用一个文件描述符来引用,打开或和创建一个新文件的时候,内核会给进程返回一个文件描述符,而当使用read write时,可以使用这个文件 ...

  3. UNIX环境高级编程 第8章 进程控制

    本章是UNIX系统中进程控制原语,包括进程创建.执行新程序.进程终止,另外还会对进程的属性加以说明,包括进程ID.实际/有效用户ID. 进程标识 每个进程某一时刻在系统中都是独一无二的,它们之间是用一 ...

  4. UNIX环境高级编程 第7章 进程环境

    本章涉及C/C++程序中main函数是如何被调用的.命令行参数如何传递给main函数.程序的内存空间布局.程序如何使用环境变量.程序如何终止退出. main函数 C程序或C++程序总是从main函数开 ...

  5. UNIX环境高级编程 第13章 守护进程

    守护进程daemon是一种生存周期很长的进程.它们通常在系统引导时启动,在系统关闭时终止.守护进程是没有终端的,它们一直在后台运行. 守护进程的特征 在Linux系统中,可以通过命令 ps -efj ...

  6. UNIX环境高级编程 第9章 进程关系

    在第8章学习了进程的控制原语,通过各种进程原语可以对进程进行控制,包括新建进程.执行新程序.终止进程等.在使用fork( )产生新进程后,就出现了进程父子进程的概念,这是进程间的关系.本章更加详细地说 ...

  7. UNIX环境高级编程 第6章 系统数据文件和信息

    UNIX系统的正常运作需要用到大量与系统有关的数据文件,例如系统用户账号.用户密码.用户组等文件.出于历史原因,这些数据文件都是ASCII文本文件,并且使用标准I/O库函数来读取. 口令文件 /etc ...

  8. UNIX环境高级编程 第5章 标准I/O库

    本章是关于C语言标准I/O库的,之所以在UNIX类系统的编程中会介绍C语言标准库,主要是因为UNIX和C之间具有密不可分的关系.由于UNIX系统存在很多实现,而每个实现都有自己的标准I/O库,为了统一 ...

  9. UNIX环境高级编程 第4章 文件和目录

    第三章说明了关于文件I/O的基本函数,主要是针对普通regular类型文件.本章描述文件的属性,除了regular文件还有其他类型的文件. 函数stat.fstat.fstatat和lstat sta ...

随机推荐

  1. 强大生产力工具Alfred

    今天要给大家介绍的工具是Alfred,一款Mac下的高效生产力产品.它能做什么呢?简单的说就是:让你能够通过打几个字,就可以完成原本需要一顿操作的事情.举一个简单的栗子:如果我们要在Google搜索一 ...

  2. VRP CommandLines

    <> 用户视图 通过 system-view 进入系统视图 [] 系统视图 通过interface 0/0/0 进入接口视图 CTRL+Z 返回用户视图 CTRL+A 把光标移动到当前命令 ...

  3. 【Linux】vim小技巧,如何批量添加或者删除注释

    环境:centos vim或者vi都可以 例如文件如下: aaa bbb ccc ddd 有四行文件,想将前三行都添加注释 先查看行数: :set nu  可以这样做: :1,3s%^%#% 即可,如 ...

  4. Oracle获取session的IP方法

    方法1 创建触发器:  create orreplace trigger login_on  alfterlogon on database  begin  dbms_application_info ...

  5. 【Linux】以001格式循环到100保证位数是3位

    这里有一个前提,要保证数位是相同的 确实数字是1-100  但是数位是不同的,需要统一一下位数必须是3位的 这个问题在很多论坛上用的都是printf这个命令,确实可以达到这个效果,但是没有我下面介绍的 ...

  6. kubernets之statefulset资源

    一  了解Statefulset 1.1  对比statefulset与RS以及RC的区别以及相同点 Statefulset是有状态的,而RC以及RS等是没有状态的 Statefulset是有序的,拥 ...

  7. Mysql--由prepared sql statement引发的问题

    问题回顾 最近生产环境数据库查询接口异常,抛出异常信息表明预处理sql语句声明已经超过mysql系统设置限制max_prepared_stmt_count:通过网上一些资料,分析大概是程序中数据库查询 ...

  8. 面向对象的延伸与Java内部定义类的应用

    识别类 传统的过程化程序设计,必须从顶部的main函数开始编写程序,在面向对象程序设计时没有所谓的"顶部".首先从设计类开始,然后再往每个类中添加方法. 识别类的规则是在分析问题的 ...

  9. 1.5V升压3V集成电路升压芯片

    干电池1.5V升压3V的升压芯片,适用于干电池升压产品输出3V供电 1.5V输入时,输出3V,电流可达500MA. PW5100是一款效率大.10uA低功耗 PW5100输入电压:0.7V-5V PW ...

  10. Android iText向pdf模板插入数据和图片

    一.需求 这些日志在写App程序,有这么一个需求,就是需要生成格式统一的一个pdf文件,并向固定表格中填充数据,并且再在pdf中追加两页图片. 二.方案 手工设计一个pdf模板,这个具体步骤就不再赘述 ...