NetBSD-Bugs archive

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

Re: lib/43310: dirent(5) standard compliance



The following reply was made to PR lib/43310; it has been noted by GNATS.

From: Matthew Mondor <mm_lists%pulsar-zone.net@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc: 
Subject: Re: lib/43310: dirent(5) standard compliance
Date: Sat, 15 May 2010 19:41:03 -0400

 On Sat, 15 May 2010 10:35:02 +0000 (UTC)
 Jukka Ruohonen <jruohonen%iki.fi@localhost> wrote:
 
 > The following reply was made to PR lib/43310; it has been noted by GNATS.
 > 
 > From: Jukka Ruohonen <jruohonen%iki.fi@localhost>
 > To: gnats-bugs%NetBSD.org@localhost
 > Cc: 
 > Subject: Re: lib/43310: dirent(5) standard compliance
 > Date: Sat, 15 May 2010 13:26:38 +0300
 > 
 >  Actually this appears to be more involved.
 >  
 >  The d_name is statically allocated:
 >  
 >  > struct dirent {
 >  >         ino_t d_fileno;                 /* file number of entry */
 >  >         uint16_t d_reclen;              /* length of this record */
 >  >         uint16_t d_namlen;              /* length of string in d_name */
 >  >         uint8_t  d_type;                /* file type, see below */
 >  > #if defined(_NETBSD_SOURCE)
 >  > #define MAXNAMLEN       511
 >  >         char    d_name[MAXNAMLEN + 1];  /* name must be no longer than 
 > this
 >  > #*/
 >  > #else
 >  >         char    d_name[511 + 1];        /* name must be no longer than 
 > this
 >  > #*/
 >  > #endif
 >  > };
 >  
 >  While the standard specifically stresses that:
 >  
 >      "The array of char d_name is not a fixed size. Implementations may
 >       need to declare struct dirent with an array size for d_name of 1,
 >       but the actual number of characters provided matches (or only
 >       slightly exceeds) the length of the filename."
 >  
 >  To my reading this means that some implementations may define only a pointer
 >  to d_name and then allocate it dynamically.
 >  
 >  Consider what the Linux manual page recommends:
 >  
 >         "Since POSIX.1 does not specify the size of the d_name field, and 
 > other
 >         nonstandard fields may precede that field within the dirent 
 > structure,
 >         portable  applications  that use readdir_r() should allocate the 
 > buffer
 >         whose address is passed in entry as follows:
 >  
 >             len = offsetof(struct dirent, d_name) +
 >                       pathconf(dirpath, _PC_NAME_MAX) + 1
 >             entryp = malloc(len);
 >  
 >      (POSIX.1 requires that d_name is the last field in a struct dirent.)"
 >  
 >  And indeed glibc goes and defines this as:
 >  
 >      struct linux_dirent64 {
 >              u64             d_ino;
 >              s64             d_off;
 >              unsigned short  d_reclen;
 >              unsigned char   d_type;
 >              char            d_name[0];
 >      };
 >  
 >  I do not know how severely this affects portability, but at least the
 >  readdir_r(3) function, where the dirent is supplied by the caller, is
 >  affected.
 
 I however still see on a not so old Linux system here:
 
 #ifdef __USE_LARGEFILE64
 struct dirent64
   {
     __ino64_t d_ino;
     __off64_t d_off;
     unsigned short int d_reclen;
     unsigned char d_type;
     char d_name[256];           /* We must not include limits.h! */
   };
 #endif
 
 and know of multiple code assuming that the following should work:
 
 [...]
 {
     struct dirent ent, *entp;
 
     if ((err = readdir_r(dir, &ent, &entp)) == 0) {
 
 To me it seems to make sense to have this API, and what I understand
 from the OG text is not that we're obliged to dynamically allocate the
 d_name string, but that some implementations may internally do it (i.e.
 provide a string to an existing input from getdents(2) or equivalent),
 and that strlen(3) should be used on the string rather than
 memcpy(2) with NAME_MAX...  Such that simply changing NAME_MAX would
 make sense.  NetBSD provides the unstandard d_namlen extension which
 could permit to avoid the strlen(3) overhead, though.
 -- 
 Matt
 


Home | Main Index | Thread Index | Old Index