# HG changeset patch # User Timo Sirainen # Date 1030319219 -10800 # Node ID e9375147c0cbfb763ac0c823feb845bc8f8f202e # Parent 6ac07b3fe0ff004d320107c912f40eeef08e3429 Added write_full() which is a simple wrapper around write() meant for writing into files. When there's too much deleted data in index files, they're now compressed when the index is being opened. diff -r 6ac07b3fe0ff -r e9375147c0cb TODO --- a/TODO Mon Aug 26 02:22:41 2002 +0300 +++ b/TODO Mon Aug 26 02:46:59 2002 +0300 @@ -25,27 +25,17 @@ the first UID in index. - mbox: - BUG: adding new mail after indexes are created doesn't work - - save MD5 sums for messages? - - update Status and X-Status headers when flags are changed - - last \n shouldn't be sent for messages. also remember to fix - the From-checks to check for [\r]\nFrom instead then.. + - update Status and X-Status headers when flags are changed. + how? probably by just writing a new mbox file at close time. - EXPUNGE doesn't delete the mail from the mbox file - - fsck should probably (or optionally?) really scan the message body - for "\nFrom " text instead of just jumping over the message body. - Quite useless actually, but this would make it fully reliable with md5 - anyway.. - there's some race condition issues when opening mailboxes.. - - when opening index files, check the flags and do what's needed. fsck and - rebuild is supported currently. compression and hash rebuilding is still - needed. and the cache_fields .. not sure when that'd be done, preferably - in the separate compress-process.. - set_lock() is ugly and horrible and should really be done something. does the syncing really need to be there? maybe put it into separate function which can be called after set_lock() by functions which actually care about the sync state (fetch, search, store, etc). - read-only support for mailboxes where we don't have write-access? Could be - a bigger job. At least the mmap()ed file contents can't be trusted since - they might change at any time. + a bigger job. At least the mmap()ed file contents (== pretty much + everything) can't be trusted since they might change at any time. - if index was just rebuilt, modify log complains about indexid mismatch at first open - does append work? @@ -65,7 +55,8 @@ - maildir: atomic COPY could be done by setting a "temporary" flag into the file's name. once copying is done, set an ignore-temporary field into index's header. at next sync the temporary flag will be removed. - - mbox: internal_date isn't saved + - mbox: should we bother checking if mbox file doesn't end with \n when + appending? - select "" shouldn't work. general: @@ -108,7 +99,13 @@ - Something's wrong with expunging mails from maildir .. - PAM: support some options so /etc/passwd-lookup isn't needed. uid=x, gid=y, mailroot=/var/mail. maildirs should be then created when needed - - check for "../" folder names with mbox + - index_rec->full_virtual_size could be 0 to indicate it's not calculated + yet. this way we don't need to read the messages fully just to find out + that. + - ability to automatically try again if some command fails because error + occured in the middle of it, but was most likely also fixed. for example + if mbox is compressed in the middle of FETCH operation or some index + corruption was noticed cleanups / checks: - grep for FIXME @@ -121,7 +118,7 @@ - allocating readwrite pools now just uses system_pool .. so pool_unref() can't free memory used by it .. what to do about it? at least count the malloc/free calls and make complain if at the exit they don't match - - Make sure messages of size INT_MAX..UINT_MAX (and more) work correctly + - Make sure messages of size INT_MAX..UINT_MAX (and more) work correctly. virtual_size can also overflow making it less than physical_size optional optimizations: diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/Makefile.am --- a/src/lib-index/Makefile.am Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/Makefile.am Mon Aug 26 02:46:59 2002 +0300 @@ -10,6 +10,7 @@ libstorage_index_a_SOURCES = \ mail-hash.c \ mail-index.c \ + mail-index-compress.c \ mail-index-fsck.c \ mail-index-data.c \ mail-index-update.c \ diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-hash.c --- a/src/lib-index/mail-hash.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-hash.c Mon Aug 26 02:46:59 2002 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "primes.h" #include "mmap-util.h" +#include "write-full.h" #include "mail-index.h" #include "mail-index-util.h" #include "mail-hash.h" @@ -172,13 +173,13 @@ /* write in 1kb blocks */ full_blocks = size / sizeof(block); for (i = 0; i < full_blocks; i++) { - if (write(fd, block, sizeof(block)) != sizeof(block)) + if (write_full(fd, block, sizeof(block)) < 0) return FALSE; } /* write the remainder */ i = size % sizeof(block); - return i == 0 ? TRUE : (size_t) write(fd, block, i) == i; + return i == 0 ? TRUE : write_full(fd, block, i) == 0; } static int hash_rebuild_to_file(MailIndex *index, int fd, diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-hash.h --- a/src/lib-index/mail-hash.h Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-hash.h Mon Aug 26 02:46:59 2002 +0300 @@ -24,7 +24,7 @@ /* Synchronize the hash file with memory map */ int mail_hash_sync_file(MailHash *hash); -/* Rebuild hash from index and reset the FLAG_REBUILD in header. +/* Rebuild hash from index and reset the FLAG_REBUILD_HASH in header. The index must have an exclusive lock before this function is called. */ int mail_hash_rebuild(MailHash *hash); diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-index-compress.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-index/mail-index-compress.c Mon Aug 26 02:46:59 2002 +0300 @@ -0,0 +1,152 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "lib.h" +#include "write-full.h" +#include "mail-index.h" +#include "mail-index-data.h" +#include "mail-index-util.h" + +#include +#include + +int mail_index_compress(MailIndex *index) +{ + MailIndexHeader *hdr; + MailIndexRecord *rec, *hole_rec, *end_rec; + off_t fsize; + + if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) + return FALSE; + + hdr = index->get_header(index); + + if (hdr->first_hole_position == 0) { + /* we don't need to compress after all. shouldn't happen.. */ + index->header->flags &= ~MAIL_INDEX_FLAG_CACHE_FIELDS; + return TRUE; + } + + /* if we get interrupted, the whole index is probably corrupted. + so keep rebuild-flag on while doing this */ + hdr->flags |= MAIL_INDEX_FLAG_REBUILD; + if (!mail_index_fmsync(index, sizeof(MailIndexHeader))) + return FALSE; + + /* first actually compress the data */ + end_rec = (MailIndexRecord *) ((char *) index->mmap_base + + index->mmap_length); + hole_rec = (MailIndexRecord *) ((char *) index->mmap_base + + hdr->first_hole_position); + rec = hole_rec + hdr->first_hole_records; + while (rec < end_rec) { + if (rec->uid != 0) { + memcpy(hole_rec, rec, sizeof(MailIndexRecord)); + hole_rec++; + } + rec++; + } + + /* truncate the file to get rid of the extra records */ + fsize = (char *) hole_rec - (char *) index->mmap_base; + if (ftruncate(index->fd, fsize) == -1) { + index_set_error(index, "ftruncate() failed for %s: %m", + index->filepath); + return FALSE; + } + + /* update headers */ + index->header->first_hole_position = 0; + index->header->first_hole_records = 0; + + /* make sure the whole file is synced before removing rebuild-flag */ + if (!mail_index_fmsync(index, fsize)) + return FALSE; + + index->header->flags &= ~(MAIL_INDEX_FLAG_CACHE_FIELDS | + MAIL_INDEX_FLAG_REBUILD); + return TRUE; +} + +int mail_index_compress_data(MailIndex *index) +{ + MailIndexRecord *rec; + MailIndexDataHeader data_hdr; + unsigned char *mmap_data; + size_t mmap_data_size; + off_t offset; + const char *temppath, *datapath; + int fd; + + /* write the data into temporary file updating the offsets in index + while doing it. if we fail (especially if out of disk space/quota) + we'll simply fail and index is rebuilt later */ + if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) + return FALSE; + + mmap_data = mail_index_data_get_mmaped(index->data, &mmap_data_size); + if (mmap_data == NULL) + return FALSE; + + fd = mail_index_create_temp_file(index, &temppath); + if (fd == -1) + return FALSE; + + /* write data header */ + memset(&data_hdr, 0, sizeof(data_hdr)); + data_hdr.indexid = index->indexid; + if (write_full(fd, &data_hdr, sizeof(data_hdr)) < 0) { + index_set_error(index, "Error writing to temp index data " + "%s: %m", temppath); + (void)close(fd); + (void)unlink(temppath); + return FALSE; + } + + /* no we'll begin the actual moving. keep rebuild-flag on + while doing it. */ + index->header->flags |= MAIL_INDEX_FLAG_REBUILD; + if (!mail_index_fmsync(index, sizeof(MailIndexHeader))) { + (void)close(fd); + (void)unlink(temppath); + return FALSE; + } + + offset = sizeof(data_hdr); + rec = index->lookup(index, 1); + while (rec != NULL) { + if (write_full(fd, mmap_data + rec->data_position, + rec->data_size) < 0) { + index_set_error(index, "Error writing to temp index " + "data %s: %m", temppath); + (void)close(fd); + (void)unlink(temppath); + return FALSE; + } + + rec->data_position = offset; + offset += rec->data_size; + + rec = index->next(index, rec); + } + + /* now, close the old data file and rename the temp file into + new data file */ + mail_index_data_free(index->data); + (void)close(fd); + + datapath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL); + if (rename(temppath, datapath) < 0) { + index_set_error(index, "rename(%s, %s) failed: %m", + temppath, datapath); + return FALSE; + } + + /* make sure the whole file is synced before removing rebuild-flag */ + if (!mail_index_fmsync(index, index->mmap_length)) + return FALSE; + + index->header->flags &= ~(MAIL_INDEX_FLAG_CACHE_FIELDS | + MAIL_INDEX_FLAG_REBUILD); + + return mail_index_data_open(index); +} diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-index-data.c --- a/src/lib-index/mail-index-data.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-index-data.c Mon Aug 26 02:46:59 2002 +0300 @@ -2,6 +2,7 @@ #include "lib.h" #include "mmap-util.h" +#include "write-full.h" #include "mail-index.h" #include "mail-index-data.h" #include "mail-index-util.h" @@ -62,7 +63,7 @@ const char *path; int fd; - path = t_strconcat(index->filepath, ".data", NULL); + path = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL); fd = open(path, O_RDWR); if (fd == -1) { if (errno == ENOENT) { @@ -109,7 +110,7 @@ memset(&hdr, 0, sizeof(hdr)); hdr.indexid = index->indexid; - if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + if (write_full(fd, &hdr, sizeof(hdr)) < 0) { index_set_error(index, "Error writing to temp index data " "%s: %m", temppath); return NULL; @@ -117,7 +118,7 @@ /* move temp file into .data file, deleting old one if it already exists */ - realpath = t_strconcat(index->filepath, ".data", NULL); + realpath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL); if (rename(temppath, realpath) == -1) { index_set_error(index, "rename(%s, %s) failed: %m", temppath, realpath); @@ -189,7 +190,7 @@ return FALSE; } - if (write(data->fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + if (write_full(data->fd, &hdr, sizeof(hdr)) < 0) { index_set_error(data->index, "write() failed for data file " "%s: %m", data->filepath); return FALSE; @@ -216,7 +217,7 @@ return -1; } - if ((size_t) write(data->fd, buffer, size) != size) { + if (write_full(data->fd, buffer, size) < 0) { index_set_error(data->index, "Error appending to file %s: %m", data->filepath); return -1; @@ -376,3 +377,12 @@ (unsigned long) DATA_FILE_POSITION(data, rec)); return FALSE; } + +void *mail_index_data_get_mmaped(MailIndexData *data, size_t *size) +{ + if (!mmap_update(data, 0, UINT_MAX)) + return NULL; + + *size = data->mmap_length; + return data->mmap_base; +} diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-index-data.h --- a/src/lib-index/mail-index-data.h Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-index-data.h Mon Aug 26 02:46:59 2002 +0300 @@ -1,6 +1,8 @@ #ifndef __MAIL_INDEX_DATA_H #define __MAIL_INDEX_DATA_H +#define DATA_FILE_PREFIX ".data" + int mail_index_data_open(MailIndex *index); int mail_index_data_create(MailIndex *index); void mail_index_data_free(MailIndexData *data); @@ -38,4 +40,7 @@ int mail_index_data_record_verify(MailIndexData *data, MailIndexDataRecord *rec); +/* Return the whole data file mmap()ed. */ +void *mail_index_data_get_mmaped(MailIndexData *data, size_t *size); + #endif diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-index.c --- a/src/lib-index/mail-index.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-index.c Mon Aug 26 02:46:59 2002 +0300 @@ -4,6 +4,7 @@ #include "ioloop.h" #include "hostpid.h" #include "mmap-util.h" +#include "write-full.h" #include "mail-index.h" #include "mail-index-data.h" #include "mail-index-util.h" @@ -149,6 +150,24 @@ return !failed; } +int mail_index_fmsync(MailIndex *index, size_t size) +{ + i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE); + + if (msync(index->mmap_base, size, MS_SYNC) == -1) { + index_set_error(index, "msync() failed for %s: %m", + index->filepath); + return FALSE; + } + if (fsync(index->fd) == -1) { + index_set_error(index, "fsync() failed for %s: %m", + index->filepath); + return FALSE; + } + + return TRUE; +} + int mail_index_rebuild_all(MailIndex *index) { if (!index->rebuild(index)) @@ -309,16 +328,7 @@ when the lock is released, the FSCK flag will also be removed. */ index->header->flags |= MAIL_INDEX_FLAG_FSCK; - if (msync(index->mmap_base, sizeof(MailIndexHeader), - MS_SYNC) == -1) { - index_set_error(index, "msync() failed for %s: %m", - index->filepath); - (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK); - return FALSE; - } - if (fsync(index->fd) == -1) { - index_set_error(index, "fsync() failed for %s: %m", - index->filepath); + if (!mail_index_fmsync(index, sizeof(MailIndexHeader))) { (void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK); return FALSE; } @@ -515,12 +525,31 @@ break; } + if (hdr.flags & MAIL_INDEX_FLAG_COMPRESS) { + /* remove deleted blocks from index file */ + if (!mail_index_compress(index)) + break; + } + + if (hdr.flags & MAIL_INDEX_FLAG_REBUILD_HASH) { + if (!mail_hash_rebuild(index->hash)) + break; + } + if (hdr.flags & MAIL_INDEX_FLAG_CACHE_FIELDS) { /* need to update cached fields */ if (!mail_index_update_cache(index)) break; } + if (hdr.flags & MAIL_INDEX_FLAG_COMPRESS_DATA) { + /* remove unused space from index data file. + keep after cache_fields which may move data + and create unused space.. */ + if (!mail_index_compress_data(index)) + break; + } + if (!index->sync(index)) break; if (!mail_index_open_init(index, update_recent, &hdr)) @@ -582,7 +611,7 @@ mail_index_init_header(&hdr); /* write header */ - if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + if (write_full(fd, &hdr, sizeof(hdr)) < 0) { index_set_error(index, "Error writing to temp index %s: %m", path); (void)close(fd); @@ -728,7 +757,7 @@ unsigned int lookup_seq) { MailIndexHeader *hdr; - MailIndexRecord *rec, *last_rec; + MailIndexRecord *rec, *end_rec; unsigned int seq; off_t seekpos; @@ -764,9 +793,6 @@ } /* we need to walk through the index to get to wanted position */ - last_rec = rec + (index->mmap_length-sizeof(MailIndexHeader)) / - sizeof(MailIndexRecord); - if (lookup_seq > index->last_lookup_seq && index->last_lookup != NULL) { /* we want to lookup data after last lookup - this helps us some */ @@ -781,17 +807,11 @@ rec += seq-1 + hdr->first_hole_records; } - if (rec == last_rec) - return NULL; - - while (seq < lookup_seq || rec->uid == 0) { + end_rec = (MailIndexRecord *) ((char *) index->mmap_base + + index->mmap_length); + while (seq < lookup_seq && rec < end_rec) { if (rec->uid != 0) seq++; - - if (rec == last_rec) { - /* out of range */ - return NULL; - } rec++; } @@ -1119,8 +1139,7 @@ return FALSE; } - if (write(index->fd, *rec, sizeof(MailIndexRecord)) != - sizeof(MailIndexRecord)) { + if (write_full(index->fd, *rec, sizeof(MailIndexRecord)) < 0) { index_set_error(index, "Error appending to file %s: %m", index->filepath); return FALSE; diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-index.h --- a/src/lib-index/mail-index.h Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-index.h Mon Aug 26 02:46:59 2002 +0300 @@ -343,10 +343,13 @@ void mail_index_close(MailIndex *index); int mail_index_rebuild_all(MailIndex *index); int mail_index_sync_file(MailIndex *index); +int mail_index_fmsync(MailIndex *index, size_t size); void mail_index_update_headers(MailIndexUpdate *update, IOBuffer *inbuf, MailField cache_fields, MessageHeaderFunc header_func, void *context); int mail_index_update_cache(MailIndex *index); +int mail_index_compress(MailIndex *index); +int mail_index_compress_data(MailIndex *index); /* Max. mmap()ed size for a message */ #define MAIL_MMAP_BLOCK_SIZE (1024*256) diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-index/mail-modifylog.c --- a/src/lib-index/mail-modifylog.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-index/mail-modifylog.c Mon Aug 26 02:46:59 2002 +0300 @@ -2,6 +2,7 @@ #include "lib.h" #include "mmap-util.h" +#include "write-full.h" #include "mail-index.h" #include "mail-index-util.h" #include "mail-modifylog.h" @@ -181,7 +182,7 @@ memset(&hdr, 0, sizeof(hdr)); hdr.indexid = log->index->indexid; - if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + if (write_full(fd, &hdr, sizeof(hdr)) < 0) { index_set_error(log->index, "write() failed for modify " "log %s: %m", path); return FALSE; @@ -397,8 +398,7 @@ return FALSE; } - if (write(log->fd, rec, sizeof(ModifyLogRecord)) != - sizeof(ModifyLogRecord)) { + if (write_full(log->fd, rec, sizeof(ModifyLogRecord)) < 0) { index_set_error(log->index, "Error appending to file %s: %m", log->filepath); return FALSE; diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-storage/flags-file/flags-file.c --- a/src/lib-storage/flags-file/flags-file.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-storage/flags-file/flags-file.c Mon Aug 26 02:46:59 2002 +0300 @@ -2,6 +2,7 @@ #include "lib.h" #include "mmap-util.h" +#include "write-full.h" #include "imap-util.h" #include "flags-file.h" @@ -64,7 +65,7 @@ } /* write the header - it's a 4 byte counter as hex */ - if (write(ff->fd, buf, HEADER_SIZE) != HEADER_SIZE) { + if (write_full(ff->fd, buf, HEADER_SIZE) < 0) { mail_storage_set_critical(ff->storage, "write() failed for " "flags file %s: %m", ff->path); return FALSE; @@ -276,7 +277,7 @@ } } - if (write(ff->fd, ff->sync_counter, COUNTER_SIZE) != COUNTER_SIZE) { + if (write_full(ff->fd, ff->sync_counter, COUNTER_SIZE) < 0) { mail_storage_set_critical(ff->storage, "write() failed for " "flags file %s: %m", ff->path); return FALSE; @@ -321,7 +322,7 @@ len--; } - if ((size_t) write(ff->fd, buf, len) != len) { + if (write_full(ff->fd, buf, len) < 0) { mail_storage_set_critical(ff->storage, "write() failed for " "flags file %s: %m", ff->path); return FALSE; diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-storage/index/index-save.c --- a/src/lib-storage/index/index-save.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-storage/index/index-save.c Mon Aug 26 02:46:59 2002 +0300 @@ -2,6 +2,7 @@ #include "lib.h" #include "iobuffer.h" +#include "write-full.h" #include "index-storage.h" #include @@ -10,19 +11,17 @@ static int write_with_crlf(int fd, const unsigned char *data, unsigned int size, unsigned int *last_cr) { - int i, cr; - - i_assert(size < INT_MAX); + unsigned int i, cr; cr = *last_cr ? -1 : -2; - for (i = 0; i < (int)size; i++) { + for (i = 0; i < size; i++) { if (data[i] == '\r') cr = i; else if (data[i] == '\n' && cr != i-1) { /* missing CR */ - if (write(fd, data, (size_t) i) != i) + if (write_full(fd, data, i) < 0) return FALSE; - if (write(fd, "\r", 1) != 1) + if (write_full(fd, "\r", 1) < 0) return FALSE; /* skip the data so far. \n is left into buffer and @@ -33,7 +32,7 @@ } } - return write(fd, data, size) == i; + return write_full(fd, data, size) < 0; } int index_storage_save_into_fd(MailStorage *storage, int fd, const char *path, diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-storage/index/mbox/mbox-save.c --- a/src/lib-storage/index/mbox/mbox-save.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-storage/index/mbox/mbox-save.c Mon Aug 26 02:46:59 2002 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "hostpid.h" #include "iobuffer.h" +#include "write-full.h" #include "mbox-index.h" #include "mbox-lock.h" #include "mbox-storage.h" @@ -40,7 +41,7 @@ line = mbox_from_create(sender, internal_date); len = strlen(line); - return (size_t)write(fd, line, len) == len; + return write_full(fd, line, len) < 0; } int mbox_storage_save(Mailbox *box, MailFlags flags, const char *custom_flags[], diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib-storage/subscription-file/subscription-file.c --- a/src/lib-storage/subscription-file/subscription-file.c Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib-storage/subscription-file/subscription-file.c Mon Aug 26 02:46:59 2002 +0300 @@ -4,6 +4,7 @@ #include "lib.h" #include "mmap-util.h" +#include "write-full.h" #include "imap-match.h" #include "mail-storage.h" #include "subscription-file.h" @@ -95,7 +96,7 @@ len++; } - if ((size_t) write(fd, buf, len) != len) { + if (write_full(fd, buf, len) < 0) { mail_storage_set_critical(storage, "write() failed for " "subscription file %s: %m", path); return FALSE; diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib/Makefile.am --- a/src/lib/Makefile.am Mon Aug 26 02:22:41 2002 +0300 +++ b/src/lib/Makefile.am Mon Aug 26 02:46:59 2002 +0300 @@ -38,7 +38,8 @@ temp-mempool.c \ temp-string.c \ unlink-directory.c \ - unlink-lockfiles.c + unlink-lockfiles.c \ + write-full.c noinst_HEADERS = \ base64.h \ @@ -67,7 +68,8 @@ temp-mempool.h \ temp-string.h \ unlink-directory.h \ - unlink-lockfiles.h + unlink-lockfiles.h \ + write-full.h EXTRA_DIST = \ $(ioloop_sources) diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib/write-full.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/write-full.c Mon Aug 26 02:46:59 2002 +0300 @@ -0,0 +1,49 @@ +/* + write-full.c - Simpler API to write to file + + Copyright (c) 2002 Timo Sirainen + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +int write_full(int fd, const void *data, size_t size) +{ + ssize_t ret; + + do { + ret = write(fd, data, size < INT_MAX ? size : INT_MAX); + if (ret < 0) + return -1; + + if (ret == 0) { + /* nothing was written, only reason for this should + be out of disk space */ + errno = ENOSPC; + return -1; + } + size -= ret; + } while (size > 0); + + return 0; +} diff -r 6ac07b3fe0ff -r e9375147c0cb src/lib/write-full.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/write-full.h Mon Aug 26 02:46:59 2002 +0300 @@ -0,0 +1,9 @@ +#ifndef __WRITE_FULL_H +#define __WRITE_FULL_H + +/* Write data into file. Returns -1 if error occured, or 0 if all was ok. + If there's not enough space in device -1 with ENOSPC is returned, and + it's unspecified how much data was actually written. */ +int write_full(int fd, const void *data, size_t size); + +#endif