const failable rewrite()

in components/constdb/tinycdb.hpp [230:299]


const failable<bool> rewrite(const lambda<const failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)>& update, const lambda<const failable<bool>(struct cdb_make&)>& finish, buffer& buf, const int tmpfd, const TinyCDB& cdb) {

    // Initialize new db structure
    struct cdb_make cdbm;
    cdb_make_start(&cdbm, tmpfd);

    // Open existing db
    failable<int> ffd = cdbopen(cdb);
    if (!hasContent(ffd))
        return mkfailure<bool>(ffd);
    const int fd = content(ffd);

    // Read the db header
    unsigned int pos = 0;
    if (lseek(fd, 0, SEEK_SET) != 0)
        return mkfailure<bool>("Couldn't seek to tinycdb database start");
    if (::read(fd, buf, 2048) != 2048)
        return mkfailure<bool>("Couldn't read tinycdb database header");
    pos += 2048;
    const unsigned int eod = cdb_unpack(buf);
    debug(pos, "tinycdb::rewrite::eod");

    // Read and add the existing entries
    while(pos < eod) {
        if (eod - pos < 8)
            return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry header");
        if (::read(fd, buf, 8) != 8)
            return mkfailure<bool>("Couldn't read tinycdb entry header");
        pos += 8;
        const unsigned int klen = cdb_unpack(buf);
        const unsigned int vlen = cdb_unpack(((unsigned char*)buf) + 4);
        const unsigned int elen = klen + vlen;

        // Read existing entry
        buf = mkbuffer(buf, elen);
        if (eod - pos < elen)
            return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry");
        if ((unsigned int)::read(fd, buf, elen) != elen)
            return mkfailure<bool>("Couldn't read tinycdb entry");
        pos += elen;

        // Apply the update function to the entry
        debug(string((const char* const)buf, klen), "tinycdb::rewrite::existing key");
        debug(string(((const char* const)buf) + klen, vlen), "tinycdb::rewrite::existing value");
        const failable<bool> u = update(buf, klen, vlen);
        if (!hasContent(u))
            return u;

        // Skip the entry if the update function returned false
        if (u == false)
            continue;

        // Add the entry to the new db
        if (cdb_make_add(&cdbm, buf, klen, ((unsigned char*)buf)+klen, vlen) == -1)
            return mkfailure<bool>("Couldn'tt add tinycdb entry");
    }
    if (pos != eod)
        return mkfailure<bool>("Invalid tinycdb database format");

    // Call the finish function
    const failable<bool> f = finish(cdbm);
    if (!hasContent(f))
        return f;

    // Save the new db
    if (cdb_make_finish(&cdbm) == -1)
        return mkfailure<bool>("Couldn't save tinycdb database");

    return true;
}