GnuCash 2.4.99
Data Structures | Files | Defines | Typedefs | Functions
GncGUID
Entity: Types, Identity and Instance Framework

Data Structures

union  GNC_INTERNAL_GUID

Files

file  guid.h
 

globally unique ID User API


Defines

#define GUID_DATA_SIZE   16
#define GNC_TYPE_GUID   (gnc_guid_get_type())
#define GNC_VALUE_HOLDS_GUID(value)   G_VALUE_HOLDS(value, GNC_TYPE_GUID)
#define GUID_ENCODING_LENGTH   32

Typedefs

typedef union GNC_INTERNAL_GUID GncGUID

Functions

GType gnc_guid_get_type (void)
G_CONST_RETURN GncGUIDgnc_value_get_guid (const GValue *value)
void guid_init (void)
void guid_shutdown (void)
void guid_new (GncGUID *guid)
GncGUID guid_new_return (void)
const GncGUIDguid_null (void)
GncGUIDguid_malloc (void)
void guid_free (GncGUID *guid)
GncGUIDguid_copy (const GncGUID *guid)
const gchar * guid_to_string (const GncGUID *guid)
gchar * guid_to_string_buff (const GncGUID *guid, gchar *buff)
gboolean string_to_guid (const gchar *string, GncGUID *guid)
gboolean guid_equal (const GncGUID *guid_1, const GncGUID *guid_2)
gint guid_compare (const GncGUID *g1, const GncGUID *g2)
guint guid_hash_to_guint (gconstpointer ptr)
gint guid_g_hash_table_equal (gconstpointer guid_a, gconstpointer guid_b)
GHashTable * guid_hash_table_new (void)

Detailed Description

Globally Unique ID's provide a way to uniquely identify some thing. A GncGUID is a unique, cryptographically random 128-bit value. The identifier is so random that it is safe to assume that there is no other such item on the planet Earth, and indeed, not even in the Galaxy or beyond.

QOF GncGUID's can be used independently of any other subsystem in QOF. In particular, they do not require the use of other parts of the object subsystem. New GncGUID's are usually created by initialising a new entity using qof_instance_init, rather than calling GncGUID functions directly.


Define Documentation

#define GUID_DATA_SIZE   16

The type used to store guids

Definition at line 53 of file guid.h.

#define GUID_ENCODING_LENGTH   32

number of characters needed to encode a guid as a string not including the null terminator.

Definition at line 71 of file guid.h.


Function Documentation

G_CONST_RETURN GncGUID* gnc_value_get_guid ( const GValue *  value)

gnc_value_get_guid

Parameters:
valuea GValue whose value we want to get.
Returns:
the value stored in value

Definition at line 75 of file guid.c.

{
    GncGUID *val;

    g_return_val_if_fail (value && G_IS_VALUE (value), NULL);
    g_return_val_if_fail (GNC_VALUE_HOLDS_GUID (value), NULL);

    val = (GncGUID*) g_value_get_boxed (value);

    return val;
}
gboolean guid_equal ( const GncGUID guid_1,
const GncGUID guid_2 
)

Given two GUIDs, return TRUE if they are non-NULL and equal. Return FALSE, otherwise.

Definition at line 696 of file guid.c.

{
    if (guid_1 && guid_2)
        return (memcmp(guid_1, guid_2, GUID_DATA_SIZE) == 0);
    else
        return FALSE;
}
gint guid_g_hash_table_equal ( gconstpointer  guid_a,
gconstpointer  guid_b 
)

Equality function for two GUIDs in a GHashTable.

Definition at line 754 of file guid.c.

{
    return guid_equal (guid_a, guid_b);
}
GHashTable* guid_hash_table_new ( void  )

Returns a GHashTable with <GUID*> as key and a <gpointer> as value and no destructor functions for key or value set.

Definition at line 760 of file guid.c.

{
    return g_hash_table_new (guid_hash_to_guint, guid_g_hash_table_equal);
}
guint guid_hash_to_guint ( gconstpointer  ptr)

Hash function for a GUID. Given a GncGUID *, hash it to a guint

Definition at line 721 of file guid.c.

{
    const GncGUID *guid = ptr;

    if (!guid)
    {
        PERR ("received NULL guid pointer.");
        return 0;
    }

    if (sizeof(guint) <= sizeof(guid->data))
    {
        const guint* ptr_data = (const guint *) guid->data;
        return (*ptr_data);
    }
    else
    {
        guint hash = 0;
        unsigned int i, j;

        for (i = 0, j = 0; i < sizeof(guint); i++, j++)
        {
            if (j == GUID_DATA_SIZE) j = 0;

            hash <<= 4;
            hash |= guid->data[j];
        }

        return hash;
    }
}
void guid_init ( void  )

