1.dup和dup2函数
dup和dup2系统调用都可以用来复制文件描述符。复制成功返回最小且尚未使用的文件描述符,若有错误返回-1。返回的新的文件描述符和参数oldfd指向同一个文件,共享所有的锁定、读写指针和各项权限或标志位。dup2与dup的区别是dup2可以用参数newfd指定新文件描述符的数值。若newfd已经被程序使用系统就会将其关闭以释放该文件描述符,若newfd与oldfd相等,则dup2返回newfd而不关闭它,调用成功返回新的文件描述符,出错返回-1。
2.fcntl函数
fcntl系统调用可以用来对已打开的文件描述符进行各种控制操作以改变已打开文件的各种属性。
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
fcntl的功能依据cmd值的不同而不同,具体有以下功能:
(1).F_DUPFD:复制由fd指向的文件描述符,调用成功返回新的文件描述符,失败返回-1。
(2).F_GETFD:获取文件描述符的close-on-exce标志。调用成功返回标志值,若标志值最后一位为0,则该标志没有被设置,即意味着在执行exec相关函数后文件描述符仍然保持打开。否则在执行exec相关函数时将关闭该文件描述符,失败返回-1。
(3).F_SETFD:用来设置文件描述符的close-on- exec标志为第三个参数arg的最后一位。成功返回0,失败返回-1。
(4).F_GETFL:用来获得文件的打开方式,成功返回标志值,失败返回-1。
(5).F_SETFL:用来设置文件打开方式为第三个参数arg指定的方式。有O_APPEND、O_NONBLOCK、O_ASYNC标志。
文件记录锁:当有多个进程同时对一个文件进行操作时,就有可能发生数据的不同步,从而引发错误,该文件的最后状态取决于写该文件的最后一个程序。有时为确保它正在单独写一个文件,linux提供了记录锁机制。多个进程在一个给定的字节上可以有一把共享的读锁,但是在一个给定的字节上写锁只能由一个进程单独使用。l_whence、l_start和l_len用来确定需要进行文件记录锁操作的区域,含义和lseek一致。为了锁整个文件,通常的方法是将l_start说明为0,l_whence说明为SEEK_SET,l_len说明为0.
(6).F_SETLK:用来设置或者释放锁,当l_type取F_RDLCK或F_WDLCK时,则在指定的区域上设置锁,当取F_UNLCK时释放锁,若锁被其他进程占用,则返回-1。
(7).F_SETLKW:与F_SETLK时类似,不同是当希望设置的锁因为存在其他锁而被阻止设置时,该命令会等待相冲突的锁被释放。
(8).F_GETLK :第三个参数指向一个希望被设置的锁的属性的结构,若能被设置,并不真的设置,只是修改lock的l_type域为F_UNLCK,然后返回,若存在相冲突的锁,则返回一个锁的flock结构。
单个进程在同一字节上只能设置一种锁,新的锁会取代旧的锁,锁的不兼容规则是针对于多个进程之间的。
(9). F_GETOWN:返回当前接受的SIGIO或SIGURG信号,进程组ID以负值指定,进程ID用正值指定。
(10).F_SETOWN:设置进程或进程组接收SIGIO和SIGURG信号。
(11).F_GETSIG:在输入输出时,获得发送的信号。
(12).F_SETSIG :设置在输入输出时发送的信号。
3.ioctl函数
int ioctl(int fd, int request, …);
ioctl系统调用通常用来控制设备,文件的属性,第一个参数fd必须是一个已经打开的文件描述符,第三个参数一般为char *argp,它随第二个参数的不同而不同,参数request决定了参数argp是向ioctl传递数据还是从ioctl获取参数。
如下代码是获取网络设备的信息:
//实例ioctl的使用
#include<stdio.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<net/if.h>
#include<string.h>
unsigned char g_eth_name[16];
unsigned char g_macaddr[6];
unsigned char g_subnetmask;
unsigned char g_ipaddr;
unsigned char g_broadcast_ipaddr;
//初始化网络,获取当前网络设备的信息
void init_net(void)
{
int i;
int sock;
struct sockaddr_in sin;
struct ifreq ifr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == -1)
{
perror("socket");
}
strcpy(g_eth_name, "eth0");
strcpy(ifr.ifr_name, g_eth_name);
printf("eth name:\t%s\n", g_eth_name);
//获取并打印网卡地址
if(ioctl(sock, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl");
}
memcpy(g_macaddr, ifr.ifr_hwaddr.sa_data, 6);
printf("local mac:\t");
for(i = 0; i < 5; i++)
{
printf("%.2x:", g_macaddr[i]);
}
printf("%.2x\n", g_macaddr[i]);
//获取并打印IP地址
if(ioctl(sock, SIOCGIFADDR, &ifr) < 0)
{
perror("ioctl");
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
g_ipaddr = sin.sin_addr.s_addr;
printf("local eth0:\t%s\n", inet_ntoa(sin.sin_addr));
//获取并打印广播地址
if(ioctl(sock, SIOCGIFBRDADDR, &ifr) < 0)
{
perror("ioctl");
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
g_broadcast_ipaddr = sin.sin_addr.s_addr;
printf("broadcast:\t%s\n", inet_ntoa(sin.sin_addr));
//获取并打印子网掩码
if(ioctl(sock, SIOCGIFNETMASK, &ifr) < 0)
{
perror("ioctl");
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
g_subnetmask = sin.sin_addr.s_addr;
printf("subnetmask:\t%s\n", inet_ntoa(sin.sin_addr));
close(sock);
}
int main()
{
//initialize
init_net();
//do something
return 0;
}
4.获取文件属性
在shell下直接使用ls就可获取文件的属性,在程序中需要使用stat/fstat/lstat函数,执行成功返回0,失败返回-1。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
stat用于获取由参数file_name指定的文件名的状态信息,保存在参数struct stat * buf中,fstat是通过文件描述符来指定文件的。lstat对于符号链接,返回的是符号链接本身的状态信息,而stat返回的是符号链接指向的文件状态信息。
参数struct stat *buf是一个保存文件状态信息的结构体,具体类型如下:
struct stat
{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
若某一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。
对于st_mode包含的文件类型信息,POSIX标准定义了一系列的宏:
- S_ISLNK(st_mode):判读是否为符号链接
- S_ISREG(st_mode):·判断是否为一般文件
- S_ISDIR(st_mode):判断是否为目录文件
- S_ISCHR(st_mode):判断是否是字符设备文件
- S_ISBLK(st_mode):判断是否为块设备文件
- S_ISFIFO(st_mode):判断是否为先进先出FIFO
- S_ISSOCK(st_mode):判断是否为socket
5.设置文件属性
1.hmode/fchmode:用于修改文件的存取权限
2.chown/fchown/lchown:用于修改文件的用户id和组id
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
chown将参数path指定的文件所有者id变更为参数owner代表的用户id,而将该文件所有者的组id变更为参数group组id。fchown只是以文件描述符作为参数的,lchown更改的是符号链接本身的所有者id,而不是该符号链接所指向的文件。
文件的所有者只能改变文件的组id为其所属组中的一个,超级用户才能修改文件的所有者id,并且超级用户可以任意修改文件的用户组id。如果参数owner或group指定为-1,那么文件的用户组id和组id不会改变。函数执行成功返回1,错误返回-1。
3.truncate/ftruncate
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
truncate将参数path指定的文件大小修改为length指定的大小。如果原来的文件大小比length大,则超过的部分会被删除,如果原来的文件大小比参数length小,则文件将被扩展,与lseek系统调用类似,文件扩展部分将以0填充,若文件的大小改变,则文件的st_time域和st_ctime域将会更新。
4.utime
用于改变任何文件的st_time域和st_ctime域,即存取时间和修改时间。
#include <sys/types.h>
#include <utime.h>
int utime(const char *filename, const struct utimbuf *times);
#include <sys/time.h>
int utimes(const char *filename, const struct timeval times[2]);
参数struct utime *buf的定义如下:
struct utimbuf
{
time_t actime; /* access time */
time_t modtime; /* modification time */
};
utime系统调用会把由第一个参数指向的filename指定的文件的存取时间改为第二个参数buf的actime域,把修改时间改为第二个参数buf的modtime域,如果buf是一个空指针,则存取时间和修改时间都将改为当前时间。
5.umask
用于设置文件创建是使用的屏蔽字,并返回以前的值,在进程创建一个新文件或目录时,如调用open函数创建一个新文件,新文件的实际存取权限是mode与umask按照(mode & ~umask)运算以后的结果,umask函数用来修改进程的umask。参数mask可以直接取数值也可以为open系统调用的第三个参数mode的11个宏或它们的组合。
具体参考如下:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
umask(0); //不屏蔽任何权限
if (creat("example_681.test", S_IRWXU|S_IRWXG|S_IRWXO) < 0)
{
perror("creat");
exit(1);
}
umask(S_IRWXO); //屏蔽其他用户的所有权限
if (creat("example_682.test", S_IRWXU|S_IRWXO|S_IRWXG) < 0)
{
perror("creat");
exit(1);
}
return 0;
}
执行结果如下:
在第一次创建时未使用屏蔽任何选项得到的文件所有权限都在,而第二次屏蔽掉了其他用户的所有权限。