Beispiel #1
0
/* Prepare metadata */
int prepare_metadata(uint32_t metaflags,
                     struct collection_item **metadata,
                     int *save_error)
{
    int error = EOK;
    struct collection_item *metasec = NULL;

    TRACE_FLOW_STRING("prepare_metadata", "Entry");

    /* Are we supposed to collect or process meta data ? */
    if (!metadata) {
        TRACE_FLOW_STRING("No meta data", "Exit");
        return EOK;
    }

    /* Allocate metadata */
    error = col_create_collection(metadata,
                                  INI_METADATA,
                                  COL_CLASS_INI_META);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to create meta data", error);
        return error;
    }

    /* Check and create section for file error if needed */
    if (metaflags & INI_META_SEC_ERROR_FLAG) {
        /* Create ERROR collection */
        if ((error = col_create_collection(&metasec,
                                           INI_META_SEC_ERROR,
                                           COL_CLASS_INI_SECTION)) ||
            (error = col_add_collection_to_collection(
                                           *metadata,
                                           NULL,
                                           NULL,
                                           metasec,
                                           COL_ADD_MODE_REFERENCE))) {
            TRACE_ERROR_NUMBER("Failed to create error section", error);
            col_destroy_collection(metasec);
            col_destroy_collection(*metadata);
            *metadata = NULL;
            return error;
        }
        /* If we are here we would have to save file open error */
        *save_error = 1;
        col_destroy_collection(metasec);
    }

    TRACE_FLOW_STRING("prepare_metadata", "Exit");
    return error;
}
/* Function that creates a stack object */
int col_create_stack(struct collection_item **stack)
{
    int error = EOK;

    TRACE_FLOW_STRING("col_create_stack", "Entry point.");

    error = col_create_collection(stack, COL_NAME_STACK, COL_CLASS_STACK);

    TRACE_FLOW_STRING("col_create_stack", "Exit.");
    return error;
}
Beispiel #3
0
/* Create a config object */
int ini_config_create(struct ini_cfgobj **ini_config)
{
    int error = EOK;
    struct ini_cfgobj *new_co = NULL;

    TRACE_FLOW_ENTRY();

    if (!ini_config) {
        TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
        return EINVAL;
    }

    errno = 0;
    new_co = malloc(sizeof(struct ini_cfgobj));
    if (!new_co) {
        error = errno;
        TRACE_ERROR_NUMBER("Failed to allocate memory", ENOMEM);
        return ENOMEM;
    }

    new_co->cfg = NULL;
    new_co->boundary = INI_WRAP_BOUNDARY;

    /* Create a collection to hold configuration data */
    error = col_create_collection(&(new_co->cfg),
                                  INI_CONFIG_NAME,
                                  COL_CLASS_INI_CONFIG);
    if (error != EOK) {
        TRACE_ERROR_NUMBER("Failed to create collection.", error);
        ini_config_destroy(new_co);
        return error;
    }

    *ini_config = new_co;

    TRACE_FLOW_EXIT();
    return error;
}
Beispiel #4
0
/* Complete value processing */
static int complete_value_processing(struct parser_obj *po)
{
    int error = EOK;
    int error2 = EOK;
    struct value_obj *vo = NULL;
    struct value_obj *vo_old = NULL;
    unsigned insertmode;
    uint32_t mergemode;
    int suppress = 0;
    int doinsert = 0;
    struct collection_item *item = NULL;
    struct collection_item *section = NULL;
    int merging = 0;

    TRACE_FLOW_ENTRY();

    if (po->merge_sec) {
        TRACE_INFO_STRING("Processing value in merge mode", "");
        section = po->merge_sec;
        merging = 1;
    }
    else if(!(po->sec)) {
        TRACE_INFO_STRING("Creating default section", "");
        /* If there is not open section create a default one */
        error = col_create_collection(&po->sec,
                                      INI_DEFAULT_SECTION,
                                      COL_CLASS_INI_SECTION);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to create default section", error);
            return error;
        }
        section = po->sec;
    }
    else {
        TRACE_INFO_STRING("Processing value in normal mode", "");
        section = po->sec;
    }

    if (merging) {
        TRACE_INFO_STRING("Using merge key:", po->merge_key);
        vo = po->merge_vo;
        /* We are adding to the merge section so use MV2S flags.
         * But flags are done in such a way that deviding MV2S by MV1S mask
         * will translate MV2S flags into MV1S so we can use
         * MV1S constants. */
        TRACE_INFO_NUMBER("Collisions flags:", po->collision_flags);
        mergemode = (po->collision_flags & INI_MV2S_MASK) / INI_MV1S_MASK;
    }
    else {
        /* Construct value object from what we have */
        error = value_create_from_refarray(po->raw_lines,
                                           po->raw_lengths,
                                           po->keylinenum,
                                           INI_VALUE_READ,
                                           po->key_len,
                                           po->boundary,
                                           po->ic,
                                           &vo);

        if (error) {
            TRACE_ERROR_NUMBER("Failed to create value object", error);
            return error;
        }
        /* Forget about the arrays. They are now owned by the value object */
        po->ic = NULL;
        po->raw_lines = NULL;
        po->raw_lengths = NULL;
        mergemode = po->collision_flags & INI_MV1S_MASK;
    }

    switch (mergemode) {
    case INI_MV1S_ERROR:

        insertmode = COL_INSERT_DUPERROR;
        doinsert = 1;
        break;

    case INI_MV1S_PRESERVE:

        insertmode = COL_INSERT_DUPERROR;
        doinsert = 1;
        suppress = 1;
        break;

    case INI_MV1S_ALLOW:

        insertmode = COL_INSERT_NOCHECK;
        doinsert = 1;
        break;

    case INI_MV1S_OVERWRITE: /* Special handling */
    case INI_MV1S_DETECT:
    default:
        break;
    }

    /* Do not insert but search for dups first */
    if (!doinsert) {
        TRACE_INFO_STRING("Overwrite mode. Looking for:",
                          (char *)(merging ? po->merge_key : po->key));

        error = col_get_item(section,
                             merging ? po->merge_key : po->key,
                             COL_TYPE_BINARY,
                             COL_TRAVERSE_DEFAULT,
                             &item);

        if (error) {
            TRACE_ERROR_NUMBER("Failed searching for dup", error);
            value_destroy(vo);
            return error;
        }

        /* Check if there is a dup */
        if (item) {
            /* Check if we are in the detect mode */
            if (mergemode == INI_MV1S_DETECT) {
                po->merge_error = EEXIST;
                /* There is a dup - inform user about it and continue */
                error = save_error(po->el,
                                   merging ? po->seclinenum : po->keylinenum,
                                   merging ? ERR_DUPKEYSEC : ERR_DUPKEY,
                                   ERROR_TXT);
                if (error) {
                    TRACE_ERROR_NUMBER("Failed to save error", error);
                    value_destroy(vo);
                    return error;
                }
                doinsert = 1;
                insertmode = COL_INSERT_NOCHECK;

            }
            else {

                /* Dup exists - update it */
                vo_old = *((struct value_obj **)(col_get_item_data(item)));
                error = col_modify_binary_item(item,
                                               NULL,
                                               &vo,
                                               sizeof(struct value_obj *));
                if (error) {
                    TRACE_ERROR_NUMBER("Failed updating the value", error);
                    value_destroy(vo);
                    return error;
                }

                /* If we failed to update it is better to leak then crash,
                 * so destroy original value only on the successful update.
                 */
                value_destroy(vo_old);
            }
        }
        else {
            /* No dup found so we can insert with no check */
            doinsert = 1;
            insertmode = COL_INSERT_NOCHECK;
        }
    }

    if (doinsert) {
        /* Add value to collection */
        error = col_insert_binary_property(section,
                                           NULL,
                                           COL_DSP_END,
                                           NULL,
                                           0,
                                           insertmode,
                                           merging ? po->merge_key : po->key,
                                           &vo,
                                           sizeof(struct value_obj *));
        if (error) {
            value_destroy(vo);

            if ((suppress) && (error == EEXIST)) {
                TRACE_INFO_STRING("Preseved exisitng value",
                                  (char *)(merging ? po->merge_key : po->key));
            }
            else {
                /* Check if this is a critical error or not */
                if ((mergemode == INI_MV1S_ERROR) && (error == EEXIST)) {
                    TRACE_ERROR_NUMBER("Failed to add value object "
                                       "to the section", error);
                    error2 = save_error(po->el,
                                       merging ? po->seclinenum : po->keylinenum,
                                       merging ? ERR_DUPKEYSEC : ERR_DUPKEY,
                                       ERROR_TXT);
                    if (error2) {
                        TRACE_ERROR_NUMBER("Failed to save error", error2);
                        return error2;
                    }
                    return error;
                }
                else {
                    TRACE_ERROR_NUMBER("Failed to add value object"
                                       " to the section", error);
                    return error;
                }
            }
        }
    }

    if (!merging) {
        free(po->key);
        po->key = NULL;
        po->key_len = 0;
    }

    TRACE_FLOW_EXIT();
    return EOK;
}
Beispiel #5
0
/* Create parse object
 *
 * It assumes that the ini collection
 * has been precreated.
 */
