Back to index

glibc  2.9
tst-dir.c
Go to the documentation of this file.
00001 /* Copyright (C) 2000-2002 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <dirent.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <mcheck.h>
00024 #include <stddef.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <sys/stat.h>
00030 
00031 
00032 /* We expect four arguments:
00033    - source directory name
00034    - object directory
00035    - common object directory
00036    - the program name with path
00037 */
00038 int
00039 main (int argc, char *argv[])
00040 {
00041   const char *srcdir;
00042   const char *objdir;
00043   const char *common_objdir;
00044   const char *progpath;
00045   struct stat64 st1;
00046   struct stat64 st2;
00047   struct stat64 st3;
00048   DIR *dir1;
00049   DIR *dir2;
00050   int result = 0;
00051   struct dirent64 *d;
00052   union
00053     {
00054       struct dirent64 d;
00055       char room [offsetof (struct dirent64, d_name[0]) + NAME_MAX + 1];
00056     }
00057     direntbuf;
00058   char *objdir_copy1;
00059   char *objdir_copy2;
00060   char *buf;
00061   int fd;
00062 
00063   mtrace ();
00064 
00065   if (argc < 5)
00066     {
00067       puts ("not enough parameters");
00068       exit (1);
00069     }
00070 
00071   /* Make parameters available with nicer names.  */
00072   srcdir = argv[1];
00073   objdir = argv[2];
00074   common_objdir = argv[3];
00075   progpath = argv[4];
00076 
00077   /* First test the current source dir.  We cannot really compare the
00078      result of `getpwd' with the srcdir string but we have other means.  */
00079   if (stat64 (".", &st1) < 0)
00080     {
00081       printf ("cannot stat starting directory: %m\n");
00082       exit (1);
00083     }
00084 
00085   if (chdir (srcdir) < 0)
00086     {
00087       printf ("cannot change to source directory: %m\n");
00088       exit (1);
00089     }
00090   if (stat64 (".", &st2) < 0)
00091     {
00092       printf ("cannot stat source directory: %m\n");
00093       exit (1);
00094     }
00095 
00096   /* The two last stat64 calls better were for the same directory.  */
00097   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
00098     {
00099       printf ("stat of source directory failed: (%lld,%lld) vs (%lld,%lld)\n",
00100              (long long int) st1.st_dev, (long long int) st1.st_ino,
00101              (long long int) st2.st_dev, (long long int) st2.st_ino);
00102       exit (1);
00103     }
00104 
00105   /* Change to the object directory.  */
00106   if (chdir (objdir) < 0)
00107     {
00108       printf ("cannot change to object directory: %m\n");
00109       exit (1);
00110     }
00111   if (stat64 (".", &st1) < 0)
00112     {
00113       printf ("cannot stat object directory: %m\n");
00114       exit (1);
00115     }
00116   /* Is this the same we get as with the full path?  */
00117   if (stat64 (objdir, &st2) < 0)
00118     {
00119       printf ("cannot stat object directory with full path: %m\n");
00120       exit (1);
00121     }
00122   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
00123     {
00124       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
00125              (long long int) st1.st_dev, (long long int) st1.st_ino,
00126              (long long int) st2.st_dev, (long long int) st2.st_ino);
00127       exit (1);
00128     }
00129 
00130   objdir_copy1 = getcwd (NULL, 0);
00131   if (objdir_copy1 == NULL)
00132     {
00133       printf ("cannot get current directory name for object directory: %m\n");
00134       result = 1;
00135     }
00136 
00137   /* First test: this directory must include our program.  */
00138   if (stat64 (progpath, &st2) < 0)
00139     {
00140       printf ("cannot stat program: %m\n");
00141       exit (1);
00142     }
00143 
00144   dir1 = opendir (".");
00145   if (dir1 == NULL)
00146     {
00147       printf ("cannot open object directory: %m\n");
00148       exit (1);
00149     }
00150 
00151   while ((d = readdir64 (dir1)) != NULL)
00152     {
00153 #ifdef _DIRENT_HAVE_D_TYPE
00154       if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
00155        continue;
00156 #endif
00157 
00158       if (d->d_ino == st2.st_ino)
00159        {
00160          /* Might be it.  Test the device.  We could use the st_dev
00161             element from st1 but what the heck, do more testing.  */
00162          if (stat64 (d->d_name, &st3) < 0)
00163            {
00164              printf ("cannot stat entry from readdir: %m\n");
00165              result = 1;
00166              d = NULL;
00167              break;
00168            }
00169 
00170          if (st3.st_dev == st2.st_dev)
00171            break;
00172        }
00173     }
00174 
00175   if (d == NULL)
00176     {
00177       puts ("haven't found program in object directory");
00178       result = 1;
00179     }
00180 
00181   /* We leave dir1 open.  */
00182 
00183   /* Stat using file descriptor.  */
00184   if (fstat64 (dirfd (dir1), &st2) < 0)
00185     {
00186       printf ("cannot fstat object directory: %m\n");
00187       result = 1;
00188     }
00189   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
00190     {
00191       printf ("fstat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
00192              (long long int) st1.st_dev, (long long int) st1.st_ino,
00193              (long long int) st2.st_dev, (long long int) st2.st_ino);
00194       exit (1);
00195     }
00196 
00197   if (chdir ("..") < 0)
00198     {
00199       printf ("cannot go to common object directory with \"..\": %m\n");
00200       exit (1);
00201     }
00202 
00203   if (stat64 (".", &st1) < 0)
00204     {
00205       printf ("cannot stat common object directory: %m\n");
00206       exit (1);
00207     }
00208   /* Is this the same we get as with the full path?  */
00209   if (stat64 (common_objdir, &st2) < 0)
00210     {
00211       printf ("cannot stat common object directory with full path: %m\n");
00212       exit (1);
00213     }
00214   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
00215     {
00216       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
00217              (long long int) st1.st_dev, (long long int) st1.st_ino,
00218              (long long int) st2.st_dev, (long long int) st2.st_ino);
00219       exit (1);
00220     }
00221 
00222   /* Stat using file descriptor.  */
00223   if (fstat64 (dirfd (dir1), &st2) < 0)
00224     {
00225       printf ("cannot fstat object directory: %m\n");
00226       result = 1;
00227     }
00228 
00229   dir2 = opendir (common_objdir);
00230   if (dir2 == NULL)
00231     {
00232       printf ("cannot open common object directory: %m\n");
00233       exit (1);
00234     }
00235 
00236   while ((d = readdir64 (dir2)) != NULL)
00237     {
00238 #ifdef _DIRENT_HAVE_D_TYPE
00239       if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
00240        continue;
00241 #endif
00242 
00243       if (d->d_ino == st2.st_ino)
00244        {
00245          /* Might be it.  Test the device.  We could use the st_dev
00246             element from st1 but what the heck, do more testing.  */
00247          if (stat64 (d->d_name, &st3) < 0)
00248            {
00249              printf ("cannot stat entry from readdir: %m\n");
00250              result = 1;
00251              d = NULL;
00252              break;
00253            }
00254 
00255          if (st3.st_dev == st2.st_dev)
00256            break;
00257        }
00258     }
00259 
00260   /* This better should be the object directory again.  */
00261   if (fchdir (dirfd (dir1)) < 0)
00262     {
00263       printf ("cannot fchdir to object directory: %m\n");
00264       exit (1);
00265     }
00266 
00267   objdir_copy2 = getcwd (NULL, 0);
00268   if (objdir_copy2 == NULL)
00269     {
00270       printf ("cannot get current directory name for object directory: %m\n");
00271       result = 1;
00272     }
00273   if (strcmp (objdir_copy1, objdir_copy2) != 0)
00274     {
00275       puts ("getcwd returned a different string the second time");
00276       result = 1;
00277     }
00278 
00279   /* This better should be the common object directory again.  */
00280   if (fchdir (dirfd (dir2)) < 0)
00281     {
00282       printf ("cannot fchdir to common object directory: %m\n");
00283       exit (1);
00284     }
00285 
00286   if (stat64 (".", &st2) < 0)
00287     {
00288       printf ("cannot stat common object directory: %m\n");
00289       exit (1);
00290     }
00291   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
00292     {
00293       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
00294              (long long int) st1.st_dev, (long long int) st1.st_ino,
00295              (long long int) st2.st_dev, (long long int) st2.st_ino);
00296       exit (1);
00297     }
00298 
00299   buf = (char *) malloc (strlen (objdir_copy1) + 1 + sizeof "tst-dir.XXXXXX");
00300   if (buf == NULL)
00301     {
00302       printf ("cannot allocate buffer: %m");
00303       exit (1);
00304     }
00305 
00306   stpcpy (stpcpy (stpcpy (buf, objdir_copy1), "/"), "tst-dir.XXXXXX");
00307   if (mkdtemp (buf) == NULL)
00308     {
00309       printf ("cannot create test directory in object directory: %m\n");
00310       exit (1);
00311     }
00312   if (stat64 (buf, &st1) < 0)
00313     {
00314       printf ("cannot stat new directory \"%s\": %m\n", buf);
00315       exit (1);
00316     }
00317   if (chmod (buf, 0700) < 0)
00318     {
00319       printf ("cannot change mode of new directory: %m\n");
00320       exit (1);
00321     }
00322 
00323   /* Try to find the new directory.  */
00324   rewinddir (dir1);
00325   while (readdir64_r (dir1, &direntbuf.d, &d) == 0 && d != NULL)
00326     {
00327 #ifdef _DIRENT_HAVE_D_TYPE
00328       if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
00329        continue;
00330 #endif
00331 
00332       if (d->d_ino == st1.st_ino)
00333        {
00334          /* Might be it.  Test the device.  We could use the st_dev
00335             element from st1 but what the heck, do more testing.  */
00336          size_t len = strlen (objdir) + 1 + _D_EXACT_NAMLEN (d) + 1;
00337          char tmpbuf[len];
00338 
00339          stpcpy (stpcpy (stpcpy (tmpbuf, objdir), "/"), d->d_name);
00340 
00341          if (stat64 (tmpbuf, &st3) < 0)
00342            {
00343              printf ("cannot stat entry from readdir: %m\n");
00344              result = 1;
00345              d = NULL;
00346              break;
00347            }
00348 
00349          if (st3.st_dev == st2.st_dev
00350              && strcmp (d->d_name, buf + strlen (buf) - 14) == 0)
00351            break;
00352        }
00353     }
00354 
00355   if (d == NULL)
00356     {
00357       printf ("haven't found new directory \"%s\"\n", buf);
00358       exit (1);
00359     }
00360 
00361   if (closedir (dir2) < 0)
00362     {
00363       printf ("closing dir2 failed: %m\n");
00364       result = 1;
00365     }
00366 
00367   if (chdir (buf) < 0)
00368     {
00369       printf ("cannot change to new directory: %m\n");
00370       exit (1);
00371     }
00372 
00373   dir2 = opendir (buf);
00374   if (dir2 == NULL)
00375     {
00376       printf ("cannot open new directory: %m\n");
00377       exit (1);
00378     }
00379 
00380   if (fstat64 (dirfd (dir2), &st2) < 0)
00381     {
00382       printf ("cannot fstat new directory \"%s\": %m\n", buf);
00383       exit (1);
00384     }
00385   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
00386     {
00387       printf ("stat of new directory failed: (%lld,%lld) vs (%lld,%lld)\n",
00388              (long long int) st1.st_dev, (long long int) st1.st_ino,
00389              (long long int) st2.st_dev, (long long int) st2.st_ino);
00390       exit (1);
00391     }
00392 
00393   if (mkdir ("another-dir", 0777) < 0)
00394     {
00395       printf ("cannot create \"another-dir\": %m\n");
00396       exit (1);
00397     }
00398   fd = open ("and-a-file", O_RDWR | O_CREAT | O_EXCL, 0666);
00399   if (fd == -1)
00400     {
00401       printf ("cannot create \"and-a-file\": %m\n");
00402       exit (1);
00403     }
00404   close (fd);
00405 
00406   /* Some tests about error reporting.  */
00407   errno = 0;
00408   if (chdir ("and-a-file") >= 0)
00409     {
00410       printf ("chdir to \"and-a-file\" succeeded\n");
00411       exit (1);
00412     }
00413   if (errno != ENOTDIR)
00414     {
00415       printf ("chdir to \"and-a-file\" didn't set correct error\n");
00416       result = 1;
00417     }
00418 
00419   errno = 0;
00420   if (chdir ("and-a-file/..") >= 0)
00421     {
00422       printf ("chdir to \"and-a-file/..\" succeeded\n");
00423       exit (1);
00424     }
00425   if (errno != ENOTDIR)
00426     {
00427       printf ("chdir to \"and-a-file/..\" didn't set correct error\n");
00428       result = 1;
00429     }
00430 
00431   errno = 0;
00432   if (chdir ("another-dir/../and-a-file") >= 0)
00433     {
00434       printf ("chdir to \"another-dir/../and-a-file\" succeeded\n");
00435       exit (1);
00436     }
00437   if (errno != ENOTDIR)
00438     {
00439       printf ("chdir to \"another-dir/../and-a-file\" didn't set correct error\n");
00440       result = 1;
00441     }
00442 
00443   /* We now should have a directory and a file in the new directory.  */
00444   rewinddir (dir2);
00445   while (readdir64_r (dir2, &direntbuf.d, &d) == 0 && d != NULL)
00446     {
00447       if (strcmp (d->d_name, ".") == 0
00448          || strcmp (d->d_name, "..") == 0
00449          || strcmp (d->d_name, "another-dir") == 0)
00450        {
00451 #ifdef _DIRENT_HAVE_D_TYPE
00452          if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
00453            {
00454              printf ("d_type for \"%s\" is wrong\n", d->d_name);
00455              result = 1;
00456            }
00457 #endif
00458          if (stat64 (d->d_name, &st3) < 0)
00459            {
00460              printf ("cannot stat \"%s\" is wrong\n", d->d_name);
00461              result = 1;
00462            }
00463          else if (! S_ISDIR (st3.st_mode))
00464            {
00465              printf ("\"%s\" is no directory\n", d->d_name);
00466              result = 1;
00467            }
00468        }
00469       else if (strcmp (d->d_name, "and-a-file") == 0)
00470        {
00471 #ifdef _DIRENT_HAVE_D_TYPE
00472          if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
00473            {
00474              printf ("d_type for \"%s\" is wrong\n", d->d_name);
00475              result = 1;
00476            }
00477 #endif
00478          if (stat64 (d->d_name, &st3) < 0)
00479            {
00480              printf ("cannot stat \"%s\" is wrong\n", d->d_name);
00481              result = 1;
00482            }
00483          else if (! S_ISREG (st3.st_mode))
00484            {
00485              printf ("\"%s\" is no regular file\n", d->d_name);
00486              result = 1;
00487            }
00488        }
00489       else
00490        {
00491          printf ("unexpected directory entry \"%s\"\n", d->d_name);
00492          result = 1;
00493        }
00494     }
00495 
00496   if (stat64 ("does-not-exist", &st1) >= 0)
00497     {
00498       puts ("stat for unexisting file did not fail");
00499       result = 1;
00500     }
00501 
00502   /* Free all resources.  */
00503 
00504   if (closedir (dir1) < 0)
00505     {
00506       printf ("closing dir1 failed: %m\n");
00507       result = 1;
00508     }
00509   if (closedir (dir2) < 0)
00510     {
00511       printf ("second closing dir2 failed: %m\n");
00512       result = 1;
00513     }
00514 
00515   if (rmdir ("another-dir") < 0)
00516     {
00517       printf ("cannot remove \"another-dir\": %m\n");
00518       result = 1;
00519     }
00520 
00521   if (unlink ("and-a-file") < 0)
00522     {
00523       printf ("cannot remove \"and-a-file\": %m\n");
00524       result = 1;
00525     }
00526 
00527   /* One more test before we leave: mkdir() is supposed to fail with
00528      EEXIST if the named file is a symlink.  */
00529   if (symlink ("a-symlink", "a-symlink") != 0)
00530     {
00531       printf ("cannot create symlink \"a-symlink\": %m\n");
00532       result = 1;
00533     }
00534   else
00535     {
00536       if (mkdir ("a-symlink", 0666) == 0)
00537        {
00538          puts ("can make directory \"a-symlink\"");
00539          result = 1;
00540        }
00541       else if (errno != EEXIST)
00542        {
00543          puts ("mkdir(\"a-symlink\") does not fail with EEXIST\n");
00544          result = 1;
00545        }
00546       if (unlink ("a-symlink") < 0)
00547        {
00548          printf ("cannot unlink \"a-symlink\": %m\n");
00549          result = 1;
00550        }
00551     }
00552 
00553   if (chdir (srcdir) < 0)
00554     {
00555       printf ("cannot change back to source directory: %m\n");
00556       exit (1);
00557     }
00558 
00559   if (rmdir (buf) < 0)
00560     {
00561       printf ("cannot remove \"%s\": %m\n", buf);
00562       result = 1;
00563     }
00564   free (objdir_copy1);
00565   free (objdir_copy2);
00566 
00567   if (result == 0)
00568     puts ("all OK");
00569 
00570   return result;
00571 }