其他分享
首页 > 其他分享> > 0x08_文件和目录

0x08_文件和目录

作者:互联网

文件系统

inode

其本质为结构体,存储文件的属性信息。如:权限、类型、大小、时间、用户、盘块位置(指向内容存储的磁盘位置)、引用计数等。也叫做文件属性管理结构,大多数的inode都存储在磁盘上。

近期使用的inode会被缓存到内存中。创建硬链接时,这些链接有相同的inode(不同的dentry),指向的磁盘存储空间也一致。

dentry

目录项,其本质依然是结构体,重要成员变量有两个:文件名、inode号(关联到inode中),而文件内容保存在磁盘盘块中。

函数stat、fstat、statat和lstat

#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);
成功返回0;失败返回-1。

给出pathname,stat函数返回与此命名文件有关的信息结构。fstat获得已在描述符fd上打开的文件的有关信息。lstat函数类似于stat,但是当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用的文件的信息(stat会有符号穿透,lstat不会)。

fstatat函数为一个相对于当前打开目录(由fd参数指向)的路径名返回文件统计信息。flag参数控制着是否跟随着一个符号链接。当flag设置为AT_SYMLINK_NOFOLLOW时,fstatat不会跟符号链接,而是返回符号链接本身的信息,否则默认情况下,返回的是符号链接所指向的实际文件的信息。如果fd的值是AT_FDCWD,并且pathname参数是一个相对路径名,fstatat会计算相对于当前目录的pathname参数。如果pathname是一个绝对路径,fd参数就会被忽略,这种情况下,根据flag的取值,fstatat的作用和stat或lstat一样。

buf是一个指针,函数来填充buf指向的结构,其基本形式是:

struct stat {
    mode_t          st_mode;    /* file type & mode (permissions) */
    ino_t           st_ino;     /* i-node number (serial number) */
    dev_t           st_dev;     /* ID of device containing file */
    dev_t           st_rdev;    /* device ID (if special file) */
    nlink_t         st_nlink;   /* number of links */
    uid_t           st_uid;     /* user ID of owner */
    gid_t           st_gid;     /* group ID of owner */
    off_t           st_size;    /* total size, in bytes, for regular files */
    struct timespec st_atime;   /* time of last access */
    struct timespec st_mtime;   /* time of last modification */
    struct timespec st_ctime;   /* time of last file status change */
    blksize_t       st_blksize; /* blocksize for filesystem I/O */
    blkcnt_t        st_blocks;  /* number of disk blocks allocated */
};

timespec结构类型按照秒和纳秒定义了时间,至少包括下面两个字段:

time_t tv_sec;
long   tv_nsec;

文件类型

  1. 普通文件。最常用的文件类型,数据是文本还是二进制数据对UNIX内核而言并无区别。对普通文件内容的解释由处理该文件的应用程序进行。一个例外是二进制可执行文件,为了执行程序,内核必须理解其格式,所有二进制可执行文件都遵循一种标准化的格式,这种格式使得内核能够确定程序文本和数据的加载位置。
  2. 目录文件。这种文件包含了其他文件的名字以及指向这些文件有关信息的指针。对一个目录文件具有读权限的任一进程都可以读该目录的内容,但只有内核可以直接写目录文件。进程必须使用函数才能更改目录。
  3. 块特殊文件。这种类型的文件提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
  4. 字符特殊文件。这种类型的文件提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件。
  5. FIFO。这种类型的文件用于进程间通信,有时也称为命名管道。
  6. 套接字。这种类型的文件用于进程间的网络通信。套接字也可用在进程间的非网络通信。
  7. 符号链接。这种类型的文件指向另一个文件。

文件类型信息都包含在stat结构的st_mode成员中。可以使用一些宏来确定文件类型:这些宏的参数都是stat结构中的st_mode成员。

S_ISREG(m)   普通文件
S_ISDIR(m)   目录文件
S_ISBLK(m)   块特殊文件
S_ISCHR(m)   字符特殊文件
S_ISFIFO(m)  管道或FIFO
S_ISSOCK(m)  套接字
S_ISLINK(m)  符号链接

