2.Linux文件IO编程

2.1Linux文件IO概述

2.1.0POSIX规范

POSIX:(Portable Operating System Interface)可移植操作系统接口规范。

由IEEE制定,是为了提高UNIX(也适用于Linux)环境下应用程序的可移植性。

2.1.1虚拟文件系统

Linux具有与其他操作系统和谐共存的能力。

Linux文件系统由两层构建:第一层是虚拟文件系统(VFS),第二层是各种不同的具体的文件系统。

VFS把各种具体的文件系统的公共部分抽取出来,形成一个抽象层,是系统内核的一部分。

位于用户程序和具体的文件系统之间,为用户程序提供标准的文件系统调用接口。对用户屏蔽底层文件系统的实现细节和差异。

2.Linux文件IO编程

 nodev    sysfs
nodev rootfs
nodev ramfs
nodev bdev
nodev proc
nodev cpuset
nodev cgroup
nodev tmpfs
nodev devtmpfs
nodev debugfs
nodev tracefs
nodev securityfs
nodev sockfs
nodev bpf
nodev pipefs
nodev devpts
ext3
ext2
ext4
squashfs
nodev hugetlbfs
vfat
nodev ecryptfs
fuseblk
nodev fuse
nodev fusectl
nodev pstore
nodev mqueue
nodev rpc_pipefs
nodev nfs
nodev nfs4
nodev nfsd

cat /proc/filesystems

2.1.2 文件和文件描述符

Linux文件系统是基于文件概念的。文件是以字符序列构成的信息载体。可以把IO设备当做文件来处理。

Linux中的文件主要分为6种:普通文件、目录文件、符号链接文件、管道文件、套接字文件和设备文件。

一个进程启动时,都会打开3个流,标准输入、标准输出和标准错误。

对应的文件描述符0、1、2,宏分别STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。

2.1.3 文件IO和标准IO的区别

1.只要在开发环境中有标准C库,标准IO就可以使用。Linux既可以使用标准IO,也可以使用文件IO。

2.通过文件IO读写文件时,每次操作都会执行相关系统调用。好处:直接读写实际文件。坏处:频繁的系统调用会增加系统开销。

3.文件IO中用文件描述符表示一个打开的文件,可以访问不同类型的文件(普通文件、管道文件、设备文件等)。

标准IO中用FILE(流)表示一个打开的文件,通常只是用来访问普通文件。

2.2文件IO操作

主要介绍文件IO相关函数:open()、read()、write()、lseek()和close()。它们不带缓冲,直接对文件(包括设备)进行读写操作。

2.2.1 文件打开和关闭

打开:

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

说明:open用于创建或打开文件,在打开或创建文件时可以指定文件打开方式及文件的访问权限。

关闭: int close(int fd);

说明:用于关闭一个被打开的文件。当一个进程终止时,所有打开的文件都有内核自动关闭。

        很多程序都利用这一特性而不显式地关闭一个文件。

 /*******************************************************************
* > File Name: 01-open.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Sun 03 Sep 2017 09:01:10 PM CST
******************************************************************/ #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> int main(int argc, char* argv[])
{
int fd; if((fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, )) < ){
perror("Fail to open test.txt :");
return (-);
}else{
printf("Succeed to open test.txt, fd = %d\n ", fd);
} close(fd); return ;
}

open.c

 OPEN()                                       Linux Programmer's Manual                                      OPEN(2)

 NAME
