dirpool.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Novell Inc.
00003  *
00004  * This program is licensed under the BSD license, read LICENSE.BSD
00005  * for further information
00006  */
00007 
00008 #include <stdio.h>
00009 #include <string.h>
00010 
00011 #include "pool.h"
00012 #include "util.h"
00013 #include "dirpool.h"
00014 
00015 #define DIR_BLOCK 127
00016 
00017 /* directories are stored as components,
00018  * components are simple ids from the string pool
00019  *   /usr/bin   ->  "", "usr", "bin"
00020  *   /usr/lib   ->  "", "usr", "lib"
00021  *   foo/bar    ->  "foo", "bar"
00022  *   /usr/games ->  "", "usr", "games"
00023  *
00024  * all directories are stores in the "dirs" array
00025  *   dirs[id] > 0 : component string pool id
00026  *   dirs[id] <= 0 : -(parent directory id)
00027  *
00028  * Directories with the same parent are stored as
00029  * multiple blocks. We need multiple blocks, because
00030  * we cannot insert entries into old blocks, as that
00031  * would shift the ids of already used directories.
00032  * Each block starts with (-parent_dirid) and contains
00033  * component ids of the directory entries.
00034  * (The (-parent_dirid) entry is not a valid directory
00035  * id, it's just used internally)
00036  *
00037  * There is also the aux "dirtraverse" array, which
00038  * is created on demand to speed things up a bit.
00039  * if dirs[id] > 0, dirtravers[id] points to the first
00040  * entry in the last block with parent id
00041  * if dirs[id] <= 0, dirtravers[id] points to the entry
00042  * in the previous block with the same parent.
00043  * (Thus it acts as a linked list that starts at the
00044  * parent dirid and chains all the blocks with that
00045  * parent.)
00046  *
00047  *  id    dirs[id]  dirtraverse[id]
00048  *   0     0           8       [block#0 no parent]
00049  *   1    ""           3
00050  *   2    -1                   [block#0 parent 1, /]
00051  *   3    "usr"       12
00052  *   4    -3                   [block#0 parent 3, /usr]
00053  *   5    "bin"
00054  *   6    "lib"
00055  *   7     0           1       [block#1 no parent]
00056  *   8    "foo"       10
00057  *   9    -8                   [block#0 parent 8, foo]
00058  *  10    "bar"
00059  *  11    -3           5       [block#1 parent 3, /usr]
00060  *  12    "games"
00061  *   
00062  * to find all children of dirid 3, "/usr", follow the
00063  * dirtraverse link to 12 -> "games". Then follow the
00064  * dirtraverse link of this block to 5 -> "bin", "lib"
00065  */
00066 
00067 void
00068 dirpool_init(Dirpool *dp)
00069 {
00070   memset(dp, 0, sizeof(*dp));
00071 }
00072 
00073 void
00074 dirpool_free(Dirpool *dp)
00075 {
00076   sat_free(dp->dirs);
00077   sat_free(dp->dirtraverse);
00078 }
00079 
00080 void
00081 dirpool_make_dirtraverse(Dirpool *dp)
00082 {
00083   Id parent, i, *dirtraverse;
00084   if (!dp->ndirs)
00085     return;
00086   dp->dirs = sat_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
00087   dirtraverse = sat_calloc_block(dp->ndirs, sizeof(Id), DIR_BLOCK);
00088   for (parent = 0, i = 0; i < dp->ndirs; i++)
00089     {
00090       if (dp->dirs[i] > 0)
00091         continue;
00092       parent = -dp->dirs[i];
00093       dirtraverse[i] = dirtraverse[parent];
00094       dirtraverse[parent] = i + 1;
00095     }
00096   dp->dirtraverse = dirtraverse;
00097 }
00098 
00099 Id
00100 dirpool_add_dir(Dirpool *dp, Id parent, Id comp, int create)
00101 {
00102   Id did, d, ds, *dirtraverse;
00103 
00104   if (!dp->ndirs)
00105     {
00106       if (!create)
00107         return 0;
00108       dp->ndirs = 2;
00109       dp->dirs = sat_extend_resize(dp->dirs, dp->ndirs, sizeof(Id), DIR_BLOCK);
00110       dp->dirs[0] = 0;
00111       dp->dirs[1] = 1;  /* "" */
00112     }
00113   if (parent == 0 && comp == 1)
00114     return 1;
00115   if (!dp->dirtraverse)
00116     dirpool_make_dirtraverse(dp);
00117   /* check all entries with this parent if we
00118    * already have this component */
00119   dirtraverse = dp->dirtraverse;
00120   ds = dirtraverse[parent];
00121   while (ds)
00122     {
00123       /* ds: first component in this block
00124        * ds-1: parent link */
00125       for (d = ds--; d < dp->ndirs; d++)
00126         {
00127           if (dp->dirs[d] == comp)
00128             return d;
00129           if (dp->dirs[d] <= 0) /* reached end of this block */
00130             break;
00131         }
00132       if (ds)
00133         ds = dp->dirtraverse[ds];
00134     }
00135   if (!create)
00136     return 0;
00137   /* a new one, find last parent */
00138   for (did = dp->ndirs - 1; did > 0; did--)
00139     if (dp->dirs[did] <= 0)
00140       break;
00141   if (dp->dirs[did] != -parent)
00142     {
00143       /* make room for parent entry */
00144       dp->dirs = sat_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
00145       dp->dirtraverse = sat_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
00146       /* new parent block, link in */
00147       dp->dirs[dp->ndirs] = -parent;
00148       dp->dirtraverse[dp->ndirs] = dp->dirtraverse[parent];
00149       dp->dirtraverse[parent] = ++dp->ndirs;
00150     }
00151   /* make room for new entry */
00152   dp->dirs = sat_extend(dp->dirs, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
00153   dp->dirtraverse = sat_extend(dp->dirtraverse, dp->ndirs, 1, sizeof(Id), DIR_BLOCK);
00154   dp->dirs[dp->ndirs] = comp;
00155   dp->dirtraverse[dp->ndirs] = 0;
00156   return dp->ndirs++;
00157 }

Generated on Mon Dec 15 17:56:24 2014 for satsolver by  doxygen 1.5.6