c /c++复习笔记 第四天

来源:互联网 发布:origin8怎么导入数据 编辑:程序博客网 时间:2024/05/21 07:04

  • 文件系统下
  • 一 sync和fsync以及fdatasync
    • 基本介绍
    • 函数说明
    • 解析流程
  • 二 fcntl
    • 函数说明
    • 常用形式
      • 范例dupc
      • 范例flagsc
    • 文件锁
    • 函数说明
    • 参数说明
      • 范例lock1c
    • 图片展示
      • 范例lock2c
      • 范例 wlockc
      • 范例rlockc
      • 执行结果
  • 三 stat和fstat以及lstat
    • 函数说明
    • 其它说明
    • 辅助分析st_mode
      • 范例statc
  • 四 access
      • 范例accessc
  • 五 umask
    • 函数说明
    • 参数说明
      • 范例umaskc
  • 六 chmod和fchmod
    • 函数说明
    • 参数说明
      • 范例chmodc
  • 七 chown和fchown以及lchown
    • 函数说明
    • 附加说明
  • 八 truncate和ftruncate
    • 函数说明
      • 范例truncc
      • 范例mmapc
    • 附加说明
  • 九 link和unlink remove和rename
  • 十 symlink readlink
      • 范例slinkc
  • 十一 mkdir rmdir
  • 十二 chdir fchdir getcwd
  • 十三 opendir fdopendir closedir readdir rewinddir telldir seekdir
    • 基本说明
    • 函数说明
    • 参数说明
      • 范例listc
      • 范例seekc

=================================

文件系统(下)

一、 sync和fsync以及fdatasync


基本介绍

  1. 大多数磁盘I/O都通过缓冲进行,
    写入文件其实只是写入缓冲区,直到缓冲区满,
    才将其排入写队列。

  2. 延迟写降低了写操作的次数,提高了写操作的效率,
    但可能导致磁盘文件与缓冲区数据不同步。

  3. sync/fsync/fdatasync用于强制磁盘文件与缓冲区同步。

  4. sync将所有被修改过的缓冲区排入写队列即返回,
    不等待写磁盘操作完成。

  5. fsync只针对一个文件,且直到写磁盘操作完成才返回。

  6. fdatasync只同步文件数据,不同步文件属性。

函数说明

#include <unistd.h>void sync (void);int fsync (    int fd);

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

int fdatasync (    int fd);

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

解析流程

              +-fwrite-> 标准库缓冲 -fflush-+             sync应用程序内存 -+                             +-> 内核缓冲 -fdatasync-> 磁盘(缓冲)              +------------write------------+             fsync

二、 fcntl


函数说明

#include <fcntl.h>int fcntl (    int fd,  // 文件描述符    int cmd, // 操作指令    ...      // 可变参数,因操作指令而异);

对fd文件执行cmd操作,某些操作需要提供参数。

1. 常用形式

~~~~~~~

#include <fcntl.h>int fcntl (int fd, int cmd);int fcntl (int fd, int cmd, long arg);

成功返回值因cmd而异,失败返回-1。

cmd取值:

F_DUPFD - 复制fd为不小于arg的文件描述符。
若arg文件描述符已用,
该函数会选择比arg大的最小未用值,
而非如dup2函数那样关闭之。

范例:dup.c

#include <stdio.h>#include <unistd.h>#include <string.h>#include <fcntl.h>int main (void) {    int fd1 = open ("dup.txt", O_RDWR | O_CREAT |        O_TRUNC, 0664);    if (fd1 == -1) {        perror ("open");        return -1;    }    printf ("fd1 = %d\n", fd1);    int fd2 = dup (fd1);    if (fd2 == -1) {        perror ("dup");        return -1;    }    printf ("fd2 = %d\n", fd2);    int fd3 = dup2 (fd2, 100);    if (fd3 == -1) {        perror ("dup2");        return -1;    }    printf ("fd3 = %d\n", fd3);    const char* text = "Hello, World !";    if (write (fd1, text,        strlen (text) * sizeof (text[0])) == -1) {        perror ("write");        return -1;    }    if (lseek (fd2, -7, SEEK_CUR) == -1) {        perror ("lseek");        return -1;    }    text = "Linux";    if (write (fd3, text,        strlen (text) * sizeof (text[0])) == -1) {        perror ("write");        return -1;    }    close (fd3);    close (fd2);    close (fd1);    return 0;}

F_GETFD - 获取文件描述符标志。

F_SETFD - 设置文件描述符标志。