open, creat - open and possibly create a file or device SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode); int creat(const char *pathname, mode_t mode); DESCRIPTION
Given a pathname for a file, open() returns a file descriptor, a small, nonnegative integer for use in subse‐
quent system calls (read(), write(), lseek(), fcntl(), etc.). The file descriptor returned by a success‐
ful call will be the lowest-numbered file descriptor not currently open for the process. By default, the new file descriptor is set to remain open across an execve() (i.e., the FD_CLOEXEC file
descriptor flag described in fcntl() is initially disabled; the O_CLOEXEC flag, described below, can be used
to change this default). The file offset is set to the beginning of the file (see lseek()). A call to open() creates a new open file description, an entry in the system-wide table of open files. This
entry records the file offset and the file status flags (modifiable via the fcntl() F_SETFL operation). A
file descriptor is a reference to one of these entries; this reference is unaffected if pathname is subse‐
quently removed or modified to refer to a different file. The new open file description is initially not
shared with any other process, but sharing may arise via fork(). The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR. These
request opening the file read-only, write-only, or read/write, respectively. In addition, zero or more file creation flags and file status flags can be bitwise-or'd in flags. The file
creation flags are O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TRUNC, and O_TTY_INIT.
The file status flags are all of the remaining flags listed below. The distinction between these two groups
of flags is that the file status flags can be retrieved and (in some cases) modified using fcntl(). The
full list of file creation flags and file status flags is as follows: O_APPEND
The file is opened in append mode. Before each write(), the file offset is positioned at the end of
the file, as if with lseek(). O_APPEND may lead to corrupted files on NFS filesystems if more than
one process appends data to a file at once. This is because NFS does not support appending to a file,
so the client kernel has to simulate it, which can't be done without a race condition. O_ASYNC
Enable signal-driven I/O: generate a signal (SIGIO by default, but this can be changed via fcntl())
when input or output becomes possible on this file descriptor. This feature is available only for
terminals, pseudoterminals, sockets, and (since Linux 2.6) pipes and FIFOs. See fcntl() for further
details. O_CLOEXEC (Since Linux 2.6.)
Enable the close-on-exec flag for the new file descriptor. Specifying this flag permits a program to
avoid additional fcntl() F_SETFD operations to set the FD_CLOEXEC flag. Additionally, use of this
flag is essential in some multithreaded programs since using a separate fcntl() F_SETFD operation to
set the FD_CLOEXEC flag does not suffice to avoid race conditions where one thread opens a file
descriptor at the same time as another thread does a fork() plus execve(). O_CREAT
If the file does not exist it will be created. The owner (user ID) of the file is set to the effec‐
tive user ID of the process. The group ownership (group ID) is set either to the effective group ID
of the process or to the group ID of the parent directory (depending on filesystem type and mount
options, and the mode of the parent directory, see the mount options bsdgroups and sysvgroups
described in mount()). mode specifies the permissions to use in case a new file is created. This argument must be supplied
when O_CREAT is specified in flags; if O_CREAT is not specified, then mode is ignored. The effective
permissions are modified by the process's umask in the usual way: The permissions of the created file
are (mode & ~umask). Note that this mode applies only to future accesses of the newly created file;
the open() call that creates a read-only file may well return a read/write file descriptor. The following symbolic constants are provided for mode: S_IRWXU user (file owner) has read, write and execute permission S_IRUSR user has read permission S_IWUSR user has write permission S_IXUSR user has execute permission S_IRWXG group has read, write and execute permission S_IRGRP group has read permission S_IWGRP group has write permission S_IXGRP group has execute permission S_IRWXO others have read, write and execute permission S_IROTH others have read permission S_IWOTH others have write permission S_IXOTH others have execute permission O_DIRECT (Since Linux 2.4.)
Try to minimize cache effects of the I/O to and from this file. In general this will degrade perfor‐
mance, but it is useful in special situations, such as when applications do their own caching. File
I/O is done directly to/from user-space buffers. The O_DIRECT flag on its own makes an effort to
transfer data synchronously, but does not give the guarantees of the O_SYNC flag that data and neces‐
sary metadata are transferred. To guarantee synchronous I/O, O_SYNC must be used in addition to
O_DIRECT. See NOTES below for further discussion. A semantically similar (but deprecated) interface for block devices is described in raw(). O_DIRECTORY
If pathname is not a directory, cause the open to fail. This flag is Linux-specific, and was added in
kernel version 2.1., to avoid denial-of-service problems if opendir() is called on a FIFO or tape
device. O_EXCL Ensure that this call creates the file: if this flag is specified in conjunction with O_CREAT, and
pathname already exists, then open() will fail. When these two flags are specified, symbolic links are not followed: if pathname is a symbolic link,
then open() fails regardless of where the symbolic link points to. In general, the behavior of O_EXCL is undefined if it is used without O_CREAT. There is one excep‐
tion: on Linux 2.6 and later, O_EXCL can be used without O_CREAT if pathname refers to a block device.
If the block device is in use by the system (e.g., mounted), open() fails with the error EBUSY. On NFS, O_EXCL is supported only when using NFSv3 or later on kernel 2.6 or later. In NFS environ‐
ments where O_EXCL support is not provided, programs that rely on it for performing locking tasks will
contain a race condition. Portable programs that want to perform atomic file locking using a lock‐
file, and need to avoid reliance on NFS support for O_EXCL, can create a unique file on the same
filesystem (e.g., incorporating hostname and PID), and use link() to make a link to the lockfile. If
link() returns , the lock is successful. Otherwise, use stat() on the unique file to check if its
link count has increased to , in which case the lock is also successful. O_LARGEFILE
(LFS) Allow files whose sizes cannot be represented in an off_t (but can be represented in an off64_t)
to be opened. The _LARGEFILE64_SOURCE macro must be defined (before including any header files) in
order to obtain this definition. Setting the _FILE_OFFSET_BITS feature test macro to (rather than
using O_LARGEFILE) is the preferred method of accessing large files on -bit systems (see fea‐
ture_test_macros()). O_NOATIME (Since Linux 2.6.)
Do not update the file last access time (st_atime in the inode) when the file is read(). This flag
is intended for use by indexing or backup programs, where its use can significantly reduce the amount
of disk activity. This flag may not be effective on all filesystems. One example is NFS, where the
server maintains the access time. O_NOCTTY
If pathname refers to a terminal device—see tty()—it will not become the process's controlling termi‐
nal even if the process does not have one. O_NOFOLLOW
If pathname is a symbolic link, then the open fails. This is a FreeBSD extension, which was added to
Linux in version 2.1.. Symbolic links in earlier components of the pathname will still be fol‐
lowed. See also O_NOPATH below. O_NONBLOCK or O_NDELAY
When possible, the file is opened in nonblocking mode. Neither the open() nor any subsequent opera‐
tions on the file descriptor which is returned will cause the calling process to wait. For the han‐
dling of FIFOs (named pipes), see also fifo(). For a discussion of the effect of O_NONBLOCK in con‐
junction with mandatory file locks and with file leases, see fcntl(). O_PATH (since Linux 2.6.)
Obtain a file descriptor that can be used for two purposes: to indicate a location in the filesystem
tree and to perform operations that act purely at the file descriptor level. The file itself is not
opened, and other file operations (e.g., read(), write(), fchmod(), fchown(), fgetxattr(),
mmap()) fail with the error EBADF. The following operations can be performed on the resulting file descriptor: * close(); fchdir() (since Linux 3.5); fstat() (since Linux 3.6). * Duplicating the file descriptor (dup(), fcntl() F_DUPFD, etc.). * Getting and setting file descriptor flags (fcntl() F_GETFD and F_SETFD). * Retrieving open file status flags using the fcntl() F_GETFL operation: the returned flags will
include the bit O_PATH. * Passing the file descriptor as the dirfd argument of openat() and the other "*at()" system calls. * Passing the file descriptor to another process via a UNIX domain socket (see SCM_RIGHTS in
unix()). When O_PATH is specified in flags, flag bits other than O_DIRECTORY and O_NOFOLLOW are ignored. If the O_NOFOLLOW flag is also specified, then the call returns a file descriptor referring to the
symbolic link. This file descriptor can be used as the dirfd argument in calls to fchownat(),
fstatat(), linkat(), and readlinkat() with an empty pathname to have the calls operate on the sym‐
bolic link. O_SYNC The file is opened for synchronous I/O. Any write()s on the resulting file descriptor will block the
calling process until the data has been physically written to the underlying hardware. But see NOTES
below. O_TRUNC
If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or
O_WRONLY) it will be truncated to length . If the file is a FIFO or terminal device file, the
O_TRUNC flag is ignored. Otherwise the effect of O_TRUNC is unspecified. Some of these optional flags can be altered using fcntl() after the file has been opened. creat() is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC. RETURN VALUE
open() and creat() return the new file descriptor, or - if an error occurred (in which case, errno is set
appropriately). ERRORS
EACCES The requested access to the file is not allowed, or search permission is denied for one of the direc‐
tories in the path prefix of pathname, or the file did not exist yet and write access to the parent
directory is not allowed. (See also path_resolution().) EDQUOT Where O_CREAT is specified, the file does not exist, and the user's quota of disk blocks or inodes on
the filesystem has been exhausted. EEXIST pathname already exists and O_CREAT and O_EXCL were used. EFAULT pathname points outside your accessible address space. EFBIG See EOVERFLOW. EINTR While blocked waiting to complete an open of a slow device (e.g., a FIFO; see fifo()), the call was
interrupted by a signal handler; see signal(). EINVAL The filesystem does not support the O_DIRECT flag. See NOTES for more information. EISDIR pathname refers to a directory and the access requested involved writing (that is, O_WRONLY or O_RDWR
is set). ELOOP Too many symbolic links were encountered in resolving pathname, or O_NOFOLLOW was specified but path‐
name was a symbolic link. EMFILE The process already has the maximum number of files open. ENAMETOOLONG
pathname was too long. ENFILE The system limit on the total number of open files has been reached. ENODEV pathname refers to a device special file and no corresponding device exists. (This is a Linux kernel
bug; in this situation ENXIO must be returned.) ENOENT O_CREAT is not set and the named file does not exist. Or, a directory component in pathname does not
exist or is a dangling symbolic link. ENOMEM Insufficient kernel memory was available. ENOSPC pathname was to be created but the device containing pathname has no room for the new file. ENOTDIR
A component used as a directory in pathname is not, in fact, a directory, or O_DIRECTORY was specified
and pathname was not a directory. ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading.
Or, the file is a device special file and no corresponding device exists. EOVERFLOW
pathname refers to a regular file that is too large to be opened. The usual scenario here is that an
application compiled on a -bit platform without -D_FILE_OFFSET_BITS= tried to open a file whose
size exceeds (<<)- bits; see also O_LARGEFILE above. This is the error specified by POSIX.-;
in kernels before 2.6., Linux gave the error EFBIG for this case. EPERM The O_NOATIME flag was specified, but the effective user ID of the caller did not match the owner of
the file and the caller was not privileged (CAP_FOWNER). EROFS pathname refers to a file on a read-only filesystem and write access was requested. ETXTBSY
pathname refers to an executable image which is currently being executed and write access was
requested. EWOULDBLOCK
The O_NONBLOCK flag was specified, and an incompatible lease was held on the file (see fcntl()). CONFORMING TO
SVr4, .3BSD, POSIX.-. The O_DIRECTORY, O_NOATIME, O_NOFOLLOW, and O_PATH flags are Linux-specific, and
one may need to define _GNU_SOURCE (before including any header files) to obtain their definitions. The O_CLOEXEC flag is not specified in POSIX.-, but is specified in POSIX.-. O_DIRECT is not specified in POSIX; one has to define _GNU_SOURCE (before including any header files) to get
its definition. NOTES
Under Linux, the O_NONBLOCK flag indicates that one wants to open but does not necessarily have the intention
to read or write. This is typically used to open devices in order to get a file descriptor for use with
ioctl(). Unlike the other values that can be specified in flags, the access mode values O_RDONLY, O_WRONLY, and
O_RDWR, do not specify individual bits. Rather, they define the low order two bits of flags, and are defined
respectively as , , and . In other words, the combination O_RDONLY | O_WRONLY is a logical error, and
certainly does not have the same meaning as O_RDWR. Linux reserves the special, nonstandard access mode
(binary ) in flags to mean: check for read and write permission on the file and return a descriptor that
can't be used for reading or writing. This nonstandard access mode is used by some Linux drivers to return a
descriptor that is to be used only for device-specific ioctl() operations. The (undefined) effect of O_RDONLY | O_TRUNC varies among implementations. On many systems the file is actu‐
ally truncated. There are many infelicities in the protocol underlying NFS, affecting amongst others O_SYNC and O_NDELAY. POSIX provides for three different variants of synchronized I/O, corresponding to the flags O_SYNC, O_DSYNC,
and O_RSYNC. Currently (2.6.), Linux implements only O_SYNC, but glibc maps O_DSYNC and O_RSYNC to the
same numerical value as O_SYNC. Most Linux filesystems don't actually implement the POSIX O_SYNC semantics,
which require all metadata updates of a write to be on disk on returning to user space, but only the O_DSYNC
semantics, which require only actual file data and metadata necessary to retrieve it to be on disk by the
time the system call returns. Note that open() can open device special files, but creat() cannot create them; use mknod() instead. On NFS filesystems with UID mapping enabled, open() may return a file descriptor but, for example, read()
requests are denied with EACCES. This is because the client performs open() by checking the permissions, but
UID mapping is performed by the server upon read and write requests. If the file is newly created, its st_atime, st_ctime, st_mtime fields (respectively, time of last access,
time of last status change, and time of last modification; see stat()) are set to the current time, and so
are the st_ctime and st_mtime fields of the parent directory. Otherwise, if the file is modified because of
the O_TRUNC flag, its st_ctime and st_mtime fields are set to the current time. O_DIRECT
The O_DIRECT flag may impose alignment restrictions on the length and address of user-space buffers and the
file offset of I/Os. In Linux alignment restrictions vary by filesystem and kernel version and might be
absent entirely. However there is currently no filesystem-independent interface for an application to dis‐
cover these restrictions for a given file or filesystem. Some filesystems provide their own interfaces for
doing so, for example the XFS_IOC_DIOINFO operation in xfsctl(). Under Linux 2.4, transfer sizes, and the alignment of the user buffer and the file offset must all be multi‐
ples of the logical block size of the filesystem. Under Linux 2.6, alignment to -byte boundaries suf‐
fices. O_DIRECT I/Os should never be run concurrently with the fork() system call, if the memory buffer is a pri‐
vate mapping (i.e., any mapping created with the mmap() MAP_PRIVATE flag; this includes memory allocated on
the heap and statically allocated buffers). Any such I/Os, whether submitted via an asynchronous I/O inter‐
face or from another thread in the process, should be completed before fork() is called. Failure to do so
can result in data corruption and undefined behavior in parent and child processes. This restriction does
not apply when the memory buffer for the O_DIRECT I/Os was created using shmat() or mmap() with the
MAP_SHARED flag. Nor does this restriction apply when the memory buffer has been advised as MADV_DONTFORK
with madvise(), ensuring that it will not be available to the child after fork(). The O_DIRECT flag was introduced in SGI IRIX, where it has alignment restrictions similar to those of Linux
2.4. IRIX has also a fcntl() call to query appropriate alignments, and sizes. FreeBSD .x introduced a
flag of the same name, but without alignment restrictions. O_DIRECT support was added under Linux in kernel version 2.4.. Older Linux kernels simply ignore this
flag. Some filesystems may not implement the flag and open() will fail with EINVAL if it is used. Applications should avoid mixing O_DIRECT and normal I/O to the same file, and especially to overlapping byte
regions in the same file. Even when the filesystem correctly handles the coherency issues in this situation,
overall I/O throughput is likely to be slower than using either mode alone. Likewise, applications should
avoid mixing mmap() of files with direct I/O to the same files. The behaviour of O_DIRECT with NFS will differ from local filesystems. Older kernels, or kernels configured
in certain ways, may not support this combination. The NFS protocol does not support passing the flag to the
server, so O_DIRECT I/O will bypass the page cache only on the client; the server may still cache the I/O.
The client asks the server to make the I/O synchronous to preserve the synchronous semantics of O_DIRECT.
Some servers will perform poorly under these circumstances, especially if the I/O size is small. Some
servers may also be configured to lie to clients about the I/O having reached stable storage; this will avoid
the performance penalty at some risk to data integrity in the event of server power failure. The Linux NFS
client places no alignment restrictions on O_DIRECT I/O. In summary, O_DIRECT is a potentially powerful tool that should be used with caution. It is recommended that
applications treat use of O_DIRECT as a performance option which is disabled by default. "The thing that has always disturbed me about O_DIRECT is that the whole interface is just stupid, and
was probably designed by a deranged monkey on some serious mind-controlling substances."—Linus BUGS
Currently, it is not possible to enable signal-driven I/O by specifying O_ASYNC when calling open(); use
fcntl() to enable this flag. SEE ALSO
chmod(), chown(), close(), dup(), fcntl(), link(), lseek(), mknod(), mmap(), mount(), openat(),
read(), socket(), stat(), umask(), unlink(), write(), fopen(), fifo(), path_resolution(), symlink() COLOPHON
This page is part of release 3.54 of the Linux man-pages project. A description of the project, and informa‐
tion about reporting bugs, can be found at http://www.kernel.org/doc/man-pages/. Linux -- OPEN()

