Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 18 Aug 2000 02:04:18 -0400 (EDT)
From:      "Mark W. Krentel" <krentel@dreamscape.com>
To:        scott@zorch.sf-bay.org
Cc:        freebsd-emulation@FreeBSD.ORG, marcel@cup.hp.com
Subject:   Re: Linuxulator, getdents and Citrix
Message-ID:  <200008180604.CAA04991@dreamscape.com>

next in thread | raw e-mail | index | archive | help
> As nearly as I can tell, the linux_getdents call is returning a null result
> instead of a correct set of directory entries.

I have also seen a problem with the Linux ls, readdir and getdents
when reading non-ufs partitions.  Take a look at PR kern/19407.  It
started with a panic when running Linux binaries from an ext2
partition.  Bruce Evans found and fixed some buffer overruns in the
ext2fs code.  But I must have found two separate problems because I'm
still seeing a problem with readdir.

The remaining problem is that the Linux readdir(3) prematurely returns
NULL on non-ufs partitions, and hence ls outputs too few files.  Are
your directories on ext2 or NFS partitions?  Does it make a difference
if you move them to a local ufs partition?  For me, readdir correctly
reads ufs directories, but fails on ext2 and cdrom.  I haven't tried
NFS yet.

I'd be very interested in your results of these experiments.  Below
are two simple programs to list a directory, using readdir(3) and
getdents(2).  Compile the programs in Linux and run them in the
Linuxulator on various directories.  For me, getdents returns the
right answer with any buffer size, but readdir prematurely returns
NULL.  I can send you uuencoded binaries, if you don't have access to
a Linux machine.

--Mark

--------------------------------------------

/*
 * List directory contents with opendir and readdir.
 * Basically the same as "ls -1af".
 * Usage: readdir directory
 */

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>

void my_err(char *mesg)
{
  printf("Error: %s\n", mesg);
  exit(1);
}

int main(int argc, char **argv)
{
  DIR  *dp;
  struct dirent  *de;
  int   n;

  if (argc < 2) my_err("missing directory");

  if ((dp = opendir(argv[1])) == NULL)
    my_err("unable to open directory");

  n = 0;
  while ((de = readdir(dp)) != NULL)
    {
      printf("%s\n", de->d_name);
      n++;
    }

  printf("Total: %d files\n", n);

  return 0;
}

--------------------------------------------

/*
 * Print directory contents with getdents.
 * Usage: getdents directory [ buffer-size ]
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <linux/unistd.h>

#include <stdio.h>

#define MAX_BUF_SIZE  100000
#define DEF_BUF_SIZE   90000
#define DEF_MAGIC       0x0f

_syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count);

void my_err(char *mesg)
{
  printf("Error: %s\n", mesg);
  exit(1);
}

int main(int argc, char **argv)
{
  char area[MAX_BUF_SIZE];

  struct { 
    int    inode;
    int    offset;
    short  len;
    char   d_name[4];
  } *dep;

  int  used, size, magic;
  int  num_calls,  num_files;
  int  max_touch,  touch;
  int  pos,  fd,  i;

  /* 
   * Open directory and set fd.
   */
  if (argc < 2) my_err("missing directory");
  if ((fd = open(argv[1], O_RDONLY)) == -1)
    my_err("unable to open directory");

  /*
   * Set buffer size.
   */
  if (argc < 3)
    size = DEF_BUF_SIZE;
  else if (sscanf(argv[2], "%d", &size) != 1)
    my_err("unable to scanf buffer size");
  if (size > MAX_BUF_SIZE) 
    my_err("buffer size too large");

  /*
   * Main loop: call getdents until returns 0.
   */
  magic = DEF_MAGIC;

  num_calls = 0;
  num_files = 0;
  max_touch = 0;

  for (i = 0; i < MAX_BUF_SIZE; i++) area[i] = magic;
  while ((used = getdents(fd, (struct dirent *) area, size)) > 0)
    {
      num_calls++;

      touch = 0;
      for (i = size; i < MAX_BUF_SIZE; i++)
	{ if (area[i] != magic) touch = i; }
      if (touch > max_touch) max_touch = touch;

      printf("\nCall: %d    Used: %d    Size: %d    Touch: %d\n",
	     num_calls, used, size, touch);

      pos = 0;
      while (pos < used)
	{
	  num_files++;
	  dep = (void *) (area + pos);
	  printf("%s  ", dep->d_name);
	  pos += dep->len;
	}
      printf("\n");

      for (i = 0; i < MAX_BUF_SIZE; i++) area[i] = magic;
    }

  printf("\nCalls: %d    Files: %d    Touch: %d\n", 
	 num_calls, num_files, max_touch);

  return 0;
}



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-emulation" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200008180604.CAA04991>