OS_NS_dirent.cpp

Go to the documentation of this file.
00001 // OS_NS_dirent.cpp,v 1.8 2006/06/08 11:59:22 jtc Exp
00002 
00003 #include "ace/OS_NS_dirent.h"
00004 
00005 ACE_RCSID(ace, OS_NS_dirent, "OS_NS_dirent.cpp,v 1.8 2006/06/08 11:59:22 jtc Exp")
00006 
00007 #if !defined (ACE_HAS_INLINED_OSCALLS)
00008 # include "ace/OS_NS_dirent.inl"
00009 #endif /* ACE_HAS_INLINED_OS_CALLS */
00010 
00011 #include "ace/OS_NS_errno.h"
00012 #include "ace/OS_NS_string.h"
00013 #include "ace/Log_Msg.h"
00014 #include "ace/OS_NS_stdlib.h"
00015 
00016 // On Windows, we explicitly set this up as __cdecl so it's correct even
00017 // if building with another calling convention, such as __stdcall.
00018 #if defined (ACE_WIN32) && defined (_MSC_VER)
00019 extern "C"
00020 {
00021   typedef int (__cdecl *ACE_SCANDIR_COMPARATOR) (const void *, const void *);
00022 }
00023 #else
00024 extern "C"
00025 {
00026   typedef int (*ACE_SCANDIR_COMPARATOR) (const void *, const void *);
00027 }
00028 #endif /* ACE_WIN32 && _MSC_VER */
00029 
00030 /*
00031    These definitions are missing on the original VC6 distribution.  The new
00032    headers that define these are available in the Platform SDK and are defined
00033    for those that don't have it.
00034  */
00035 #if defined (ACE_WIN32)
00036 #  if !defined (INVALID_FILE_ATTRIBUTES)
00037 #    define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
00038 #  endif /* INVALID_FILE_ATTRIBUTES */
00039 #  if !defined (INVALID_SET_FILE_POINTER)
00040 #    define INVALID_SET_FILE_POINTER ((DWORD)-1)
00041 #  endif /* INVALID_SET_FILE_POINTER */
00042 #endif /* ACE_WIN32 */
00043 
00044 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00045 
00046 #if defined (ACE_LACKS_CLOSEDIR)
00047 void
00048 ACE_OS::closedir_emulation (ACE_DIR *d)
00049 {
00050 #if defined (ACE_WIN32)
00051   if (d->current_handle_ != INVALID_HANDLE_VALUE)
00052     ::FindClose (d->current_handle_);
00053 
00054   d->current_handle_ = INVALID_HANDLE_VALUE;
00055   d->started_reading_ = 0;
00056   if (d->dirent_ != 0)
00057     {
00058       ACE_OS::free (d->dirent_->d_name);
00059       ACE_OS::free (d->dirent_);
00060     }
00061 #else /* ACE_WIN32 */
00062   ACE_UNUSED_ARG (d);
00063 #endif /* ACE_WIN32 */
00064 }
00065 #endif /* ACE_LACKS_CLOSEDIR */
00066 
00067 #if defined (ACE_LACKS_OPENDIR)
00068 ACE_DIR *
00069 ACE_OS::opendir_emulation (const ACE_TCHAR *filename)
00070 {
00071 #if defined (ACE_WIN32)
00072   ACE_DIR *dir;
00073   ACE_TCHAR extra[3] = {0,0,0};
00074 
00075    // Check if filename is a directory.
00076    DWORD fileAttribute = ACE_TEXT_GetFileAttributes (filename);
00077    if (fileAttribute == INVALID_FILE_ATTRIBUTES
00078        || !(fileAttribute & FILE_ATTRIBUTE_DIRECTORY))
00079      return 0;
00080 
00081 /*
00082   Note: the semantics of the win32 function FindFirstFile take the
00083   basename(filename) as a pattern to be matched within the dirname(filename).
00084   This is contrary to the behavior of the posix function readdir which treats
00085   basename(filename) as a directory to be opened and read.
00086 
00087   For this reason, we append a slash-star or backslash-star to the supplied
00088   filename so the result is that FindFirstFile will do what we need.
00089 
00090   According to the documentation for FindFirstFile, either a '/' or a '\' may
00091   be used as a directory name separator.
00092 
00093   Of course, it is necessary to ensure that this is only done if the trailing
00094   filespec is not already there.
00095 
00096   Phil Mesnier
00097 */
00098 
00099   size_t lastchar = ACE_OS::strlen (filename);
00100   if (lastchar > 0)
00101     {
00102       if (filename[lastchar-1] != '*')
00103         {
00104           if (filename[lastchar-1] != '/' && filename[lastchar-1] != '\\')
00105             ACE_OS::strcpy (extra, ACE_LIB_TEXT ("/*"));
00106           else
00107             ACE_OS::strcpy (extra, ACE_LIB_TEXT ("*"));
00108         }
00109     }
00110 
00111   ACE_NEW_RETURN (dir, ACE_DIR, 0);
00112   ACE_NEW_RETURN (dir->directory_name_,
00113                   ACE_TCHAR[lastchar + ACE_OS::strlen (extra) + 1],
00114                   0);
00115   ACE_OS::strcpy (dir->directory_name_, filename);
00116   if (extra[0])
00117     ACE_OS::strcat (dir->directory_name_, extra);
00118   dir->current_handle_ = INVALID_HANDLE_VALUE;
00119   dir->started_reading_ = 0;
00120   dir->dirent_ = 0;
00121   return dir;
00122 #else /* WIN32 */
00123   ACE_UNUSED_ARG (filename);
00124   ACE_NOTSUP_RETURN (0);
00125 #endif /* WIN32 */
00126 }
00127 #endif /* ACE_LACKS_CLOSEDIR */
00128 
00129 #if defined (ACE_LACKS_READDIR)
00130 struct ACE_DIRENT *
00131 ACE_OS::readdir_emulation (ACE_DIR *d)
00132 {
00133 #if defined (ACE_WIN32)
00134   if (d->dirent_ != 0)
00135     {
00136       ACE_OS::free (d->dirent_->d_name);
00137       ACE_OS::free (d->dirent_);
00138       d->dirent_ = 0;
00139     }
00140 
00141   if (!d->started_reading_)
00142     {
00143       d->current_handle_ = ACE_TEXT_FindFirstFile (d->directory_name_,
00144                                                    &d->fdata_);
00145       d->started_reading_ = 1;
00146     }
00147   else
00148     {
00149       int retval = ACE_TEXT_FindNextFile (d->current_handle_,
00150                                           &d->fdata_);
00151       if (retval == 0)
00152         {
00153           // Make sure to close the handle explicitly to avoid a leak!
00154           ::FindClose (d->current_handle_);
00155           d->current_handle_ = INVALID_HANDLE_VALUE;
00156         }
00157     }
00158 
00159   if (d->current_handle_ != INVALID_HANDLE_VALUE)
00160     {
00161       d->dirent_ = (ACE_DIRENT *)
00162         ACE_OS::malloc (sizeof (ACE_DIRENT));
00163 
00164       if (d->dirent_ != 0)
00165         {
00166           d->dirent_->d_name = (ACE_TCHAR*)
00167             ACE_OS::malloc ((ACE_OS::strlen (d->fdata_.cFileName) + 1)
00168                             * sizeof (ACE_TCHAR));
00169           ACE_OS::strcpy (d->dirent_->d_name, d->fdata_.cFileName);
00170           d->dirent_->d_reclen = sizeof (ACE_DIRENT);
00171         }
00172 
00173       return d->dirent_;
00174     }
00175   else
00176     return 0;
00177 #else /* ACE_WIN32 */
00178   ACE_UNUSED_ARG (d);
00179   ACE_NOTSUP_RETURN (0);
00180 #endif /* ACE_WIN32 */
00181 }
00182 #endif /* ACE_LACKS_READDIR */
00183 
00184 #if !defined (ACE_HAS_SCANDIR)
00185 int
00186 ACE_OS::scandir_emulation (const ACE_TCHAR *dirname,
00187                            ACE_DIRENT **namelist[],
00188                            int (*selector) (const ACE_DIRENT *entry),
00189                            int (*comparator) (const ACE_DIRENT **f1,
00190                                               const ACE_DIRENT **f2))
00191 {
00192   ACE_DIR *dirp = ACE_OS::opendir (dirname);
00193 
00194   if (dirp == 0)
00195     return -1;
00196   // A sanity check here.  "namelist" had better not be zero.
00197   else if (namelist == 0)
00198     return -1;
00199 
00200   ACE_DIRENT **vector = 0;
00201   ACE_DIRENT *dp = 0;
00202   int arena_size = 0;
00203 
00204   int nfiles = 0;
00205   int fail = 0;
00206 
00207   // @@ This code shoulduse readdir_r() rather than readdir().
00208   for (dp = ACE_OS::readdir (dirp);
00209        dp != 0;
00210        dp = ACE_OS::readdir (dirp))
00211     {
00212       if (selector && (*selector)(dp) == 0)
00213         continue;
00214 
00215       // If we get here, we have a dirent that the user likes.
00216       if (nfiles == arena_size)
00217         {
00218           ACE_DIRENT **newv = 0;
00219           if (arena_size == 0)
00220             arena_size = 10;
00221           else
00222             arena_size *= 2;
00223 
00224           newv = (ACE_DIRENT **) ACE_OS::realloc (vector,
00225                                               arena_size * sizeof (ACE_DIRENT *));
00226           if (newv == 0)
00227             {
00228               fail = 1;
00229               break;
00230             }
00231           vector = newv;
00232         }
00233 
00234 #if defined (ACE_LACKS_STRUCT_DIR)
00235       ACE_DIRENT *newdp = (ACE_DIRENT *) ACE_OS::malloc (sizeof (ACE_DIRENT));
00236 #else
00237       size_t dsize =
00238         sizeof (ACE_DIRENT) +
00239         ((ACE_OS::strlen (dp->d_name) + 1) * sizeof (ACE_TCHAR));
00240       ACE_DIRENT *newdp = (ACE_DIRENT *) ACE_OS::malloc (dsize);
00241 #endif /* ACE_LACKS_STRUCT_DIR */
00242 
00243       if (newdp == 0)
00244         {
00245           fail = 1;
00246           break;
00247         }
00248 
00249 #if defined (ACE_LACKS_STRUCT_DIR)
00250       newdp->d_name = (ACE_TCHAR*) ACE_OS::malloc (
00251         (ACE_OS::strlen (dp->d_name) + 1) * sizeof (ACE_TCHAR));
00252 
00253       if (newdp->d_name == 0)
00254         {
00255           fail = 1;
00256           ACE_OS::free (newdp);
00257           break;
00258         }
00259 
00260       // Don't use memcpy here since d_name is now a pointer
00261       newdp->d_ino = dp->d_ino;
00262       newdp->d_off = dp->d_off;
00263       newdp->d_reclen = dp->d_reclen;
00264       ACE_OS::strcpy (newdp->d_name, dp->d_name);
00265       vector[nfiles++] = newdp;
00266 #else
00267       vector[nfiles++] = (ACE_DIRENT *) ACE_OS::memcpy (newdp, dp, dsize);
00268 #endif /* ACE_LACKS_STRUCT_DIR */
00269     }
00270 
00271   if (fail)
00272     {
00273       ACE_OS::closedir (dirp);
00274       while (nfiles-- > 0)
00275         {
00276 #if defined (ACE_LACKS_STRUCT_DIR)
00277           ACE_OS::free (vector[nfiles]->d_name);
00278 #endif /* ACE_LACKS_STRUCT_DIR */
00279           ACE_OS::free (vector[nfiles]);
00280         }
00281       ACE_OS::free (vector);
00282       return -1;
00283     }
00284 
00285   ACE_OS::closedir (dirp);
00286 
00287   *namelist = vector;
00288 
00289   if (comparator)
00290     ACE_OS::qsort (*namelist,
00291                    nfiles,
00292                    sizeof (ACE_DIRENT *),
00293                    (ACE_SCANDIR_COMPARATOR) comparator);
00294 
00295   return nfiles;
00296 }
00297 #endif /* !ACE_HAS_SCANDIR */
00298 
00299 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:41:57 2006 for ACE by doxygen 1.3.6