man open

2.2.2 文件读写

ssize_t read(int fd, void *buf, size_t count);

说明:read函数从文件中读取数据存放到缓冲区中,并返回实际读取的字节数。若返回0,则表示没有数据可读,

即已达到文件尾。读操作从文件的当前读写位置开始读取内容,当前读写位置自动往后移动。

ssize_t write(int fd, const void *buf, size_t count);

说明:write函数将数据写入文件中,并将返回实际写入的字节数。写操作从文件的当前读写位置开始写入。

        对磁盘文件进行写操作时,若磁盘已满,返回失败。

 /*******************************************************************
* > File Name: 02-read.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Sun 03 Sep 2017 09:41:03 PM CST
******************************************************************/ #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> #define N 64 int main(int argc, char* argv[])
{
int fd, nbyte, sum = ;
char buf[N]; /*1.判断命令行参数*/
if(argc < ){
printf("Usage : %s <file_name>\n", argv[]);
return (-);
} /*2.打开文件*/
if((fd = open(argv[], O_RDONLY)) < ){
perror("Fail to open :");
return (-);
} /*3.循环读取文件,累加读到的字节数*/
while((nbyte = read(fd, buf, N)) > ){
sum += nbyte;
} printf("The length of %s is %d bytes\n", argv[], sum); close(fd); return ;
}

read.c

2.2.3文件定位

off_t lseek(int fd, off_t offset, int whence);

offset(@param):相对基准点whence的偏移量,以字节为单位,正数表示向前移动,负数表示向后移动;

whence:SEEK_SET:文件的起始位置;SEEK_CUR:文件的当前读写位置;SEEK_END:文件的结束位置;

