[APUE]再读之文件和目录

本章讨论了不带缓存IO的各文件操作。


1. stat 函数族。

int stat(const char* pathname, struct stat* buf)
int fstat(int fd, struct stat* buf)
int lstat(const char* pathname,struct stat* buf) //lstat 返回连接的属性

struct stat 结构体成员:

struct stat
{
mode_t st_mode; // file type & mode, permittion
ino_t st_ino ; //文件系统i节点号
dev_t st_dev ;//文件设备号
dev_t st_rdev; //特殊文件的文件设备号
nlink_t st_nlink; //链接数量
uid_t st_uid; // uid
gid_t st_gid; //gid
off_t st_size; //文件bytes.
time_t st_atime; //上次访问时间, read操作便可
time_t st_mtime; //修改时间
time_t st_ctime; // chown, chmod,文件夹操作等
long st_blksize; //文件块大小
long st_blocks; //512 byte 的块数目
}

2. 文件类型

普通文件, 目录,FIFO,socket, 字符特殊文件, 块特殊文件,符号链接。

测试文件类型的demo.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
    struct stat buf;
    char* ptr;
    int i;
    for(i=1;i< argc;i++)
    {
        if (lstat(argv[i],&buf)==-1)
        {
            printf("can not lstat file. %s", argv[i]);
            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";
        else if (S_ISBLK(buf.st_mode)) ptr="bulk";
        else if (S_ISFIFO(buf.st_mode)) ptr="FIFO";
        else if (S_ISLNK(buf.st_mode)) ptr="LINK";
        else if (S_ISSOCK(buf.st_mode)) ptr="SOCKET";
        else
            ptr ="unknown";
        printf("file %s is %s\n",argv[i],ptr);
    }
    exit(0);

}

3. 用户ID

用户ID分为实际用户ID, 有效用户ID,设置用户ID。 

文字描述苍白无力,套用以前某领导一句话,上代码。

#include <string.h>
#include <stdio.h>

int main()
{
    printf("uid is %d\n", getuid());
    printf("euid is %d\n", geteuid());
}
以非root用户编译,执行。

得到结果504 504

执行chown root:root a.out; chmod u+s a.out

再以非root 用户运行

得到结果 504 0


4. 文件许可权限

st_mode 包含了9位的文件许可权限。

文件许可权限的6个规则:

  • 访问文件需要对文件夹具有执行权限
  • 写一个文件时需要对文件夹具有写权限和执行权限
  • 读文件时需要有读文件权限,O_RDONLY, O_RDWR
  • 写文件时需要有写文件权限,O_WRONLY,O_RDWR,O_TRUNC
  • 删除文件必须对目录具有写许可权限和执行许可权限,对文件本身权限不做要求
  • exec函数族需要具有执行权限
5. 新文件的所有权
新文件所有权用户跟随进程uid,组ID可以跟随进程gid,或者所在目录gid.

6. access 函数
测试文件权限
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
   if(argc<2)
   {
      printf("need two argument\n");
      exit(-1);
   }
   if(access(argv[1],O_RDONLY)<0)
   {
      printf("read %s not ok\n", argv[1]);
   }
   else
      printf("read %s  ok\n", argv[1]);
}
7. umask屏蔽位
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    umask(0);
    if(creat("foo", S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)<0)
    {
        printf("create file error\n");
    }
    umask(S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    if(creat("bar", S_IRUSR| S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)<0)
    {
        printf("create file error\n");
    }
}

创建出来的foo 文件mode 为 666, 而bar为000


8. chmod 和fchmod函数
#include <sys/types.h>
#include <sys/stat.h>

int chmod(const char* pathname,  mode_t mode)
int fchmod(int fileds, mode_t mode)

chmod改变文件mode 参数demo:
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>

int main()
{
    struct stat buf;
    if(stat("foo", &buf)<0)
    {
        printf("stat error. %d\n",errno);
        exit(-1);
    }
    if(chmod("foo",buf.st_mode & ~ S_IWGRP)<0)
    {
        printf("chmode error. %d\n",errno);
        exit(-1);
    }
}

9. 粘住位

对目录设置粘住位后,只有拥有下列权限,才可以删除和更改目录的文件:
  • 超级用户
  • 拥有此目录
  • 拥有此文件

粘住位的简单demo

mkdir stick
chmod 777 stick
cd stick/
touch 1.txt
chmod 777 1.txt
su test
rm -rf 1.txt //成功


