C语言实现linux pwd命令
linux的文件格式
在linux文件系统中,文件=N(N>=1)个iNode和M(M>=1)个数据块
数据块存放文件的内容数据,数据块的数目随文件内容的大小而定。
iNode称为信息节点,与文件一一对应
作用:1.存储与文件相关的属性信息,如修改时间、所有人、文件类型和文件长度。不包含文件名
2.存储指向文件内容数据块的指针信息。
在一个文件系统中,一个iNode代表一个文件,用一个整数值inode_number唯一标志,通过其可以找到对应的inode
可以编程获取一个文件的iNode,从而得到它的inode_number
在linux系统中,文件系统通过目录包含子目录及文件的方式,组织成一个树状结构
目录在linux中也是一种文件,其文件内容是一个列表,每个列表项记录"inode_number + filename"
因此,目录a包含b文件,实现层面上就是目录a的内容列表里有一个关于b文件的列表项,即b的inode_number + filename
可以编程获取一个目录文件的内容列表,根据inode_number找到对应的filename
有两个特殊的文件名 .-目录自身、..-父目录
如果..和.的inode_number相同,那么说明已经到达根目录
pwd的实现如下:
1.从当前目录开始,判断是否已经到达根目录
2.若已经到达根目录则结束,并将字符串数组中的内容循环打印,如果一开始就在根目录,则输出“/”
3.若没有到达根目录,那么记录当前目录的inode_number,跳到父目录,找到记录的inode_number对应的文件名,存储到字符串数组中
需要实现的子模块:
1.搜索目录文件,根据inode_number获取对应的filename
2.搜索目录文件,根据filename获取对应的inode_number(用于获取当前目录.的inode_number
程序:
子模块:1.根据inode_number找到对应的filename
char *get_filename_byino(ino_t ino) {
DIR *dp = NULL;
struct dirent *dptr = NULL;
char *filename = NULL;
//打开当前目录文件.并将句柄传给dp
if ((dp = opendir(".")) == NULL) {
fprintf(stderr, "Cannot open Current Directory\n");
exit(-1);
} else {
//用dptr逐条读取dp的目录项,找到指定inode_number对应的filename
while ((dptr = dirread(dp)) != NULL) {
if (dptr->d_ino == ino) {
filename = strdup(dptr->d_name);
break;
}
}
closedir(dp);
}
return filename;
}
2.根据filename找到对应的inode_number
ino_t get_number_byname(char *filename) {
struct stat file_stat;
if (stat(filename, &file_stat) != 0) {
perror("stat");
exit(-1);
}
return file_stat.st_ino;
}
函数:
#include
int stat(const char *restrict pathname, struct stat *restrict buf);
返回一个结构,里面包含文件的全部属性
按照
成功返回0,失败返回-1
struct stat {
dev_t st_dev; //文件所在设备ID
ino_t st_ino; //inode编号
mode_t st_mode; //保护模式-文件访问权限
nlink_t st_nlink; //硬链接个数
uid_t st_uid; //所有者用户id
gid_t st_git; //所有者组id
dev_t st_rdev; //设备id-设备文件的设备id
off_t ** st_size; //总体尺寸(in bytes)
blksize_t st_blksize; //文件系统I/O块大小
blkcnt_t st_blocks; //已分配512B块的个数
time_t st_atime; //上次访问的时间
time_t st_mtime; //上次更新的时间
time_t st_ctime; //上次状态更改的时间
};
DIR结构体
struct _dirstream {
void *__fd;
char *__data;
int __entry_data;
char *__ptr;
int __entry_ptr;
size_t __allocation;
size_t __size;
__libc_lock_define (, __lock)
};
dirent结构体
struct dirent {
long d_ino; // inode_number
off_t d_off; //offset to this dirent 在目录文件中的偏移
unsigned short d_reclen; //length of this d_name 文件名长度
unsigned char d_type; // the type of d_name文件类型
char d_name [NAMX_MAX + 1]; //文件名
typedef struct __dirstream DIR;
DIR *opendir(const char *pathname); 打开文件目录,返回指向DIR结构体的指针
struct dirent *readdir(DIR *dp);
DIR指向目录,dirent指向目录中的文件项,获取文件名d_name和索引节点d_ino
int closedir(DIR *dp);
主函数:
int main(int argc, char *argv[]) {
char *dir_stack[MAX_DIR_DEPTH];
unsigned current_depth = 0;
for (;;) {
ino_t current_ino = get_number_byname(".");
ino_t parent_ino = get_number_byname("..");
if (current_ino == parent_ino) {
break;
}
chdir("..");
dir_stack[current_depth++] = get_filename_byino(current_ino);
if (current_depth >= MAX_DIR_DEPTH) {
fprintf(stderr, "Directory tree is too deep.\n");
exit(-1);
}
}
int i = current_depth - 1;
for (; i>= 0; i--) {
fprintf(stdout, "/%s", dir_stack[i]);
}
fprintf(stdout, "%s\n", current_depth == 0? "/":"");
return 0;
}