说明:lseek函数对文件当前读写位置进行定位。它只能对可定位(可随机访问)文件操作。

    管道、套接字和大部分字符设备文件不支持此类访问。

 /*******************************************************************
* > File Name: 05-lseek.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Mon 04 Sep 2017 11:49:08 PM CST
******************************************************************/ #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h> #define BUFFER_SIZE (1024*1) /*每次读写缓存大小,影响运行效率*/
#define SRC_FILE_NAME "src_file" /*源文件名*/
#define DEST_FILE_NAME "dst_file" /*目标文件名*/
#define OFFSET (1024*10) /*复制的数据大小*/ int main(int argc, char* argv[])
{
int fds, fdd;
unsigned char buff[BUFFER_SIZE];
int read_len; /*1.以只读方式打开源文件*/
if((fds = open(SRC_FILE_NAME, O_RDONLY)) < ){
perror("Fail to open src_file :");
return (-);
} /*2.以只写方式打开目标文件,若此文件不存在则创建,访问权限644*/
if((fdd = open(DEST_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, )) < ){
perror("Fail to open dest_file :");
return (-);
} /*3.将源文件的读写指针移到最后10KB的起始位置*/
lseek(fds , -OFFSET, SEEK_END); /*4.读取源文件的最后10KB数据并写入目标文件,每次读写1KB*/
while((read_len = read(fds, buff, sizeof(buff))) > ){
write(fdd, buff, read_len);
} close(fds);
close(fdd); return ;
}

lseek.c

 LSEEK()                                      Linux Programmer's Manual                                     LSEEK(2)

 NAME
lseek - reposition read/write file offset SYNOPSIS
#include <sys/types.h>
#include <unistd.h> off_t lseek(int fd, off_t offset, int whence); DESCRIPTION
The lseek() function repositions the offset of the open file associated with the file descriptor fd to the
argument offset according to the directive whence as follows: SEEK_SET
The offset is set to offset bytes. SEEK_CUR
The offset is set to its current location plus offset bytes. SEEK_END
The offset is set to the size of the file plus offset bytes. The lseek() function allows the file offset to be set beyond the end of the file (but this does not change
the size of the file). If data is later written at this point, subsequent reads of the data in the gap (a
"hole") return null bytes ('\0') until data is actually written into the gap. Seeking file data and holes
Since version 3.1, Linux supports the following additional values for whence: SEEK_DATA
Adjust the file offset to the next location in the file greater than or equal to offset containing
data. If offset points to data, then the file offset is set to offset. SEEK_HOLE
Adjust the file offset to the next hole in the file greater than or equal to offset. If offset points
into the middle of a hole, then the file offset is set to offset. If there is no hole past offset,
then the file offset is adjusted to the end of the file (i.e., there is an implicit hole at the end of
any file). In both of the above cases, lseek() fails if offset points past the end of the file. These operations allow applications to map holes in a sparsely allocated file. This can be useful for appli‐
cations such as file backup tools, which can save space when creating backups and preserve holes, if they
have a mechanism for discovering holes. For the purposes of these operations, a hole is a sequence of zeros that (normally) has not been allocated in
the underlying file storage. However, a filesystem is not obliged to report holes, so these operations are
not a guaranteed mechanism for mapping the storage space actually allocated to a file. (Furthermore, a
sequence of zeros that actually has been written to the underlying storage may not be reported as a hole.)
In the simplest implementation, a filesystem can support the operations by making SEEK_HOLE always return the
offset of the end of the file, and making SEEK_DATA always return offset (i.e., even if the location referred
to by offset is a hole, it can be considered to consist of data that is a sequence of zeros). The _GNU_SOURCE feature test macro must be defined in order to obtain the definitions of SEEK_DATA and
SEEK_HOLE from <unistd.h>. RETURN VALUE
Upon successful completion, lseek() returns the resulting offset location as measured in bytes from the
beginning of the file. On error, the value (off_t) - is returned and errno is set to indicate the error. ERRORS
EBADF fd is not an open file descriptor. EINVAL whence is not valid. Or: the resulting file offset would be negative, or beyond the end of a seekable
device. EOVERFLOW
The resulting file offset cannot be represented in an off_t. ESPIPE fd is associated with a pipe, socket, or FIFO. ENXIO whence is SEEK_DATA or SEEK_HOLE, and the current file offset is beyond the end of the file. CONFORMING TO
SVr4, .3BSD, POSIX.-. SEEK_DATA and SEEK_HOLE are nonstandard extensions also present in Solaris, FreeBSD, and DragonFly BSD; they
are proposed for inclusion in the next POSIX revision (Issue ). NOTES
Some devices are incapable of seeking and POSIX does not specify which devices must support lseek(). On Linux, using lseek() on a terminal device returns ESPIPE. When converting old code, substitute values for whence with the following macros: old new
SEEK_SET
SEEK_CUR
SEEK_END
L_SET SEEK_SET
L_INCR SEEK_CUR
L_XTND SEEK_END Note that file descriptors created by dup() or fork() share the current file position pointer, so seeking
on such files may be subject to race conditions. SEE ALSO
dup(), fork(), open(), fseek(), lseek64(), posix_fallocate() COLOPHON
This page is part of release 3.54 of the Linux man-pages project. A description of the project, and informa‐
tion about reporting bugs, can be found at http://www.kernel.org/doc/man-pages/. Linux -- LSEEK()

man lseek

2.2.4 文件锁

int fcntl(int fd, int cmd, ... /* arg */ );

当多个程序共同操作一个文件时,给文件上锁,来解决对共享资源的竞争。

建议性锁:要求每个相关程序在访问文件之前检查是否有锁存在,并且尊重已有锁。(不建议使用,无法保证每个程序都自动检查是否有锁)

强制性锁:由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何程序对该文件进行读写操作。

         采用强制性锁对性能的影响较大,每次读写内核都检查是否有锁存在。

实现上锁的函数:lockf():对文件施加建议性锁。

    fcntl():可以施加建议性锁,也可以施加强制性锁。还能对文件的某一记录上锁,即记录锁。

记录锁:分读取锁(共享锁)和写入锁(排斥锁)。

 FCNTL()                                      Linux Programmer's Manual                                     FCNTL(2)

 NAME
