标签:
本篇主要介绍文件和文件系统中常用的一些函数,文件系统的组织结构和硬链接、符号链接。
通过对这些知识的了解,可以对Linux文件系统有更为全面的了解。
?
之前我们已经了解了每个文件与权限相关的9个位(bit),我们现在来了解一下当每个进程创建文件时默认会设置该文件的文件权限(the file mode creation mask)。
umask函数设置该进程默认创建文件的权限掩码(the file mode creation mask),并且返回之前的权限掩码值。
#include <sys/stat.h>
mode_t umask(mode_t cmask);
the file mode creation mask的作用:当进程创建新文件时,会根据这个掩码值创建文件,在掩码值中打开的位,对应的新文件的权限位会被关闭。
umask的功能简单地说就是创建新文件时屏蔽掉用户不希望生效的权限位。
Example:
#include "apue.h"
#include <fcntl.h>
?
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
?
int
main(void)
{
? ? umask(0);
? ? if (creat("foo", RWRWRW) < 0)
? ? ? ? err_sys("creat error for foo");
? ? umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
? ? if (creat("bar", RWRWRW) < 0)
? ? ? ? err_sys("creat error for bar");
? ? exit(0);
}
运行截图:
结果说明:
shell的umask命令显示当前文件创建权限掩码。
0022表示创建出来的新文件,组用户和other用户没有写该文件的权限。
在程序中,首先用默认的权限设置创建了文件foo,它的权限位666,至于为什么当前用户也没有执行权限,我还没搞清楚,留一个坑 @suzhou。
然后修改umask值为0077,这样就屏蔽掉了组用户和其他用户的读写权限位,因此再创建新文件bar,它的权限位是600。
?
函数作用:修改已有文件的权限位。
函数声明:
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodeat(int fd, const char *pathname, mode_t mode, int flag);
?区别:
权限要求:要修改一个文件的权限,需要当前进程的effective user ID和文件的所有者ID相同,或者进程有超级用户权限。
代表各个权限位的常量如下表所示:
Example:
修改在上例中创建的两个文件foo和bar的权限。
#include "apue.h"
?
int
main(void)
{
? ? struct stat ? ? statbuf;
?
? ? /* turn on set-group-ID and turn off group-execute */
?
? ? if (stat("foo", &statbuf) < 0)
? ? ? ? err_sys("stat error for foo");
? ? if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
? ? ? ? err_sys("chmod error for foo");
?
? ? /* set absolute mode to "rw-r--r--" */
?
? ? if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
? ? ? ? err_sys("chmod error for bar");
?
? ? exit(0);
}
运行结果:
结果说明:
高级权限(SUID/SGID/Sticky Bit )档案特殊权限 说明:
?
Sticky bit有一个冗长的历史,这里并不赘述。
作用:如果文件夹的sticky bit被打开,则文件夹中的文件被删除或者重命名需要满足一下的条件之一:当前用户对该文件夹有写权限;当前用户是该文件的所有者;当前用户是该文件夹的所有者;当前用户是超级用户。
典型的打开了sticky bit的两个文件夹是/tmp 和/var/tmp,这两个文件夹对所有用户都有读写和执行权限,这样所有用户都可以在该文件夹下创建文件,但是并不能删除由其他用户所有的文件。
?
函数作用:修改文件所属的用户ID和组ID,如果参数owner和group有一个的值为-1,对应的ID值不变。
#include <unistd.h>
int chown(const char* pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int fchownat(int fd, const char* pathname, uid_t owner, gid_t grou, int flag);
int lchown(const char* pathname, uid_t owner, gid_t group);
区别:
当目标文件不是一个符号链接时,上面的四个函数的作用基本相同。
当目标文件是一个符号链接文件时,并且函数lchown和fchownat的flag设置为AT_SYMLINK_NOFOLLOW时,这两个函数修改符号链接文件本身的所有者,而不是符号链接指向的文件。
fchown函数修改fd代表的已打开文件的所有者。因为fchown操作的是已经打开的文件,所以它不可以用来修改符号链接的所有者。
fchownat函数的行为:当参数pathname是绝对路径,或者参数fd的值为AT_FDCWD并且pathname为相对路径时,fchownat函数的行为和chown和lchown类似;具体来说,flag取值AT_SYMLINK_NOFOLLOW时,行为和lchown类似;否则行为和chown类似。当fd代表已打开的文件夹,pathname为一个相对路径时,目标文件为以fd为父目录,pathname为相对的子目录所指的文件。
?
stat结构体中的成员st_size表示文件大小字节数。
字段st_size只对常规文件(regular files)、目录文件(directories)和符号链接文件(symbolic links)。
更多的细节:
?
有时候我们需要通过丢弃文件结尾一部分来截短文件。
函数声明:
#include <unistd.h>
int truncate(const char* pathname, off_t length);
itn ftruncate(int fd, off_t length);
函数作用:把目标文件截断到参数length指定的长度。
参数:如果参数length的值比指定文件的长度小,则文件超过length长度的部分不可读;如果length的值比指定文件的长度大,文件长度扩大到length,扩充部分填充0(可能是一个hole)
?
为了理解文件链接,我们需要对Unix文件系统的结构有一个概念性地认识。
一个磁盘(disk drive)可以被分为多个分区(partition),每个分区都可以包含一个文件系统(file system)。
inode是一个定长的索引,包含了一个文件的大部分信息。
关于 i-nodes和data blocks的内存布局如下图所示:
说明:
我们再了解一下目录文件的link count字段。
当我们执行下面的命令:
mkdir testdir
?内存中数据组织结构如下所示:
从上图可以看到,目录下每多加一个文件或文件夹,link count都会加1。
图中显示的都很清楚,不做过多赘述(其实是我懒了,哈哈...)
?
从前面可以知道,多个目录索引可以指向同一个文件,即多个目录可以包含同一个文件。
link和linkat的作用是创建一个已存在文件的链接。
函数声明:
#include <unistd.h>
int link(const char* existingpath, const char* newpath);
int linkat(int efd, const char* existingpath, int nfd, const char* newpath, int flag);
函数细节:
函数声明:
#include <unistd.h>
int unlink(const char* pathname);
int unlinkat(int fd, const char* pathname, int flag);
函数细节:
和unlink类似功能的函数remove:
#include <stdio.h>
int remove(const char* pathname);
函数细节:
?
函数声明:
#include <stdio.h>
int rename(const char* oldname, const char* newname);
int renameat(int oldfd, const char* oldname, int newfd, const char* newname);
函数细节:
对renameat函数的参数含义不再赘述。
?
符号链接可以认为是文件的非直接指针,而硬链接(hard link)可以看做是文件的直接指针,因为它直接指向文件的inode。
符号链接并没有文件系统间的限制。
由于符号链接的存在,我们在操作文件或目录时,总是需要知道该文件是否是一个符号链接,然后判断该函数的操作对象是符号链接指向的文件还是符号链接本身。
下图总结了一些常用函数是否追踪链接,仅供参考:
Example:
链接情况如下图所示:
可以发现,由于符号链接而出现了一个环。
再来试验一下:
我们发现,这样会无限循环下去。
解除循环的方法就是使用unlink删除该符号链接。需要注意的一点是,如果这里出现的链接是硬链接,则删除这个循环链接会困难得多。因此只有管理员权限才可以用link函数对一个文件建立硬链接。
有时候符号链接会造成一些迷惑的事情,如果使用者对符号链接不熟悉的话。
如下所示:
符号链接可以链接一个不存在的文件,如果使用者对符号链接不熟悉,则很容易被这种情况迷惑。
这时,可以使用ls的”-l"命令看到有 “->"符号,或者前面符号位第一位的”l”表示符号链接,或者用ls得“-F”命令,符号链接文件后面会跟一个@符。
?
函数作用:创建符号链接
函数声明:
#include <unistd.h>
int symlink(const char *actualpath, const char* sympath);
int symlinkat(const char* actualpath, int fd, const char* sympath);
参数说明:
因为open函数会打开符号链接指向的实际文件,所以需要一个函数打开符号链接本身。
函数声明:
#include <unistd.h>
ssize_t readlink(const char* restrict pathname, char* restrict buf, size_t bufsize);
ssize_t readlinkat(int fd, const char* restrict pathname, char* restrict buf, size_t bufsize);
如果调用成功,函数从符号链接中读取buf长的内容。
?
?
参考资料:
《Advanced Programming in the UNIX Envinronment 3rd》
?
UNIX高级环境编程(4)Files And Directories - umask、chmod、文件系统组织结构和链接
标签:
原文地址:http://www.cnblogs.com/suzhou/p/4302062.html