早起的UNIX版本不提供S_ISxxx宏,需要将st_mode与屏蔽字S_IFMT进行逻辑与运算,然后与名为S_IFxxx的常量相比较。

设置用户ID和设置组ID

与一个进程相关联的ID有6个或更多:

实际用户ID
实际组ID
有效用户ID
有效组ID
附属组ID
保存的设置用户ID
保存的设置组ID

通常,有效用户ID等于实际用户ID,有效组ID等于实际组ID。每个文件有一个所有者和组所有者,所有者由stat结构中的st_uid指定,组所有者则由st_gid指定。

当执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,但是可以在st_mode中设置一个特殊标志,其含义是“当执行此文件时,将进程的有效用户ID设置为文件所有者的用户ID(st_uid)”。与此类似,在st_mode中可以设置另一位,将执行此文件的进程的有效组ID设置为文件的组所有者ID(st_gid)。

例如,若文件所有者是超级用户,而且设置了该文件的设置用户ID位,那么当该程序文件由一个进程执行时,该进程具有超级用户权限,不管执行此文件的进程的实际用户ID是什么。

文件访问权限

st_mode值也包含了对文件的访问权限位。所有文件类型(目录、字符特别文件等)都有访问权限。每个文件有9个权限位,可分为3类。

S_IRUSR   用户读
S_IWUSR   用户写
S_IXUSR   用户执行
S_IRGRP   组读
S_IWGRP   组写
S_IXGRP   组执行
S_IROTH   其他读
S_IWOTH   其他写
S_OXOTH   其他执行

3类访问权限以各种方式由不同的函数使用:

进程每次打开、删除或删除一个文件,内核就进行文件访问权限测试:

  1. 若进程的有效用户ID是0,则允许访问。给予了超级用户对整个文件系统最充分的自由。
  2. 若进程的有效用户ID等于文件的所有者ID(也就是进程拥有此文件),那么如果所有者适当的访问权限位被设置,则允许访问;否则拒绝访问。
  3. 若进程的有效组ID或进程的附属组ID之一等于文件的组ID,那么如果组适当的访问权限被设置,则允许访问;否则拒绝访问。
  4. 若其他用户适当的访问权限位被设置,则允许访问;否则拒绝访问。

新文件和目录的所有权

新文件的用户ID设置为进程的有效用户ID。组ID可以是进程的有效组ID或它所在目录的组ID。

函数access和faccessat

当用open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试。有时,进程也希望按其实际用户ID和实际组ID来测试其访问能力。例如,当一个进程使用设置用户ID或设置组ID功能作为另一个用户(或组)运行时,就可能有这种需要。

即使一个进程可能已经通过设置用户ID以超级用户权限运行,它仍可能想验证其实际用户能否访问一个给定的文件。access和faccessat函数是按实际用户ID和实际组ID进行访问权限测试的。

#include <unistd.h>
int access(const char *pathname, int mode);
int faccessat(int fd, const char *pathname, int mode, int flag);
若成功,返回0;若出错,返回-1。

如果测试文件是否已经存在,mode就为F_OK;否则,mode是常量的按位或:

R_OK   测试读权限
W_OK   测试写权限
X_OK   测试执行权限

faccessat函数与access函数在下面两种情况下是相同的:一种是pathname参数为绝对路径,另一种是fd参数取值为AT_FDCWD而pathname参数为相对路径。否则,faccessat计算相对于打开目录(由fd参数指向)的pathname。

flag参数可以用于改变faccessat的行为,如果flag设置为AT_EACCESS,访问检查用的是调用进程的有效用户ID和有效组ID,而不是实际用户ID和实际组ID。

函数umask

#include <sys/stat.h>
mode_t umask(mode_t cmask);

umask函数为进程设置文件模式创建屏蔽字,并返回之前的值。cmask是由9个常量(S_IRUSR、S_IWUSR等)中的若干个按位或构成的。在创建屏蔽字中为1的位,在文件权限中的相应位一定被关闭。