fcntl - manipulate file descriptor SYNOPSIS
#include <unistd.h>
#include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); DESCRIPTION
fcntl() performs one of the operations described below on the open file descriptor fd. The operation is
determined by cmd. fcntl() can take an optional third argument. Whether or not this argument is required is determined by cmd.
The required argument type is indicated in parentheses after each cmd name (in most cases, the required type
is int, and we identify the argument using the name arg), or void is specified if the argument is not
required. Duplicating a file descriptor
F_DUPFD (int)
Find the lowest numbered available file descriptor greater than or equal to arg and make it be a copy
of fd. This is different from dup2(), which uses exactly the descriptor specified. On success, the new descriptor is returned. See dup() for further details. F_DUPFD_CLOEXEC (int; since Linux 2.6.)
As for F_DUPFD, but additionally set the close-on-exec flag for the duplicate descriptor. Specifying
this flag permits a program to avoid an additional fcntl() F_SETFD operation to set the FD_CLOEXEC
flag. For an explanation of why this flag is useful, see the description of O_CLOEXEC in open(). File descriptor flags
The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag
is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit is , the file descriptor will remain
open across an execve(), otherwise it will be closed. F_GETFD (void)
Read the file descriptor flags; arg is ignored. F_SETFD (int)
Set the file descriptor flags to the value specified by arg. File status flags
Each open file description has certain associated status flags, initialized by open() and possibly modified
by fcntl(). Duplicated file descriptors (made with dup(), fcntl(F_DUPFD), fork(), etc.) refer to the same
open file description, and thus share the same file status flags. The file status flags and their semantics are described in open(). F_GETFL (void)
Get the file access mode and the file status flags; arg is ignored. F_SETFL (int)
Set the file status flags to the value specified by arg. File access mode (O_RDONLY, O_WRONLY,
O_RDWR) and file creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. On
Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags. Advisory locking
F_GETLK, F_SETLK and F_SETLKW are used to acquire, release, and test for the existence of record locks (also
known as file-segment or file-region locks). The third argument, lock, is a pointer to a structure that has
at least the following fields (in unspecified order). struct flock {
...
short l_type; /* Type of lock: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock
(F_GETLK only) */
...
}; The l_whence, l_start, and l_len fields of this structure specify the range of bytes we wish to lock. Bytes
past the end of the file may be locked, but not bytes before the start of the file. l_start is the starting offset for the lock, and is interpreted relative to either: the start of the file (if
l_whence is SEEK_SET); the current file offset (if l_whence is SEEK_CUR); or the end of the file (if l_whence
is SEEK_END). In the final two cases, l_start can be a negative number provided the offset does not lie
before the start of the file. l_len specifies the number of bytes to be locked. If l_len is positive, then the range to be locked covers
bytes l_start up to and including l_start+l_len-. Specifying for l_len has the special meaning: lock all
bytes starting at the location specified by l_whence and l_start through to the end of file, no matter how
large the file grows. POSIX.- allows (but does not require) an implementation to support a negative l_len value; if l_len is
negative, the interval described by lock covers bytes l_start+l_len up to and including l_start-. This is
supported by Linux since kernel versions 2.4. and 2.5.. The l_type field can be used to place a read (F_RDLCK) or a write (F_WRLCK) lock on a file. Any number of
processes may hold a read lock (shared lock) on a file region, but only one process may hold a write lock
(exclusive lock). An exclusive lock excludes all other locks, both shared and exclusive. A single process
can hold only one type of lock on a file region; if a new lock is applied to an already-locked region, then
the existing lock is converted to the new lock type. (Such conversions may involve splitting, shrinking, or
coalescing with an existing lock if the byte range specified by the new lock does not precisely coincide with
the range of the existing lock.) F_SETLK (struct flock *)
Acquire a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the
bytes specified by the l_whence, l_start, and l_len fields of lock. If a conflicting lock is held by
another process, this call returns - and sets errno to EACCES or EAGAIN. F_SETLKW (struct flock *)
As for F_SETLK, but if a conflicting lock is held on the file, then wait for that lock to be released.
If a signal is caught while waiting, then the call is interrupted and (after the signal handler has
returned) returns immediately (with return value - and errno set to EINTR; see signal()). F_GETLK (struct flock *)
On input to this call, lock describes a lock we would like to place on the file. If the lock could be
placed, fcntl() does not actually place it, but returns F_UNLCK in the l_type field of lock and leaves
the other fields of the structure unchanged. If one or more incompatible locks would prevent this
lock being placed, then fcntl() returns details about one of these locks in the l_type, l_whence,
l_start, and l_len fields of lock and sets l_pid to be the PID of the process holding that lock. In order to place a read lock, fd must be open for reading. In order to place a write lock, fd must be open
for writing. To place both types of lock, open a file read-write. As well as being removed by an explicit F_UNLCK, record locks are automatically released when the process
terminates or if it closes any file descriptor referring to a file on which locks are held. This is bad: it
means that a process can lose the locks on a file like /etc/passwd or /etc/mtab when for some reason a
library function decides to open, read and close it. Record locks are not inherited by a child created via fork(), but are preserved across an execve(). Because of the buffering performed by the stdio() library, the use of record locking with routines in that
package should be avoided; use read() and write() instead. Mandatory locking
(Non-POSIX.) The above record locks may be either advisory or mandatory, and are advisory by default. Advisory locks are not enforced and are useful only between cooperating processes. Mandatory locks are enforced for all processes. If a process tries to perform an incompatible access (e.g.,
read() or write()) on a file region that has an incompatible mandatory lock, then the result depends upon
whether the O_NONBLOCK flag is enabled for its open file description. If the O_NONBLOCK flag is not enabled,
then system call is blocked until the lock is removed or converted to a mode that is compatible with the
access. If the O_NONBLOCK flag is enabled, then the system call fails with the error EAGAIN. To make use of mandatory locks, mandatory locking must be enabled both on the filesystem that contains the
file to be locked, and on the file itself. Mandatory locking is enabled on a filesystem using the "-o mand"
option to mount(), or the MS_MANDLOCK flag for mount(). Mandatory locking is enabled on a file by dis‐
abling group execute permission on the file and enabling the set-group-ID permission bit (see chmod() and
chmod()). The Linux implementation of mandatory locking is unreliable. See BUGS below. Managing signals
F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG and F_SETSIG are used to manage I/O availability sig‐
nals: F_GETOWN (void)
Return (as the function result) the process ID or process group currently receiving SIGIO and SIGURG
signals for events on file descriptor fd. Process IDs are returned as positive values; process group
IDs are returned as negative values (but see BUGS below). arg is ignored. F_SETOWN (int)
Set the process ID or process group ID that will receive SIGIO and SIGURG signals for events on file
descriptor fd to the ID given in arg. A process ID is specified as a positive value; a process group
ID is specified as a negative value. Most commonly, the calling process specifies itself as the owner
(that is, arg is specified as getpid()). If you set the O_ASYNC status flag on a file descriptor by using the F_SETFL command of fcntl(), a
SIGIO signal is sent whenever input or output becomes possible on that file descriptor. F_SETSIG can
be used to obtain delivery of a signal other than SIGIO. If this permission check fails, then the
signal is silently discarded. Sending a signal to the owner process (group) specified by F_SETOWN is subject to the same permissions
checks as are described for kill(), where the sending process is the one that employs F_SETOWN (but
see BUGS below). If the file descriptor fd refers to a socket, F_SETOWN also selects the recipient of SIGURG signals
that are delivered when out-of-band data arrives on that socket. (SIGURG is sent in any situation
where select() would report the socket as having an "exceptional condition".) The following was true in 2.6.x kernels up to and including kernel 2.6.: If a nonzero value is given to F_SETSIG in a multithreaded process running with a threading
library that supports thread groups (e.g., NPTL), then a positive value given to F_SETOWN has a
different meaning: instead of being a process ID identifying a whole process, it is a thread ID
identifying a specific thread within a process. Consequently, it may be necessary to pass
F_SETOWN the result of gettid() instead of getpid() to get sensible results when F_SETSIG is
used. (In current Linux threading implementations, a main thread's thread ID is the same as
its process ID. This means that a single-threaded program can equally use gettid() or get‐
pid() in this scenario.) Note, however, that the statements in this paragraph do not apply to
the SIGURG signal generated for out-of-band data on a socket: this signal is always sent to
either a process or a process group, depending on the value given to F_SETOWN. The above behavior was accidentally dropped in Linux 2.6., and won't be restored. From Linux 2.6.32
onward, use F_SETOWN_EX to target SIGIO and SIGURG signals at a particular thread. F_GETOWN_EX (struct f_owner_ex *) (since Linux 2.6.)
Return the current file descriptor owner settings as defined by a previous F_SETOWN_EX operation. The
information is returned in the structure pointed to by arg, which has the following form: struct f_owner_ex {
int type;
pid_t pid;
}; The type field will have one of the values F_OWNER_TID, F_OWNER_PID, or F_OWNER_PGRP. The pid field
is a positive integer representing a thread ID, process ID, or process group ID. See F_SETOWN_EX for
more details. F_SETOWN_EX (struct f_owner_ex *) (since Linux 2.6.)
This operation performs a similar task to F_SETOWN. It allows the caller to direct I/O availability
signals to a specific thread, process, or process group. The caller specifies the target of signals
via arg, which is a pointer to a f_owner_ex structure. The type field has one of the following val‐
ues, which define how pid is interpreted: F_OWNER_TID
Send the signal to the thread whose thread ID (the value returned by a call to clone() or get‐
tid()) is specified in pid. F_OWNER_PID
Send the signal to the process whose ID is specified in pid. F_OWNER_PGRP
Send the signal to the process group whose ID is specified in pid. (Note that, unlike with
F_SETOWN, a process group ID is specified as a positive value here.) F_GETSIG (void)
Return (as the function result) the signal sent when input or output becomes possible. A value of
zero means SIGIO is sent. Any other value (including SIGIO) is the signal sent instead, and in this
case additional info is available to the signal handler if installed with SA_SIGINFO. arg is ignored. F_SETSIG (int)
Set the signal sent when input or output becomes possible to the value given in arg. A value of zero
means to send the default SIGIO signal. Any other value (including SIGIO) is the signal to send
instead, and in this case additional info is available to the signal handler if installed with SA_SIG‐
INFO. By using F_SETSIG with a nonzero value, and setting SA_SIGINFO for the signal handler (see sigac‐
tion()), extra information about I/O events is passed to the handler in a siginfo_t structure. If
the si_code field indicates the source is SI_SIGIO, the si_fd field gives the file descriptor associ‐
ated with the event. Otherwise, there is no indication which file descriptors are pending, and you
should use the usual mechanisms (select(), poll(), read() with O_NONBLOCK set etc.) to determine
which file descriptors are available for I/O. By selecting a real time signal (value >= SIGRTMIN), multiple I/O events may be queued using the same
signal numbers. (Queuing is dependent on available memory). Extra information is available if
SA_SIGINFO is set for the signal handler, as above. Note that Linux imposes a limit on the number of real-time signals that may be queued to a process
(see getrlimit() and signal()) and if this limit is reached, then the kernel reverts to delivering
SIGIO, and this signal is delivered to the entire process rather than to a specific thread. Using these mechanisms, a program can implement fully asynchronous I/O without using select() or poll()
most of the time. The use of O_ASYNC, F_GETOWN, F_SETOWN is specific to BSD and Linux. F_GETOWN_EX, F_SETOWN_EX, F_GETSIG, and
F_SETSIG are Linux-specific. POSIX has asynchronous I/O and the aio_sigevent structure to achieve similar
things; these are also available in Linux as part of the GNU C Library (Glibc). Leases
F_SETLEASE and F_GETLEASE (Linux 2.4 onward) are used (respectively) to establish a new lease, and retrieve
the current lease, on the open file description referred to by the file descriptor fd. A file lease provides
a mechanism whereby the process holding the lease (the "lease holder") is notified (via delivery of a signal)
when a process (the "lease breaker") tries to open() or truncate() the file referred to by that file
descriptor. F_SETLEASE (int)
Set or remove a file lease according to which of the following values is specified in the integer arg: F_RDLCK
Take out a read lease. This will cause the calling process to be notified when the file is
opened for writing or is truncated. A read lease can be placed only on a file descriptor that
is opened read-only. F_WRLCK
Take out a write lease. This will cause the caller to be notified when the file is opened for
reading or writing or is truncated. A write lease may be placed on a file only if there are no
other open file descriptors for the file. F_UNLCK
Remove our lease from the file. Leases are associated with an open file description (see open()). This means that duplicate file descrip‐
tors (created by, for example, fork() or dup()) refer to the same lease, and this lease may be modified or
released using any of these descriptors. Furthermore, the lease is released by either an explicit F_UNLCK
operation on any of these duplicate descriptors, or when all such descriptors have been closed. Leases may be taken out only on regular files. An unprivileged process may take out a lease only on a file
whose UID (owner) matches the filesystem UID of the process. A process with the CAP_LEASE capability may
take out leases on arbitrary files. F_GETLEASE (void)
Indicates what type of lease is associated with the file descriptor fd by returning either F_RDLCK,
F_WRLCK, or F_UNLCK, indicating, respectively, a read lease , a write lease, or no lease. arg is
ignored. When a process (the "lease breaker") performs an open() or truncate() that conflicts with a lease estab‐
lished via F_SETLEASE, the system call is blocked by the kernel and the kernel notifies the lease holder by
sending it a signal (SIGIO by default). The lease holder should respond to receipt of this signal by doing
whatever cleanup is required in preparation for the file to be accessed by another process (e.g., flushing
cached buffers) and then either remove or downgrade its lease. A lease is removed by performing an
F_SETLEASE command specifying arg as F_UNLCK. If the lease holder currently holds a write lease on the file,
and the lease breaker is opening the file for reading, then it is sufficient for the lease holder to down‐
grade the lease to a read lease. This is done by performing an F_SETLEASE command specifying arg as F_RDLCK. If the lease holder fails to downgrade or remove the lease within the number of seconds specified in
/proc/sys/fs/lease-break-time then the kernel forcibly removes or downgrades the lease holder's lease. Once a lease break has been initiated, F_GETLEASE returns the target lease type (either F_RDLCK or F_UNLCK,
depending on what would be compatible with the lease breaker) until the lease holder voluntarily downgrades
or removes the lease or the kernel forcibly does so after the lease break timer expires. Once the lease has been voluntarily or forcibly removed or downgraded, and assuming the lease breaker has not
unblocked its system call, the kernel permits the lease breaker's system call to proceed. If the lease breaker's blocked open(2) or truncate(2) is interrupted by a signal handler, then the system
call fails with the error EINTR, but the other steps still occur as described above. If the lease breaker is
killed by a signal while blocked in open() or truncate(), then the other steps still occur as described
above. If the lease breaker specifies the O_NONBLOCK flag when calling open(), then the call immediately
fails with the error EWOULDBLOCK, but the other steps still occur as described above. The default signal used to notify the lease holder is SIGIO, but this can be changed using the F_SETSIG com‐
mand to fcntl(). If a F_SETSIG command is performed (even one specifying SIGIO), and the signal handler is
established using SA_SIGINFO, then the handler will receive a siginfo_t structure as its second argument, and
the si_fd field of this argument will hold the descriptor of the leased file that has been accessed by
another process. (This is useful if the caller holds leases against multiple files). File and directory change notification (dnotify)
F_NOTIFY (int)
(Linux 2.4 onward) Provide notification when the directory referred to by fd or any of the files that
it contains is changed. The events to be notified are specified in arg, which is a bit mask specified
by ORing together zero or more of the following bits: DN_ACCESS A file was accessed (read, pread, readv)
DN_MODIFY A file was modified (write, pwrite, writev, truncate, ftruncate).
DN_CREATE A file was created (open, creat, mknod, mkdir, link, symlink, rename).
DN_DELETE A file was unlinked (unlink, rename to another directory, rmdir).
DN_RENAME A file was renamed within this directory (rename).
DN_ATTRIB The attributes of a file were changed (chown, chmod, utime[s]). (In order to obtain these definitions, the _GNU_SOURCE feature test macro must be defined before
including any header files.) Directory notifications are normally "one-shot", and the application must reregister to receive fur‐
ther notifications. Alternatively, if DN_MULTISHOT is included in arg, then notification will remain
in effect until explicitly removed. A series of F_NOTIFY requests is cumulative, with the events in arg being added to the set already
monitored. To disable notification of all events, make an F_NOTIFY call specifying arg as . Notification occurs via delivery of a signal. The default signal is SIGIO, but this can be changed
using the F_SETSIG command to fcntl(). In the latter case, the signal handler receives a siginfo_t
structure as its second argument (if the handler was established using SA_SIGINFO) and the si_fd field
of this structure contains the file descriptor which generated the notification (useful when estab‐
lishing notification on multiple directories). Especially when using DN_MULTISHOT, a real time signal should be used for notification, so that multi‐
ple notifications can be queued. NOTE: New applications should use the inotify interface (available since kernel 2.6.), which pro‐
vides a much superior interface for obtaining notifications of filesystem events. See inotify(). Changing the capacity of a pipe
F_SETPIPE_SZ (int; since Linux 2.6.)
Change the capacity of the pipe referred to by fd to be at least arg bytes. An unprivileged process
can adjust the pipe capacity to any value between the system page size and the limit defined in
/proc/sys/fs/pipe-max-size (see proc()). Attempts to set the pipe capacity below the page size are
silently rounded up to the page size. Attempts by an unprivileged process to set the pipe capacity
above the limit in /proc/sys/fs/pipe-max-size yield the error EPERM; a privileged process
(CAP_SYS_RESOURCE) can override the limit. When allocating the buffer for the pipe, the kernel may
use a capacity larger than arg, if that is convenient for the implementation. The F_GETPIPE_SZ opera‐
tion returns the actual size used. Attempting to set the pipe capacity smaller than the amount of
buffer space currently used to store data produces the error EBUSY. F_GETPIPE_SZ (void; since Linux 2.6.)
Return (as the function result) the capacity of the pipe referred to by fd. RETURN VALUE
For a successful call, the return value depends on the operation: F_DUPFD The new descriptor. F_GETFD Value of file descriptor flags. F_GETFL Value of file status flags. F_GETLEASE
Type of lease held on file descriptor. F_GETOWN Value of descriptor owner. F_GETSIG Value of signal sent when read or write becomes possible, or zero for traditional SIGIO behavior. F_GETPIPE_SZ
The pipe capacity. All other commands
Zero. On error, - is returned, and errno is set appropriately. ERRORS
EACCES or EAGAIN
Operation is prohibited by locks held by other processes. EAGAIN The operation is prohibited because the file has been memory-mapped by another process. EBADF fd is not an open file descriptor, or the command was F_SETLK or F_SETLKW and the file descriptor open
mode doesn't match with the type of lock requested. EDEADLK
It was detected that the specified F_SETLKW command would cause a deadlock. EFAULT lock is outside your accessible address space. EINTR For F_SETLKW, the command was interrupted by a signal; see signal(). For F_GETLK and F_SETLK, the
command was interrupted by a signal before the lock was checked or acquired. Most likely when locking
a remote file (e.g., locking over NFS), but can sometimes happen locally. EINVAL For F_DUPFD, arg is negative or is greater than the maximum allowable value. For F_SETSIG, arg is not
an allowable signal number. EMFILE For F_DUPFD, the process already has the maximum number of file descriptors open. ENOLCK Too many segment locks open, lock table is full, or a remote locking protocol failed (e.g., locking
over NFS). EPERM Attempted to clear the O_APPEND flag on a file that has the append-only attribute set. CONFORMING TO
SVr4, .3BSD, POSIX.-. Only the operations F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK,
F_SETLK and F_SETLKW, are specified in POSIX.-. F_GETOWN and F_SETOWN are specified in POSIX.-. (To get their definitions, define BSD_SOURCE, or
_XOPEN_SOURCE with the value or greater, or define _POSIX_C_SOURCE with the value 200809L or greater.) F_DUPFD_CLOEXEC is specified in POSIX.-. (To get this definition, define _POSIX_C_SOURCE with the value
200809L or greater, or _XOPEN_SOURCE with the value or greater.) F_GETOWN_EX, F_SETOWN_EX, F_SETPIPE_SZ, F_GETPIPE_SZ, F_GETSIG, F_SETSIG, F_NOTIFY, F_GETLEASE, and
F_SETLEASE are Linux-specific. (Define the _GNU_SOURCE macro to obtain these definitions.) NOTES
The original Linux fcntl() system call was not designed to handle large file offsets (in the flock struc‐
ture). Consequently, an fcntl64() system call was added in Linux 2.4. The newer system call employs a dif‐
ferent structure for file locking, flock64, and corresponding commands, F_GETLK64, F_SETLK64, and F_SETLKW64.
However, these details can be ignored by applications using glibc, whose fcntl() wrapper function transpar‐
ently employs the more recent system call where it is available. The errors returned by dup2() are different from those returned by F_DUPFD. Since kernel 2.0, there is no interaction between the types of lock placed by flock() and fcntl(). Several systems have more fields in struct flock such as, for example, l_sysid. Clearly, l_pid alone is not
going to be very useful if the process holding the lock may live on a different machine. BUGS
A limitation of the Linux system call conventions on some architectures (notably i386) means that if a (nega‐
tive) process group ID to be returned by F_GETOWN falls in the range - to -, then the return value is
wrongly interpreted by glibc as an error in the system call; that is, the return value of fcntl() will be -,
and errno will contain the (positive) process group ID. The Linux-specific F_GETOWN_EX operation avoids this
problem. Since glibc version 2.11, glibc makes the kernel F_GETOWN problem invisible by implementing
F_GETOWN using F_GETOWN_EX. In Linux 2.4 and earlier, there is bug that can occur when an unprivileged process uses F_SETOWN to specify
the owner of a socket file descriptor as a process (group) other than the caller. In this case, fcntl() can
return - with errno set to EPERM, even when the owner process (group) is one that the caller has permission
to send signals to. Despite this error return, the file descriptor owner is set, and signals will be sent to
the owner. The implementation of mandatory locking in all known versions of Linux is subject to race conditions which
render it unreliable: a write() call that overlaps with a lock may modify data after the mandatory lock is
acquired; a read() call that overlaps with a lock may detect changes to data that were made only after a
write lock was acquired. Similar races exist between mandatory locks and mmap(). It is therefore inadvis‐
able to rely on mandatory locking. SEE ALSO
dup2(), flock(), open(), socket(), lockf(), capabilities(), feature_test_macros() locks.txt, mandatory-locking.txt, and dnotify.txt in the Linux kernel source directory Documentation/filesys‐
tems/ (on older kernels, these files are directly under the Documentation/ directory, and mandatory-lock‐
ing.txt is called mandatory.txt) COLOPHON
This page is part of release 3.54 of the Linux man-pages project. A description of the project, and informa‐
tion about reporting bugs, can be found at http://www.kernel.org/doc/man-pages/. Linux -- FCNTL()