目前仅定义了一个文件描述符标志位FD_CLOEXEC:

0 - 在通过execve()函数所创建的进程中,
该文件描述符依然保持打开。

1 - 在通过execve()函数所创建的进程中,
该文件描述符将被关闭。

F_GETFL - 获取文件状态标志。
不能获取O_CREAT/O_EXCL/O_TRUNC。

F_SETFL - 追加文件状态标志。
只能追加O_APPEND/O_NONBLOCK。

范例:flags.c

这里写代码片

2. 文件锁

~~~~~

函数说明

#include <fcntl.h>int fcntl (int fd, int cmd, struct flock* lock);

其中:

struct flock {    short int l_type;   // 锁的类型:                        // F_RDLCK/F_WRLCK/F_UNLCK                        // (读锁/写锁/解锁)    short int l_whence; // 偏移起点:                        // SEEK_SET/SEEK_CUR/SEEK_END                        // (文件头/当前位置/文件尾)    off_t     l_start;  // 锁区偏移,从l_whence开始    off_t     l_len;    // 锁区长度,0表示锁到文件尾    pid_t     l_pid;    // 加锁进程,-1表示自动设置};

参数说明

cmd取值:

F_GETLK - 测试lock所表示的锁是否可加。
若可加则将lock.l_type置为F_UNLCK,
否则通过lock返回当前锁的信息。

F_SETLK - 设置锁定状态为lock.l_type,
成功返回0,失败返回-1。
若因其它进程持有锁而导致失败,
则errno为EACCES或EAGAIN。

F_SETLKW - 设置锁定状态为lock.l_type,
成功返回0,否则一直等待,
除非被信号打断返回-1。

1) 既可以锁定整个文件,也可以锁定特定区域。

2) 读锁(共享锁)、写锁(独占锁/排它锁)、解锁。

范例:lock1.c

#include <stdio.h>#include <unistd.h>#include <string.h>#include <fcntl.h>// 加读锁int rlock (int fd, off_t start, off_t len, int wait) {    struct flock lock;    lock.l_type   = F_RDLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, wait ? F_SETLKW : F_SETLK,&lock);}// 加写锁int wlock (int fd, off_t start, off_t len, int wait) {    struct flock lock;    lock.l_type   = F_WRLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, wait ? F_SETLKW : F_SETLK,&lock);}// 解锁int ulock (int fd, off_t start, off_t len) {    struct flock lock;    lock.l_type   = F_UNLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, F_SETLK, &lock);}int main (void) {    printf ("进程标识(PID):%d\n", getpid ());    int fd = open ("lock.txt",        O_RDWR | O_CREAT | O_TRUNC, 0664);    if (fd == -1) {        perror ("open");        return -1;    }    const char* text = "ABCDEFGHIJKLMNOPQR";    if (write (fd, text,        strlen (text) * sizeof (text[0])) == -1) {        perror ("write");        return -1;    }    // 对EFGH加读锁    printf ("对EFGH加读锁");    if (rlock (fd, 4, 4, 0) == -1) {        printf ("失败:%m\n");        return -1;    }    printf ("成功!\n");    // 对MNOP加写锁    printf ("对MNOP加写锁");    if (wlock (fd, 12, 4, 0) == -1) {        printf ("失败:%m\n");        return -1;    }    printf ("成功!\n");    printf ("按<回车>,解锁MN...");    getchar ();    // 解锁MN    ulock (fd, 12, 2);    printf ("按<回车>,解锁EFGH...");    getchar ();    // 解锁EFGH    ulock (fd, 4, 4);    close (fd);    return 0;}

图片展示

图示:rwlock.bmp
这里写图片描述
图示: flock.bmp
这里写图片描述
3) 文件描述符被关闭(进程结束)时,自动解锁。

4) 劝谏锁(协议锁)、强制锁。

范例:lock2.c

