LCOV - code coverage report
Current view: top level - lib - fts-cycle.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 48 57 84.2 %
Date: 2018-01-30 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* Detect cycles in file tree walks.
       2             : 
       3             :    Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
       4             : 
       5             :    Written by Jim Meyering.
       6             : 
       7             :    This program is free software: you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      19             : 
      20             : #include "cycle-check.h"
      21             : #include "hash.h"
      22             : 
      23             : /* Use each of these to map a device/inode pair to an FTSENT.  */
      24             : struct Active_dir
      25             : {
      26             :   dev_t dev;
      27             :   ino_t ino;
      28             :   FTSENT *fts_ent;
      29             : };
      30             : 
      31             : static bool
      32       42327 : AD_compare (void const *x, void const *y)
      33             : {
      34       42327 :   struct Active_dir const *ax = x;
      35       42327 :   struct Active_dir const *ay = y;
      36       42327 :   return ax->ino == ay->ino
      37       42327 :       && ax->dev == ay->dev;
      38             : }
      39             : 
      40             : static size_t
      41       87933 : AD_hash (void const *x, size_t table_size)
      42             : {
      43       87933 :   struct Active_dir const *ax = x;
      44       87933 :   return (uintmax_t) ax->ino % table_size;
      45             : }
      46             : 
      47             : /* Set up the cycle-detection machinery.  */
      48             : 
      49             : static bool
      50         176 : setup_dir (FTS *fts)
      51             : {
      52         176 :   if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
      53             :     {
      54             :       enum { HT_INITIAL_SIZE = 31 };
      55          54 :       fts->fts_cycle.ht = hash_initialize (HT_INITIAL_SIZE, NULL, AD_hash,
      56             :                                            AD_compare, free);
      57          54 :       if (! fts->fts_cycle.ht)
      58           0 :         return false;
      59             :     }
      60             :   else
      61             :     {
      62         122 :       fts->fts_cycle.state = malloc (sizeof *fts->fts_cycle.state);
      63         122 :       if (! fts->fts_cycle.state)
      64           0 :         return false;
      65         122 :       cycle_check_init (fts->fts_cycle.state);
      66             :     }
      67             : 
      68         176 :   return true;
      69             : }
      70             : 
      71             : /* Enter a directory during a file tree walk.  */
      72             : 
      73             : static bool
      74      106142 : enter_dir (FTS *fts, FTSENT *ent)
      75             : {
      76      106142 :   if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
      77             :     {
      78       39810 :       struct stat const *st = ent->fts_statp;
      79       39810 :       struct Active_dir *ad = malloc (sizeof *ad);
      80             :       struct Active_dir *ad_from_table;
      81             : 
      82       39810 :       if (!ad)
      83           0 :         return false;
      84             : 
      85       39810 :       ad->dev = st->st_dev;
      86       39810 :       ad->ino = st->st_ino;
      87       39810 :       ad->fts_ent = ent;
      88             : 
      89             :       /* See if we've already encountered this directory.
      90             :          This can happen when following symlinks as well as
      91             :          with a corrupted directory hierarchy. */
      92       39810 :       ad_from_table = hash_insert (fts->fts_cycle.ht, ad);
      93             : 
      94       39810 :       if (ad_from_table != ad)
      95             :         {
      96           0 :           free (ad);
      97           0 :           if (!ad_from_table)
      98           0 :             return false;
      99             : 
     100             :           /* There was an entry with matching dev/inode already in the table.
     101             :              Record the fact that we've found a cycle.  */
     102           0 :           ent->fts_cycle = ad_from_table->fts_ent;
     103           0 :           ent->fts_info = FTS_DC;
     104             :         }
     105             :     }
     106             :   else
     107             :     {
     108       66332 :       if (cycle_check (fts->fts_cycle.state, ent->fts_statp))
     109             :         {
     110             :           /* FIXME: setting fts_cycle like this isn't proper.
     111             :              To do what the documentation requires, we'd have to
     112             :              go around the cycle again and find the right entry.
     113             :              But no callers in coreutils use the fts_cycle member. */
     114           3 :           ent->fts_cycle = ent;
     115           3 :           ent->fts_info = FTS_DC;
     116             :         }
     117             :     }
     118             : 
     119      106142 :   return true;
     120             : }
     121             : 
     122             : /* Leave a directory during a file tree walk.  */
     123             : 
     124             : static void
     125      106139 : leave_dir (FTS *fts, FTSENT *ent)
     126             : {
     127      106139 :   struct stat const *st = ent->fts_statp;
     128      106139 :   if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
     129             :     {
     130             :       struct Active_dir obj;
     131             :       void *found;
     132       39810 :       obj.dev = st->st_dev;
     133       39810 :       obj.ino = st->st_ino;
     134       39810 :       found = hash_delete (fts->fts_cycle.ht, &obj);
     135       39810 :       if (!found)
     136           0 :         abort ();
     137       39810 :       free (found);
     138             :     }
     139             :   else
     140             :     {
     141       66329 :       FTSENT *parent = ent->fts_parent;
     142       66329 :       if (parent != NULL && 0 <= parent->fts_level)
     143       66270 :         CYCLE_CHECK_REFLECT_CHDIR_UP (fts->fts_cycle.state,
     144             :                                       *(parent->fts_statp), *st);
     145             :     }
     146      106139 : }
     147             : 
     148             : /* Free any memory used for cycle detection.  */
     149             : 
     150             : static void
     151         176 : free_dir (FTS *sp)
     152             : {
     153         176 :   if (sp->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
     154             :     {
     155          54 :       if (sp->fts_cycle.ht)
     156          54 :         hash_free (sp->fts_cycle.ht);
     157             :     }
     158             :   else
     159         122 :     free (sp->fts_cycle.state);
     160         176 : }

Generated by: LCOV version 1.10