man fcntl

 /*******************************************************************
* > File Name: lock_set.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Mon 27 Nov 2017 10:35:41 PM CST
******************************************************************/ #include "lock_set.h" int lock_set(int fd, int type){
struct flock old_lock, lock; lock.l_whence = SEEK_SET;
lock.l_start = ;
lock.l_len = ;
lock.l_type = type;
lock.l_pid = -; /*判断文件是否上锁*/
fcntl(fd, F_GETLK, &lock); if(lock.l_type != F_UNLCK){
/*判断文件不能上锁的原因*/
if(lock.l_type == F_RDLCK){
/*该文件已有读取锁*/
printf("Read lock already set by %d\n", lock.l_pid);
}else if(lock.l_type == F_WRLCK){
/*该文件已有写入锁*/
printf("Write lock already set by %d\n", lock.l_pid);
}
} /*l_type可能已被F_GETLK修改过*/
lock.l_type = type;
/*根据不同的type值进行阻塞上锁或解锁*/
if((fcntl(fd, F_SETLKW, &lock)) < ){
printf("Lock failed :type = %d\n", lock.l_type);
return (-);
} switch(lock.l_type){
case F_RDLCK:
{
printf("Read lock set by %d\n", getpid());
}
break;
case F_WRLCK:
{
printf("Write lock set by %d\n", getpid());
}
break;
case F_UNLCK:
{
printf("Release lock by %d\n", getpid());
return ;
}
break;
}/*end of switch*/ return ;
} #if (0)
int main(void)
{
return ;
}
#endif