#include <stdio.h>#include <unistd.h>#include <string.h>#include <fcntl.h>// 打印锁void plock (struct flock lock) {    if (lock.l_type == F_UNLCK)        printf ("没有锁。\n");    else {        printf ("%d进程", lock.l_pid);        switch (lock.l_whence) {            case SEEK_SET:                printf ("在距文件头");                break;            case SEEK_CUR:                printf ("在距当前位置");                break;            case SEEK_END:                printf ("在距文件尾");                break;        }        printf ("%ld字节处,为%ld字节加了",            lock.l_start, lock.l_len);        switch (lock.l_type) {            case F_RDLCK:                printf ("读锁。\n");                break;            case F_WRLCK:                printf ("写锁。\n");                break;        }    }}// 读锁测试int rtest (int fd, off_t start, off_t len) {    struct flock lock;    lock.l_type   = F_RDLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    if (fcntl (fd, F_GETLK, &lock) == -1)        return -1;    plock (lock);    return 0;}// 写锁测试int wtest (int fd, off_t start, off_t len) {    struct flock lock;    lock.l_type   = F_WRLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    if (fcntl (fd, F_GETLK, &lock) == -1)        return -1;    plock (lock);    return 0;}// 加读锁int rlock (int fd, off_t start, off_t len, int wait) {    struct flock lock;    lock.l_type   = F_RDLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, wait ? F_SETLKW : F_SETLK,&lock);}// 加写锁int wlock (int fd, off_t start, off_t len, int wait) {    struct flock lock;    lock.l_type   = F_WRLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, wait ? F_SETLKW : F_SETLK,&lock);}// 解锁int ulock (int fd, off_t start, off_t len) {    struct flock lock;    lock.l_type   = F_UNLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, F_SETLK, &lock);}int main (void) {    int fd = open ("lock.txt", O_RDWR);    if (fd == -1) {        perror ("open");        return -1;    }    // 对CDEF做读锁测试    printf ("对CDEF做读锁测试。");    if (rtest (fd, 2, 4) == -1) {        printf ("失败:%m\n");        return -1;    }    // 对CDEF加读锁    printf ("对CDEF加读锁");    if (rlock (fd, 2, 4, 0) == -1)        printf ("失败:%m\n");    else {        printf ("成功!\n");        ulock (fd, 2, 4);    }    // 对CDEF做写锁测试    printf ("对CDEF做写锁测试。");    if (wtest (fd, 2, 4) == -1) {        printf ("失败:%m\n");        return -1;    }    // 对CDEF加写锁    printf ("对CDEF加写锁");    if (wlock (fd, 2, 4, 0) == -1)        printf ("失败:%m\n");    else {        printf ("成功!\n");        ulock (fd, 2, 4);    }    // 对KLMN做读锁测试    printf ("对KLMN做读锁测试。");    if (rtest (fd, 10, 4) == -1) {        printf ("失败:%m\n");        return -1;    }    // 对KLMN加读锁    printf ("对KLMN加读锁");    if (rlock (fd, 10, 4, 0) == -1)        printf ("失败:%m\n");    else {        printf ("成功!\n");        ulock (fd, 10, 4);    }    // 对KLMN做写锁测试    printf ("对KLMN做写锁测试。");    if (wtest (fd, 10, 4) == -1) {        printf ("失败:%m\n");        return -1;    }    // 对KLMN加写锁    printf ("对KLMN加写锁");    if (wlock (fd, 10, 4, 0) == -1)        printf ("失败:%m\n");    else {        printf ("成功!\n");        ulock (fd, 10, 4);    }    printf ("等待KLMN上的写锁被解除...\n");    // 对KLMN加写锁    printf ("对KLMN加写锁");    if (wlock (fd, 10, 4, 1) == -1)        printf ("失败:%m\n");    else {        printf ("成功!\n");        ulock (fd, 10, 4);    }    close (fd);    return 0;}

5) 文件锁仅在不同进程间起作用。

6) 通过锁同步多个进程对同一个文件的读写访问。

范例: wlock.c