当编写创建新文件的程序时,如果想确保指定的访问权限位已经激活,就必须在进程运行时修改umask值,否则当进程运行时,有效的umask值可能关闭权限位。更改进程的文件模式创建屏蔽字并不影响其父进程(常常是shell)的屏蔽字。

可以设置umask值以控制他们所创建文件的默认权限,该值表示成八进制数,一位表示一种要屏蔽的权限。

shell支持符号形式的umask命令,与八进制格式不同,符号格式指定许可的权限而非拒绝的权限。

umask -S

函数chmod、fchmod和fchmodat

#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodat(int fd, const char *pathname, mode_t mode, int flag);

chmod函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。fchmodat函数与chmod函数在下面两种情况下是相同的:一种是pathname参数为绝对路径,另一种是fd参数取值为AT_FDCWD而pathname参数为相对路径。否则,fchmodat计算相对于打开目录(由fd参数指向)的pathname。flag参数可以用于改变fchmodat的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,fchmodat并不会跟随符号链接。

为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程必须具有超级用户权限。参数mode是常量的按位或:

S_ISUID   执行时设置用户ID
S_ISGID   执行时设置组ID
S_ISVTX   保存正文(粘着位)
S_IRWXU   所有者读写执行
S_IRUSR   所有者读
S_IWUSR   所有者写
S_IXUSR   所有者执行
S_IRWXG   组读写执行
S_IRGRP   组读
S_IWGRP   组写
S_IXGRP   组执行
S_IRWXO   其他读写执行
S_IROTH   其他读
S_IWOTH   其他写
S_OXOTH   其他执行
chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID)

粘着位

在早期UNIX,如果一个可执行程序文件的粘着位被设置了,那么当该程序第一次被执行,在其终止时,程序正文部分的一个副本仍被保存在交换区,使得下次执行该程序时能较快地将其装载入内存。

现在的系统扩展了粘着位的使用范围。如果一个目录设置了粘着位,只有对该目录具有写权限的用户并且满足下列条件之一,才能删除或重命名该目录下的文件:

函数chown、fchown、fchownat和lchown

#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 group, int flag);
int lchown(const char *pathname, uid_t owner, gid_t group);

chown函数可用于更改文件的用户ID和组ID。如果两个参数owner或group中的任意一个是-1,则对应的ID不变。

在符号链接情况下,lchown和fchownat(设置了AT_SYMLINK_NOFOLLOW标志)更改符号链接本身的所有者,而不是该符号链接所指向的文件的所有者。

文件长度

stat结构成员st_size表示以字节为单位的文件的长度。此字段只对普通文件、目录文件和符号链接有意义。对于普通文件,其文件长度可以是0,在开始读这种文件时,将得到文件结束(end-of-file)指示。对于目录,文件长度通常是一个数(如16或512)的整倍数。对于符号链接,文件长度是在文件名中的实际字节数,注意,因为符号链接文件长度总是由st_size指示,所以它并不包含通常的C语言用作字符串结尾的null字节。

文件中的空洞

空洞是由所设置的偏移量超过文件尾端,并写入了某些数据后造成的。

ls -l core
-rw-r--r-- l sar     8483248 Nox 18 12:18 core

du -s core
272   core

文件core的长度稍稍超过8MB,而du命令报告该文件所使用的的磁盘空间总量是272个512字节块(即139264字节),此文件有很多空洞。

对于没有写过的字节位置,read函数读到的字节是0.如果使用程序复制这个文件,那么所有的空洞都会被填满,其中所有实际数据字节皆填写为0。

文件截断

#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int fd, off_t length);

将一个现有文件长度截断为length,如果该文件以前的长度大于length,则超过length以外的数据就不再能访问。如果以前的长度小于length,文件长度将增加,在以前的文件尾端和新的文件尾端之间的数据将读作0(也就是可能在文件中创建了一个空洞)。

文件系统

如果两个目录项dentry指向同一个inode节点,(每个inode中都有一个链接计数,其值是指向该inode的目录项数)。只有当链接计数减少至0时,才可删除该文件,也就是可以释放该文件占用的数据块。在stat结构中,链接计数包含在st_nlink成员中。这种链接类型称为硬链接。

