[Top][All Lists]
[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);
}