Feature #676

Compilation under cygwin

Added by Eric Thomas over 2 years ago. Updated over 2 years ago.

Status:ClosedStart date:03/09/2015
Priority:NormalDue date:
Assignee:Chad Trabant% Done:

0%

Category:-
Target version:-
Resolution:Fixed

Description

With one small change I am able to get 'ringserver' to compile and run under cygwin:

Modified 'mseedscan.c' to make it not reference the 'reclen' member of 'struct dirent' by changing "de->d_reclen" to "sizeof(struct dirent)" in two places.

I'm pretty sure using 'sizeof' is equivalent to 'reclen', but you may want to double check. You could also use "#ifdef _DIRENT_HAVE_D_RECLEN" to detect if 'reclen' is available.

--ET

History

#1 Updated by Chad Trabant over 2 years ago

Thanks Eric.

Problem is that some architectures define struct dirent like:

typedef struct dirent {
    ino_t        d_ino;
    off_t        d_off;
    unsigned short    d_reclen;
    char        d_name[1];
} dirent_t;

Note: the d_name field is basically only a pointer to a string allocated in addition to the struct.

So a simple sizeof(struct dirent) will quietly not have enough space for the entry. It is for this reason that there is a d_reclen value at all.

The macro _DIRENT_HAVE_D_RECLEN does not appear to be on many platforms, e.g. I can't find it on my Mac.

The more portable solution is to allocate space for: sizeof(struct dirent) + strlen(de.d_name)

it'll be too much on the platforms where the d_name entry is a fixed size in the struct but at least it'll never be too little.

I'll search around for common solutions a bit more.

#2 Updated by Eric Thomas over 2 years ago

Hi Chad,
Perhaps the best approach at this point is to implement a cygwin-only workaround. In cygwin, the "dirent.h" header has this:

struct dirent
{
  uint32_t __d_version;            /* Used internally */
  ino_t d_ino;
  unsigned char d_type;
  unsigned char __d_unused1[3];
  __uint32_t __d_internal1;
  char d_name[NAME_MAX + 1];
};
So, I think for cygwin, using "sizeof(struct dirent)" should be OK. So, how about this?:
--- mseedscan.c.orig    2011-05-24 10:57:39.000000000 -0400
+++ mseedscan.c 2015-03-12 00:48:22.558194300 -0400
@@ -1320,6 +1320,7 @@
   struct dirent *de, *decopy;
   struct edirent *ede;
   struct edirent *prevede = 0;
+  unsigned short reclen;

   if ( ! dirname )
     return NULL;
@@ -1339,8 +1340,13 @@
   /* Read all directory entries */
   while ( (de = readdir (dirp)) )
     {
+#if !defined(__CYGWIN__)
+      reclen = de->d_reclen;
+#else    /* no "dirent.d_reclen" in cygwin; use struct size */
+      reclen = sizeof(struct dirent);
+#endif
       /* Allocate space for directory entry copy */
-      if ( ! (decopy = (struct dirent *) malloc (de->d_reclen)) )
+      if ( ! (decopy = (struct dirent *) malloc (reclen)) )
        {
          closedir (dirp);
          ECloseDir (edirp);
@@ -1348,7 +1354,7 @@
        }

       /* Copy directory entry */
-      memcpy (decopy, de, de->d_reclen);
+      memcpy (decopy, de, reclen);

       /* Allocate space for enhanced directory entry */
       if ( ! (ede = (struct edirent *) calloc (1, sizeof(struct edirent))) )
--ET

#3 Updated by Chad Trabant over 2 years ago

  • Status changed from New to Closed
  • Assignee set to Chad Trabant
  • Resolution set to Fixed

Only the dirent.d_name and dirent.d_ino values are needed by the code. Instead of copying the dirent struct I have opted to store those values instead. So there is no need to know the length of the dirent anymore.

Fixed in next release.

Thanks for reporting this issue with Cygwin.

Also available in: Atom PDF