summaryrefslogtreecommitdiff
path: root/m4/readdir.m4
blob: 03ac3312de3e6aa4014b3b22fc23fa86b3820335 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#serial 4

dnl SunOS's readdir is broken in such a way that rm.c has to add extra code
dnl to test whether a NULL return value really means there are no more files
dnl in the directory.
dnl
dnl Detect the problem by creating a directory containing 300 files (254 not
dnl counting . and .. is the minimum) and see if a loop doing `readdir; unlink'
dnl removes all of them.
dnl
dnl Define HAVE_WORKING_READDIR if readdir does *not* have this problem.

dnl Written by Jim Meyering.

AC_DEFUN([jm_FUNC_READDIR],
[dnl
AC_REQUIRE([AC_HEADER_DIRENT])
AC_CHECK_HEADERS(string.h)
AC_CACHE_CHECK([for working readdir], jm_cv_func_working_readdir,
  [dnl
  # Arrange for deletion of the temporary directory this test creates, in
  # case the test itself fails to delete everything -- as happens on Sunos.
  ac_clean_files="$ac_clean_files conf-dir"

  AC_TRY_RUN(
[#   include <stdio.h>
#   include <sys/types.h>
#   if HAVE_STRING_H
#    include <string.h>
#   endif

#   ifdef HAVE_DIRENT_H
#    include <dirent.h>
#    define NLENGTH(direct) (strlen((direct)->d_name))
#   else /* not HAVE_DIRENT_H */
#    define dirent direct
#    define NLENGTH(direct) ((direct)->d_namlen)
#    ifdef HAVE_SYS_NDIR_H
#     include <sys/ndir.h>
#    endif /* HAVE_SYS_NDIR_H */
#    ifdef HAVE_SYS_DIR_H
#     include <sys/dir.h>
#    endif /* HAVE_SYS_DIR_H */
#    ifdef HAVE_NDIR_H
#     include <ndir.h>
#    endif /* HAVE_NDIR_H */
#   endif /* HAVE_DIRENT_H */

#   define DOT_OR_DOTDOT(Basename) \
     (Basename[0] == '.' && (Basename[1] == '\0' \
			     || (Basename[1] == '.' && Basename[2] == '\0')))

/* Don't try to use replacement mkdir; it wouldn't resolve at link time.  */
#   undef mkdir

    static void
    create_300_file_dir (const char *dir)
    {
      int i;

      if (mkdir (dir, 0700))
	abort ();
      if (chdir (dir))
	abort ();

      for (i = 0; i < 300; i++)
	{
	  char file_name[4];
	  FILE *out;

	  sprintf (file_name, "%03d", i);
	  out = fopen (file_name, "w");
	  if (!out)
	    abort ();
	  if (fclose (out) == EOF)
	    abort ();
	}

      if (chdir (".."))
	abort ();
    }

    static void
    remove_dir (const char *dir)
    {
      DIR *dirp;

      if (chdir (dir))
	abort ();

      dirp = opendir (".");
      if (dirp == NULL)
	abort ();

      while (1)
	{
	  struct dirent *dp = readdir (dirp);
	  if (dp == NULL)
	    break;

	  if (DOT_OR_DOTDOT (dp->d_name))
	    continue;

	  if (unlink (dp->d_name))
	    abort ();
	}
      closedir (dirp);

      if (chdir (".."))
	abort ();

      if (rmdir (dir))
	exit (1);
    }

    int
    main ()
    {
      const char *dir = "conf-dir";
      create_300_file_dir (dir);
      remove_dir (dir);
      exit (0);
    }],
  jm_cv_func_working_readdir=yes,
  jm_cv_func_working_readdir=no,
  jm_cv_func_working_readdir=no)])

  if test $jm_cv_func_working_readdir = yes; then
    AC_DEFINE(HAVE_WORKING_READDIR, 1,
[Define if readdir is found to work properly in some unusual cases. ])
  fi
])