lock_set.c

 #ifndef __LOCK_SET_H__
#define __LOCK_SET_H__ #include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "lock_set.h" int lock_set(int fd, int type); #endif

lock_set.h

 /*******************************************************************
* > File Name: fcntl_read.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Tue 28 Nov 2017 12:25:57 AM CST
******************************************************************/ #include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "lock_set.h" int main(int argc, char* argv[])
{
int fd; fd = open("Hello", O_RDWR|O_CREAT, );
if(fd < ){
printf("Open file error\n");
exit();
} /*给文件上读取锁*/
lock_set(fd, F_RDLCK);
getchar(); /*给文件解锁*/
lock_set(fd, FUNLCK);
getchar();
close(fd); return ;
}

fcntl_read.c

 /*******************************************************************
* > File Name: write_lock.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Mon 27 Nov 2017 11:45:20 PM CST
******************************************************************/ #include <stdio.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include "lock_set.h" int lock_set(int fd, int type); int main(int argc, char* argv[])
{
int fd; /*首先打开文件*/
if((fd = open("hello", O_RDWR|O_CREAT)) < ){
perror("fail to open");
return -;
} /*给文件上锁*/
lock_set(fd, F_WRLCK);
getchar(); //等待用户键盘输入 /*给文件解锁*/
lock_set(fd, F_UNLCK);
getchar();
close(fd); return ;
}

