pwd源码分析就到这里了,学到了很多知识,更重要的是体会到了活在当下的喜悦,下一个是tree的源码分析
自己实现的代码
static void
find_dir_entry (struct stat* dot_sb, struct file_name* file_name,
size_t parent_height)
{
/* get last dir stat info and prepend it's name to FILE_NAME */
DIR* dp;
struct dirent *ep;
struct stat pdot_sb;
struct stat ent_sb;
bool found;
if (chdir ("..") != 0)
exit (1);
if ((dp = opendir (".")) == NULL)
exit (1);
if (lstat (".", &pdot_sb) < 0)
exit (1);
found = false;
while (1)
{
if ((ep = readdir (dp)) == NULL)
{
closedir (dp);
dp = NULL;
break;
}
if (strcmp (ep->d_name, "..") == 0 || strcmp (ep->d_name, ".") == 0)
continue;
if (lstat (ep->d_name, &ent_sb) < 0)
continue;
if (ent_sb.st_dev == dot_sb->st_dev && ent_sb.st_ino == dot_sb->st_ino)
{
file_name_prepend (file_name, ep->d_name, strlen(ep->d_name));
found = true;
break;
}
}
if (dp == NULL || closedir (dp) != 0)
exit (1);
if ( ! found )
exit (1);
*dot_sb = pdot_sb;
}
反思与完善
1. 代码之间要具有逻辑性,比如下面这部分代码就不具备逻辑性,随便什么顺序都可以,看起来费尽。
if (chdir ("..") != 0)
exit (1);
if ((dp = opendir (".")) == NULL)
exit (1);
if (lstat (".", &pdot_sb) < 0)
exit (1);
可以修改为如下代码:
dirp = opendir ("..");
if (dirp == NULL):
exit(1);
fd = dirfd (dirp);
if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0):
exit(1);
if ((0 <= fd ? fstat (fd) : lstata ("..")) < 0):
exit(1);
这样看下来,3处的判断具备逻辑性了!!很nice。
2. 变量的定义应该在使用区域的最前面定义,而不是都定义在函数的开始。
static void
find_dir_entry (struct stat* dot_sb, struct file_name* file_name,
size_t parent_height)
{
/* get last dir stat info and prepend it's name to FILE_NAME */
DIR* dp;
struct dirent *ep;
struct stat pdot_sb;
struct stat ent_sb;
bool found;
...
可以改为如下:
static void
find_dir_entry (struct stat* dot_sb, struct file_name* file_name,
size_t parent_height)
{
/* get last dir stat info and prepend it's name to FILE_NAME */
DIR* dirp;
struct stat pdot_sb;
bool found;
...
while (1)
{
struct dirent *ep;
struct stat ent_sb;
...
}
...
}
3. readdir没有处理错误的情况,正确代码如下
errno = 0;
if ((ep = readdir (dirp)) == NULL)
{
if (errno)
{
int e = errno; /* save errno, because the caller could need. */
closedir (dirp);
errno = e;
dirp = NULL;
break;
}
}
...
4. 当dot 和parent 在同一个device上可以只考虑inode是否相等。完整代码如下:
static void
find_dir_entry (struct stat* dot_sb, struct file_name* file_name,
size_t parent_height)
{
/* get last dir stat info and prepend it's name to FILE_NAME */
DIR* dirp;
int fd;
struct stat parent_sb;
bool use_lstat;
bool found;
dirp = opendir ("..");
if (dirp == NULL)
exit(1);
fd = dirfd (dirp);
if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
exit(1);
if ((0 <= fd ? fstat (fd, &parent_sb) : lstat ("..", &parent_sb)) < 0)
exit(1);
use_lstat = (parent_sb.st_dev != dot_sb->st_dev);
found = false;
while (1)
{
struct dirent* ep;
struct stat ent_sb;
ino_t ino;
errno = 0;
if ((ep = readdir (dirp)) == NULL)
{
if (errno)
{
int e = errno; /* save errno, because the caller could need. */
closedir (dirp);
errno = e;
dirp = NULL;
}
break;
}
if (strcmp (ep->d_name, "..") == 0 || strcmp (ep->d_name, ".") == 0)
continue;
ino = ep->d_ino;
if (use_lstat)
{
if (lstat (ep->d_name, &ent_sb) < 0) continue;
ino = ent_sb.st_ino;
}
if (ino != dot_sb->st_ino)
continue;
if ( ! use_lstat || ent_sb.st_dev == dot_sb->st_dev)
{
file_name_prepend (file_name, ep->d_name, strlen(ep->d_name));
found = true;
break;
}
}
if (dirp == NULL || closedir (dirp) != 0)
exit (1);
if ( ! found )
exit (1);
*dot_sb = parent_sb;
}