#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>// 写锁测试// 返回//  1 - 可加写锁//  0 - 不可加写锁// -1 - 系统错误int wtest (int fd, off_t start, off_t len) {    struct flock lock;    lock.l_type   = F_WRLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    if (fcntl (fd, F_GETLK, &lock) == -1)        return -1;    if (lock.l_type == F_UNLCK)        return 1;    return 0;}// 加写锁int wlock (int fd, off_t start, off_t len, int wait) {    struct flock lock;    lock.l_type   = F_WRLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, wait ? F_SETLKW : F_SETLK,&lock);}// 解锁int ulock (int fd, off_t start, off_t len) {    struct flock lock;    lock.l_type   = F_UNLCK;    lock.l_whence = SEEK_SET;    lock.l_start  = start;    lock.l_len    = len;    lock.l_pid    = -1;    return fcntl (fd, F_SETLK, &lock);}int main (int argc, char* argv[]) {    if (argc < 2) {        fprintf (stderr,"用法:%s <字符串>\n",argv[0]);        return -1;    }    int fd = open ("wlock.txt",        O_WRONLY | O_CREAT | O_APPEND, 0664);    if (fd == -1) {        perror ("open");        return -1;    }    /*    int unlock = 0;    do {        if ((unlock = wtest (fd, 0, 0)) == -1) {            perror ("wtest");            return -1;        }        if (! unlock) {            printf ("该文件已被锁定,稍后再试...\n");            // 空闲处理            // ...        }    }   while (! unlock);    if (wlock (fd, 0, 0, 0) == -1) {        perror ("wlock");        return -1;    }    */    while (wlock (fd, 0, 0, 0) == -1) {        if (errno != EACCES && errno != EAGAIN) {            perror ("wlock");            return -1;        }        printf ("该文件已被锁定,稍后再试...\n");        // 空闲处理        // ...    }    /*    if (wlock (fd, 0, 0, 1) == -1) {        perror ("wlock");        return -1;    }    */    size_t i, len = strlen (argv[1]);    for (i = 0; i < len; ++i) {        if (write (fd, &argv[1][i],            sizeof (argv[1][i])) == -1) {            perror ("write");            return -1;        }        sleep (1);    }    if (ulock (fd, 0, 0) == -1) {        perror ("ulock");        return -1;    }    close (fd);    return 0;}

范例:rlock.c

#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>int main (int argc, char* argv[]) {    int fd = open ("wlock.txt", O_RDONLY, 0664);    if (fd == -1) {        perror ("open");        return -1;    }    char buf[1024];    ssize_t readed;    while ((readed = read (fd, buf, sizeof (buf)))>0)        write (STDOUT_FILENO, buf, readed);    if (readed == -1) {        perror ("read");        return -1;    }    close (fd);    return 0;}

执行结果

# wlock 非常时刻科技 | # wlock 有限公司wlock.txt<乱码># wlock 非常时刻科技 -l | # wlock 有限公司 -lwlock.txt非常时刻奋斗奋斗-----------------------------------------# wlock 非常时刻奋斗奋斗 | # rlock<乱码># wlock 非常时刻奋斗奋斗 -l | # rlock -l非常时刻奋斗奋斗

三、 stat和fstat以及lstat


获取文件属性。

函数说明

#include  <sys/stat.h>int stat (    const char*  path, // 文件路径    struct stat* buf   // 文件属性);int fstat (    int          fd, // 文件描述符    struct stat* buf // 文件属性);int lstat (    const char*  path, // 文件路径    struct stat* buf   // 文件属性);

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

stat函数跟踪软链接,lstat函数不跟踪软链接。

struct stat {
dev_t st_dev; // 设备ID
ino_t st_ino; // i节点号
mode_t st_mode; // 文件类型和权限
nlink_t st_nlink; // 硬链接数
uid_t st_uid; // 属主ID
gid_t st_gid; // 属组ID
dev_t st_rdev; // 特殊设备ID
off_t st_size; // 总字节数
blksize_t st_blksize; // I/O块字节数
blkcnt_t st_blocks; // 占用块(512字节)数
time_t st_atime; // 最后访问时间
time_t st_mtime; // 最后修改时间
time_t st_ctime; // 最后状态改变时间
};

st_mode(0TTSUGO)为以下值的位或:

S_IFDIR           - 目录        \S_IFREG           - 普通文件     |S_IFLNK           - 软链接       |S_IFBLK           - 块设备       > TT (S_IFMT)S_IFCHR           - 字符设备     |S_IFSOCK          - Unix域套接字 |S_IFIFO           - 有名管道    /--------------------------------S_ISUID           - 设置用户ID  \S_ISGID           - 设置组ID     > SS_ISVTX           - 粘滞        /--------------------------------S_IRUSR(S_IREAD)  - 属主可读    \S_IWUSR(S_IWRITE) - 属主可写     > U (S_IRWXU)S_IXUSR(S_IEXEC)  - 属主可执行  /--------------------------------S_IRGRP           - 属组可读    \S_IWGRP           - 属组可写     > G (S_IRWXG)S_IXGRP           - 属组可执行  /--------------------------------S_IROTH           - 其它可读    \S_IWOTH           - 其它可写     > O (S_IRWXO)S_IXOTH           - 其它可执行  /

其它说明

1.有关S_ISUID/S_ISGID/S_ISVTX的说明

1) 具有S_ISUID/S_ISGID位的可执行文件,
其有效用户ID/有效组ID,
并不取自由其父进程(比如登录shell)所决定的,
实际用户ID/实际组ID,
而是取自该可执行文件的属主ID/属组ID。
如:/usr/bin/passwd

