您的位置:首页 > 其它

uc笔记06---chmod/fchmod,chown/fchown/lchown

2015-09-30 16:58 393 查看
1. 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 U G D

7 6 5 4

4 2 1 4 2 0 4 0 1 4 0 0

ugt rw- r-x r-- -> 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 <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) {

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;

}

2. 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. 超级用户进程可以修改文件的属主和属组,

普通进程必须拥有该文件才可以修改其属主和属组。

3. 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 <fcntl.h>

#include <sys/mman.h>

int main (void) {

const char* text = "Hello, World !";

size_t size = (strlen (text) + 1) * sizeof (text[0]); // +1 给 \0 用

int fd = open ("trunc.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);

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", map);

// 解映射

munmap (map, size);

close (fd);

return 0;

}

运行测试:

#gcc trunc.c

#hexdump -C trunc.txt // 十六进制查看

#./a.out

Hello, World !

在 trunc.txt 建立好的基础上,我们写下面的测试程序,实现两个程序之间共享数据:

范例:mmap.c

#include <stdio.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", map);

munmap (map, st.st_size);

close (fd);

return 0;

}

运行测试:

#gcc mmap.c

#hexdump -C trunc.txt // 十六进制查看

#./a.out

Hello, World !

注意:对于文件映射,

私有映射 (MAP_PRIVATE) 将数据写到缓冲区而非文件中,只有自己可以访问。

而对于内存映射,

私有 (MAP_PRIVATE) 和公有 (MAP_SHARED) 没有区别,都是仅自己可以访问。

4. 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。

5. 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 <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] = {0}; // 目标文件路径

if (readlink (argv[2], slink,

sizeof (slink) - sizeof (slink[0])) == -1) { // - sizeof (slink[0] 用于留一位给 \0

perror ("readlink");

return -1;

}

printf ("%s是%s的软链接。\n", argv[2], slink);

return 0;

}

运行测试:

#./a.out

#./a.out none.txt slink.txt

slink.txt 是 none.txt 的软链接。

slink.txt 大小为 8 字节,刚好是 none.txt 的名字大小;

而 none.txt 大小为 20 字节,里面存放的是真正的内容,所以较大;

6. 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。

7. 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。

范例:dir.c

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <limits.h>

int main (void) {

char cwd[PATH_MAX+1]; // 用于装载当前目录

if (! getcwd (cwd, sizeof (cwd))) {

perror ("getcwd");

return -1;

}

printf ("当前工作目录:%s\n", cwd);

// 创建目录

if (mkdir ("work", 0755) == -1) {

perror ("mkdir");

return -1;

}

// 相当于 cd,进入目录

if (chdir ("work") == -1) {

perror ("chdir");

return -1;

}

if (! getcwd (cwd, sizeof (cwd))) {

perror ("getcwd");

return -1;

}

printf ("当前工作目录:%s\n", cwd);

if (mkdir ("empty", 0755) == -1) {

perror ("mkdir");

return -1;

}

if (rmdir ("empty") == -1) {

perror ("rmdir");

return -1;

}

// 如果没有删除 empty,下面这段代码就会报错,因为 work 目录非空;

if (rmdir ("../work") == -1) {

perror ("rmdir");

return -1;

}

return 0;

}

8. 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 - 未知

范例:list.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;

}

errno = 0;

struct dirent* de;

for (de = readdir (dp); de; de = readdir (dp)) {

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 (errno) {

perror ("readdir");

return -1;

}

closedir (dp);

return 0;

}

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

代码:tree.c

#include <stdio.h>

#include <dirent.h>

#include <errno.h>

/*

#include <limits.h>

*/

int tree (const char* dir, size_t depth) {

DIR* dp = opendir (dir);

if (! dp) {

perror ("opendir");

return -1;

}

if (chdir (dir) == -1) { // 进入目录

perror ("chdir");

return -1;

}

errno = 0;

struct dirent* de;

for (de = readdir (dp); de; de = readdir (dp))

if (de -> d_type != DT_DIR)

printf ("%*s%s\n", depth * 2, "", de -> d_name); // 缩进

else if (strcmp (de -> d_name, ".") && // 不能进入本目录和父目录

strcmp (de -> d_name, "..")) {

printf ("%*s%s/\n", depth * 2, "", de -> d_name);

/*

char subdir[PATH_MAX+1];

sprintf (subdir, "%s/%s", dir, de -> d_name);

if (tree (subdir, depth + 1) == -1)

return -1;

*/

if (tree (de -> d_name, depth + 1) == -1)

return -1;

}

if (errno) { // errno 非零则表示出错

perror ("readdir");

return -1;

}

if (chdir ("..") == -1) {

perror ("chdir");

return -1;

}

closedir (dp);

return 0;

}

int main (int argc, char* argv[]) {

if (argc < 2) {

fprintf (stderr, "用法:%s <目录>\n", argv[0]);

return -1;

}

return tree (argv[1], 0);

}

回到头位置:

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, 1722002057); // 设置起始位置

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 ("[%010d %010d] ", 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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: