文件和目录

start fstart lstart函数

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

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

参数:

pathname:文件路径

fd:文件描述符

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

返回值:

成功返回0 失败返回1

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

文件类型

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

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

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

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

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

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

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

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

  S_ISREG()        /* 普通文件 */
S_ISDIR() /* 目录 */
S_ISCHR() /* 字符文件 */
S_ISBLK() /* 块文件 */
S_ISFIFO() /* 管道文件 */
S_ISLINK() /* 链接文件 */
S_ISSOCK() /* 网络套接字 */

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

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

简单用法:

  #include "apue.h"
int
main(int argc, char *argv[])
{
int i;
struct stat buf;
char *ptr; 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);
}
exit(0);
}

输入:./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函数

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

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

参数:

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

返回值:

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

umask函数

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

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

返回值:

以前的文件模式屏蔽字

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

chmod和fchmod函数

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

  #include <sys_start.h>
int chmod(const char* pathname ,mode_t mode);
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

  #include<unistd>
int chown(const char* pathname,uid_t owner,gid_t group);
int fchown(int fd , uid_t owner ,gid_t group);
/*lchown更改符号链接本身的所有者,而不是符号链接指向的文件*/
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

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

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

返回值:

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

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

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

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

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

返回值:

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

remove函数

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

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

返回值:

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

rename函数

文件或者目录更名

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

返回值:

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

符号链接

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

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

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

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

返回值:

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

文件的时间

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

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

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

目录相关函数

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

chdir、fchdir、getcwd函数

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

  #include<unist.h>
int chdir(const char * pathname);
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. 观《if (domain logic) then CQRS, or Saga?》所悟

    引言 Udi Dahan曾在2017年阿姆斯特丹的DDD欧洲年会上发表过一篇演讲--if (domain logic) then CQRS, or Saga.视频是UP主从Youtube搬运的,我听力 ...

  2. 附录 A ES6附加特性

    目录 模板字符串 解构 对象的解构 数组的解构 增强版对象字面量 模板字符串 const student = { name: "Wango", age: 24, } // 普通字符 ...

  3. Cisco常用命令

    • 首次配置网络设备        ○ 需要使用Console线连接进行初始化配置            § 在PC使用"超级终端"或其他软件.    • 交换机的工作模式:   ...

  4. Python作业---内置数据类型

    实验2 内置数据类型 实验性质:验证性 一.实验目的 1.掌握内置函数.列表.切片.元组的基本操作: 2.掌握字典.集合和列表表达式的基本操作. 二.实验预备知识 1.掌握Python内置函数的基/本 ...

  5. 数学建模学习笔记 | matlab基本命令及用法

    前言 数学建模对matlab水平的要求 了解matlab的基本用法,如常用命令.脚本结构.矩阵的基本操作.绘图等: 熟悉matlab的程序结构,能创建和引用函数: 熟悉常见模型的求解算法和套路: 自主 ...

  6. 【Oracle】Script to Collect DRM Information (drmdiag.sql) (文档 ID 1492990.1)

    脚本对应如下: The following (drmdiag.sql) is a script to collect information related to DRM (Dyanamic Reso ...

  7. DataGridView控件使用Demo

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  8. BDC应用

    第一步:SHDB或者是SM35进入BDC录制事务.开始录制. 第二部:保存录制的记录. 第三步:在你自己的程序中定义一个内表如:ITAB TYPE TABLE OF BDCDATA. 再定义一个工作空 ...

  9. 单线程的as-if-serial语义

    单线程的as-if-serial语义 关于指令重排序有个问题不明白的一个问题 int a = 2; int c = 1 + a; float b = 3f / 2f; 举个栗子,从CPU的设计者以及编 ...

  10. bootstrap 后端模板

    Twitter Bootstrap 框架已经广为人知,用于加快网站,应用程序或主题的界面开发,并被公认为是迄今对于 Web 开发的最有实质性帮助的工具之一.在此之前的,各种各样的界面库伴随着高昂的维护 ...