另外一种链接称为符号链接(软链接),符号链接文件的实际内容(在数据块中)包含了该符号链接所指向的文件的名字。

inode中包含了文件有关的所有信息:文件类型、文件访问权限位、文件长度和指向文件数据块的指针等。stat结构中的大多数信息都取自inode。只有两项数据存放在目录项dentry中:文件名和inode号。

因为目录项中的inode编号指向同一文件系统中的相应inode,一个目录项不能指向另一个文件系统的inode。这就是ln(构造一个指向一个现有文件的新目录项)不能跨越文件系统的原因。

当在不更换文件系统的情况下为一个文件重命名时,该文件的实际内容并未移动,只需构造一个指向指向现有inode的新目录项,并删除老的目录项。链接计数不会改变。

对于目录文件,任何一个叶目录(不包含任何其他目录的目录)的链接计数总是2,来自于命名该目录的目录项以及在该目录中的.项。注意,在父目录中的每一个子目录都使该父目录的链接计数增加1来自于..

函数link、linkat、unlink、unlinkat和remove

任何一个文件可以有多个目录项指向其inode。创建一个指向现有文件的链接(硬链接)的方法是使用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);
若成功,返回0;若出错,返回-1。

两个函数创建一个新目录项newpath,它引用现有文件existingpath。如果newpath已经存在,则返回出错。函数只创建newpath中的最后一个分量,路径中的其他部分应当已经存在。

对于linkat函数,现有文件是通过efd和existingpath参数指定的,新的路径名是通过nfd和newpath参数指定的。默认情况下,如果两个路径名中的任一个是相对路径,则它需要通过相对于对应的文件描述符进行计算。如果两个文件描述符的任一个设置为AT_FDCWD,那么相应的路径名(如果它是相对路径)就通过相对于当前目录进行计算。如果任一路径名是绝对路径,相应的文件描述符参数就会被忽略。

当现有文件是符号链接时,由flag参数来控制linkat函数是创建指向现有符号链接的链接还是创建指向现有符号链接所指向的文件的连接。如果在flag参数中设置了AT_SYMLINK_FOLLOW标志,就创建指向符号链接目标的连接,如果这个标志被清除了,则创建一个指向符号链接本身的链接。

为了删除一个现有的目录项,可以调用unlink函数。

#include <unistd.h>
int unlink(const char *pathname);
int unlinkat(int fd, const char *pathname, int flag);
若成功,返回0;若出错,返回-1。

这两个函数删除目录项,并将由pathname所引用文件的链接计数减1,如果对该文件还有其他链接,则仍可通过其他链接访问该文件的数据,如果出错,则不对该文件做任何更改。

只有当链接计数达到0时,该文件的内容才可被删除,无目录项对应的文件,将会被操作系统择机释放。另一个条件也会阻止删除文件的内容——只要有进程打开了该文件,其内容也不能删除。关闭一个文件时,内核首先检查打开该文件的进程个数,如果这个计数达到0,内核再去检查其链接计数,如果计数也是0,那么就删除该文件的内容。

如果pathname参数是相对路径名,那么unlinkat函数计算相对于由fd文件描述符参数代表的目录的路径名。如果fd参数设置为AT_FDCWD,那么通过相对于调用进程的当前工作目录来计算路径名。如果pathname参数是绝对路径名,那么fd参数被忽略。

flag参数给出了一种方法,使调用进程可以改变unlinkat函数的默认行为。当AT_REMOVEDIR标志被设置时,unlinkat函数可以类似于rmdir一样删除目录。如果这个标志被清除,unlinkat与unlink执行同样的动作。

unlink的特性经常被程序用来确保即使是在程序崩溃时,它所创建的临时文件也不会遗留下来。进程用open或creat创建一个文件,然后立即调用unlink,因为该文件仍旧是打开的,所以不会将其内容删除。只有当进程关闭该文件或终止时(此时,内核关闭该进程所打开的全部文件),该文件的内容才被删除。

