static int i_stream_metawrap_stat(struct istream_private *stream, bool exact) { struct metawrap_istream *mstream = (struct metawrap_istream *)stream; const struct stat *st; int ret; if (i_stream_stat(stream->parent, exact, &st) < 0) { stream->istream.stream_errno = stream->parent->stream_errno; return -1; } stream->statbuf = *st; if (mstream->in_metadata) { ret = i_stream_read(&stream->istream); if (ret < 0 && stream->istream.stream_errno != 0) return -1; if (ret == 0) { stream->statbuf.st_size = -1; return 0; } } i_assert((uoff_t)stream->statbuf.st_size >= mstream->start_offset); stream->statbuf.st_size -= mstream->start_offset; return 0; }
static const struct stat * i_stream_bzlib_stat(struct istream_private *stream, bool exact) { struct bzlib_istream *zstream = (struct bzlib_istream *) stream; const struct stat *st; size_t size; st = i_stream_stat(stream->parent, exact); if (st == NULL) return NULL; if (zstream->eof_offset == (uoff_t)-1 && !exact) return st; stream->statbuf = *st; if (zstream->eof_offset == (uoff_t)-1) { uoff_t old_offset = stream->istream.v_offset; do { (void)i_stream_get_data(&stream->istream, &size); i_stream_skip(&stream->istream, size); } while (i_stream_read(&stream->istream) > 0); i_stream_seek(&stream->istream, old_offset); if (zstream->eof_offset == (uoff_t)-1) return NULL; } stream->statbuf.st_size = zstream->eof_offset; return &stream->statbuf; }
static int i_stream_base64_encoder_stat(struct istream_private *stream, bool exact ATTR_UNUSED) { struct base64_encoder_istream *bstream = (struct base64_encoder_istream *)stream; const struct stat *st; off_t newlines, size; if (i_stream_stat(stream->parent, exact, &st) < 0) { stream->istream.stream_errno = stream->parent->stream_errno; return -1; } stream->statbuf = *st; if (st->st_size == 0) return 0; /* calculate size of encoded data */ size = (st->st_size / 3) * 4 + ((st->st_size % 3) == 0 ? 0 : 4); /* update size with added newlines */ newlines = (size / bstream->chars_per_line - 1) + ((size % bstream->chars_per_line) == 0 ? 0 : 1); size += newlines * (bstream->crlf ? 2 : 1); stream->statbuf.st_size = size; return 0; }
static int raw_mail_stat(struct mail *mail) { struct raw_mailbox *mbox = (struct raw_mailbox *)mail->box; const struct stat *st; if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE) { mail_set_aborted(mail); return -1; } mail->transaction->stats.fstat_lookup_count++; if (i_stream_stat(mail->box->input, TRUE, &st) < 0) { mail_storage_set_critical(mail->box->storage, "stat(%s) failed: %m", i_stream_get_name(mail->box->input)); return -1; } if (mbox->mtime != (time_t)-1) mbox->mtime = st->st_mtime; if (mbox->ctime != (time_t)-1) mbox->ctime = st->st_ctime; mbox->size = st->st_size; return 0; }
static const struct stat * i_stream_tee_stat(struct istream_private *stream, bool exact) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; return i_stream_stat(tstream->tee->input, exact); }
static int i_stream_lzma_stat(struct istream_private *stream, bool exact) { struct lzma_istream *zstream = (struct lzma_istream *) stream; const struct stat *st; size_t size; if (i_stream_stat(stream->parent, exact, &st) < 0) { stream->istream.stream_errno = stream->parent->stream_errno; return -1; } stream->statbuf = *st; /* when exact=FALSE always return the parent stat's size, even if we know the exact value. this is necessary because otherwise e.g. mbox code can see two different values and think that a compressed mbox file keeps changing. */ if (!exact) return 0; if (zstream->stream_size == (uoff_t)-1) { uoff_t old_offset = stream->istream.v_offset; do { size = i_stream_get_data_size(&stream->istream); i_stream_skip(&stream->istream, size); } while (i_stream_read(&stream->istream) > 0); i_stream_seek(&stream->istream, old_offset); if (zstream->stream_size == (uoff_t)-1) return -1; } stream->statbuf.st_size = zstream->stream_size; return 0; }
static bool fs_sis_try_link(struct sis_fs_file *file) { const char *path = fs_file_path(&file->file); const struct stat *st; struct stat st2; st = i_stream_stat(file->hash_input, FALSE); /* we can use the existing file */ if (fs_link(file->super->fs, file->hash_path, path) < 0) { if (errno != ENOENT && errno != EMLINK) i_error("fs-sis: %s", fs_last_error(file->super->fs)); /* failed to use link(), continue as if it hadn't been equal */ return FALSE; } if (fs_stat(file->super->fs, path, &st2) < 0) { i_error("fs-sis: %s", fs_last_error(file->super->fs)); if (fs_unlink(file->super->fs, path) < 0) i_error("fs-sis: %s", fs_last_error(file->super->fs)); return FALSE; } if (st->st_ino != st2.st_ino) { /* the hashes/ file was already replaced with something else */ if (fs_unlink(file->super->fs, path) < 0) i_error("fs-sis: %s", fs_last_error(file->super->fs)); return FALSE; } return TRUE; }
static const struct stat * i_stream_base64_encoder_stat(struct istream_private *stream, bool exact) { if (exact) { /* too much trouble to implement until it's actually needed */ i_panic("istream-base64-encoder: " "stat() doesn't support getting exact size"); } return i_stream_stat(stream->parent, exact); }
static int i_stream_tee_stat(struct istream_private *stream, bool exact) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; const struct stat *st; if (i_stream_stat(tstream->tee->input, exact, &st) < 0) return -1; stream->statbuf = *st; return 0; }
static int quoted_string_istream_stat (struct istream_private *stream, bool exact) { const struct stat *st; if (i_stream_stat(stream->parent, exact, &st) < 0) return -1; stream->statbuf = *st; return 0; }
static void maildir_mail_remove_sizes_from_filename(struct mail *mail, enum mail_fetch_field field) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box; struct mail_private *pmail = (struct mail_private *)mail; enum maildir_uidlist_rec_flag flags; const char *fname; uoff_t size; struct maildir_size_fix_ctx ctx; if (mbox->storage->set->maildir_broken_filename_sizes) { /* never try to fix sizes in maildir filenames */ return; } if (maildir_sync_lookup(mbox, mail->uid, &flags, &fname) <= 0) return; if (strchr(fname, MAILDIR_EXTRA_SEP) == NULL) return; memset(&ctx, 0, sizeof(ctx)); ctx.physical_size = (uoff_t)-1; if (field == MAIL_FETCH_VIRTUAL_SIZE && maildir_filename_get_size(fname, MAILDIR_EXTRA_VIRTUAL_SIZE, &size)) { ctx.wrong_key = 'W'; } else if (field == MAIL_FETCH_PHYSICAL_SIZE && maildir_filename_get_size(fname, MAILDIR_EXTRA_FILE_SIZE, &size)) { ctx.wrong_key = 'S'; } else { /* the broken size isn't in filename */ return; } if (pmail->v.istream_opened != NULL) { /* the mail could be e.g. compressed. get the physical size the slow way by actually reading the mail. */ struct istream *input; const struct stat *stp; if (mail_get_stream(mail, NULL, NULL, &input) < 0) return; if (i_stream_stat(input, TRUE, &stp) < 0) return; ctx.physical_size = stp->st_size; } (void)maildir_file_do(mbox, mail->uid, do_fix_size, &ctx); }
int subsfile_list_fstat(struct subsfile_list_context *ctx, struct stat *st_r) { const struct stat *st; if (ctx->failed) return -1; if (i_stream_stat(ctx->input, FALSE, &st) < 0) { ctx->failed = TRUE; return -1; } *st_r = *st; return 0; }
static int i_stream_limit_stat(struct istream_private *stream, bool exact) { struct limit_istream *lstream = (struct limit_istream *) stream; const struct stat *st; if (i_stream_stat(stream->parent, exact, &st) < 0) return -1; stream->statbuf = *st; if (lstream->v_size != (uoff_t)-1) stream->statbuf.st_size = lstream->v_size; return 0; }
static int i_stream_mail_filter_stat(struct istream_private *stream, bool exact) { const struct stat *st; i_assert(!exact); if (i_stream_stat(stream->parent, exact, &st) < 0) { stream->istream.stream_errno = stream->parent->stream_errno; return -1; } stream->statbuf = *st; return 0; }
static int i_stream_seekable_stat(struct istream_private *stream, bool exact) { struct seekable_istream *sstream = (struct seekable_istream *)stream; const struct stat *st; uoff_t old_offset; ssize_t ret; if (sstream->size != (uoff_t)-1) { /* we've already reached EOF and know the size */ stream->statbuf.st_size = sstream->size; return 0; } if (sstream->membuf != NULL) { /* we want to know the full size of the file, so read until we're finished */ old_offset = stream->istream.v_offset; do { i_stream_skip(&stream->istream, stream->pos - stream->skip); } while ((ret = i_stream_seekable_read(stream)) > 0); if (ret == 0) { i_panic("i_stream_stat() used for non-blocking " "seekable stream %s offset %"PRIuUOFF_T, i_stream_get_name(sstream->cur_input), sstream->cur_input->v_offset); } i_stream_skip(&stream->istream, stream->pos - stream->skip); i_stream_seek(&stream->istream, old_offset); unref_streams(sstream); } if (stream->istream.stream_errno != 0) return -1; if (sstream->fd_input != NULL) { /* using a file backed buffer, we can use real fstat() */ if (i_stream_stat(sstream->fd_input, exact, &st) < 0) return -1; stream->statbuf = *st; } else { /* buffer is completely in memory */ i_assert(sstream->membuf != NULL); stream->statbuf.st_size = sstream->membuf->used; } return 0; }
static int i_stream_raw_mbox_stat(struct istream_private *stream, bool exact) { const struct stat *st; struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream; if (i_stream_stat(stream->parent, exact, &st) < 0) return -1; stream->statbuf = *st; stream->statbuf.st_size = !exact && rstream->seeked && rstream->mail_size != (uoff_t)-1 ? (off_t)rstream->mail_size : -1; return 0; }
static const struct stat * i_stream_limit_stat(struct istream_private *stream, bool exact) { struct limit_istream *lstream = (struct limit_istream *) stream; const struct stat *st; st = i_stream_stat(stream->parent, exact); if (st == NULL) return NULL; stream->statbuf = *st; if (lstream->v_size != (uoff_t)-1) stream->statbuf.st_size = lstream->v_size; return &stream->statbuf; }
static void i_stream_lzma_sync(struct istream_private *stream) { struct lzma_istream *zstream = (struct lzma_istream *) stream; const struct stat *st; if (i_stream_stat(stream->parent, FALSE, &st) < 0) { if (memcmp(&zstream->last_parent_statbuf, st, sizeof(*st)) == 0) { /* a compressed file doesn't change unexpectedly, don't clear our caches unnecessarily */ return; } zstream->last_parent_statbuf = *st; } i_stream_lzma_reset(zstream); }
static int i_stream_default_stat(struct istream_private *stream, bool exact) { const struct stat *st; if (stream->parent == NULL) return stream->istream.stream_errno == 0 ? 0 : -1; if (i_stream_stat(stream->parent, exact, &st) < 0) return -1; stream->statbuf = *st; if (exact && !stream->stream_size_passthrough) { /* exact size is not known, even if parent returned something */ stream->statbuf.st_size = -1; } return 0; }
static int maildir_mail_stat(struct mail *mail, struct stat *st_r) { struct maildir_mailbox *mbox = (struct maildir_mailbox *)mail->box; struct index_mail *imail = (struct index_mail *)mail; const struct stat *stp; const char *path; int ret; if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE) { mail_set_aborted(mail); return -1; } if (imail->data.access_part != 0 && imail->data.stream == NULL) { /* we're going to open the mail anyway */ struct istream *input; (void)mail_get_stream(mail, NULL, NULL, &input); } if (imail->data.stream != NULL) { mail->transaction->stats.fstat_lookup_count++; if (i_stream_stat(imail->data.stream, FALSE, &stp) < 0) return -1; *st_r = *stp; } else if (!mail->saving) { mail->transaction->stats.stat_lookup_count++; ret = maildir_file_do(mbox, mail->uid, do_stat, st_r); if (ret <= 0) { if (ret == 0) mail_set_expunged(mail); return -1; } } else { mail->transaction->stats.stat_lookup_count++; path = maildir_save_file_get_path(mail->transaction, mail->seq); if (stat(path, st_r) < 0) { mail_storage_set_critical(mail->box->storage, "stat(%s) failed: %m", path); return -1; } } return 0; }
static int sieve_attribute_retrieve_script(struct mail_storage *storage, struct sieve_storage *svstorage, struct sieve_script *script, bool add_type_prefix, struct mail_attribute_value *value_r, const char **errorstr_r) { static char type = MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT; struct istream *input, *inputs[3]; const struct stat *st; enum sieve_error error; if (script == NULL) *errorstr_r = sieve_storage_get_last_error(svstorage, &error); else if (sieve_script_get_stream(script, &input, &error) < 0) sieve_script_unref(&script); if (script == NULL) { if (error == SIEVE_ERROR_NOT_FOUND) { /* already deleted, but return the last_change */ (void)sieve_storage_get_last_change(svstorage, &value_r->last_change); return 0; } *errorstr_r = sieve_storage_get_last_error(svstorage, &error); return -1; } if (i_stream_stat(input, FALSE, &st) < 0) { mail_storage_set_critical(storage, "stat(%s) failed: %m", i_stream_get_name(input)); } else { value_r->last_change = st->st_mtime; } if (!add_type_prefix) { i_stream_ref(input); value_r->value_stream = input; } else { inputs[0] = i_stream_create_from_data(&type, 1); inputs[1] = input; inputs[2] = NULL; value_r->value_stream = i_stream_create_concat(inputs); i_stream_unref(&inputs[0]); } sieve_script_unref(&script); return 1; }
static int i_stream_limit_get_size(struct istream_private *stream, bool exact, uoff_t *size_r) { struct limit_istream *lstream = (struct limit_istream *) stream; const struct stat *st; if (lstream->v_size != (uoff_t)-1) { *size_r = lstream->v_size; return 1; } if (i_stream_stat(&stream->istream, exact, &st) < 0) return -1; if (st->st_size == -1) return 0; *size_r = st->st_size; return 1; }
static int raw_mail_stat(struct mail *mail) { struct raw_mailbox *mbox = (struct raw_mailbox *)mail->box; struct mail_private *p = (struct mail_private *)mail; const struct stat *st; if (mail->lookup_abort == MAIL_LOOKUP_ABORT_NOT_IN_CACHE) return mail_set_aborted(mail); p->stats_fstat_lookup_count++; st = i_stream_stat(mail->box->input, TRUE); if (st == NULL) { mail_storage_set_critical(mail->box->storage, "stat(%s) failed: %m", mail->box->path); return -1; } if (mbox->mtime != (time_t)-1) mbox->mtime = st->st_mtime; if (mbox->ctime != (time_t)-1) mbox->ctime = st->st_ctime; mbox->size = st->st_size; return 0; }
static const struct stat * i_stream_mail_stats_stat(struct istream_private *stream, bool exact) { return i_stream_stat(stream->parent, exact); }