-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfilestat.html
411 lines (380 loc) · 17.4 KB
/
filestat.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<title>文件属性 | 《UNIX环境高级编程》学习笔记</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="" name="description"/>
<meta content="GitBook 2.6.7" name="generator"/>
<meta content="true" name="HandheldFriendly"/>
<meta content="width=device-width, initial-scale=1, user-scalable=no" name="viewport"/>
<meta content="yes" name="apple-mobile-web-app-capable"/>
<meta content="black" name="apple-mobile-web-app-status-bar-style"/>
<link href="gitbook/images/apple-touch-icon-precomposed-152.png" rel="apple-touch-icon-precomposed" sizes="152x152"/>
<link href="gitbook/images/favicon.ico" rel="shortcut icon" type="image/x-icon"/>
<link href="gitbook/style.css" rel="stylesheet"/>
<link href="gitbook/plugins/gitbook-plugin-highlight/website.css" rel="stylesheet"/>
<link href="gitbook/plugins/gitbook-plugin-search/search.css" rel="stylesheet"/>
<link href="gitbook/plugins/gitbook-plugin-fontsettings/website.css" rel="stylesheet"/>
<link href="./libio.html" rel="next"/>
<link href="./fileio.html" rel="prev"/>
</head>
<body>
<div class="book" data-basepath="." data-chapter-title="文件属性" data-filepath="filestat.md" data-innerlanguage="" data-level="4" data-revision="Thu May 17 2018 00:06:37 GMT+0800 (CST)">
<div class="book-summary">
<nav role="navigation">
<ul class="summary">
<li class="chapter " data-level="0" data-path="index.html">
<a href="./index.html">
<i class="fa fa-check"></i>
Introduction
</a>
</li>
<li class="chapter " data-level="1" data-path="unixbase.html">
<a href="./unixbase.html">
<i class="fa fa-check"></i>
<b>1.</b>
UNIX 基础
</a>
</li>
<li class="chapter " data-level="2" data-path="unixstandard.html">
<a href="./unixstandard.html">
<i class="fa fa-check"></i>
<b>2.</b>
UNIX标准及其实现
</a>
</li>
<li class="chapter " data-level="3" data-path="fileio.html">
<a href="./fileio.html">
<i class="fa fa-check"></i>
<b>3.</b>
文件IO
</a>
</li>
<li class="chapter active" data-level="4" data-path="filestat.html">
<a href="./filestat.html">
<i class="fa fa-check"></i>
<b>4.</b>
文件属性
</a>
</li>
<li class="chapter " data-level="5" data-path="libio.html">
<a href="./libio.html">
<i class="fa fa-check"></i>
<b>5.</b>
标准IO库
</a>
</li>
<li class="chapter " data-level="6" data-path="sysinfo.html">
<a href="./sysinfo.html">
<i class="fa fa-check"></i>
<b>6.</b>
系统文件和信息
</a>
</li>
<li class="chapter " data-level="7" data-path="processenv.html">
<a href="./processenv.html">
<i class="fa fa-check"></i>
<b>7.</b>
进程环境
</a>
</li>
<li class="chapter " data-level="8" data-path="processctl.html">
<a href="./processctl.html">
<i class="fa fa-check"></i>
<b>8.</b>
进程控制
</a>
</li>
<li class="divider"></li>
<li>
<a class="homepage-back" href="https://freebug.top/book/" target="_self">
Back to Book</a>
</li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<!-- Actions Left -->
<!-- Title -->
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i>
<a href="./">《UNIX环境高级编程》学习笔记</a>
</h1>
</div>
<div class="page-wrapper" role="main" tabindex="-1">
<div class="page-inner">
<section class="normal" id="section-">
<h1 id="文件属性">文件属性</h1>
<hr/>
<h4 id="文件类型">文件类型</h4>
<p>UNIX下有七种文件类型: </p>
<ul>
<li><strong>普通文件</strong>,普通文件包含某种数据,无论是文本还是二进制数据,对于内核并无区别,对普通文件内容的解释由应用程序来完成,但是可执行程序是个例外,内核必需理解其格式。</li>
<li><strong>目录文件</strong>,这种文件包含了其他文件的名字以及指向这些文件的有关信息,进程只要对目录具有读权限就可以读取目录的内容,但是只有内核才可以直接写目录文件。</li>
<li><strong>块特殊文件</strong>,提供对设备带缓冲的访问,每次读取长度固定。</li>
<li><strong>字符特殊文件</strong>,提供对设备不带缓冲的访问,每次访问长度可变。</li>
<li><strong>FIFO</strong>, 用于进程间通信,有时也称为命名管道。</li>
<li><strong>套接字</strong>,用于进程间网络通信。</li>
<li><strong>符号链接</strong>,这种文件指向另一个文件。
文件类型信息包含在stat结构的st_mode,中可以用下面的宏来确定文件类型,这些宏的参数都是st_mode数据。</li>
</ul>
<table>
<thead>
<tr>
<th>宏</th>
<th>文件类型</th>
</tr>
</thead>
<tbody>
<tr>
<td>S_ISREG</td>
<td>普通文件</td>
</tr>
<tr>
<td>S_ISDIR</td>
<td>目录文件</td>
</tr>
<tr>
<td>S_ISBLK</td>
<td>块特殊文件</td>
</tr>
<tr>
<td>S_ISCHR</td>
<td>字符特殊文件</td>
</tr>
<tr>
<td>S_ISFIFO</td>
<td>FIFO或命名管道</td>
</tr>
<tr>
<td>S_ISLINK</td>
<td>符号链接</td>
</tr>
<tr>
<td>S_ISSOCK</td>
<td>套接字</td>
</tr>
</tbody>
</table>
<h4 id="文件stat">文件stat</h4>
<p>stat的实际定义可能随具体实现有所不同,但其基本形式如下:</p>
<pre><code>struct stat {
mode_t st_mode; //
ino_t st_ino; //
dev_t st_dev; //
dev_t st_rdev; //
nlink_t st_nlink; //
uid_t st_uid; //
gid_t st_gid; //
off_t st_size; //
struct timespec st_atime; //
struct timespec st_mtime; //
struct timespec st_ctime; //
blksize_t st_blksize; //
blkcnt_t st_blocks; //
</code></pre><p>stat 的四个操作函数定义如下</p>
<pre><code>#include<sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int fd, struct *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
</code></pre><p>使用stat函数最多的应该是<code>ls -l</code>命令,用ls可以获取一个文件的所有信息。</p>
<h4 id="用户id和组id">用户ID和组ID</h4>
<p>和一个进程相关联的ID至少有6个</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td>实际用户ID和实际组ID</td>
<td>我们是谁,取自口令文件登录项,只有超级进程可以改变</td>
</tr>
<tr>
<td>有效用户ID和有效组ID</td>
<td>用于文件访问权限检查</td>
</tr>
<tr>
<td>保存的设置用户ID和组ID</td>
<td>由exec函数保存</td>
</tr>
</tbody>
</table>
<p>当执行一个程序文件的时候,进程的有效ID通常就是实际ID,但是在st_mode中有两个位被称为设置用户ID和设置组ID,可以由S_ISUID和S_ISGID测试,他们在进程执行时,可以把进程的有效ID设置为文件所有者的ID。所以编写这样的函数需要特别小心,</p>
<h4 id="文件访问权限">文件访问权限</h4>
<p>一个文件有9个访问权限位,分为user,group,other。如`drwxr-xr-x`,第一位表示他是一个目录。
<code>S_IEUSR|S_IWUSR|S_IXUSR,S_IEGRP|S_IWGRP|S_IXGRP,S_IEOTH|S_IWOTH|S_IXOTH</code></p>
<h4 id="访问权限测试">访问权限测试</h4>
<pre><code>#include<unistd.h>
int access(const char *pathname, int mode);//mode=R_OK | W_OK | X_OK
int faccess(ingt fd, const char *pathname, int mode, int flag);
//成功返回0 ,出错返回-1
</code></pre><h4 id="创建文件屏蔽字">创建文件屏蔽字</h4>
<pre><code>#include<sys/stat.h>
mode_t umask(mode_t cmask);//cmask=S_IRUSR|S_IWUSR...等或成
//返回之前的文件模式创建屏蔽字
</code></pre><p>进程创建新文件一定会使用umask,open和creat都有一个mode参数,</p>
<h4 id="文件权限修改">文件权限修改</h4>
<p>改变文件的权限,进程必须是超级用户权限或者有效用户ID等于文件的所有者ID</p>
<pre><code>#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);
//成功返回0 ,出错返回-1
</code></pre><h4 id="更改文件的用户id和组id">更改文件的用户ID和组ID</h4>
<pre><code>#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, git_t group, int flag);
int lchown(const char *pathname, uid_t owner, git_t group);
//成功返回0 ,出错返回-1
</code></pre><p>这四个函数操作类似,在符号链接情况下,lchown,fchownat(flag=AT_SYMLINK_NOFOLLOW)更改符号链接本身的所有者,而不是指向该符号链接所指向的文件的所有者。
基于BSD的系统只允许超级用户更改文件的所有者,而System V允许任一用户更改他所拥有的文件的所有者,POSIX.1允许在这两种操作中选用一种,由宏<code>_POSIX_CHOWN_RESTRICTED</code>控制,它可以用pathconf和fpathconf函数查询,还可以在每个文件系统基础上,使该选项起作用或不起作用。</p>
<h4 id="文件长度">文件长度</h4>
<p>stat的结构成员st_size表示以字节为单位的文件长度,此字段只对普通文件,目录文件和符号链接有意义。此外,大多数UNIX系统还提供st_blocksize,st_blocks,第一个是对文件IO较合适的块长度,第二个是所分配的实际xx字节字节块块数。xx由系统制定。st_blocksize用于读写操作时,读写一个文件所需的时间最少。</p>
<h4 id="文件的空洞">文件的空洞</h4>
<p>文件的空洞是由所设置的偏移量超过文件尾端照成的,除非写入数据,空洞可能不会占用实际物理内存,但是如果复制这个文件,那么新文件的空洞都会被0填满。</p>
<h4 id="文件截断">文件截断</h4>
<p>O_TRUNC可以把文件截断为0,此外截断文件还可以调用下面的函数</p>
<pre><code>#include<unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int fd, off_t length);
//成功返回0,出错返回-1
</code></pre><h4 id="文件系统">文件系统</h4>
<p>我们可以把一个磁盘分成一个或者多个分区,每个分区可以包含一个文件系统,文件系统mount在根文件系统下,<code>i</code>节点是固定长度的记录项,它包含有关文件系统的大部分信息。每一个<code>i</code>节点都有一个链接计数,表示有多少个目录项指向该文件,只有计数为0时才能删除该文件。在stat结构中,链接计数包含在st_nlink中,这种链接类型称为硬链接。还有一种链接是符号链接(软链接),在软链接中包含了实际指向的文件的名字,stat中大多数信息都来自<code>i</code>节点。只有文件名和i节点编号存在目录项中,需要注意的是目录项中的<code>i</code>节点编号指向同一个文件系统中的相应<code>i</code>节点,这也是ln创建的硬链接不能跨越文件系统的原因。</p>
<h4 id="link操作">LINK操作</h4>
<p>任何一个文件可以有多个目录项指向其<code>i</code>节点,创建一个指向现有文件的链接方法是用link和linkat函数,相关操作具体如下</p>
<pre><code>#include<unistd.h>
int link(const char *existngpath, const char *newpath);
int linkat(int efd, chonst char * existngpath, int nfd, const char *newpath, int flag);
int ulink(const char *pathname);
int ulinkat(int fd, const char *pathname, int flag);
int remove(const char *pathname);
//成功返回0,出错返回-1
</code></pre><p>对于文件remove等于ulink,对于目录,remove等雨rmdir</p>
<h4 id="文件目录重命名">文件目录重命名</h4>
<pre><code>#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
</code></pre><h4 id="符号链接">符号链接</h4>
<p>符号链接是对一个文件的间接指针,而硬链接直接指向文件得<code>i</code>节点,两者区别如下:</p>
<ul>
<li>硬链接通常要求文件和链接位于同一个文件系统中。</li>
<li>只有超级用户才能创建指向目录的硬链接,需要底层文件系统支持,但是这样会带来循环的隐患。</li>
<li>对符号链接以及它指向何种对象和文件系统并没有限制,一般用于将文件和目录移到系统的另一个位置。我开发的时候经常会用到这个操作。多种方案共用一个符号链接指向不同的目录。</li>
</ul>
<pre><code>#include<unistd.h>
int symlink(const char *actualpath, const char *sympath);
int symlinkat(const char *actualpath, int fd, const cahr *sympath);
//成功返回0,出错返回-1
</code></pre><p>由于open跟随符号链接,打开链接会打开实际的目录或者文件所以需要一个方法打开链接本身并读取链接中的名字</p>
<pre><code>#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);
//成功返回读取的字节数,失败返回-1
</code></pre><h4 id="文件时间">文件时间</h4>
<p>对于每个文件维护三个时间段,如图所示:</p>
<table>
<thead>
<tr>
<th>字段</th>
<th>说明</th>
<th>例子</th>
<th>ls选项</th>
</tr>
</thead>
<tbody>
<tr>
<td>st_atim</td>
<td>文件数据的最后访问时间</td>
<td>read</td>
<td>-u</td>
</tr>
<tr>
<td>st_mtim</td>
<td>文件数据的最后修改时间</td>
<td>write</td>
<td>默认</td>
</tr>
<tr>
<td>st_ctim</td>
<td>i节点状态的最后修改时间</td>
<td>chmod,chown</td>
<td>-c</td>
</tr>
</tbody>
</table>
<p>相关操作函数如下:</p>
<pre><code>#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 flags);
//成功返回0,出错返回-1
</code></pre><pre><code>#include<sys/time.h>
struct timeval{
time_t tv_sec;/* seconds */
long tv_usec;
};
int utime(const char *pathname, const struct timeval times[2]);
//成功返回0,出错返回-1
</code></pre><h4 id="目录操作">目录操作</h4>
<p>目录需要执行权限,以允许访问该目录中的文件名。<code>.</code>,<code>..</code>目录项自动创建。</p>
<pre><code>#include<sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
int mkdirat(int fd, const char *pathname, mode_t mode);
//成功返回0,出错返回-1
#inlcude<unistd.h>
int rmdir(const char *pathname);
//成功返回0,出错返回-1
#include<dirent.h>
DIR opendir(const cahr *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);
</code></pre><p>每个进程都有一个当前工作目录,可以通过chdir和fchdir更改,注意当前工作目录是进程的一个属性,修改不会影响其他进程。这也是cd命令内建在shell中的原因。</p>
<pre><code>#include<unistd.h>
int chdir(const char *pathname);
int fchdir(int fd);
//成功返回0,出错返回-1
</code></pre><p>内核不保存完整的路径名,但是Linux可以确定完整的路径名,我们需要一个函数来获取获取绝对路径</p>
<pre><code>#include<unistd.h>
char *getcwd(cahr *buf, size_t size);
//成功返回buf,出错返回NULL,buf必须足够大,否则返回出错。
</code></pre><h5 id="设备特殊文件">设备特殊文件</h5>
<p>每个文件系统的存储设备都有主次设备号表示,可以用major和minor宏命令获取,st_dev和st_rdev经常容易混淆,前者表示的是文件系统的设备号,后者只有字符和块设备才有,包含了实际设备的设备号。对同一磁盘的不同文件系统,通常主设备号相同,次设备号不同。</p>
</section>
</div>
</div>
</div>
<a aria-label="Previous page: 文件IO" class="navigation navigation-prev " href="./fileio.html"><i class="fa fa-angle-left"></i></a>
<a aria-label="Next page: 标准IO库" class="navigation navigation-next " href="./libio.html"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="gitbook/app.js"></script>
<script src="gitbook/plugins/gitbook-plugin-search/lunr.min.js"></script>
<script src="gitbook/plugins/gitbook-plugin-search/search.js"></script>
<script src="gitbook/plugins/gitbook-plugin-sharing/buttons.js"></script>
<script src="gitbook/plugins/gitbook-plugin-fontsettings/buttons.js"></script>
<script>
require(["gitbook"], function(gitbook) {
var config = {"highlight":{},"search":{"maxIndexSize":1000000},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2}};
gitbook.start(config);
});
</script>
</body>
</html>