static int parser_create(struct ini_cfgobj *co,
                         FILE *file,
                         const char *config_filename,
                         int error_level,
                         uint32_t collision_flags,
                         uint32_t parse_flags,
                         struct parser_obj **po)
{
    int error = EOK;
    struct parser_obj *new_po = NULL;
    unsigned count = 0;

    TRACE_FLOW_ENTRY();

    /* Make sure that all the parts are initialized */
    if ((!po) ||
        (!co) ||
        (!(co->cfg)) ||
        (!file) ||
        (!config_filename)) {
        TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
        return EINVAL;
    }

    error = col_get_collection_count(co->cfg, &count);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to check object size", error);
        return error;
    }

    if (count != 1) {
        TRACE_ERROR_NUMBER("Configuration is not empty", EINVAL);
        return EINVAL;
    }

    new_po = malloc(sizeof(struct parser_obj));
    if (!new_po) {
        TRACE_ERROR_NUMBER("No memory", ENOMEM);
        return ENOMEM;
    }

    /* Save external data */
    new_po->file = file;
    new_po->el = co->error_list;
    new_po->filename = config_filename;
    new_po->error_level = error_level;
    new_po->collision_flags = collision_flags;
    new_po->parse_flags = parse_flags;
    new_po->boundary = co->boundary;
    new_po->co = co;

    /* Initialize internal varibles */
    new_po->sec = NULL;
    new_po->merge_sec = NULL;
    new_po->ic = NULL;
    new_po->last_error = 0;
    new_po->linenum = 0;
    new_po->keylinenum = 0;
    new_po->seclinenum = 0;
    new_po->last_read = NULL;
    new_po->last_read_len = 0;
    new_po->inside_comment = 0;
    new_po->key = NULL;
    new_po->key_len = 0;
    new_po->raw_lines = NULL;
    new_po->raw_lengths = NULL;
    new_po->ret = EOK;
    new_po->merge_key = NULL;
    new_po->merge_vo = NULL;
    new_po->merge_error = 0;
    new_po->top = NULL;
    new_po->queue = NULL;

    /* Create top collection */
    error = col_create_collection(&(new_po->top),
                                  INI_CONFIG_NAME,
                                  COL_CLASS_INI_CONFIG);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to create top collection", error);
        parser_destroy(new_po);
        return error;
    }

    /* Create a queue */
    error = col_create_queue(&(new_po->queue));
    if (error) {
        TRACE_ERROR_NUMBER("Failed to create queue", error);
        parser_destroy(new_po);
        return error;
    }

    error = col_enqueue_unsigned_property(new_po->queue,
                                          PARSE_ACTION,
                                          PARSE_READ);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to create queue", error);
        parser_destroy(new_po);
        return error;
    }

    *po = new_po;

    TRACE_FLOW_EXIT();
    return error;
}
Beispiel #6
0
/* Parse and process section */
static int handle_section(struct parser_obj *po, uint32_t *action)
{
    int error = EOK;
    char *start;
    char *end;
    char *dupval;
    uint32_t len;

    TRACE_FLOW_ENTRY();

    /* We are safe to substract 1
     * since we know that there is at
     * least one character on the line
     * based on the check above.
     */
    end = po->last_read + po->last_read_len - 1;
    while (isspace(*end)) end--;
    if (*end != ']') {
        *action = PARSE_ERROR;
        po->last_error = ERR_NOCLOSESEC;
        return EOK;
    }

    /* Skip spaces at the beginning of the section name */
    start = po->last_read + 1;
    while (isspace(*start)) start++;

    /* Check if there is a section name */
    if (start == end) {
        *action = PARSE_ERROR;
        po->last_error = ERR_NOSECTION;
        return EOK;
    }

    /* Skip spaces at the end of the section name */
    end--;
    while (isspace(*end)) end--;

    /* We got section name */
    len = end - start + 1;

    if (len > MAX_KEY) {
        *action = PARSE_ERROR;
        po->last_error = ERR_SECTIONLONG;
        return EOK;
    }

    if (po->key) {
        /* Complete processing of the previous value */
        error = complete_value_processing(po);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to complete value processing", error);
            return error;
        }
    }

    /* Save section if we have one*/
    error = parser_save_section(po);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to save section", error);
        return error;
    }

    /* Dup the name */
    dupval = malloc(len + 1);
    if (!dupval) {
        TRACE_ERROR_NUMBER("Failed to dup section name", ENOMEM);
        return ENOMEM;
    }

    memcpy(dupval, start, len);
    dupval[len] = '\0';

    /* Create a new section */
    error = col_create_collection(&po->sec,
                                  dupval,
                                  COL_CLASS_INI_SECTION);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to create a section", error);
        free(dupval);
        return error;
    }

    /* But if there is just a comment then create a special key */
    po->key_len = sizeof(INI_SECTION_KEY) - 1;
    po->key = strndup(INI_SECTION_KEY, sizeof(INI_SECTION_KEY));
    /* Create new arrays */
    error = value_create_arrays(&(po->raw_lines),
                                &(po->raw_lengths));
    if (error) {
        TRACE_ERROR_NUMBER("Failed to create arrays", error);
        free(dupval);
        return error;
    }

    /* Save a duplicated part in the value */
    error = value_add_to_arrays(dupval,
                                len,
                                po->raw_lines,
                                po->raw_lengths);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to add value to the arrays", error);
        free(dupval);
        return error;
    }

    /* Save the line number of the last found key */
    po->seclinenum = po->linenum;

    /* Complete processing of this value.
     * A new section will be created inside and a special
     * value will be added.
     */
    error = complete_value_processing(po);
    if (error) {
        TRACE_ERROR_NUMBER("Failed to complete value processing", error);
        return error;
    }

    /* We are done dealing with section */
    free(po->last_read);
    po->last_read = NULL;
    po->last_read_len = 0;
    *action = PARSE_READ;

    TRACE_FLOW_EXIT();
    return EOK;

}
Beispiel #7
0
/* Collect metadata for the file */
int collect_metadata(uint32_t metaflags,
                     struct collection_item **metadata,
                     FILE *config_file,
                     const char *config_filename)
{
    int error = EOK;
    struct collection_item *metasec = NULL;
    int filedes;
    struct stat file_stats;
    char buff[CONVERSION_BUFFER];

    TRACE_FLOW_STRING("collect_metadata", "Entry");
    /* Check and create section for file error if needed */
    if (metaflags & INI_META_SEC_ACCESS_FLAG) {
        /* Create ACCESS collection */
        error = col_create_collection(&metasec,
                                      INI_META_SEC_ACCESS,
                                      COL_CLASS_INI_SECTION);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to create access section.", error);
            col_destroy_collection(metasec);
            return error;
        }

        filedes = fileno(config_file);

        /* Collect statistics */
        errno = 0;
        if (fstat(filedes, &file_stats) < 0) {
            error = errno;
            TRACE_ERROR_NUMBER("Failed to get statistics.", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* Record statistics */
        /* UID */
        snprintf(buff, CONVERSION_BUFFER, "%lu",
                 (unsigned long)file_stats.st_uid);
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_UID,
                                     buff,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save uid", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* GID */
        snprintf(buff, CONVERSION_BUFFER, "%lu",
                 (unsigned long)file_stats.st_gid);
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_GID,
                                     buff,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save gid", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* PERMISSIONS */
        snprintf(buff, CONVERSION_BUFFER, "%lu",
                 (unsigned long)file_stats.st_mode);
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_PERM,
                                     buff,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save permissions", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* Modification time stamp */
        snprintf(buff, CONVERSION_BUFFER, "%ld",
                 (long int)file_stats.st_mtime);
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_MODIFIED,
                                     buff,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save modification time", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* Name */
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_NAME,
                                     config_filename,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save file name", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* The device ID can actualy be bigger than
         * 32-bits according to the type sizes.
         * However it is probaly not going to happen
         * on a real system.
         * Add a check for this case.
         */
        if (file_stats.st_dev > ULONG_MAX) {
            TRACE_ERROR_NUMBER("Device is out of range", ERANGE);
            col_destroy_collection(metasec);
            return ERANGE;
        }

        /* Device  ID */
        TRACE_INFO_LNUMBER("Device ID", file_stats.st_dev);

        snprintf(buff, CONVERSION_BUFFER, "%lu",
                 (unsigned long)file_stats.st_dev);
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_DEV,
                                     buff,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save inode", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* i-node */
        snprintf(buff, CONVERSION_BUFFER, "%lu",
                (unsigned long)file_stats.st_ino);
        error = col_add_str_property(metasec,
                                     NULL,
                                     INI_META_KEY_INODE,
                                     buff,
                                     0);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to save inode", error);
            col_destroy_collection(metasec);
            return error;
        }

        /* Add section to metadata */
        error = col_add_collection_to_collection(
                                    *metadata,
                                    NULL,
                                    NULL,
                                    metasec,
                                    COL_ADD_MODE_REFERENCE);

        col_destroy_collection(metasec);

        if (error) {
            TRACE_ERROR_NUMBER("Failed to save file name", error);
            return error;
        }
    }

    TRACE_FLOW_STRING("collect_metadata", "Exit");
    return error;
}