2) 具有S_ISUID位的目录,
其中的文件或目录除root外,
只有其属主可以删除。

3) 具有S_ISGID位的目录,
在该目录下所创建的文件,继承该目录的属组ID,
而非其创建者进程的有效组ID。

4) 具有S_ISVTX位的可执行文件,
在其首次执行并结束后,
其代码区将被连续地保存在磁盘交换区中,
而一般磁盘文件中的数据块是离散存放的。
因此,下次执行该程序可以获得较快的载入速度。
现代Unix系统大都采用快速文件系统,
已不再需要这种技术。

5) 具有S_ISVTX位的目录,
只有对该目录具有写权限的用户,
在满足下列条件之一的情况下,
才能删除或更名该目录下的文件或目录:

A. 拥有此文件;
B. 拥有此目录;
C. 是超级用户。

如:/tmp

任何用户都可在该目录下创建文件,
任何用户对该目录都享有读/写/执行权限,
但除root以外的任何用户在目录下,
都只能删除或更名属于自己的文件。

辅助分析st_mode

2. 常用以下宏辅助分析st_mode

S_ISDIR() - 是否目录
S_ISREG() - 是否普通文件
S_ISLNK() - 是否软链接
S_ISBLK() - 是否块设备
S_ISCHR() - 是否字符设备
S_ISSOCK() - 是否Unix域套接字
S_ISFIFO() - 是否有名管道

范例:stat.c

#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <time.h>const char* mtos (mode_t m) {    static char s[11];    if (S_ISDIR (m))        strcpy (s, "d");    else    if (S_ISLNK (m))        strcpy (s, "l");    else    if (S_ISBLK (m))        strcpy (s, "b");    else    if (S_ISCHR (m))        strcpy (s, "c");    else    if (S_ISSOCK (m))        strcpy (s, "s");    else    if (S_ISFIFO (m))        strcpy (s, "p");    else        strcpy (s, "-");    strcat (s, m & S_IRUSR ? "r" : "-");    strcat (s, m & S_IWUSR ? "w" : "-");    strcat (s, m & S_IXUSR ? "x" : "-");    strcat (s, m & S_IRGRP ? "r" : "-");    strcat (s, m & S_IWGRP ? "w" : "-");    strcat (s, m & S_IXGRP ? "x" : "-");    strcat (s, m & S_IROTH ? "r" : "-");    strcat (s, m & S_IWOTH ? "w" : "-");    strcat (s, m & S_IXOTH ? "x" : "-");    if (m & S_ISUID)        s[3] = (s[3] == 'x' ? 's' : 'S');    if (m & S_ISGID)        s[6] = (s[6] == 'x' ? 's' : 'S');    if (m & S_ISVTX)        s[9] = (s[9] == 'x' ? 't' : 'T');    return s;}const char* ttos (time_t t) {    static char s[20];    struct tm* lt = localtime (&t);    sprintf (s, "%04d-%02d-%02d %02d:%02d:%02d",        lt->tm_year + 1900,        lt->tm_mon + 1,        lt->tm_mday,        lt->tm_hour,        lt->tm_min,        lt->tm_sec);    return s;}int main (int argc, char* argv[]) {    if (argc < 2)        goto usage;    struct stat st;    if (argc < 3) {        if (stat (argv[1], &st) == -1) {            perror ("stat");            return -1;        }    }    else if (! strcmp (argv[2], "-l")) {        if (lstat (argv[1], &st) == -1) {            perror ("lstat");            return -1;        }    }    else        goto usage;    printf ("           设备ID:%lld\n", st.st_dev);    printf ("          i节点号:%ld\n", st.st_ino);    printf ("             模式:%s\n",        mtos (st.st_mode));    printf ("         硬链接数:%u\n", st.st_nlink);    printf ("           属主ID:%u\n", st.st_uid);    printf ("           属组ID:%u\n", st.st_gid);    printf ("       特殊设备ID:%lld\n", st.st_rdev);    printf ("         总字节数:%ld\n", st.st_size);    printf ("      I/O块字节数:%ld\n", st.st_blksize);    printf ("占用块(512字节)数:%ld\n", st.st_blocks);    printf ("     最后访问时间:%s\n",        ttos (st.st_atime));    printf ("     最后修改时间:%s\n",        ttos (st.st_mtime));    printf (" 最后状态改变时间:%s\n",        ttos (st.st_ctime));    return 0;usage:    fprintf (stderr, "用法:%s <文件> [-l]\n",argv[0]);    return -1;}

