文件 I/O
2
时 以 新 调 。
EINTR
或 给出的时 。
EINVAL n
的内存 。
ENOMEM
2.10.2.1 select() 示例程序
我们 的 程 然 单 对 select() 的
。 子 stdin 的 的 时 设 。
5
文件 实 上 调 的 。
I/O
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define TIMEOUT 5 /* select timeout in seconds */
#define BUF_LEN 1024 /* read buffer in bytes */
int main (void)
{
struct timeval tv;
fd_set readfds;
int ret;
/* Wait on stdin for input. */
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
/* Wait up to five seconds. */
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
/* All right, now block! */
ret = select (STDIN_FILENO + 1,
&readfds,
NULL,
NULL,
– 53 –
文件 I/O
2
&tv);
if (ret == -1) {
perror (”select”);
return 1;
} else if (!ret) {
printf (”%d seconds elapsed.\\n”, TIMEOUT);
return 0;
}
/*
* Is our file descriptor ready to read?
* (It must be, as it was the only fd that
* we provided and the call returned
* nonzero, but we will humor ourselves.)
*/
if (FD_ISSET(STDIN_FILENO, &readfds)) {
char buf[BUF_LEN+1];
int len;
/* guaranteed to not block */
len = read (STDIN_FILENO, buf, BUF_LEN);
if (len == -1) {
perror (”read”);
return 1;
}
if (len) {
buf[len] = ’\\0’;
printf (”read: %s\\n”, buf);
}
return 0;
}
fprintf (stderr, ”This should not happen!\\n”);
– 54 –
文件 I/O
4
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/uio.h>
int main ()
{
struct iovec iov[3];
ssize_t nr;
int fd, i;
char *buf[] = {”The term buccaneer comes from
the word boucan.\\n”, ”A boucan is a wooden
frame used for cooking meat.\\n”, ”Buccaneer
is the West Indies name for a pirate.\\n” };
fd = open (”buccaneer.txt”, O_WRONLY | O_CREAT
| O_TRUNC);
if (fd == -1) {
perror (”open”);
return 1;
}
/* fill out three iovec structures */
for (i = 0; i < 3; i++) {
iov[i].iov_base = buf[i];
iov[i].iov_len = strlen (buf[i]+1);
}
/* with a single call, write them all out */
nr = writev (fd, iov, 3);
if (nr == -1) {
perror (”writev”);
return 1;
}
– 92 –
文件 I/O
4
printf (”wrote %d bytes\\n”, nr);
if (close (fd)) {
perror (”close”);
return 1;
}
return 0;
}
程 :
$ ./writev
wrote 148 bytes
读 文件 内 :
$ cat buccaneer.txt
The term buccaneer comes from the word boucan.
A boucan is a wooden frame used for cooking meat.
Buccaneer is the West Indies name for a pirate.
4.1.1.3 readv() 示例
我们 的文 文件读 。 程 同
readv()
单:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
int main ()
{
char foo[48], bar[51], baz[49];
struct iovec iov[3];
ssize_t nr;
– 93 –
文件 I/O
4
int fd, i;
fd = open (”buccaneer.txt”, O_RDONLY);
if (fd == -1) {
perror (”open”);
return 1;
}
/* set up our iovec structures */
iov[0].iov_base = foo;
iov[0].iov_len = sizeof (foo);
iov[1].iov_base = bar;
iov[1].iov_len = sizeof (bar);
iov[2].iov_base = baz;
iov[2].iov_len = sizeof (baz);
/* read into the structures with a single call
*/
nr = readv (fd, iov, 3);
if (nr == -1) {
perror (”readv”);
return 1;
}
for (i = 0; i < 3; i++)
printf (”%d: %s”, i, (char *)
iov[i].iov_base);
if (close (fd)) {
perror (”close”);
return 1;
}
return 0;
}
上 程 程 出
$ ./readv
– 94 –
文件 I/O
4
0: The term buccaneer comes from the word boucan.
1: A boucan is a wooden frame used for cooking meat.
2: Buccaneer is the West Indies name for a pirate.
4.1.1.4 实现
我们 以 空间实 单的 readv() 的
writev()
#include <unistd.h>
#include <sys/uio.h>
ssize_t naive_writev (int fd, const struct iovec
*iov, int count)
{
ssize_t ret = 0;
int i;
for (i = 0; i < count; i++) {
ssize_t nr;
nr = write (fd, iov[i].iov_base,
iov[i].iov_len);
if (nr == -1) {
ret = -1;
break;
}
ret += nr;
}
return ret;
}
的 Linux 的实 writev() 作 调
Linux readv()
实 内 散布 / 聚集 I/O。实 上 内 的 I/O I/O
的 段。
read() write() I/O
– 95 –
文件 I/O
4
。
内 提 文件 理 的方 。 调
ioctl()
我们将 提
FIBMAP
ret = ioctl (fd, FIBMAP, &block);
if (ret < 0)
perror (”ioctl”);
文件的文件 我们 理
fd block
的 。调 理 。
block 0
文件相 。 文件 效
8 0 7。
理 的映射 步。 步 文件 的 。
以 stat() 调 。 对 我们 ioctl() 调
相 的 理 。
以 示 程 对 的文件进 相 操作
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
/*
* get_block - for the file associated with the
given fd, returns
* the physical block mapping to logical_block
*/
int get_block (int fd, int logical_block)
{
int ret;
ret = ioctl (fd, FIBMAP, &logical_block);
if (ret < 0) {
– 129 –
文件 I/O
4
perror (”ioctl”);
return -1;
}
return logical_block;
}
/*
* get_nr_blocks - returns the number of logical
blocks
* consumed by the file associated with fd
*/
int get_nr_blocks (int fd)
{
struct stat buf;
int ret;
ret = fstat (fd, &buf);
if (ret < 0) {
perror (”fstat”);
return -1;
}
return buf.st_blocks;
}
/*
* print_blocks - for each logical block consumed
by the file
* associated with fd, prints to standard out the
tuple
* ”(logical block, physical block)”
*/
void print_blocks (int fd)
{
int nr_blocks, i;
nr_blocks = get_nr_blocks (fd);
– 130 –
文件 I/O
4
if (nr_blocks < 0) {
fprintf (stderr, ”get_nr_blocks failed!\\n”);
return;
}
if (nr_blocks == 0) {
printf (”no allocated blocks\\n”);
return;
} else if (nr_blocks == 1)
printf (”1 block\\n\\n”);
else
printf (”%d blocks\\n\\n”, nr_blocks);
for (i = 0; i < nr_blocks; i++) {
int phys_block;
phys_block = get_block (fd, i);
if (phys_block < 0) {
fprintf (stderr, ”get_block failed!\\n”);
return;
}
if (!phys_block)
continue;
printf (”(%u, %u) ”, i, phys_block);
}
putchar (’\\n’);
}
int main (int argc, char *argv[])
{
int fd;
if (argc < 2) {
fprintf (stderr, ”usage: %s <file>\\n”,
argv[0]);
return 1;
}
– 131 –
文件 理
7
int main (int argc, char *argv[])
{
struct stat sb;
int ret;
if (argc < 2) {
fprintf (stderr, ” usage %s <file>\\n”,
argv[0]);
return 1;
}
ret = stat (argv[1], &sb);
if (ret) {
perror (”stat”);
return 1;
}
printf (”%s is %ld bytes\\n”, argv[1],
sb.st_size);
return 0;
}
程 自 文件上的
$ ./stat stat.c
stat.c is 392 bytes
以 段 的文件 理(或 相对
fstat()
的 设备上
/*
* is_on_physical_device – returns a positive
* integer if ’fd’ resides on a physical device,
* 0 if the file resides on a nonphysical or
* virtual device (e.g., on an NFS mount), and
* -1 on error.
*/
– 210 –
文件 理
7
int is_on_physical_device (int fd)
{
struct stat sb;
int ret;
ret = fstat (fd, &sb);
if (ret) {
perror (”fstat”);
return -1;
}
return gnu_dev_major (sb.st_dev);
}
7.1.2 权限
调 给 文件的 调 设
stat
#include <sys/types.h>
#include <sys/stat.h>
int chmod (const char *path, mode_t mode);
int fchmod (int fd, mode_t mode);
设 文件
chmod() fchmod() mode。 chmod() path
的文件的相对或绝对 。对 文件 文件 fd 给
fchmod()
。
示的 mode 段 st mode
mode t( ) stat
的 。 然 单 们对 Unix 实 的
同 的。 以 的 集( 新文件的
POSIX 2
能 进 或 。
)。 mode (S IRUSR |
S IRGRP) 同时设 文件 属 的 读 。
文件的 调 chmod() 或 fchmod() 的进程 效 ID 文件
或 进程 CAP FOWNER 能 。
时 时 设
0。 -1 errno
– 211 –
文件 理
7
调 的进程 对 的
path
EACCESS
( chmod() 。
效的文件 fchmod() 。
fd(
EBADF
效的 path ( chmod() 。
EFAULT
文件 内 。 的 的
I/O
EIO
的 或文件 。
内 path 时 ( chmod() 。
ELOOP
( chmod() 。
ENAMETOOLONG path
存 ( chmod() 。
path
ENOENT
内存 。
ENOMEM
( chmod() 。
path
ENOTDIR
调 的进程 效 ID 文件 进程
EPERM
CAP FOWNER 能 。
文件 读文件 上。
EROFS
段 将文件 map.png 设 读 写
int ret;
/*
* Set ’map.png’ in the current directory to
* owner-readable and -writable. This is the
* same as ’chmod 600 ./map.png’.
*/
ret = chmod (”./map.png”, S_IRUSR | S_IWUSR);
if (ret)
perror (”chmod”);
段 上段 能 的文件 map.png
fd
int ret;
/*
* Set the file behind ’fd’ to owner-readable
* and -writable.
*/
– 212 –
文件 理
7
内 I/O ( )。
EIO
内 path 时 ( chown()
ELOOP
lchown() 。
(
ENAMETOOLONG path chown() lchown() )。
文件 存 。
ENOENT
内存 。
ENOMEM
的 (
path chown()
ENOTDIR
。
lchown()
调 的进程 的 或
EPERM
属 。
读的文件 。
EROFS
段 工作 文件 manifest.txt 的 属 officers。
操作 调 的 备 CAP CHOWN 能 或 kidd
officers
struct group *gr;
int ret;
/*
* getgrnam( ) returns information on a group
* given its name.
*/
gr = getgrnam (”officers”);
if (!gr) {
/* likely an invalid group */
perror (”getgrnam”);
return 1;
}
/* set manifest.txt’s group to ’officers’ */
ret = chown (”manifest.txt”, -1, gr->gr_gid);
if (ret)
perror (”chown”);
操作 文件 属 crew
– 214 –
文件 理
7
$ ls –l
-rw-r--r-- 1 kidd crew 13274 May 23 09:20 manifest.txt
操作 以
officers
$ ls –l
-rw-r--r-- 1 kidd officers 13274 May 23 09:20 manifest.txt
文件的 -1 给 uid。以 将
kidd
的文件的 设
fd root
/*
* make_root_owner - changes the owner and group
of the file
* given by ’fd’ to root. Returns 0 on success and
-1 on
* failure.
*/
int make_root_owner (int fd)
{
int ret;
/* 0 is both the gid and the uid for root */
ret = fchown (fd, 0, 0);
if (ret)
perror (”fchown”);
return ret;
}
调 的进程 CAP CHOWN 能 。 进程 CAP CHOWN
的能 进程 。
root
7.1.4 扩展属性
扩展属性 ( 作 xattrs) 提 文件 对相 的
/
。 我们 文件 的 的 文件的
/
– 215 –
文件 理
7
char *swd;
int ret;
/* save the current working directory */
swd = getcwd (NULL, 0);
if (!swd) {
perror (”getcwd”);
exit (EXIT_FAILURE);
}
/* change to a different directory */
ret = chdir (some_other_dir);
if (ret) {
perror (”chdir”);
exit (EXIT_FAILURE);
}
/* do some other work in the new directory... */
/* return to the saved directory */
ret = chdir (swd);
if (ret) {
perror (”chdir”);
exit (EXIT_FAILURE);
}
free (swd);
调 方 更 。内 内
open() fchdir()
存 存 工作 的 存 inode 以 方 更 。
何时 调 内 。相
getcwd()
工作 的 更 内 inode,
文件。 的 方
int swd_fd;
swd_fd = open (”.”, O_RDONLY);
if (swd_fd == -1) {
perror (”open”);
– 228 –
文件 理
7
exit (EXIT_FAILURE);
}
/* change to a different directory */
ret = chdir (some_other_dir);
if (ret) {
perror (”chdir”);
exit (EXIT_FAILURE);
}
/* do some other work in the new directory... */
/* return to the saved directory */
ret = fchdir (swd_fd);
if (ret) {
perror (”fchdir”);
exit (EXIT_FAILURE);
}
/* close the directory’s fd */
ret = close (swd_fd);
if (ret) {
perror (”close”);
exit (EXIT_FAILURE);
}
存以 的方 ( cd 。
shell bash
工作 的进程( 进程 调 chdir(”/”) 设
工作 及 及 的 程 文 处
/。 (
理 设 工作 或 的文 。 工
)
作 相对 相 更 工作 shell 调 的
实 工 实 的。
7.2.2 创建目录
新 提 的 POSIX 调
Linux
#include <sys/stat.h>
– 229 –
文件 理
7
的程 以 CD-ROM 设备 出
CDROMEJECT
。设备 程 的 。 程 的 能 eject
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/cdrom.h>
#include <stdio.h>
int main (int argc, char *argv[])
{
int fd, ret;
if (argc < 2) {
fprintf (stderr, ”usage: %s <device to
eject>\\n”, argv[0]);
return 1;
}
/*
* Opens the CD-ROM device, read-only. O_NONBLOCK
* tells the kernel that we want to open the
device
* even if there is no media present in the
drive.
*/
fd = open (argv[1], O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror (”open”);
return 1;
}
/* Send the eject command to the CD-ROM device.
– 245 –
0 comments
Post a comment