pwd-find_dir_entry(pwd核心算法)

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值