如果pathname是符号链接(软链接),那么unlink删除该符号链接,而不是删除由该链接所引用的文件。给出符号链接名的情况下,没有一个函数能删除由该链接所引用的文件。

也可以用remove函数解除对一个文件或目录的链接,对于文件,remove的功能与unlink相同,对于目录,remove的功能与rmdir相同。

#include <stdio.h>
int remove(const char *pathname);

函数rename和renameat

文件或目录可以用rename函数或者renameat函数进行重命名。

#include <stdio.h>
int rename(const char *oldname, const char *newname);
int renameat(int oldfd, const char *oldname, int newfd, const char *newname);
若成功,返回0;若出错,返回-1。
  1. 如果oldname指的是一个文件而不是目录,那么为该文件或符号链接重命名。在这种情况下,如果newname已经存在,则它不能引用一个目录,如果newname已经存在,而且不是一个目录,则先将该目录项删除然后将oldname重命名为newname。对包含oldname的目录以及包含newname的目录,调用进程必须具有写权限,因为将更改这两个目录。
  2. 如若oldname指的是一个目录,那么为该目录重命名。如果newname已存在,则它必须引用一个目录,而且该目录应当是空目录(该目录中只有...项)。如果newname存在(而且是一个空目录),则先将其删除,然后将oldname重命名为newname。另外,当为一个目录重命名时,newname不能包含oldname作为其路径前缀。例如,不能将/usr/foo重命名为/usr/foo/testdir,因为旧名字是新名字的路径前缀,因而不能将其删除。
  3. 如果oldname或newname引用符号链接,则处理的是符号链接本身,而不是它所引用的文件。
  4. 不能对...重命名。
  5. 作为一个特例,如果oldname和newname引用同一文件,则函数不做任何更改而成功返回。

oldfa或newfd参数都能设置成AT_FDCWD,此时相对于当前目录来计算相应的路径名。

符号链接

符号链接是对一个文件的间接指针,与硬链接有所不同,硬链接直接指向文件的inode。引入符号链接的原因是为了避免硬链接的一些限制。

当使用以名字引用文件的函数时,应当了解该函数是否处理符号链接。也就是该函数是否跟随符号链接到达它所链接的文件。如果该函数具有处理符号链接的功能,则其路径名参数引用由符号链接指向的文件。否则,一个路径名参数引用链接本身,而不是由该链接指向的文件。当前所接触的函数中,lchown、lstat、readlink、remove、rename、unlink都不跟随符号链接。

用open打开文件时,如果传递给open函数的路径名指定了一个符号链接,那么open跟随此链接到达所指定的文件。若此符号链接所指向的文件并不存在,则open返回出错,表示它不能打开该文件。

创建和读取符号链接

可以用symlink或symlinkat函数创建一个符号链接:

#include <unistd.h>
int symlink(const char *actualpath, const char *sympath);
int symlinkat(const char *actualpath, int fd, const char *sympath);

函数创建一个指向actualpath的新目录项sympath。在创建此符号链接时,并不要求actualpath已经存在。symlinkat函数与symlink函数类似,但sympath参数根据相对于打开文件描述符引用的目录(有fd参数指定)进行计算。如果sympath参数指定的是绝对路径或者fd参数设置为AT_FDCWD值,那么symlinkat就等同于symlink函数。

因为open函数跟随符号链接,所以需要有一种方法打开该链接本身,并读链接中的名字:

#include <unistd.h>
ssize_t readlink(const char *pathname, char *restrict buf, size_t bufsize);
ssize_t readlinkat(int fd, const char *restrict pathname, char *buf, size_t bufsize);

如果函数成功执行,则返回读入buf的字节数,在buf中返回的符号链接不以null字节终止。

文件的时间

每个文件维护三个时间字段:

st_atim        文件数据的最后访问时间         read                       ls -u
st_mtim        文件数据的最后修改时间         write                      ls
st_ctim        inode状态的最后更改时间        chmod、chown               ls -c

