1.3 登录
当我们登录的时候,我们输入用户名和密码,系统这时候会查找/etc/passwd这个文件,比对用户名,然后会接着查找/etc/shadow中的密码。
/etc/passwd文件由冒号分隔的7个部分组成,下面是一个例子:
sar:x:205:105:Stephen Rago:/home/sar:/bin/ksh
其含义为:
用户名:加密后的密码:数字用户ID:数字组ID:注释字段:主目录:所用SHELL类型
由于/etc/passwd权限为-rw-r--r--,也就是说所有人均为可读,故密码不能放在这里,都放在了/etc/shadow中了,shadow中的每一项有9个字段,同样由冒号分开,下面是shadow中的一例:
beinan:$1$VE.Mq2Xf$2c9Qi7EQ9JP8GKF8gH7PB1:13072:0:99999:7:::
其含义为:
用户名:密码:上次修改口令时间:两次修改口令的最小间隔天数:两次修改最多的间隔天数:提前警告用户密码要过期的天数:口令过期后多少天禁用此用户:用户过期日期:保留扩展位
详细的解释可以看这里:用户(User)和用户组(Group)配置文件详解
1.4 文件和目录
程序1.3. 列出一个目录中左右的文件(这里我将程序改写了,没有用apue.h,可以熟悉头文件)
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dir;
if (argc != 2) {
fprintf(stderr, "usage: myls directory_name\n");
return 1;
}
if ((dp = opendir(argv[1])) == NULL)
fprintf(stderr, "can't open %s\n", argv[1]);
while ((dir = readdir(dp)) != NULL)
printf("%s\n", dir->d_name);
closedir(dp);
exit(0);
}
注意顺序:opendir()-->readdir()-->closedir()
相关理解:
1.这里在while循环中使用readdir()函数,没有类似累加的动作,因此应该是readdir()函数自己保存一个指针,下一次调用的时候会累加一个偏移量,直到NULL.
2.关于struct dirent的定义在/usr/include/bits/dirent.h中:
struct dirent
{
#ifndef __USE_FILE_OFFSET64
__ino_t d_ino;
__off_t d_off;
#else
__ino64_t d_ino;
__off64_t d_off;
#endif
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
#ifdef __USE_LARGEFILE64
struct dirent64
{
__ino64_t d_ino;
__off64_t d_off;
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
#endif
其中d_type可能的取值为:
DT_UNKNOWN,未知的类型
DT_REG,普通文件
DT_DIR,普通目录
DT_FIFO,命名管道或FIFO
DT_SOCK,本地套接口
DT_CHR,字符设备文件
DT_BLK,块设备文件
知道了具体的定义就可以随便得到自己想要的信息了。
3.关于readdir的具体实现可以参考glibc-2.7/sysdeps/unix/readdir.c文件:
/* Read a directory entry from DIRP. */
DIRENT_TYPE *
__READDIR (DIR *dirp)
{
DIRENT_TYPE *dp;
int saved_errno = errno;
#ifndef NOT_IN_libc
__libc_lock_lock (dirp->lock);
#endif
do
{
size_t reclen;
if (dirp->offset >= dirp->size)
{
/* We've emptied out our buffer. Refill it. */
size_t maxread;
ssize_t bytes;
#ifndef _DIRENT_HAVE_D_RECLEN
/* Fixed-size struct; must read one at a time (see below). */
maxread = sizeof *dp;
#else
maxread = dirp->allocation;
#endif
bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
if (bytes <= 0)
{
/* On some systems getdents fails with ENOENT when the
open directory has been rmdir'd already. POSIX.1
requires that we treat this condition like normal EOF. */
if (bytes < 0 && errno == ENOENT)
bytes = 0;
/* Don't modifiy errno when reaching EOF. */
if (bytes == 0)
__set_errno (saved_errno);
dp = NULL;
break;
}
dirp->size = (size_t) bytes;
/* Reset the offset into the buffer. */
dirp->offset = 0;
}
dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];
#ifdef _DIRENT_HAVE_D_RECLEN
reclen = dp->d_reclen;
#else
/* The only version of `struct dirent*' that lacks `d_reclen'
is fixed-size. */
assert (sizeof dp->d_name > 1);
reclen = sizeof *dp;
/* The name is not terminated if it is the largest possible size.
Clobber the following byte to ensure proper null termination. We
read jst one entry at a time above so we know that byte will not
be used later. */
dp->d_name[sizeof dp->d_name] = '\0';
#endif
dirp->offset += reclen;
#ifdef _DIRENT_HAVE_D_OFF
dirp->filepos = dp->d_off;
#else
dirp->filepos += reclen;
#endif
/* Skip deleted files. */
} while (dp->d_ino == 0);
#ifndef NOT_IN_libc
__libc_lock_unlock (dirp->lock);
#endif
return dp;
}
可以看到每次在do-while循环中先给dp赋值,然后每次dp都要步进一次,故能得到这个dirent中保存的信息。
关于opendir(),每次会有一个alloc的动作来分给一段内存来放置当前dir的内容,以便进行操作,源文件glibc-2.7/sysdeps/unix/opendir.c.
关于closedir(),每次会一个free的动作,释放opendir()申请的内存,故要成对使用,源文件glibc-2.7/sysdeps/unix/closedir.c.
总结:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
int readdir(unsigned int fd, struct dirent *dirp, unsigned int count);
int closedir(DIR *dir);
opendir()-->readdir()-->closedir()

没有评论:
发表评论