Author: hbelusca Date: Fri Jan 8 18:43:46 2016 New Revision: 70552 URL: http://svn.reactos.org/svn/reactos?rev=70552&view=rev Log: [CDMAKE] - Optimize splitting paths (merge chop_dirname and chop_filename functions). - Make the code working as expected for the following testcases (you can test these by adding the following lines into e.g. bootcd.lst): testdir1 --> create "testdir1" in the root directory. testdir2/ --> create "testdir2" in the root directory. No no-named subdirectory is created. testdir3// --> create "testdir3" in the root directory. No no-named subdirectory is created. dir1//\/dir14///\//\// --> create "dir1" in the root directory, and "dir14" inside dir1. No no-named subdirectory is created. EFI/ReactOS/Boot/Fonts//chs_boot.ttf=C:/somepath/chs_boot.ttf --> create the directories "EFI/ReactOS/Boot/Fonts", no no-named subdirectory is created, and create in the Fonts directory the file "chs_boot.ttf".
Before those changes, empty no-named (therefore, invalid) subdirectories were created in the second, third and fourth testcases, and an obscure error was returned in the fifth testcase. Modified: trunk/reactos/tools/cdmake/dirhash.c Modified: trunk/reactos/tools/cdmake/dirhash.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/dirhash.c?rev=70552&r1=70551&r2=70552&view=diff ============================================================================== --- trunk/reactos/tools/cdmake/dirhash.c [iso-8859-1] (original) +++ trunk/reactos/tools/cdmake/dirhash.c [iso-8859-1] Fri Jan 8 18:43:46 2016 @@ -5,12 +5,15 @@ * PURPOSE: CD-ROM Premastering Utility - Directory names hashing * PROGRAMMERS: Art Yerkes */ + #include <string.h> #include <stdlib.h> #include <ctype.h> #include "config.h" #include "dirhash.h" +#define max(a, b) ((a) > (b) ? (a) : (b)) + /* This is the famous DJB hash */ static unsigned int djb_hash(const char *name) @@ -26,59 +29,33 @@ return val; } -static const char * -chop_filename(const char *target) -{ - char *last_slash = strrchr(target, '/'); - if (!last_slash) - last_slash = strrchr(target, '\\'); - if (last_slash) - return last_slash + 1; +static void +split_path(const char *path, char **dirname, char **filename /* OPTIONAL */) +{ + const char *result; + + /* Retrieve the file name */ + char *last_slash_1 = strrchr(path, '/'); + char *last_slash_2 = strrchr(path, '\\'); + + if (last_slash_1 || last_slash_2) + result = max(last_slash_1, last_slash_2) + 1; else - return target; -} - -static void -chop_dirname(const char *name, char **dirname) -{ - char *last_slash = strrchr(name, '/'); - if (!last_slash) - last_slash = strrchr(name, '\\'); - if (!last_slash) - { - *dirname = malloc(1); - **dirname = 0; - } - else - { - char *newdata = malloc(last_slash - name + 1); - memcpy(newdata, name, last_slash - name); - newdata[last_slash - name] = 0; - *dirname = newdata; - } -} - -static struct target_dir_entry * -get_entry_by_normname(struct target_dir_hash *dh, const char *norm) -{ - unsigned int hashcode; - struct target_dir_entry *de; - hashcode = djb_hash(norm); - de = dh->buckets[hashcode % NUM_DIR_HASH_BUCKETS]; - while (de && strcmp(de->normalized_name, norm)) - de = de->next_dir_hash_entry; - return de; -} - -static void -delete_entry(struct target_dir_hash *dh, struct target_dir_entry *de) -{ - struct target_dir_entry **ent; - ent = &dh->buckets[de->hashcode % NUM_DIR_HASH_BUCKETS]; - while (*ent && ((*ent) != de)) - ent = &(*ent)->next_dir_hash_entry; - if (*ent) - *ent = (*ent)->next_dir_hash_entry; + result = path; + + /* Duplicate the file name for the user if needed */ + if (filename) + *filename = strdup(result); + + /* Remove any trailing directory separators */ + while (result > path && (*(result-1) == '/' || *(result-1) == '\\')) + result--; + + /* Retrieve and duplicate the directory */ + *dirname = malloc(result - path + 1); + if (result > path) + memcpy(*dirname, path, result - path); + (*dirname)[result - path] = '\0'; // NULL-terminate } void normalize_dirname(char *filename) @@ -109,20 +86,39 @@ } } } - filename[tgt] = 0; - - while (tgt && (filename[--tgt] == DIR_SEPARATOR_CHAR)) - { - filename[tgt] = 0; - } + filename[tgt] = '\0'; // NULL-terminate +} + +static struct target_dir_entry * +get_entry_by_normname(struct target_dir_hash *dh, const char *norm) +{ + unsigned int hashcode; + struct target_dir_entry *de; + hashcode = djb_hash(norm); + de = dh->buckets[hashcode % NUM_DIR_HASH_BUCKETS]; + while (de && strcmp(de->normalized_name, norm)) + de = de->next_dir_hash_entry; + return de; +} + +static void +delete_entry(struct target_dir_hash *dh, struct target_dir_entry *de) +{ + struct target_dir_entry **ent; + ent = &dh->buckets[de->hashcode % NUM_DIR_HASH_BUCKETS]; + while (*ent && ((*ent) != de)) + ent = &(*ent)->next_dir_hash_entry; + if (*ent) + *ent = (*ent)->next_dir_hash_entry; } struct target_dir_entry * dir_hash_create_dir(struct target_dir_hash *dh, const char *casename, const char *targetnorm) { struct target_dir_entry *de, *parent_de; + char *parentcase = NULL; + char *case_name = NULL; char *parentname = NULL; - char *parentcase = NULL; struct target_dir_entry **ent; if (!dh->root.normalized_name) @@ -133,20 +129,32 @@ dh->buckets[dh->root.hashcode % NUM_DIR_HASH_BUCKETS] = &dh->root; } + /* Check whether the directory was already created and just return it if so */ de = get_entry_by_normname(dh, targetnorm); if (de) return de; - chop_dirname(targetnorm, &parentname); - chop_dirname(casename, &parentcase); + /* + * If *case_name == '\0' after the following call to split_path(...), + * for example in the case where casename == "subdir/dir/", then just + * create the directories "subdir" and "dir" by a recursive call to + * dir_hash_create_dir(...) and return 'parent_de' instead (see after). + * We do not (and we never) create a no-name directory inside it. + */ + split_path(casename, &parentcase, &case_name); + split_path(targetnorm, &parentname, NULL); parent_de = dir_hash_create_dir(dh, parentcase, parentname); free(parentname); free(parentcase); + /* See the remark above */ + if (!*case_name) return parent_de; + + /* Now create the directory */ de = calloc(1, sizeof(*de)); de->parent = parent_de; de->normalized_name = strdup(targetnorm); - de->case_name = strdup(chop_filename(casename)); + de->case_name = case_name; de->hashcode = djb_hash(targetnorm); de->next = parent_de->child; @@ -154,9 +162,7 @@ ent = &dh->buckets[de->hashcode % NUM_DIR_HASH_BUCKETS]; while (*ent) - { ent = &(*ent)->next_dir_hash_entry; - } *ent = de; return de; @@ -166,21 +172,24 @@ { struct target_file *tf; struct target_dir_entry *de; - char *targetdir = NULL; + char *targetdir = NULL; + char *targetfile = NULL; char *targetnorm; - chop_dirname(target, &targetdir); + /* Create first the directory */ + split_path(target, &targetdir, &targetfile); targetnorm = strdup(targetdir); normalize_dirname(targetnorm); de = dir_hash_create_dir(dh, targetdir, targetnorm); free(targetnorm); free(targetdir); + /* Now add the file */ tf = calloc(1, sizeof(*tf)); tf->next = de->head; de->head = tf; tf->source_name = strdup(source); - tf->target_name = strdup(chop_filename(target)); + tf->target_name = targetfile; } static void