chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / posix / tst-dir.c
1 /* Copyright (C) 2000-2002 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <dirent.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <mcheck.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30
31
32 /* We expect four arguments:
33    - source directory name
34    - object directory
35    - common object directory
36    - the program name with path
37 */
38 int
39 main (int argc, char *argv[])
40 {
41   const char *srcdir;
42   const char *objdir;
43   const char *common_objdir;
44   const char *progpath;
45   struct stat64 st1;
46   struct stat64 st2;
47   struct stat64 st3;
48   DIR *dir1;
49   DIR *dir2;
50   int result = 0;
51   struct dirent64 *d;
52   union
53     {
54       struct dirent64 d;
55       char room [offsetof (struct dirent64, d_name[0]) + NAME_MAX + 1];
56     }
57     direntbuf;
58   char *objdir_copy1;
59   char *objdir_copy2;
60   char *buf;
61   int fd;
62
63   mtrace ();
64
65   if (argc < 5)
66     {
67       puts ("not enough parameters");
68       exit (1);
69     }
70
71   /* Make parameters available with nicer names.  */
72   srcdir = argv[1];
73   objdir = argv[2];
74   common_objdir = argv[3];
75   progpath = argv[4];
76
77   /* First test the current source dir.  We cannot really compare the
78      result of `getpwd' with the srcdir string but we have other means.  */
79   if (stat64 (".", &st1) < 0)
80     {
81       printf ("cannot stat starting directory: %m\n");
82       exit (1);
83     }
84
85   if (chdir (srcdir) < 0)
86     {
87       printf ("cannot change to source directory: %m\n");
88       exit (1);
89     }
90   if (stat64 (".", &st2) < 0)
91     {
92       printf ("cannot stat source directory: %m\n");
93       exit (1);
94     }
95
96   /* The two last stat64 calls better were for the same directory.  */
97   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
98     {
99       printf ("stat of source directory failed: (%lld,%lld) vs (%lld,%lld)\n",
100               (long long int) st1.st_dev, (long long int) st1.st_ino,
101               (long long int) st2.st_dev, (long long int) st2.st_ino);
102       exit (1);
103     }
104
105   /* Change to the object directory.  */
106   if (chdir (objdir) < 0)
107     {
108       printf ("cannot change to object directory: %m\n");
109       exit (1);
110     }
111   if (stat64 (".", &st1) < 0)
112     {
113       printf ("cannot stat object directory: %m\n");
114       exit (1);
115     }
116   /* Is this the same we get as with the full path?  */
117   if (stat64 (objdir, &st2) < 0)
118     {
119       printf ("cannot stat object directory with full path: %m\n");
120       exit (1);
121     }
122   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
123     {
124       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
125               (long long int) st1.st_dev, (long long int) st1.st_ino,
126               (long long int) st2.st_dev, (long long int) st2.st_ino);
127       exit (1);
128     }
129
130   objdir_copy1 = getcwd (NULL, 0);
131   if (objdir_copy1 == NULL)
132     {
133       printf ("cannot get current directory name for object directory: %m\n");
134       result = 1;
135     }
136
137   /* First test: this directory must include our program.  */
138   if (stat64 (progpath, &st2) < 0)
139     {
140       printf ("cannot stat program: %m\n");
141       exit (1);
142     }
143
144   dir1 = opendir (".");
145   if (dir1 == NULL)
146     {
147       printf ("cannot open object directory: %m\n");
148       exit (1);
149     }
150
151   while ((d = readdir64 (dir1)) != NULL)
152     {
153 #ifdef _DIRENT_HAVE_D_TYPE
154       if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
155         continue;
156 #endif
157
158       if (d->d_ino == st2.st_ino)
159         {
160           /* Might be it.  Test the device.  We could use the st_dev
161              element from st1 but what the heck, do more testing.  */
162           if (stat64 (d->d_name, &st3) < 0)
163             {
164               printf ("cannot stat entry from readdir: %m\n");
165               result = 1;
166               d = NULL;
167               break;
168             }
169
170           if (st3.st_dev == st2.st_dev)
171             break;
172         }
173     }
174
175   if (d == NULL)
176     {
177       puts ("haven't found program in object directory");
178       result = 1;
179     }
180
181   /* We leave dir1 open.  */
182
183   /* Stat using file descriptor.  */
184   if (fstat64 (dirfd (dir1), &st2) < 0)
185     {
186       printf ("cannot fstat object directory: %m\n");
187       result = 1;
188     }
189   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
190     {
191       printf ("fstat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
192               (long long int) st1.st_dev, (long long int) st1.st_ino,
193               (long long int) st2.st_dev, (long long int) st2.st_ino);
194       exit (1);
195     }
196
197   if (chdir ("..") < 0)
198     {
199       printf ("cannot go to common object directory with \"..\": %m\n");
200       exit (1);
201     }
202
203   if (stat64 (".", &st1) < 0)
204     {
205       printf ("cannot stat common object directory: %m\n");
206       exit (1);
207     }
208   /* Is this the same we get as with the full path?  */
209   if (stat64 (common_objdir, &st2) < 0)
210     {
211       printf ("cannot stat common object directory with full path: %m\n");
212       exit (1);
213     }
214   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
215     {
216       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
217               (long long int) st1.st_dev, (long long int) st1.st_ino,
218               (long long int) st2.st_dev, (long long int) st2.st_ino);
219       exit (1);
220     }
221
222   /* Stat using file descriptor.  */
223   if (fstat64 (dirfd (dir1), &st2) < 0)
224     {
225       printf ("cannot fstat object directory: %m\n");
226       result = 1;
227     }
228
229   dir2 = opendir (common_objdir);
230   if (dir2 == NULL)
231     {
232       printf ("cannot open common object directory: %m\n");
233       exit (1);
234     }
235
236   while ((d = readdir64 (dir2)) != NULL)
237     {
238 #ifdef _DIRENT_HAVE_D_TYPE
239       if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
240         continue;
241 #endif
242
243       if (d->d_ino == st2.st_ino)
244         {
245           /* Might be it.  Test the device.  We could use the st_dev
246              element from st1 but what the heck, do more testing.  */
247           if (stat64 (d->d_name, &st3) < 0)
248             {
249               printf ("cannot stat entry from readdir: %m\n");
250               result = 1;
251               d = NULL;
252               break;
253             }
254
255           if (st3.st_dev == st2.st_dev)
256             break;
257         }
258     }
259
260   /* This better should be the object directory again.  */
261   if (fchdir (dirfd (dir1)) < 0)
262     {
263       printf ("cannot fchdir to object directory: %m\n");
264       exit (1);
265     }
266
267   objdir_copy2 = getcwd (NULL, 0);
268   if (objdir_copy2 == NULL)
269     {
270       printf ("cannot get current directory name for object directory: %m\n");
271       result = 1;
272     }
273   if (strcmp (objdir_copy1, objdir_copy2) != 0)
274     {
275       puts ("getcwd returned a different string the second time");
276       result = 1;
277     }
278
279   /* This better should be the common object directory again.  */
280   if (fchdir (dirfd (dir2)) < 0)
281     {
282       printf ("cannot fchdir to common object directory: %m\n");
283       exit (1);
284     }
285
286   if (stat64 (".", &st2) < 0)
287     {
288       printf ("cannot stat common object directory: %m\n");
289       exit (1);
290     }
291   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
292     {
293       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
294               (long long int) st1.st_dev, (long long int) st1.st_ino,
295               (long long int) st2.st_dev, (long long int) st2.st_ino);
296       exit (1);
297     }
298
299   buf = (char *) malloc (strlen (objdir_copy1) + 1 + sizeof "tst-dir.XXXXXX");
300   if (buf == NULL)
301     {
302       printf ("cannot allocate buffer: %m");
303       exit (1);
304     }
305
306   stpcpy (stpcpy (stpcpy (buf, objdir_copy1), "/"), "tst-dir.XXXXXX");
307   if (mkdtemp (buf) == NULL)
308     {
309       printf ("cannot create test directory in object directory: %m\n");
310       exit (1);
311     }
312   if (stat64 (buf, &st1) < 0)
313     {
314       printf ("cannot stat new directory \"%s\": %m\n", buf);
315       exit (1);
316     }
317   if (chmod (buf, 0700) < 0)
318     {
319       printf ("cannot change mode of new directory: %m\n");
320       exit (1);
321     }
322
323   /* Try to find the new directory.  */
324   rewinddir (dir1);
325   while (readdir64_r (dir1, &direntbuf.d, &d) == 0 && d != NULL)
326     {
327 #ifdef _DIRENT_HAVE_D_TYPE
328       if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
329         continue;
330 #endif
331
332       if (d->d_ino == st1.st_ino)
333         {
334           /* Might be it.  Test the device.  We could use the st_dev
335              element from st1 but what the heck, do more testing.  */
336           size_t len = strlen (objdir) + 1 + _D_EXACT_NAMLEN (d) + 1;
337           char tmpbuf[len];
338
339           stpcpy (stpcpy (stpcpy (tmpbuf, objdir), "/"), d->d_name);
340
341           if (stat64 (tmpbuf, &st3) < 0)
342             {
343               printf ("cannot stat entry from readdir: %m\n");
344               result = 1;
345               d = NULL;
346               break;
347             }
348
349           if (st3.st_dev == st2.st_dev
350               && strcmp (d->d_name, buf + strlen (buf) - 14) == 0)
351             break;
352         }
353     }
354
355   if (d == NULL)
356     {
357       printf ("haven't found new directory \"%s\"\n", buf);
358       exit (1);
359     }
360
361   if (closedir (dir2) < 0)
362     {
363       printf ("closing dir2 failed: %m\n");
364       result = 1;
365     }
366
367   if (chdir (buf) < 0)
368     {
369       printf ("cannot change to new directory: %m\n");
370       exit (1);
371     }
372
373   dir2 = opendir (buf);
374   if (dir2 == NULL)
375     {
376       printf ("cannot open new directory: %m\n");
377       exit (1);
378     }
379
380   if (fstat64 (dirfd (dir2), &st2) < 0)
381     {
382       printf ("cannot fstat new directory \"%s\": %m\n", buf);
383       exit (1);
384     }
385   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
386     {
387       printf ("stat of new directory failed: (%lld,%lld) vs (%lld,%lld)\n",
388               (long long int) st1.st_dev, (long long int) st1.st_ino,
389               (long long int) st2.st_dev, (long long int) st2.st_ino);
390       exit (1);
391     }
392
393   if (mkdir ("another-dir", 0777) < 0)
394     {
395       printf ("cannot create \"another-dir\": %m\n");
396       exit (1);
397     }
398   fd = open ("and-a-file", O_RDWR | O_CREAT | O_EXCL, 0666);
399   if (fd == -1)
400     {
401       printf ("cannot create \"and-a-file\": %m\n");
402       exit (1);
403     }
404   close (fd);
405
406   /* Some tests about error reporting.  */
407   errno = 0;
408   if (chdir ("and-a-file") >= 0)
409     {
410       printf ("chdir to \"and-a-file\" succeeded\n");
411       exit (1);
412     }
413   if (errno != ENOTDIR)
414     {
415       printf ("chdir to \"and-a-file\" didn't set correct error\n");
416       result = 1;
417     }
418
419   errno = 0;
420   if (chdir ("and-a-file/..") >= 0)
421     {
422       printf ("chdir to \"and-a-file/..\" succeeded\n");
423       exit (1);
424     }
425   if (errno != ENOTDIR)
426     {
427       printf ("chdir to \"and-a-file/..\" didn't set correct error\n");
428       result = 1;
429     }
430
431   errno = 0;
432   if (chdir ("another-dir/../and-a-file") >= 0)
433     {
434       printf ("chdir to \"another-dir/../and-a-file\" succeeded\n");
435       exit (1);
436     }
437   if (errno != ENOTDIR)
438     {
439       printf ("chdir to \"another-dir/../and-a-file\" didn't set correct error\n");
440       result = 1;
441     }
442
443   /* We now should have a directory and a file in the new directory.  */
444   rewinddir (dir2);
445   while (readdir64_r (dir2, &direntbuf.d, &d) == 0 && d != NULL)
446     {
447       if (strcmp (d->d_name, ".") == 0
448           || strcmp (d->d_name, "..") == 0
449           || strcmp (d->d_name, "another-dir") == 0)
450         {
451 #ifdef _DIRENT_HAVE_D_TYPE
452           if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
453             {
454               printf ("d_type for \"%s\" is wrong\n", d->d_name);
455               result = 1;
456             }
457 #endif
458           if (stat64 (d->d_name, &st3) < 0)
459             {
460               printf ("cannot stat \"%s\" is wrong\n", d->d_name);
461               result = 1;
462             }
463           else if (! S_ISDIR (st3.st_mode))
464             {
465               printf ("\"%s\" is no directory\n", d->d_name);
466               result = 1;
467             }
468         }
469       else if (strcmp (d->d_name, "and-a-file") == 0)
470         {
471 #ifdef _DIRENT_HAVE_D_TYPE
472           if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
473             {
474               printf ("d_type for \"%s\" is wrong\n", d->d_name);
475               result = 1;
476             }
477 #endif
478           if (stat64 (d->d_name, &st3) < 0)
479             {
480               printf ("cannot stat \"%s\" is wrong\n", d->d_name);
481               result = 1;
482             }
483           else if (! S_ISREG (st3.st_mode))
484             {
485               printf ("\"%s\" is no regular file\n", d->d_name);
486               result = 1;
487             }
488         }
489       else
490         {
491           printf ("unexpected directory entry \"%s\"\n", d->d_name);
492           result = 1;
493         }
494     }
495
496   if (stat64 ("does-not-exist", &st1) >= 0)
497     {
498       puts ("stat for unexisting file did not fail");
499       result = 1;
500     }
501
502   /* Free all resources.  */
503
504   if (closedir (dir1) < 0)
505     {
506       printf ("closing dir1 failed: %m\n");
507       result = 1;
508     }
509   if (closedir (dir2) < 0)
510     {
511       printf ("second closing dir2 failed: %m\n");
512       result = 1;
513     }
514
515   if (rmdir ("another-dir") < 0)
516     {
517       printf ("cannot remove \"another-dir\": %m\n");
518       result = 1;
519     }
520
521   if (unlink ("and-a-file") < 0)
522     {
523       printf ("cannot remove \"and-a-file\": %m\n");
524       result = 1;
525     }
526
527   /* One more test before we leave: mkdir() is supposed to fail with
528      EEXIST if the named file is a symlink.  */
529   if (symlink ("a-symlink", "a-symlink") != 0)
530     {
531       printf ("cannot create symlink \"a-symlink\": %m\n");
532       result = 1;
533     }
534   else
535     {
536       if (mkdir ("a-symlink", 0666) == 0)
537         {
538           puts ("can make directory \"a-symlink\"");
539           result = 1;
540         }
541       else if (errno != EEXIST)
542         {
543           puts ("mkdir(\"a-symlink\") does not fail with EEXIST\n");
544           result = 1;
545         }
546       if (unlink ("a-symlink") < 0)
547         {
548           printf ("cannot unlink \"a-symlink\": %m\n");
549           result = 1;
550         }
551     }
552
553   if (chdir (srcdir) < 0)
554     {
555       printf ("cannot change back to source directory: %m\n");
556       exit (1);
557     }
558
559   if (rmdir (buf) < 0)
560     {
561       printf ("cannot remove \"%s\": %m\n", buf);
562       result = 1;
563     }
564   free (objdir_copy1);
565   free (objdir_copy2);
566
567   if (result == 0)
568     puts ("all OK");
569
570   return result;
571 }