2 //=============================================================================
4 * @file Dirent_Test.cpp
6 * This is a test of the opendir and readdir emulation provided by the
7 * class ACE_Dirent. It is used to ensure that the emulation code
8 * works properly on platforms that don't support this capability
9 * natively. As the emulation code is not compiled in other
10 * platforms, this test also ensures that there is no impact to
11 * platforms that natively support directory scanning operations.
13 * @author Phil Mesnier <mesnier_p@ociweb.com>
14 * @author Zvika Ashani <zvika@aspectusvi.com>
15 * @author Rich Newman <RNewman@directv.com>
16 * @author and Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
18 //=============================================================================
21 #include "test_config.h"
22 #include "ace/Dirent.h"
23 #include "ace/Dirent_Selector.h"
24 #include "ace/OS_NS_sys_stat.h"
25 #include "ace/OS_NS_unistd.h"
26 #include "ace/SString.h"
28 #if defined (ACE_HAS_TCHAR_DIRENT)
29 # define TEST_ENTRY ACE_TEXT ("run_test.lst")
31 # define TEST_ENTRY "run_test.lst"
32 #endif /* ACE_HAS_TCHAR_DIRENT */
34 // Directory to scan - we need to figure it out based on environment.
35 static ACE_TString TestDir
;
36 static const int RECURSION_INDENT
= 3;
38 // Number of entries in the directory.
39 static int entrycount
= 0;
43 selector (const ACE_DIRENT
*d
)
45 return ACE_OS::strcmp (d
->d_name
, TEST_ENTRY
) == 0;
49 comparator (const ACE_DIRENT
**d1
, const ACE_DIRENT
**d2
)
51 return ACE_OS::alphasort (d1
, d2
);
57 dirent_selector_test ()
61 const ACE_TCHAR
*test_dir
= TestDir
.c_str ();
62 ACE_Dirent_Selector sds
;
64 // Pass in functions that'll specify the selection criteria.
65 int status
= sds
.open (test_dir
, selector
, comparator
);
67 ACE_ERROR_RETURN ((LM_ERROR
,
68 ACE_TEXT ("%s, %p\n"),
73 // We should only have located ourselves!
74 if (sds
.length () != 1)
77 ACE_TEXT ("selected %d entries in %s, should be 1\n"),
83 for (n
= 0; n
< sds
.length (); ++n
)
85 #if defined (ACE_HAS_TCHAR_DIRENT)
87 ACE_TEXT ("Sorted: %d: %s\n"),
92 ACE_TEXT ("Sorted: %d: %C\n"),
98 status
= sds
.close ();
101 ACE_ERROR ((LM_ERROR
,
102 ACE_TEXT ("after selecting, %p\n"),
103 ACE_TEXT ("close")));
107 ACE_Dirent_Selector ds
;
109 // Don't specify any selection criteria.
110 status
= ds
.open (test_dir
);
113 ACE_ERROR ((LM_ERROR
,
114 ACE_TEXT ("%s w/o selection criteria; %p\n"),
120 // We counted the entries earlier by hand; should be the same here.
121 if (entrycount
!= ds
.length ())
123 ACE_ERROR ((LM_ERROR
,
124 ACE_TEXT ("Counted %d entries in %s but selector says %d\n"),
131 for (n
= 0; n
< ds
.length (); ++n
)
133 #if defined (ACE_HAS_TCHAR_DIRENT)
134 ACE_DEBUG ((LM_DEBUG
,
135 ACE_TEXT ("Entry %d: %s\n"),
139 ACE_DEBUG ((LM_DEBUG
,
140 ACE_TEXT ("Entry %d: %C\n"),
146 if (ds
.close () == -1)
148 ACE_ERROR ((LM_ERROR
,
149 ACE_TEXT ("w/o selection criteria; %p\n"),
150 ACE_TEXT ("close")));
154 return error
? -1 : 0;
162 if (dir
.open (TestDir
.c_str ()) == -1)
164 ((LM_ERROR
, ACE_TEXT ("open of dir %s failed\n"), TestDir
.c_str()), -1);
166 for (ACE_DIRENT
*directory
= 0;
167 (directory
= dir
.read ()) != 0;
170 #if defined (ACE_HAS_TCHAR_DIRENT)
171 ACE_DEBUG ((LM_DEBUG
,
172 ACE_TEXT ("Entry %d: %s\n"),
176 ACE_DEBUG ((LM_DEBUG
,
177 ACE_TEXT ("Entry %d: %C\n"),
187 ((LM_ERROR
, ACE_TEXT ("readdir failed to read anything\n")), -1);
192 ACE_TEXT ("readdir failed, only matched directory name\n")),
196 ACE_DEBUG ((LM_DEBUG
,
197 ACE_TEXT ("readdir succeeded, read %d entries\n"),
204 dirent_count (const ACE_TCHAR
*dir_path
,
209 #if !defined (ACE_LACKS_CHDIR)
210 if (ACE_OS::chdir (dir_path
) == -1)
211 ACE_ERROR_RETURN ((LM_ERROR
,
212 ACE_TEXT ("chdir: %p\n"),
216 ACE_UNUSED_ARG (dir_path
);
217 #endif /* !ACE_LACKS_CHDIR */
220 if (dir
.open (ACE_TEXT (".")) == -1)
222 ((LM_ERROR
, ACE_TEXT ("open of dir . failed\n")), -1);
224 // Since the dir struct d_name type changes depending on the setting
225 // of ACE_LACKS_STRUCT_DIR, copy each name into a neutral format
226 // array to work on it.
227 size_t const maxnamlen
= MAXNAMLEN
;
228 ACE_TCHAR tname
[maxnamlen
+ 1];
232 for (ACE_DIRENT
*directory
; (directory
= dir
.read ()) != 0;)
234 // Skip the ".." and "." files.
235 if (ACE::isdotdir(directory
->d_name
) == true)
239 #if defined (ACE_HAS_TCHAR_DIRENT)
240 ACE_OS::strncpy (tname
, directory
->d_name
, maxnamlen
);
242 ACE_OS::strncpy (tname
,
243 ACE_TEXT_CHAR_TO_TCHAR (directory
->d_name
),
245 #endif /* ACE_LACKS_STRUCT_DIR */
247 int local_file_count
= 0;
248 int local_dir_count
= 0;
250 if (ACE_OS::lstat (directory
->d_name
, &stat_buf
) == -1)
251 ACE_ERROR_RETURN ((LM_ERROR
,
256 switch (stat_buf
.st_mode
& S_IFMT
)
258 case S_IFREG
: // Either a regular file or an executable.
262 case S_IFLNK
: // Either a file or directory link, so let's find out.
263 if (ACE_OS::stat (directory
->d_name
, &stat_buf
) == -1)
264 ACE_ERROR_RETURN ((LM_ERROR
,
269 if ((stat_buf
.st_mode
& S_IFMT
) == S_IFDIR
)
270 // Don't recurse through symbolic directory links!
277 ACE_DEBUG ((LM_DEBUG
, "%*sentering subdirectory %s\n",
278 recursion_level
* RECURSION_INDENT
,
281 if (dirent_count (tname
,
284 recursion_level
+ 1) != -1)
288 ACE_TEXT ("%*ssubdirectory %s has %d files and %d subdirectories.\n"),
289 recursion_level
* RECURSION_INDENT
,
296 #if !defined (ACE_LACKS_CHDIR)
297 // Move back up a level.
298 if (ACE_OS::chdir (ACE_TEXT ("..")) == -1)
299 ACE_ERROR_RETURN ((LM_ERROR
,
300 ACE_TEXT ("chdir: %p\n"),
303 #endif /* !ACE_LACKS_CHDIR */
307 default: // Must be some other type of file (PIPE/FIFO/device)
317 dirent_recurse_test ()
321 const ACE_TCHAR
*test_dir
= TestDir
.c_str ();
323 ACE_DEBUG ((LM_DEBUG
,
324 ACE_TEXT ("Starting directory recursion test for %s\n"),
327 if (dirent_count (test_dir
,
331 ACE_ERROR_RETURN ((LM_ERROR
,
332 ACE_TEXT ("Directory recursion test failed for %s\n"),
335 ACE_DEBUG ((LM_DEBUG
,
336 ACE_TEXT ("Directory recursion test succeeded for %s, read %d files %d dirs\n"),
344 run_main (int, ACE_TCHAR
*[])
346 ACE_START_TEST (ACE_TEXT ("Dirent_Test"));
348 // First, find out where to run most of the scans. If a platform has a
349 // compiled-in setting in TEST_DIR, honor that. Else, look for:
350 // $top_srcdir/tests: The ACE_wrappers dir for autoconf builds
351 // $ACE_ROOT/tests: The ACE_wrappers dir for most other builds
352 // ../test: Last-chance try to hit the right place
353 #if defined (TEST_DIR)
356 const char *root
= ACE_OS::getenv ("top_srcdir");
358 root
= ACE_OS::getenv ("ACE_ROOT");
361 TestDir
= ACE_TEXT_CHAR_TO_TCHAR (root
);
362 TestDir
+= ACE_DIRECTORY_SEPARATOR_STR
;
363 TestDir
+= ACE_TEXT ("tests");
367 TestDir
= ACE_TEXT ("../tests");
369 #endif /* TEST_DIR */
373 if (-1 == dirent_test ())
376 if (-1 == dirent_selector_test ())
379 if (-1 == dirent_recurse_test ())