mkdir stick
chmod 777 stick
chmod +t stick/
cd stick/
touch 1.txt
chmod 777 1.txt
su test
rm -rf 1.txt //失败

10 . chown 函数族

#include <sys/types.h>
#include <unistd.h>

int chown(const char* pathname,uid_t owner,gid_t group)
int fchown(int fd, uid_t owner, gid_t group)
int lchown(const char* pathname, uid_t owner, gid_t group)

11. 文件长度

  • 普通文件长度可以为0
  • 目录文件长度为512倍数,比如我的系统的目录文件长度为4096
  • 文件链接长度不为链接文件的长度
  • 空洞文件空洞部分不占用磁盘空间,使用cat f1> f2会把空洞部分写出0,cp 则不一样
12. 文件截短

截短一个文件
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
if (truncate("1.log",0)<0)
    printf("truncate error\n");

}

13.  文件系统

文件自举块和超级块作用:

超级快存储了整个文件系统的信息。填满和空的块。

两种经典的unix v系统文件系统的概图

  • 两个目录项可同时指向同一个i节点
  • 符号链接,内容为所指文件的名字
  • i节点包含了所有文件相关信息:文件类型,文件存取许可权位,文件长度和指向该文件所占用数据块指针。
  • i节点不能跨文件系统指
  • 同文件系统下面mv,只是改变了目录项,数据块本身并没有发生拷贝。



14. unlink和link函数

  • 任何一个文件可以有多个目录项指向其i节点,当指向其i节点的目录项数量为0时,才可以被删除。
  • 内核会检查当前是否有进程打开该文件,只要有进程打开文件,即使计数为0也不被删除
  • link只能超级用户使用
unlink用于进程崩溃前删除文件的 demo
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <stdlib.h>

int main()
{
    if(open("/tmp/t.log", O_RDWR | O_CREAT)<0)
    {
        printf("open file error\n");
        exit(-1);
    }
    if(unlink("/tmp/t.log")<0)
    {
        printf("unlink file error\n");
        exit(-1);
    }
    printf("unlink file \n");
    sleep(15);
    exit(0);
}

rename 和remove 函数
#include <stdio.h>

int  rename(const char* oldname, const char* newname)
int remove(const char* pathname)

15. 符号链接

硬链接的限制为:1. 不能跨文件系统 2. 只能root用户做。 符号链接是一个间接的文件指针,没有这些限制。
int syslink(const char* actualpath,const char* syspath)
int readlink(const char* syspath, char* buf, int bufsize)

16.   utime函数
可以使用一个文件的存取和修改时间可以用utime来修改
#include <sys/types.h>
#include <utime.h>

int utime(const char* pathname,const struct utimebuf* buf)

struct utimbuf
{
time_t actime;
time_t modtime;
}

清除文件内容而不改变文件时间的demo:
#include <utime.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>

int main()
{
    const char* filepath = "/tmp/1.log";
    struct stat buf;
    if(stat(filepath,&buf)<0)
    {
        printf("stat error\n");
        return -1;
    }
    if(open(filepath, O_RDWR|O_TRUNC)<0)
    {
       printf("truncate file error\n");
       return -1;
    }
    struct utimbuf ub;
    ub.actime = buf.st_atime;
    ub.modtime= buf.st_mtime;
    if(utime(filepath,&ub)<0)
    {
       printf("utmie error\n");
       return -1;
    }
}

17. 目录操作
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <dirent.h>
int mkdir(const char* path, mode_t mode)
int rmdir(const char* path)
DIR* opendir(const char* pathname)
struct dirent *readdir(DIR* dp)
void rewinddir(DIR* dp)
int closedir(DIR* dp)

18. 切换目录
每个进程都有当前工作目录。通过chdir函数可以更改当前目录。
#include <unistd.h>
int chdir(const char* pathname)
int fchdir(int filedes)
char* getcwd(char* buf,size_t size)
获得当前目录demo:
#include <unistd.h>
#include <stdio.h>

char buf[1024];
int main()
{
    if(chdir("/tmp/")<0)
    {
       printf("change directory error\n");
       return (-1);
    }
    if(getcwd(buf,1024)<0)
    {
       printf("getcwd directory error\n");
       return (-1);
    }
    printf("directory is %s\n",buf);
    
}


19 sync 和fsync函数

大多数磁盘IO,都并非直接写磁盘,而是当在内核中的缓冲区满后,或者一定时间以后才会冲洗磁盘。这样可以减少读写磁盘的次数,提高IO 性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值