00001 #include "sysincludes.h"
00002 #include "vfat.h"
00003 #include "dirCache.h"
00004
00005
00006 void myfree(void *a)
00007 {
00008 free(a);
00009 }
00010
00011 #define free myfree
00012
00013
00014 #define BITS_PER_INT (sizeof(unsigned int) * 8)
00015
00016
00017 static inline unsigned int rol(unsigned int arg, int shift)
00018 {
00019 arg &= 0xffffffff;
00020 return (arg << shift) | (arg >> (32 - shift));
00021 }
00022
00023
00024 static int calcHash(char *name)
00025 {
00026 unsigned long hash;
00027 int i;
00028 unsigned char c;
00029
00030 hash = 0;
00031 i = 0;
00032 while(*name) {
00033
00034 hash = rol(hash,5);
00035
00036
00037
00038
00039 c = toupper(*name);
00040 hash ^= (c * (c+2)) ^ (i * (i+2));
00041 hash &= 0xffffffff;
00042 i++, name++;
00043 }
00044 hash = hash * (hash + 2);
00045
00046
00047 hash ^= (hash & 0xfff) << 12;
00048 hash ^= (hash & 0xff000) << 24;
00049 return hash;
00050 }
00051
00052 static int addBit(unsigned int *bitmap, int hash, int checkOnly)
00053 {
00054 int bit, entry;
00055
00056 bit = 1 << (hash % BITS_PER_INT);
00057 entry = (hash / BITS_PER_INT) % DC_BITMAP_SIZE;
00058
00059 if(checkOnly)
00060 return bitmap[entry] & bit;
00061 else {
00062 bitmap[entry] |= bit;
00063 return 1;
00064 }
00065 }
00066
00067 static int _addHash(dirCache_t *cache, unsigned int hash, int checkOnly)
00068 {
00069 return
00070 addBit(cache->bm0, hash, checkOnly) &&
00071 addBit(cache->bm1, rol(hash,12), checkOnly) &&
00072 addBit(cache->bm2, rol(hash,24), checkOnly);
00073 }
00074
00075
00076 static void addNameToHash(dirCache_t *cache, char *name)
00077 {
00078 _addHash(cache, calcHash(name), 0);
00079 }
00080
00081 static void hashDce(dirCache_t *cache, dirCacheEntry_t *dce)
00082 {
00083 if(dce->beginSlot != cache->nrHashed)
00084 return;
00085 cache->nrHashed = dce->endSlot;
00086 if(dce->longName)
00087 addNameToHash(cache, dce->longName);
00088 addNameToHash(cache, dce->shortName);
00089 }
00090
00091 int isHashed(dirCache_t *cache, char *name)
00092 {
00093 int ret;
00094
00095 ret = _addHash(cache, calcHash(name), 1);
00096 return ret;
00097 }
00098
00099 void checkXYZ(dirCache_t *cache)
00100 {
00101 if(cache->entries[2])
00102 printf(" at 2 = %d\n", cache->entries[2]->beginSlot);
00103 }
00104
00105
00106 int growDirCache(dirCache_t *cache, int slot)
00107 {
00108 if(slot < 0) {
00109 fprintf(stderr, "Bad slot %d\n", slot);
00110 exit(1);
00111 }
00112
00113 if( cache->nr_entries <= slot) {
00114 int i;
00115
00116 cache->entries = realloc(cache->entries,
00117 (slot+1) * 2 *
00118 sizeof(dirCacheEntry_t *));
00119 if(!cache->entries)
00120 return -1;
00121 for(i= cache->nr_entries; i < (slot+1) * 2; i++) {
00122 cache->entries[i] = 0;
00123 }
00124 cache->nr_entries = (slot+1) * 2;
00125 }
00126 return 0;
00127 }
00128
00129 dirCache_t *allocDirCache(Stream_t *Stream, int slot)
00130 {
00131 dirCache_t **dcp;
00132
00133 if(slot < 0) {
00134 fprintf(stderr, "Bad slot %d\n", slot);
00135 exit(1);
00136 }
00137
00138 dcp = getDirCacheP(Stream);
00139 if(!*dcp) {
00140 *dcp = New(dirCache_t);
00141 if(!*dcp)
00142 return 0;
00143 (*dcp)->entries = NewArray((slot+1)*2+5, dirCacheEntry_t *);
00144 if(!(*dcp)->entries) {
00145 free(*dcp);
00146 return 0;
00147 }
00148 (*dcp)->nr_entries = (slot+1) * 2;
00149 memset( (*dcp)->bm0, 0, DC_BITMAP_SIZE);
00150 memset( (*dcp)->bm1, 0, DC_BITMAP_SIZE);
00151 memset( (*dcp)->bm2, 0, DC_BITMAP_SIZE);
00152 (*dcp)->nrHashed = 0;
00153 } else
00154 if(growDirCache(*dcp, slot) < 0)
00155 return 0;
00156 return *dcp;
00157 }
00158
00159 static void freeDirCacheRange(dirCache_t *cache, int beginSlot, int endSlot)
00160 {
00161 dirCacheEntry_t *entry;
00162 int clearBegin;
00163 int clearEnd;
00164 int i;
00165
00166 if(endSlot < beginSlot) {
00167 fprintf(stderr, "Bad slots %d %d in free range\n",
00168 beginSlot, endSlot);
00169 exit(1);
00170 }
00171
00172 while(beginSlot < endSlot) {
00173 entry = cache->entries[beginSlot];
00174 if(!entry) {
00175 beginSlot++;
00176 continue;
00177 }
00178
00179 clearEnd = entry->endSlot;
00180 if(clearEnd > endSlot)
00181 clearEnd = endSlot;
00182 clearBegin = beginSlot;
00183
00184 for(i = clearBegin; i <clearEnd; i++)
00185 cache->entries[i] = 0;
00186
00187 if(entry->endSlot == endSlot)
00188 entry->endSlot = beginSlot;
00189 else if(entry->beginSlot == beginSlot)
00190 entry->beginSlot = endSlot;
00191 else {
00192 fprintf(stderr,
00193 "Internal error, non contiguous de-allocation\n");
00194 fprintf(stderr, "%d %d\n", beginSlot, endSlot);
00195 fprintf(stderr, "%d %d\n", entry->beginSlot,
00196 entry->endSlot);
00197 exit(1);
00198 }
00199
00200 if(entry->beginSlot == entry->endSlot) {
00201 if(entry->longName)
00202 free(entry->longName);
00203 if(entry->shortName)
00204 free(entry->shortName);
00205 free(entry);
00206 }
00207
00208 beginSlot = clearEnd;
00209 }
00210 }
00211
00212 static dirCacheEntry_t *allocDirCacheEntry(dirCache_t *cache, int beginSlot,
00213 int endSlot,
00214 dirCacheEntryType_t type)
00215 {
00216 dirCacheEntry_t *entry;
00217 int i;
00218
00219 if(growDirCache(cache, endSlot) < 0)
00220 return 0;
00221
00222 entry = New(dirCacheEntry_t);
00223 if(!entry)
00224 return 0;
00225 entry->type = type;
00226 entry->longName = 0;
00227 entry->shortName = 0;
00228 entry->beginSlot = beginSlot;
00229 entry->endSlot = endSlot;
00230
00231 freeDirCacheRange(cache, beginSlot, endSlot);
00232 for(i=beginSlot; i<endSlot; i++) {
00233 cache->entries[i] = entry;
00234 }
00235 return entry;
00236 }
00237
00238 dirCacheEntry_t *addUsedEntry(dirCache_t *cache, int beginSlot, int endSlot,
00239 char *longName, char *shortName,
00240 struct directory *dir)
00241 {
00242 dirCacheEntry_t *entry;
00243
00244 if(endSlot < beginSlot) {
00245 fprintf(stderr,
00246 "Bad slots %d %d in add used entry\n",
00247 beginSlot, endSlot);
00248 exit(1);
00249 }
00250
00251
00252 entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_USED);
00253 if(!entry)
00254 return 0;
00255
00256 entry->beginSlot = beginSlot;
00257 entry->endSlot = endSlot;
00258 if(longName)
00259 entry->longName = strdup(longName);
00260 entry->shortName = strdup(shortName);
00261 entry->dir = *dir;
00262 hashDce(cache, entry);
00263 return entry;
00264 }
00265
00266 static void mergeFreeSlots(dirCache_t *cache, int slot)
00267 {
00268 dirCacheEntry_t *previous, *next;
00269 int i;
00270
00271 if(slot == 0)
00272 return;
00273 previous = cache->entries[slot-1];
00274 next = cache->entries[slot];
00275 if(next && next->type == DCET_FREE &&
00276 previous && previous->type == DCET_FREE) {
00277 for(i=next->beginSlot; i < next->endSlot; i++)
00278 cache->entries[i] = previous;
00279 previous->endSlot = next->endSlot;
00280 free(next);
00281 }
00282 }
00283
00284 dirCacheEntry_t *addFreeEntry(dirCache_t *cache, int beginSlot, int endSlot)
00285 {
00286 dirCacheEntry_t *entry;
00287
00288 if(beginSlot < cache->nrHashed)
00289 cache->nrHashed = beginSlot;
00290
00291 if(endSlot < beginSlot) {
00292 fprintf(stderr, "Bad slots %d %d in add free entry\n",
00293 beginSlot, endSlot);
00294 exit(1);
00295 }
00296
00297 if(endSlot == beginSlot)
00298 return 0;
00299 entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_FREE);
00300 mergeFreeSlots(cache, beginSlot);
00301 mergeFreeSlots(cache, endSlot);
00302 return cache->entries[beginSlot];
00303 }
00304
00305
00306 dirCacheEntry_t *addEndEntry(dirCache_t *cache, int pos)
00307 {
00308 return allocDirCacheEntry(cache, pos, pos+1, DCET_END);
00309 }
00310
00311 dirCacheEntry_t *lookupInDircache(dirCache_t *cache, int pos)
00312 {
00313 if(growDirCache(cache, pos+1) < 0)
00314 return 0;
00315 return cache->entries[pos];
00316 }
00317
00318 void freeDirCache(Stream_t *Stream)
00319 {
00320 dirCache_t *cache, **dcp;
00321
00322 dcp = getDirCacheP(Stream);
00323 cache = *dcp;
00324 if(cache) {
00325 freeDirCacheRange(cache, 0, cache->nr_entries);
00326 free(cache);
00327 *dcp = 0;
00328 }
00329 }