/** * free_VolumeMap * Release memory allocated for VolumeMap structure. Optionally * release the memory for the struct itself (and not just the * instance members). */ void free_VolumeMap(VolumeMap *volMap, int freeStruct) { if (volMap == NULL) return; char **arrays[] = { volMap->raw, volMap->to, volMap->from, NULL }; char ***ptr = NULL; for (ptr = arrays; *ptr != NULL; ptr++) { char **iptr = NULL; for (iptr = *ptr; *iptr != NULL; iptr++) { free(*iptr); } free(*ptr); *ptr = NULL; } if (volMap->flags != NULL) { size_t idx = 0; for (idx = 0; idx < volMap->n; idx++) { VolumeMapFlag *flagArr = volMap->flags[idx]; if (flagArr != NULL) { free_VolumeMapFlag(flagArr, 1); } } free(volMap->flags); volMap->flags = NULL; } if (freeStruct == 1) { free(volMap); } }
TEST(VolumeMapTestGroup, VolumeMapParseFlag) { char *flag = strdup("ro"); VolumeMapFlag *flags = NULL; size_t flagsCapacity = 0; int ret = _parseFlag(flag, &flags, &flagsCapacity); CHECK(ret == 0); CHECK(flagsCapacity == 1); CHECK(flags[0].type == VOLMAP_FLAG_READONLY); free(flag); flag = strdup("rec"); ret = _parseFlag(flag, &flags, &flagsCapacity); CHECK(ret == 0); CHECK(flagsCapacity == 2); CHECK(flags[0].type == VOLMAP_FLAG_READONLY); CHECK(flags[1].type == VOLMAP_FLAG_RECURSIVE); free(flag); flag = strdup("rec=key1=value1,key2=value2"); ret = _parseFlag(flag, &flags, &flagsCapacity); CHECK(ret != 0); CHECK(flagsCapacity == 2); CHECK(flags[0].type == VOLMAP_FLAG_READONLY); CHECK(flags[1].type == VOLMAP_FLAG_RECURSIVE); free(flag); flag = strdup("perNodeCache"); ret = _parseFlag(flag, &flags, &flagsCapacity); CHECK(ret != 0); /* no default size */ free(flag); flag = strdup("perNodeCache=size=4T,bs=4M"); ret = _parseFlag(flag, &flags, &flagsCapacity); CHECK(ret == 0); CHECK(flagsCapacity == 3); CHECK(flags[0].type == VOLMAP_FLAG_READONLY); CHECK(flags[1].type == VOLMAP_FLAG_RECURSIVE); CHECK(flags[2].type == VOLMAP_FLAG_PERNODECACHE); free(flag); free_VolumeMapFlag(flags, 1); }
int _parseVolumeMap( const char *input, VolumeMap *volMap, int (*_validate_fp)(const char *, const char *, VolumeMapFlag *), short requireTo ) { if (input == NULL || volMap == NULL) return 1; char **rawPtr = volMap->raw + volMap->n; char **toPtr = volMap->to + volMap->n; char **fromPtr = volMap->from + volMap->n; VolumeMapFlag **flagPtr = volMap->flags + volMap->n; const char *ptr = input; const char *eptr = NULL; char *tmp = NULL; size_t len = strlen(input); int ret = 0; char *to = NULL; char *from = NULL; VolumeMapFlag *flags = NULL; size_t flagsCapacity = 0; char *raw = NULL; char **tokens = NULL; char **tk_ptr = NULL; size_t tokenIdx = 0; size_t rawLen = 0; size_t rawCapacity = 0; size_t flagIdx = 0; size_t flagCnt = 0; while (ptr < input + len) { size_t ntokens = 0; eptr = _findEndVolumeMapString(ptr); if (eptr == ptr && eptr != NULL) { ptr++; continue; } if (eptr == NULL) { break; } /* make copy for parsing */ tmp = (char *) malloc(sizeof(char) * (eptr - ptr + 1)); if (tmp == NULL) { fprintf(stderr, "Failed to allocate memory for tmp string\n"); goto _parseVolumeMap_unclean; } strncpy(tmp, ptr, eptr - ptr); tmp[eptr - ptr] = 0; char *volMapStr = tmp; if (*volMapStr == '"' && *(volMapStr + (eptr - ptr) - 1) == '"') { *(volMapStr + (eptr - ptr) - 1) = 0; volMapStr++; } /* tokenize the the input string */ tokens = _tokenizeVolumeMapInput(volMapStr); /* count how many non-NULL tokens there are */ for (ntokens = 0; tokens && tokens[ntokens]; ntokens++) { } if (tokens == NULL || ntokens == 0) { fprintf(stderr, "Failed to parse VolumeMap tokens from \"%s\"," " aborting!\n", tmp); goto _parseVolumeMap_unclean; } from = userInputPathFilter(tokens[0], 1); to = userInputPathFilter(tokens[1], 1); for (tokenIdx = 2; tokenIdx < ntokens; tokenIdx++) { if (_parseFlag(tokens[tokenIdx], &flags, &flagsCapacity) != 0) { fprintf(stderr, "Invalid mount flags specified: %s\n", tokens[tokenIdx]); goto _parseVolumeMap_unclean; } } /* if we only got a from and to is not required assume we are binding a path from outside the container and to can be set to from */ if (from && ntokens == 1 && !requireTo) { to = strdup(from); } /* ensure the user is asking for a legal mapping */ if ((ret = _validate_fp(from, to, flags)) != 0) { fprintf(stderr, "Invalid Volume Map: %.*s, aborting! %d\n", (int) (eptr - ptr), ptr, ret ); goto _parseVolumeMap_unclean; } if (to == NULL || from == NULL) { fprintf(stderr, "INVALID format for volume map %.*s\n", (int) (eptr - ptr), ptr ); goto _parseVolumeMap_unclean; } for (flagCnt = 0; flags && flags[flagCnt].type != 0; flagCnt++) { } if (flagCnt > 0) { qsort(flags, flagCnt, sizeof(VolumeMapFlag), _cmpFlags); } /* generate a new "raw" string from the filtered values */ rawLen = 2 + strlen(from) + strlen(to); raw = (char *) malloc(sizeof(char) * rawLen); rawCapacity = sizeof(char) * rawLen; rawLen = snprintf(raw, rawLen, "%s:%s", from, to); for (flagIdx = 0; flagIdx < flagCnt; flagIdx++) { if (flags[flagIdx].type == VOLMAP_FLAG_READONLY) { raw = alloc_strcatf(raw, &rawLen, &rawCapacity, ":ro"); } else if (flags[flagIdx].type == VOLMAP_FLAG_RECURSIVE) { raw = alloc_strcatf(raw, &rawLen, &rawCapacity, ":rec"); } else if (flags[flagIdx].type == VOLMAP_FLAG_SLAVE) { raw = alloc_strcatf(raw, &rawLen, &rawCapacity, ":slave"); } else if (flags[flagIdx].type == VOLMAP_FLAG_PRIVATE) { raw = alloc_strcatf(raw, &rawLen, &rawCapacity, ":private"); } else if (flags[flagIdx].type == VOLMAP_FLAG_PERNODECACHE) { VolMapPerNodeCacheConfig *cache = (VolMapPerNodeCacheConfig *) flags[flagIdx].value; if (cache == NULL) { fprintf(stderr, "FAILED to read perNodeCache config from memory\n"); goto _parseVolumeMap_unclean; } raw = alloc_strcatf(raw, &rawLen, &rawCapacity, ":perNodeCache=size=%lu,bs=%lu,method=%s,fstype=%s", cache->cacheSize, cache->blockSize, cache->method, cache->fstype); } } /* append to raw array */ ret = strncpy_StringArray(raw, rawLen, &rawPtr, &(volMap->raw), &(volMap->rawCapacity), VOLUME_ALLOC_BLOCK); if (ret != 0) goto _parseVolumeMap_unclean; ret = strncpy_StringArray(to, strlen(to), &toPtr, &(volMap->to), &(volMap->toCapacity), VOLUME_ALLOC_BLOCK); if (ret != 0) goto _parseVolumeMap_unclean; ret = strncpy_StringArray(from, strlen(from), &fromPtr, &(volMap->from), &(volMap->fromCapacity), VOLUME_ALLOC_BLOCK); if (ret != 0) goto _parseVolumeMap_unclean; if (volMap->n >= volMap->flagsCapacity) { VolumeMapFlag **tmp = (VolumeMapFlag **) realloc(volMap->flags, sizeof(VolumeMapFlag *) * (volMap->flagsCapacity + VOLUME_ALLOC_BLOCK)); if (tmp == NULL) { fprintf(stderr, "Failed to allocate memory!\n"); goto _parseVolumeMap_unclean; } volMap->flags = tmp; flagPtr = volMap->flags + volMap->n; volMap->flagsCapacity += VOLUME_ALLOC_BLOCK; memset(flagPtr, 0, sizeof(VolumeMapFlag *) * (volMap->flagsCapacity - volMap->n)); } *flagPtr++ = flags; *flagPtr = NULL; if (ret != 0) goto _parseVolumeMap_unclean; if (from != NULL) free(from); if (to != NULL) free(to); if (raw != NULL) free(raw); from = NULL; to = NULL; raw = NULL; flags = NULL; ptr = eptr + 1; volMap->n += 1; if (tmp != NULL) free(tmp); tmp = NULL; for (tk_ptr = tokens; tk_ptr && *tk_ptr; tk_ptr++) { free(*tk_ptr); } if (tokens != NULL) free(tokens); tokens = NULL; } return 0; _parseVolumeMap_unclean: { char *freeArray[] = {tmp, from, to, raw, NULL}; char **freePtr = NULL; for (freePtr = freeArray; *freePtr != NULL; freePtr++) { if (*freePtr != NULL) { free(*freePtr); } } for (tk_ptr = tokens; tk_ptr && *tk_ptr; tk_ptr++) { free(*tk_ptr); } if (tokens != NULL) free(tokens); tokens = NULL; if (flags != NULL) { free_VolumeMapFlag(flags, 1); flags = NULL; } } return 1; }