修改时间是文件内容最后一次被修改的时间。状态更改时间是该文件的inode最后一次被修改的时间。状态更改如:更改文件访问权限、更改用户ID、更改链接数等,但它们并没有更改文件的实际内容。因为inode中的所有信息都是与文件的实际内容分开存放的,所以,需要记录文件数据修改时间以外,还需要记录状态更改时间。

函数futimens、utimensat和utimes

一个文件的访问和修改时间可以用一下几个函数更改。futimens和utimensat函数可以指定纳秒级精度的时间戳。

#include <sys/stat.h>
int futimens(int fd, const struct timespec times[2]);
int utimensat(int fd, const char *path, const struct timespec times[2], int flag);
若成功,返回0;若出错,返回-1。

这两个函数的times数组参数的第一个元素包含访问时间,第二个元素包含修改时间。这两个时间值是日历时间,从1970年1月1日以来所经历的秒数。

时间戳可按下列4种方式之一进行指定:

  1. 如果times参数是一个空指针,则访问时间和修改时间两者都设置为当前时间。
  2. 如果times参数指向两个timespec结构的数组,任一数组元素的tv_nsec字段的值为UTIME_NOW,相应的时间戳就设置为当前时间,忽略相应的tv_sec字段。
  3. 如果times参数指向两个timespec结构的数组,任一数组元素的tv_nsec字段的值为UTIME_OMIT,相应的时间戳保持不变,忽略相应的tv_sec字段。
  4. 如果times参数指向两个timespec结构的数组,且tv_nsec字段的值既不是UTIME_NOW也不是UTIME_OMIT,这种情况下,相应的时间戳设置为相应的tv_sec和tv_nsec字段的值。

函数mkdir、mkdirat和rmdir

用mkdir和mkdirat函数创建目录,用rmdir删除目录。

#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
int mkdirat(int fd, const char *pathname, mode_t mode);
若成功,返回0;若出错,返回-1。

对于目录通常至少要设置一个执行权限位,以允许访问该目录的文件名。

用rmdir函数可以删除一个空目录,空目录是只包含...这两项的目录。

#include <unistd.h>
int rmdir(const char *pathname);
若成功,返回0;若出错,返回-1。

如果调用此函数使目录的链接计数成为0,并且也没有其他进程打开此目录,则释放由此目录占用的空间。

函数chdir、fchdir和getcwd

每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点。进程调用chdir或fchdir函数更改当前工作目录。

#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int fd);

函数getcwd获取进程当前工作目录的绝对路径。

#include <unistd.h>
char *getcwd(char *buf, size_t size);

文件、目录rwx权限

目录也是文件,其文件内容是该目录下所有子文件的目录项dentry。

读文件:cat、more、less...

写文件:vi、>...

执行文件:./fname

读目录项:ls、tree...

删除、创建、修改文件:mv、touch、mkdir...

搜索路径名:cd

目录设置粘着位,若有w权限,创建权限不受影响,修改、删除只能由root、目录所有者、文件所有者操作。

读目录

对某个目录具有访问权限的任一用户都可以读该目录,但是只有内核才能写目录。一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,并不表示能否写目录本身。

#include <dirent.h>
DIR *opendir(const char *pathname);
DIR *fdopendir(int fd);
若成功,返回指针;若出错,返回NULL

struct dirent *readdir(DIR *dp);
若成功,返回指针;若在目录尾或出错,返回NULL

void rewinddir(DIR *dp);    回卷目录读写位置至起始
int closedir(DIR *dp);
若成功,返回0;若出错,返回-1

long telldir(DIR *dp);
返回与dp关联的目录中的当前位置,获取目录读写位置

void seekdir(DIR *dp, long loc);  修改目录读写位置

dirent结构与实现有关,定义至少包括成员:

ino_t d_ino;
char d_name[];    以NULL结尾的文件名

d_name项的大小没有被指定,文件名以null字节结束,所以在头文件中如何定义数组d_name无关系,数组大小不表示文件名的长度。

标签:文件,0x08,int,目录,ID,权限,链接
来源: https://www.cnblogs.com/pannnn/p/16285992.html