四、 access


#include <unistd.h>int access (    const char* pathname, // 文件路径    int         mode      // 访问模式);
  1. 按实际用户ID和实际组ID(而非有效用户ID和有效组ID),
    进行访问模式测试。

  2. 成功返回0,失败返回-1。

  3. mode取R_OK/W_OK/X_OK的位或,
    测试调用进程对该文件,
    是否可读/可写/可执行,
    或者取F_OK,测试该文件是否存在。

范例:access.c

#include <stdio.h>#include <unistd.h>int main (int argc, char* argv[]) {    if (argc < 2) {        fprintf (stderr, "用法:%s <文件>\n", argv[0]);        return -1;    }    printf ("文件%s", argv[1]);    if (access (argv[1], F_OK) == -1)        printf ("不存在(%m)。\n");    else {        if (access (argv[1], R_OK) == -1)            printf ("不可读(%m),");        else            printf ("可读,");        if (access (argv[1], W_OK) == -1)            printf ("不可写(%m),");        else            printf ("可写,");        if (access (argv[1], X_OK) == -1)            printf ("不可执行(%m)。\n");        else            printf ("可执行。\n");    }    return 0;}

五、 umask


可以用umask命令查看/修改当前shell的文件权限屏蔽字:

函数说明

# umask0022# umask 0033# umask0033#include <sys/stat.h>mode_t umask (    mode_t cmask // 屏蔽字);

参数说明

  1. 为进程设置文件权限屏蔽字,并返回以前的值,
    此函数永远成功。

  2. cmask由9个权限宏位或组成(直接写八进制整数形式亦可,
    如022 - 屏蔽属组和其它用户的写权限):


S_IRUSR(S_IREAD) - 属主可读
S_IWUSR(S_IWRITE) - 属主可写
S_IXUSR(S_IEXEC) - 属主可执行


S_IRGRP - 属组可读
S_IWGRP - 属组可写
S_IXGRP - 属组可执行


S_IROTH - 其它可读
S_IWOTH - 其它可写
S_IXOTH - 其它可执行


3 设上屏蔽字以后,此进程所创建的文件,
都不会有屏蔽字所包含的权限。

范例:umask.c

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>int main (void) {    /*    mode_t old = umask (        S_IWUSR | S_IXUSR |        S_IWGRP | S_IXGRP |        S_IWOTH | S_IXOTH);*/    mode_t old = umask (0333);    int fd = open ("umask.txt",        O_RDWR | O_CREAT | O_TRUNC, 0777);    if (fd == -1) {        perror ("open");        return -1;    }    close (fd);    umask (old);    return 0;}

六、 chmod和fchmod


修改文件的权限。

函数说明

#include <sys/stat.h>int chmod (    const char* path, // 文件路径    mode_t      mode  // 文件权限);int fchmod (    int    fd,  // 文件路径    mode_t mode // 文件权限);

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

参数说明

mode为以下值的位或(直接写八进制整数形式亦可,
如07654 - rwSr-sr-T):

S_ISUID - 设置用户ID
S_ISGID - 设置组ID
S_ISVTX - 粘滞


S_IRUSR(S_IREAD) - 属主可读
S_IWUSR(S_IWRITE) - 属主可写
S_IXUSR(S_IEXEC) - 属主可执行


S_IRGRP - 属组可读
S_IWGRP - 属组可写
S_IXGRP - 属组可执行


S_IROTH - 其它可读
S_IWOTH - 其它可写
S_IXOTH - 其它可执行

范例:chmod.c

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>int main (void) {    int fd = open ("chmod.txt",        O_RDWR | O_CREAT | O_TRUNC, 0644);    if (fd == -1) {        perror ("open");        return -1;    }    /*    if (fchmod (fd, 07654) == -1) {// rwSr-sr-T    */    if (fchmod (fd,        S_ISUID | S_ISGID | S_ISVTX |        S_IRUSR | S_IWUSR |        S_IRGRP | S_IXGRP |        S_IROTH) == -1) {        perror ("fchmod");        return -1;    }    close (fd);    return 0;}

七、 chown和fchown以及lchown


函数说明

# chown <uid>:<gid> <file>修改文件的属主和属组。#include <unistd.h>int chown (    const char* path,  // 文件路径    uid_t       owner, // 属主ID    gid_t       group  // 属组ID);int fchown (    int   fildes, // 文件描述符    uid_t owner,  // 属主ID    gid_t group   // 属组ID);int lchown (    const char* path,  // 文件路径(不跟踪软链接)    uid_t       owner, // 属主ID    gid_t       group  // 属组ID);

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

