diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/commit.c | 284 |
1 files changed, 192 insertions, 92 deletions
diff --git a/src/commit.c b/src/commit.c index 8fbc1d6..534757c 100644 --- a/src/commit.c +++ b/src/commit.c @@ -53,6 +53,23 @@ static void make_dir() } #endif +static struct dirent * +get_next_filtered_dirent(DIR *dp, int exclude_wh) +{ + struct dirent *dirp = NULL; + while ((dirp = readdir(dp)) != NULL) { + if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0 + || strcmp(dirp->d_name, MOD_NAME) == 0 + || strcmp(dirp->d_name, opaque_name) == 0 + || (exclude_wh && strncmp(dirp->d_name, ".wh.", 4) == 0)) { + continue; + } else { + return dirp; + } + } + return dirp; +} + /************************************************* validate_dir_for_commit: validate value.value if there is one, validate @@ -114,16 +131,7 @@ static boolean validate_dir_for_commit() push_path(&t_path, tag_name); /* PUSH 2a */ } - while ((dirp = readdir(dp)) != NULL) { - - if (strcmp(dirp->d_name, ".") == 0 || - strcmp(dirp->d_name, "..") == 0 || - strcmp(dirp->d_name, MOD_NAME) == 0 || - strcmp(dirp->d_name, opaque_name) == 0 || - strncmp(dirp->d_name, ".wh.", 4) == 0) { - continue; /*ignore dot and dot-dot*/ - } - + while ((dirp = get_next_filtered_dirent(dp, 1)) != NULL) { subdirs_number++; if(uename) @@ -916,25 +924,141 @@ static boolean commit_delete_child(vtw_def *pdefp, char *child, return ok; } +/* add a value to the valstruct. struct must be initialized (memset 0). + * cp: pointer to value + * type: type of value + */ +static void +valstruct_append(valstruct *mvals, char *cp, vtw_type_e type) +{ + if (!(mvals->free_me)) { + /* empty struct. add 1st value */ + mvals->free_me = TRUE; + mvals->val = cp; + mvals->val_type = type; + } else { + if ((mvals->cnt % MULTI_ALLOC) == 0) { + /* convert into multivalue */ + mvals->vals = my_realloc(mvals->vals, (mvals->cnt + MULTI_ALLOC) + * sizeof(char *), "add_value"); + if (mvals->cnt == 0) { /* single value - convert */ + mvals->vals[0] = mvals->val; + mvals->cnt= 1; + mvals->val = NULL; + } + } + mvals->vals[mvals->cnt] = cp; + ++mvals->cnt; + } +} + +/* get the filtered directory listing and put the names in valstruct. + * dp: target directory + * mvals: structure for storing the names + * type: type of the names + * exclude_wh: exclude whiteouts + */ +static void +get_filtered_directory_listing(DIR *dp, valstruct *mvals, vtw_type_e type, + int exclude_wh) +{ + struct dirent *dirp = NULL; + char *cp = NULL; + + memset(mvals, 0, sizeof (valstruct)); + while ((dirp = get_next_filtered_dirent(dp, exclude_wh)) != NULL) { + cp = clind_unescape(dirp->d_name); + valstruct_append(mvals, cp, type); + } +} + +/* check if a value is one of those in a valstruct. + * cp: pointer to value + * vals: pointer to valstruct + * + * return 1 if yes, 0 otherwise. + * TODO: optimization + */ +static int +is_val_in_valstruct(char *cp, valstruct *vals) +{ + int i = 0; + if (!(vals->free_me)) { + /* empty struct. */ + return 0; + } + if (vals->cnt == 0) { + /* single-value struct */ + if (strcmp(cp, vals->val) == 0) { + return 1; + } + return 0; + } + /* multi-value */ + for (i = 0; i < vals->cnt; i++) { + if (strcmp(cp, vals->vals[i]) == 0) { + return 1; + } + } + return 0; +} + +/* returns the value at a particular index in a valstruct. + * vals: pointer to the valstruct + * idx: index of the value + * + * return pointer to the value, NULL if idx is not valid. + */ +static char * +idx_val_in_valstruct(valstruct *vals, int idx) +{ + if (!(vals->free_me)) { + /* empty struct. */ + return NULL; + } + if (vals->cnt == 0) { + /* single-value struct */ + if (idx == 0) { + return vals->val; + } + return NULL; + } + /* multi-value */ + if ((idx < 0) || (idx >= vals->cnt)) { + return NULL; + } + return vals->vals[idx]; +} + + static boolean commit_delete_children(vtw_def *defp, boolean deleting, boolean in_txn) { - DIR *dp; - int status; - struct dirent *dirp; + DIR *dp, *adp = NULL, *mdp = NULL; boolean ok = TRUE; char *child; vtw_type_e type; - valstruct mvals; - boolean first; - char *cp; + valstruct mvals, valsA, valsM; int elem, curi; vtw_sorted cur_sorted; - char *uename = NULL; + + if (!deleting) { + switch_path(APATH); /* switch to active */ + if ((adp = opendir(m_path.path)) == NULL) { + INTERNAL; + } + switch_path(MPATH); /* switch to modified */ + if ((mdp = opendir(m_path.path)) == NULL) { + INTERNAL; + } + switch_path(CPATH); /* back to changes */ + } if ((dp = opendir(m_path.path)) == NULL){ - if (deleting) + if (deleting) { + /* deleting. adp & mdp are not opened so no need to close. */ return TRUE; + } INTERNAL; } if (defp) @@ -943,44 +1067,56 @@ static boolean commit_delete_children(vtw_def *defp, boolean deleting, type = TEXT_TYPE; if (type == ERROR_TYPE) type = TEXT_TYPE; - first = TRUE; memset(&mvals, 0, sizeof (valstruct)); + memset(&valsA, 0, sizeof (valstruct)); + memset(&valsM, 0, sizeof (valstruct)); memset(&cur_sorted, 0, sizeof(vtw_sorted)); - while ((dirp = readdir(dp)) != NULL) { - child = dirp->d_name; - if (strcmp(child, ".") == 0 || - strcmp(child, "..") == 0 || - strcmp(child, MOD_NAME) == 0 || - strcmp(child, OPQ_NAME) == 0) - continue; - uename = clind_unescape(child); - cp = uename; - if (first) { - mvals.free_me = TRUE; - mvals.val = cp; - mvals.val_type = type; - first = FALSE; - } else { - if (mvals.cnt%MULTI_ALLOC == 0) { - /* convert into multivalue */ - mvals.vals = my_realloc(mvals.vals, - (mvals.cnt + MULTI_ALLOC) * - sizeof(char *), "add_value"); - if (mvals.cnt == 0) { /* single value - convert */ - mvals.vals[0] = mvals.val; - mvals.cnt= 1; - mvals.val = NULL; - } + /* changes directory */ + get_filtered_directory_listing(dp, &mvals, type, 0); + if (closedir(dp) != 0) { + INTERNAL; + } + + if (adp && mdp) { + /* active directory */ + get_filtered_directory_listing(adp, &valsA, type, 0); + if (closedir(adp) != 0) { + INTERNAL; + } + /* modified directory */ + get_filtered_directory_listing(mdp, &valsM, type, 0); + if (closedir(mdp) != 0) { + INTERNAL; + } + + if (valsA.free_me) { + /* A is not empty */ + int idx = 0; + char *cp = NULL; + for (idx = 0; (cp = idx_val_in_valstruct(&valsA, idx)); idx++) { + if (!is_val_in_valstruct(cp, &valsM)) { + /* cp is in A but not in M */ + /* construct whiteout name */ + char *wh_name = my_malloc(strlen(cp) + 4 + 1, "del_children"); + strcpy(wh_name, ".wh."); + strcpy(wh_name + 4, cp); + if (!is_val_in_valstruct(wh_name, &mvals)) { + /* whiteout not in C */ + /* add whiteout to mvals */ + valstruct_append(&mvals, wh_name, type); + } + } } - mvals.vals[mvals.cnt] = cp; - ++mvals.cnt; + free_val(&valsA); + } + if (valsM.free_me) { + free_val(&valsM); } } - status = closedir(dp); - if (status) - INTERNAL; - if (first) { + + if (!(mvals.free_me)) { + /* empty struct. nothing to do. */ return TRUE; } vtw_sort(&mvals, &cur_sorted); @@ -1006,18 +1142,12 @@ static boolean commit_update_children(vtw_def *defp, boolean creating, boolean in_txn, boolean *parent_update) { DIR *dp; - int status; - struct dirent *dirp; boolean ok = TRUE; char *child; vtw_type_e type; valstruct mvals; - boolean first; - char *cp; int elem, curi; vtw_sorted cur_sorted; - char *uename = NULL; - if ((dp = opendir(m_path.path)) == NULL){ printf("%s:%d: opendir error: path=%s\n", @@ -1033,43 +1163,14 @@ static boolean commit_update_children(vtw_def *defp, boolean creating, type = TEXT_TYPE; if (type == ERROR_TYPE) type = TEXT_TYPE; - first = TRUE; - while ((dirp = readdir(dp)) != NULL) { - child = dirp->d_name; - if (strcmp(child, ".") == 0 || - strcmp(child, "..") == 0 || - strcmp(child, MOD_NAME) == 0 || - strcmp(child, OPQ_NAME) == 0) - continue; - cp = uename = clind_unescape(child); - if (first) { - mvals.free_me = TRUE; - mvals.val = cp; - mvals.val_type = type; - first = FALSE; - } else { - if (mvals.cnt%MULTI_ALLOC == 0) { - /* convert into multivalue */ - mvals.vals = my_realloc(mvals.vals, - (mvals.cnt + MULTI_ALLOC) * - sizeof(char *), "add_value"); - if (mvals.cnt == 0) { /* single value - convert */ - mvals.vals[0] = mvals.val; - mvals.cnt= 1; - mvals.val = NULL; - } - } - mvals.vals[mvals.cnt] = cp; - ++mvals.cnt; - } - } - status = closedir(dp); - if (status) + get_filtered_directory_listing(dp, &mvals, type, 0); + if (closedir(dp) != 0) { INTERNAL; - if (first) { - if (uename) - my_free(uename); + } + + if (!(mvals.free_me)) { + /* empty struct. nothing to do. */ return TRUE; } vtw_sort(&mvals, &cur_sorted); @@ -1164,7 +1265,6 @@ static boolean commit_value(vtw_def *defp, char *cp, /* act_value will be freed by freeing cur_value do not zero out it here */ } - acti = 0; curi = 0; total = act_sorted.num + cur_sorted.num; |