bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: a bugger on the pwd code


From: Bob Proulx
Subject: Re: a bugger on the pwd code
Date: Wed, 14 Nov 2007 19:54:56 -0700
User-agent: Mutt/1.5.13 (2006-08-11)

杨光辉 wrote:
> The code is complete from the coreutils code. You can compile
> the code using the gcc compiler.

It was almost complete code.  :-)

> pwd3.c: In function 'get_root_dev_ino':
> pwd3.c:223: error: dereferencing pointer to incomplete type
> pwd3.c:224: error: dereferencing pointer to incomplete type
> pwd3.c: In function 'robust_getcwd':
> pwd3.c:232: error: storage size of 'dev_ino_buf' isn't known
> pwd3.c:244: error: dereferencing pointer to incomplete type
> pwd3.c:244: error: dereferencing pointer to incomplete type

Those messages say that the structure declaration of dev_ino is
missing.

I can see that you are expanding the program into a simpler all-in-one
place file.  But the following structure was missing.

Add this to the top of the program and the structure will be known to
the compiler.

struct dev_ino
{
  ino_t st_ino;
  dev_t st_dev;
};

Bob


#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>

struct dev_ino
{
  ino_t st_ino;
  dev_t st_dev;
};

#ifndef _D_EXACT_NAMLEN
# define _D_EXACT_NAMLEN(dp) strlen ((dp)->d_name)
#endif

#ifndef MIN
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif

#define D_INO(dp) (dp)->d_ino

#define ISSLASH(c)    ((c) == '/')

# define SAME_INODE(Stat_buf_1, Stat_buf_2) \
   ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
    && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)

struct file_name
{
    char *buf;
    size_t n_alloc;
    char *start;
};

void
xalloc_die (void)
{
  fprintf(stderr, "memory exhausted\n");
  exit(1);
}

void *
xmalloc (size_t n)
{
  void *p = malloc (n);
  if (!p && n != 0)
    xalloc_die ();
  return p;
}

void *
xnmalloc (size_t n, size_t s)
{
  return xmalloc (n * s);
}

bool
dot_or_dotdot (char const *file_name)
{
  if (file_name[0] == '.')
    {
      char sep = file_name[(file_name[1] == '.') + 1];
      return (! sep || ISSLASH (sep));
    }
  else
    return false;
}

struct dirent const *
readdir_ignoring_dot_and_dotdot (DIR *dirp)
{
  while (1)
    {
      struct dirent const *dp = readdir (dirp);
      if (dp == NULL || ! dot_or_dotdot (dp->d_name))
    return dp;
    }
}


void
file_name_free (struct file_name *p)
{
    free (p->buf);
    free (p);
}

struct file_name *
file_name_init(void)
{
    struct file_name *p = xmalloc(sizeof *p);

    p->n_alloc = MIN (2 * PATH_MAX, 32 * 1024);

    p->buf = xmalloc (p->n_alloc);
    p->start = p->buf + (p->n_alloc - 1);
    p->start[0] = '\0';

    return p;
}

void
file_name_prepend (struct file_name *p, char const *s, size_t s_len)
{
    size_t n_free = p->start - p->buf;
    if (n_free < 1 + s_len)
    {
    size_t half = p->n_alloc + 1 + s_len;
    char *q = xnmalloc(2, half);
    size_t n_used = p->n_alloc - n_free;

    p->start = q + 2 * half - n_used;
    memcpy (p->start, p->buf + n_free, n_used);
    free (p->buf);
    p->buf = q;
    p->n_alloc = 2 * half;
    }

    p->start -= 1 + s_len;
    p->start[0] = '/';
    memcpy (p->start + 1, s, s_len);
}

char *
nth_parent (size_t n)
{
  char *buf = xnmalloc (3, n);
  char *p = buf;
  size_t i;

  for (i = 0; i < n; i++)
    {
      memcpy (p, "../", 3);
      p += 3;
    }
  p[-1] = '\0';
  return buf;
}

void
find_dir_entry (struct stat *dot_sb, struct file_name *file_name,
        size_t parent_height)
{
  DIR *dirp;
  int fd;
  struct stat parent_sb;
  bool use_lstat;
  bool found;

  dirp = opendir ("..");
  if (dirp == NULL)
    fprintf(stderr,"cannot open directory %s\n",nth_parent (parent_height));

  fd = dirfd (dirp);
  if ((0 <= fd ? fchdir (fd) : chdir ("..")) < 0)
    fprintf(stderr,"failed to chdir to %s\n",nth_parent (parent_height));

  if ((0 <= fd ? fstat (fd, &parent_sb) : stat (".", &parent_sb)) < 0)
    fprintf(stderr, "failed to stat %s\n", nth_parent (parent_height));

  use_lstat = (parent_sb.st_dev != dot_sb->st_dev);

  found = false;
  while (1)
    {
      struct dirent const *dp;
      struct stat ent_sb;
      ino_t ino;

      errno = 0;
      if ((dp = readdir_ignoring_dot_and_dotdot (dirp)) == NULL)
    {
      if (errno)
        {
          int e = errno;
          closedir (dirp);
          errno = e;

          dirp = NULL;
        }
      break;
    }

      ino = D_INO (dp);

      if (use_lstat)
    {
      if (lstat (dp->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, dp->d_name, _D_EXACT_NAMLEN (dp));
      found = true;
      break;
    }
    }

  if (dirp == NULL || closedir (dirp) != 0)
    {
      fprintf(stderr,"reading directory %s\n",nth_parent (parent_height));
    }

  if ( ! found)
       fprintf(stderr, "couldn't find directory entry in %s with matching 
i-node\n", nth_parent(parent_height));

  *dot_sb = parent_sb;
}

struct dev_ino *
get_root_dev_ino (struct dev_ino *root_d_i)
{
  struct stat statbuf;
  if (lstat ("/", &statbuf))
    return NULL;
  root_d_i->st_ino = statbuf.st_ino;
  root_d_i->st_dev = statbuf.st_dev;
  return root_d_i;
}

void
robust_getcwd (struct file_name *file_name)
{
  size_t height = 1;
  struct dev_ino dev_ino_buf;
  struct dev_ino *root_dev_ino = get_root_dev_ino (&dev_ino_buf);
  struct stat dot_sb;

  if (root_dev_ino == NULL)
    fprintf(stderr, "failed to get attributes of /\n");

  if (stat (".", &dot_sb) < 0)
    fprintf(stderr,"failed to stat .\n");

  while (1)
    {
      if (SAME_INODE (dot_sb, *root_dev_ino))
    break;

      find_dir_entry (&dot_sb, file_name, height++);
    }

  if (file_name->start[0] == '\0')
    file_name_prepend (file_name, "", 0);
}

int
main (int argc, char **argv)
{

  struct file_name *file_name = file_name_init ();
  robust_getcwd (file_name);
  puts (file_name->start);
  file_name_free (file_name);


  exit (EXIT_SUCCESS);
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]