附加说明

注意:

  1. 属主和属组ID取-1表示不修改。

  2. 超级用户进程可以修改文件的属主和属组,
    普通进程必须拥有该文件才可以修改其属主和属组。

八、 truncate和ftruncate


修改文件的长度,截短丢弃,加长添零。

函数说明

#include <unistd.h>int truncate (    const char* path,  // 文件路径    off_t       length // 文件长度);int ftruncate (    int   fd,    // 文件描述符    off_t length // 文件长度);

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

范例:trunc.c

#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/mman.h>int main (void) {    const char* text = "Hello, World !";    size_t size = (strlen (text) + 1) *        sizeof (text[0]);    int fd = open ("trunc.txt",        O_RDWR | O_CREAT | O_TRUNC, 0664);    if (fd == -1) {        perror ("open");        return -1;    }    if (ftruncate (fd, size) == -1) {        perror ("ftruncate");        return -1;    }    void* map = mmap (NULL, size, PROT_READ|PROT_WRITE,        MAP_SHARED/*MAP_PRIVATE*/, fd, 0);    if (map == MAP_FAILED) {        perror ("mmap");        return -1;    }    memcpy (map, text, size);    printf ("%s\n", (char*)map);    munmap (map, size);    close (fd);    return 0;}

范例:mmap.c

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/mman.h>int main (void) {    int fd = open ("trunc.txt", O_RDONLY);    if (fd == -1) {        perror ("open");        return -1;    }    struct stat st;    if (fstat (fd, &st) == -1) {        perror ("fstat");        return -1;    }    void* map = mmap (NULL, st.st_size, PROT_READ,        MAP_SHARED, fd, 0);    if (map == MAP_FAILED) {        perror ("mmap");        return -1;    }    printf ("%s\n", (char*)map);    munmap (map, st.st_size);    close (fd);    return 0;}

附加说明

注意:对于文件映射,
私有映射(MAP_PRIVATE)将数据写到缓冲区而非文件中,
只有自己可以访问。
而对于内存映射,
私有(MAP_PRIVATE)和公有(MAP_SHARED)没有区别,
都是仅自己可以访问。

九、 link和unlink 、 remove和rename


link: 创建文件的硬链接(目录条目)。

unlink: 删除文件的硬链接(目录条目)。
只有当文件的硬链接数降为0时,文件才会真正被删除。
若该文件正在被某个进程打开,
其内容直到该文件被关闭才会被真正删除。

remove: 对文件同unlink,
对目录同rmdir (不能删非空目录)。

rename: 修改文件/目录名。

#include <unistd.h>int link (    const char* path1, // 文件路径    const char* path2  // 链接路径);int unlink (    const char* path // 链接路径);#include <stdio.h>int remove (    const char* pathname // 文件/目录路径);int rename (    const char* old, // 原路径名    const char* new  // 新路径名);

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

注意:硬链接只是一个文件名,即目录中的一个条目。
软链接则是一个独立的文件,
其内容是另一个文件的路径信息。

十、 symlink / readlink


symlink: 创建软链接。目标文件可以不存在,
也可以位于另一个文件系统中。

readlink: 获取软链接文件本身(而非其目标)的内容。
open不能打开软链接文件本身。

#include <unistd.h>int symlink (    const char* oldpath, // 文件路径(可以不存在)    const char* newpath  // 链接路径);成功返回0,失败返回-1。ssize_t readlink (    const char* restrict path,   // 软链接文件路径    char* restrict       buf,    // 缓冲区    size_t               bufsize // 缓冲区大小);

成功返回实际拷入缓冲区buf中软链接文件内容的字节数,
失败返回-1。

范例:slink.c

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <limits.h>int main (int argc, char* argv[]) {    if (argc < 3) {        fprintf (stderr,            "用法:%s <文件> <软链接>\n", argv[0]);        return -1;    }    if (symlink (argv[1], argv[2]) == -1) {        perror ("symlink");        return -1;    }    char slink[PATH_MAX+1] = {};    if (readlink (argv[2], slink,        sizeof (slink) - sizeof (slink[0])) == -1) {        perror ("readlink");        return -1;    }    printf ("%s是%s的软链接。\n", argv[2], slink);    return 0;}

十一、 mkdir / rmdir