write_lock.c

2.3实验内容——生产者和消费者

  2.Linux文件IO编程

 /*******************************************************************
* > File Name: producer.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Tue 28 Nov 2017 11:20:29 PM CST
******************************************************************/ #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "lock_set.h" #define MAXLEN 10 /*缓冲区大小最大值*/
#define ALPHABET 1 /*表示使用英文字符*/
#define ALPHABET_START 'a' /*头一个字符,可以用'A'*/
#define COUNT_OF_ALPHABET 26 /*字母字符的个数*/
#define DIGIT 2 /*表示使用数字字符*/
#define DIGIT_START '0' /*头一个字符*/
#define COUNT_OF_DIGIT 10 /*数字字符的个数*/
#define SIGN_TYPE ALPHABET /*本实例选用英文字符*/
const char *fifo_file = "./myfifo"; /*仿真FIFO文件名*/
char buff[MAXLEN]; /*缓冲区*/ /*功能:生产一个字符并写入仿真FIFO文件中*/
int product(void){
int fd;
unsigned int sign_type, sign_start, sign_count, size;
static unsigned int counter = ; /*打开仿真FIFO文件*/
if((fd = open(fifo_file, O_CREAT|O_RDWR|O_APPEND, )) < ){
perror("Open fifo_file error :");exit(EXIT_FAILURE);
} sign_type = SIGN_TYPE;
switch(sign_type){
case ALPHABET:/*英文字符*/
{
sign_start = ALPHABET_START;
sign_count = COUNT_OF_ALPHABET;
}
break;
case DIGIT:/*数字字符*/
{
sign_start = DIGIT_START;
sign_count = COUNT_OF_DIGIT;
}
break;
default:
{
return -;
}
}/*end of switch*/ sprintf(buff, "%c", (sign_start + counter));
counter = (counter + )%sign_count; lock_set(fd, F_WRLCK); /*上写锁*/
if((size = write(fd, buff, strlen(buff))) < ){
printf("Producer write error\n");
return -;
} lock_set(fd, F_UNLCK); /*解锁*/ close(fd);
return ;
} int main(int argc, char* argv[])
{
int time_step = ; /*生产周期*/
int time_life = ; /*需要生产的资源总数*/ if(argc > ){
/*第一个参数表示生产周期*/
sscanf(argv[], "%d", &time_step);
} if(argc > ){
/*第二个参数表示需要生产的资源数*/
sscanf(argv[], "%d", &time_life);
} while(time_life --){
if(product() <){
break;
}
sleep(time_step);
} exit(EXIT_SUCCESS);
}

producer.c

 /*******************************************************************
* > File Name: customer.c
* > Author: fly
* > Mail: XXXXXXXX@icode.com
* > Create Time: Wed 29 Nov 2017 08:32:23 PM CST
******************************************************************/ #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include "lock_set.h" #define MAX_FILE_SIZE 100*1024*1024 /*100MB*/ const char *fifo_file = "./myfifo"; /*仿真FIFO文件名*/
const char *tmp_file = "./tmp"; /*临时文件名*/ /*资源消费函数*/
int customing(const char *myfifo, int need){
int fd;
char buff;
int counter = ; /*以可读方式打开文件*/
if((fd = open(myfifo, O_RDONLY)) < ){
printf("Function customing error\n");
return -;
} printf("Enjoy :");
/*找到文件的开头*/
lseek(fd, SEEK_SET, ); while(counter < need){
while((read(fd, &buff, ) == ) && (counter < need)){
fputc(buff, stdout); /*消费者就是在屏幕上简单的显示*/
counter ++;
}
} fputs("\n", stdout);
close(fd);
return ;
} /*功能:从sour_file文件的offset偏移处开始将count个字节数据复制到dest_file文件*/
int myfilecopy(const char *sour_file, const char *dest_file, int offset, int count, int copy_mode){
int in_file, out_file;
int counter = ;
char buf_unit; if((in_file = open(sour_file, O_RDONLY|O_NONBLOCK)) < ){
printf("Function myfilecopy error in source file\n");return (-);
} if((out_file = open(dest_file, O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK, )) < ){
printf("Function myfilecopy error in destination file :");return (-);
} lseek(in_file, offset, SEEK_SET);
while((read(in_file, &buf_unit, )) && (counter < count)){
write(out_file, &buf_unit, );
counter ++;
} close(in_file);close(out_file);
return ;
} /*功能:实现FIFO消费者*/
int custom(int need){
int fd; /*对资源进行消费,need表示该消费的资源数目*/
customing(fifo_file, need); if((fd = open(fifo_file, O_RDWR)) < ){
perror("Function myfilecopy error in source_file :");return (-);
} /*为了模拟FIFO结构,对整个文件内容进行平行移动*/
lock_set(fd, F_WRLCK);
myfilecopy(fifo_file, tmp_file, need, MAX_FILE_SIZE, );
myfilecopy(tmp_file, fifo_file, , MAX_FILE_SIZE, );
lock_set(fd, F_UNLCK);
unlink(tmp_file);
close(fd);
return ;
} int main(int argc, char* argv[])
{
int customer_capacity = ; if(argc > ){
/*第一个参数指定需要消费的资源数目,默认值为10*/
sscanf(argv[], "%d", &customer_capacity);
} if(customer_capacity > ){
custom(customer_capacity);
} exit(EXIT_SUCCESS);
}

customer.c

上一篇:Linux 文件IO管理 - POSIX


下一篇:Linux实战教学笔记08:Linux 文件的属性(下半部分)