delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2008/06/17/05:46:21

X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f
X-Recipient: djgpp-workers AT delorie DOT com
X-Authenticated: #27081556
X-Provags-ID: V01U2FsdGVkX198CcMrT1d8VRvWIpN9xQmrQ8O/GANT/U5TRSZd+0
iYztMC9Ca0iZpf
From: Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
To: djgpp-workers AT delorie DOT com
Subject: What are usefull errno values produced by readdiir?
Date: Tue, 17 Jun 2008 11:46:59 +0200
User-Agent: KMail/1.9.5
MIME-Version: 1.0
Message-Id: <200806171146.59903.juan.guerrero@gmx.de>
X-Y-GMX-Trusted: 0
Reply-To: djgpp-workers AT delorie DOT com

The current version of readdir() will return "Invalid argument (EINVAL)" for
all files of 510 bytes of size if they are not symlinks.  This error message is
produced by the symlink code of readdir.  readdir performs a lot of tests to
characterize the current file and the last test is a symlink test that is only
performed if the file size has the symlink size of 510 bytes (_SYMLINK_FILE_LEN).
In this case __internal_readlink is called and this function set errno to EINVAL
If the file is not a symlink.  That is ok, but now readdir passes this errno to
the calling function.  This means that every file of _SYMLINK_FILE_LEN length
that is really not a symlink triggers errno to be EINVAL.  If the calling function
evaluates errno after the readdir call it is clear that the calling function must
probably fail.  This is again a design issue of readdir that must probably solved
by the original author of the code.  Please note that this is not a trivial issue.
My current port of findutils fails due to this readdir behaviour.  For example,
if I try to build the djlsr204.zip file from the checked ouf CVS sources using
/distrib/mkdist.bat I get the following error message:

C:\djgpp\bin/find.exe: src/libc/c99/inttypes/cvs: Invalid argument (EINVAL)

The reason for this is that the last detected file in the CVS directory is Entries
and has a size of exactly 510 bytes and thus is identtified as potential symlink.
Because __internal_readlink detects that this is not a symlink it returns errno
set to EINVAL and the whole content of the CVS directory is discarted and not
printed and a confusing error message is printed instead.  Of course, now that
I know this I can fix findutils accordingly, but the question remains if the
design of the symlink support is optimal.  To make this clear here is a extract
of the "offending" findutils code:

  dirp = opendir (dir);
  if (dirp == NULL)
    return NULL;

  errno = 0;

[snip]

  while ((dp = readdir (dirp)) != NULL)
    {
[snip]
    }
  
[snip]

  save_errno = errno;
  if (CLOSEDIR (dirp) != 0)
    save_errno = errno;
  if (save_errno != 0)
    {
      free (result->buffer);
      free (result);
      errno = save_errno;
      return NULL;
    }

  return result;
}

This is probably the conventional way to use readdir to read directory entries.
As can be seen if CLOSEDIR does not fail but readdir sets errno to something
the function fails and returns NULL.  In this particular case, this means that
the function behaviour depends on  the design of readdir.  For the djgpp port
of findutils this implies that every 510 byte size file will make find fail not
printing the containt of the directory where this file lives and printing the
EINVAL error message.  Of course every code working similar to this one will
fail too.

Because I am not the original author of readdir I do not know if this behaviour
is a bug or a feature.  Any clarification about this will be welcome.

Regards,
Juan M. Guerrero

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019