mkdir: 创建一个空目录。

rmdir: 删除一个空目录。

#include <sys/stat.h>int mkdir (    const char* path, // 目录路径    mode_t      mode  // 访问权限,                      // 目录的执行权限(x)表示可进入);#include <unistd.h>int rmdir (    const char* path // 目录路径);

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

十二、 chdir / fchdir / getcwd


chdir/fchdir: 更改当前工作目录。
工作目录是进程的属性,只影响调用进程本身。

getcwd: 获取当前工作目录。

#include <unistd.h>int chdir (    const char* path // 工作目录路径);int fchdir (    int fildes // 工作目录描述符(由open函数返回));//成功返回0,失败返回-1。char* getcwd (    char*  buf, // 缓冲区    size_t size // 缓冲区大小);

成功返回当前工作目录字符串指针,失败返回NULL。

十三、 opendir / fdopendir / closedir / readdir / rewinddir / telldir / seekdir


基本说明

opendir/fdopendir: 打开目录流。

closedir: 关闭目录流。

readdir: 读取目录流。

rewinddir: 复位目录流。

telldir: 获取目录流当前位置。

seekdir: 设置目录流当前位置。

函数说明

#include <sys/types.h>#include <dirent.h>DIR* opendir (    const char* name // 目录路径);DIR* fdopendir (    int fd // 目录描述符(由open函数返回));

成功返回目录流指针,失败返回NULL。

int closedir (    DIR* dirp // 目录流指针);

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

struct dirent* readdir (    DIR* dirp // 目录流指针);

成功返回下一个目录条目结构体的指针,
到达目录尾(不置errno)或失败(设置errno)返回NULL。

struct dirent {    ino_t          d_ino;       // i节点号    off_t          d_off;       // 下一条目的偏移量                                // 注意是磁盘偏移量                                // 而非内存地址偏移    unsigned short d_reclen;    // 记录长度    unsigned char  d_type;      // 文件类型    char           d_name[256]; // 文件名};

参数说明

d_type取值:

DT_DIR - 目录
DT_REG - 普通文件
DT_LNK - 软链接
DT_BLK - 块设备
DT_CHR - 字符设备
DT_SOCK - Unix域套接字
DT_FIFO - 有名管道
DT_UNKNOWN - 未知

图示:de.bmp
这里写图片描述

范例:list.c

练习:打印给定路径下的目录树。

代码:tree.c

void rewinddir (
DIR* dirp // 目录流指针
);

long telldir (
DIR* dirp // 目录流指针
);

成功返回目录流的当前位置,失败返回-1。

void seekdir (
DIR* dirp, // 目录流指针
long offset // 位置偏移量
);

目录流:            +-----------------------+           +-----------------------+            |                       v           |                       v+-------+---|---+-----+-------+     +-------+---|---+-----+-------+     +-------| d_ino | d_off | ... | a.txt | ... | d_ino | d_off | ... | b.txt | ... | d_ino+-------+-------+-----+-------+     +-------+-------+-----+-------+     +-------^                                   ^|          -- readdir() ->          |

范例:seek.c

#include <stdio.h>#include <dirent.h>#include <errno.h>int main (int argc, char* argv[]) {    if (argc < 2) {        fprintf (stderr, "用法:%s <目录>\n", argv[0]);        return -1;    }    DIR* dp = opendir (argv[1]);    if (! dp) {        perror ("opendir");        return -1;    }    seekdir (dp, 686782084);    rewinddir (dp);    long offset = telldir (dp);    if (offset == -1) {        perror ("telldir");        return -1;    }    errno = 0;    struct dirent* de;    for (de = readdir (dp); de; de = readdir (dp)) {        printf ("[%010ld %010ld] ", offset, de->d_off);        switch (de->d_type) {            case DT_DIR:                printf ("        目录:");                break;            case DT_REG:                printf ("    普通文件:");                break;            case DT_LNK:                printf ("      软链接:");                break;            case DT_BLK:                printf ("      块设备:");                break;            case DT_CHR:                printf ("    字符设备:");                break;            case DT_SOCK:                printf ("Unix域套接字:");                break;            case DT_FIFO:                printf ("    有名管道:");                break;            default:                printf ("        未知:");                break;        }        printf ("%s\n", de->d_name);        if ((offset = telldir (dp)) == -1) {            perror ("telldir");            return -1;        }    }    if (errno) {        perror ("readdir");        return -1;    }    closedir (dp);    return 0;}
1 0
原创粉丝点击