Initialize the id generator with a variety of random sources.

Note:
Only one of guid_init(), guid_init_with_salt() and guid_init_only_salt() should be called. Calling any initialization function a second time will reset the generator and erase the effect of the first call.

Definition at line 362 of file guid.c.

{
    size_t bytes = 0;

    ENTER("");

    /* Not needed; taken care of on first malloc.
     * guid_memchunk_init(); */

    md5_init_ctx(&guid_context);

    /* entropy pool
     * FIXME /dev/urandom doesn't exist on Windows. We should
     *       use the Windows native CryptGenRandom or RtlGenRandom
     *       functions. See
     *       http://en.wikipedia.org/wiki/CryptGenRandom */
    bytes += init_from_file ("/dev/urandom", 512);

    /* files
     * FIXME none of these directories make sense on
     *       Windows. We should figure out some proper
     *       alternatives there. */
    {
        const char * files[] =
        {
            "/etc/passwd",
            "/proc/loadavg",
            "/proc/meminfo",
            "/proc/net/dev",
            "/proc/rtc",
            "/proc/self/environ",
            "/proc/self/stat",
            "/proc/stat",
            "/proc/uptime",
            NULL
        };
        int i;

        for (i = 0; files[i] != NULL; i++)
            bytes += init_from_file(files[i], BLOCKSIZE);
    }

    /* directories
     * Note: P_tmpdir is set to "\" by mingw (Windows) This seems to
     * trigger unwanted network access attempts (see bug #521817).
     * So on Windows we explicitly set the temporary directory.
     * FIXME other than "c:/temp" none of these directories make sense on
     *       Windows. We should figure out some proper
     *       alternatives there. */
    {
        const char * dirname;
        const char * dirs[] =
        {
            "/proc",
#ifndef G_OS_WIN32
            P_tmpdir,
#else
            "c:/temp",
#endif
            "/var/lock",
            "/var/log",
            "/var/mail",
            "/var/spool/mail",
            "/var/run",
            NULL
        };
        int i;

        for (i = 0; dirs[i] != NULL; i++)
            bytes += init_from_dir(dirs[i], 32);

        dirname = g_get_home_dir();
        if (dirname != NULL)
            bytes += init_from_dir(dirname, 32);
    }

    /* process and parent ids */
    {
#ifdef HAVE_UNISTD_H
        pid_t pid;

        pid = getpid();
        md5_process_bytes(&pid, sizeof(pid), &guid_context);
        bytes += sizeof(pid);

#ifdef HAVE_GETPPID
        pid = getppid();
        md5_process_bytes(&pid, sizeof(pid), &guid_context);
        bytes += sizeof(pid);
#endif
#endif
    }

    /* user info */
    {
#ifdef HAVE_GETUID
        uid_t uid;
        gid_t gid;
        char *s;

        s = getlogin();
        if (s != NULL)
        {
            md5_process_bytes(s, strlen(s), &guid_context);
            bytes += strlen(s);
        }

        uid = getuid();
        md5_process_bytes(&uid, sizeof(uid), &guid_context);
        bytes += sizeof(uid);

        gid = getgid();
        md5_process_bytes(&gid, sizeof(gid), &guid_context);
        bytes += sizeof(gid);
#endif
    }

    /* host info */
    {
#ifdef HAVE_GETHOSTNAME
        char string[1024];

        memset(string, 0, sizeof(string));
        gethostname(string, sizeof(string));
        md5_process_bytes(string, sizeof(string), &guid_context);
        bytes += sizeof(string);
#endif
    }

    /* plain old random */
    {
        int n, i;

        srand((unsigned int) time(NULL));

        for (i = 0; i < 32; i++)
        {
            n = rand();

            md5_process_bytes(&n, sizeof(n), &guid_context);
            bytes += sizeof(n);
        }
    }

    /* time in secs and clock ticks */
    bytes += init_from_time();

#ifdef HAVE_SCANF_LLD
    PINFO ("got %llu bytes", (unsigned long long int) bytes);

    if (bytes < THRESHOLD)
        PWARN("only got %llu bytes.\n"
              "The identifiers might not be very random.\n",
              (unsigned long long int)bytes);
#else
    PINFO ("got %lu bytes", (unsigned long int) bytes);

    if (bytes < THRESHOLD)
        PWARN("only got %lu bytes.\n"
              "The identifiers might not be very random.\n",
              (unsigned long int)bytes);
#endif

    guid_initialized = TRUE;
    LEAVE();
}
GncGUID* guid_malloc ( void  )

Efficiently allocate & free memory for GUIDs

Definition at line 90 of file guid.c.

{
    return g_slice_new(GncGUID);
}
void guid_new ( GncGUID guid)

Generate a new id. If no initialization function has been called, guid_init() will be called before the id is created.

Parameters:
guidA pointer to an existing guid data structure. The existing value will be replaced with a new value.

This routine uses the md5 algorithm to build strong random guids. Note that while guid's are generated randomly, the odds of this routine returning a non-unique id are astronomically small. (Literally astronomically: If you had Cray's on every solar system in the universe running for the entire age of the universe, you'd still have less than a one-in-a-million chance of coming up with a duplicate id. 2^128 == 10^38 is a really really big number.)

Definition at line 537 of file guid.c.

{
    static int counter = 0;
    struct md5_ctx ctx;

    if (guid == NULL)
        return;

    if (!guid_initialized)
        guid_init();

    /* make the id */
    ctx = guid_context;
    md5_finish_ctx(&ctx, guid->data);

    /* update the global context */
    init_from_time();

    /* Make it a little extra salty.  I think init_from_time was buggy,
    * or something, since duplicate id's actually happened. Or something
    * like that.  I think this is because init_from_time kept returning
    * the same values too many times in a row.  So we'll do some 'block
    * chaining', and feed in the old guid as new random data.
    *
    * Anyway, I think the whole fact that I saw a bunch of duplicate
    * id's at one point, but can't reproduce the bug is rather alarming.
    * Something must be broken somewhere, and merely adding more salt
    * is just hiding the problem, not fixing it.
    */
    init_from_int (433781 * counter);
    init_from_buff (guid->data, GUID_DATA_SIZE);

    if (counter == 0)
    {
        FILE *fp;

        fp = g_fopen ("/dev/urandom", "r");
        if (fp == NULL)
            return;

        init_from_stream(fp, 32);

        fclose(fp);

        counter = GUID_PERIOD;
    }

    counter--;
}
GncGUID guid_new_return ( void  )

Generate a new id. If no initialization function has been called, guid_init() will be called before the id is created.

Returns:
guid A data structure containing a newly allocated GncGUID. Caller is responsible for calling guid_free().

Definition at line 588 of file guid.c.

{
    GncGUID guid;

    guid_new (&guid);

    return guid;
}
const GncGUID* guid_null ( void  )

Returns a GncGUID which is guaranteed to never reference any entity.

Definition at line 117 of file guid.c.

{
    static int null_inited = 0;
    static GncGUID null_guid;

    if (!null_inited)
    {
        int i;

        for (i = 0; i < GUID_DATA_SIZE; i++)
            null_guid.data[i] = '\0';

        null_inited = 1;
    }

    return &null_guid;
}
void guid_shutdown ( void  )

Release the memory chunk associated with gui storage. Use this only when shutting down the program, as it invalidates *all* GUIDs at once.

Definition at line 530 of file guid.c.

{
}
const gchar* guid_to_string ( const GncGUID guid)

The guid_to_string() routine returns a null-terminated string encoding of the id. String encodings of identifiers are hex numbers printed only with the characters '0' through '9' and 'a' through 'f'. The encoding will always be GUID_ENCODING_LENGTH characters long.

XXX This routine is not thread safe and is deprecated. Please use the routine guid_to_string_buff() instead.

Parameters:
guidThe guid to print.
Returns:
A pointer to the starting character of the string. The returned memory is owned by this routine and may not be freed by the caller.

Definition at line 656 of file guid.c.

{
#ifdef G_THREADS_ENABLED
    static GStaticPrivate guid_buffer_key = G_STATIC_PRIVATE_INIT;
    gchar *string;

    string = g_static_private_get (&guid_buffer_key);
    if (string == NULL)
    {
        string = malloc(GUID_ENCODING_LENGTH + 1);
        g_static_private_set (&guid_buffer_key, string, g_free);
    }
#else
    static char string[64];
#endif

    encode_md5_data(guid->data, string);
    string[GUID_ENCODING_LENGTH] = '\0';

    return string;
}
gchar* guid_to_string_buff ( const GncGUID guid,
gchar *  buff 
)

The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory pointed at by buff. The buffer must be at least GUID_ENCODING_LENGTH+1 characters long. This routine is handy for avoiding a malloc/free cycle. It returns a pointer to the >>end<< of what was written. (i.e. it can be used like 'stpcpy' during string concatenation)

Parameters:
guidThe guid to print.
buffThe buffer to print it into.
Returns:
A pointer to the terminating null character of the string.
gboolean string_to_guid ( const gchar *  string,
GncGUID guid 
)

Given a string, decode the id into the guid if guid is non-NULL. The function returns TRUE if the string was a valid 32 character hexadecimal number. This function accepts both upper and lower case hex digits. If the return value is FALSE, the effect on guid is undefined.

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines