コード例 #1
0
ファイル: istream-seekable.c プロジェクト: bdraco/core
static ssize_t i_stream_seekable_read(struct istream_private *stream)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	const unsigned char *data;
	size_t size, pos;
	ssize_t ret;

	if (sstream->fd == -1) {
		if (read_from_buffer(sstream, &ret))
			return ret;

		/* copy everything to temp file and use it as the stream */
		if (copy_to_temp_file(sstream) < 0) {
			stream->max_buffer_size = (size_t)-1;
			if (!read_from_buffer(sstream, &ret))
				i_unreached();
			return ret;
		}
		i_assert(sstream->fd != -1);
	}

	stream->buffer = CONST_PTR_OFFSET(stream->buffer, stream->skip);
	stream->pos -= stream->skip;
	stream->skip = 0;

	i_assert(stream->istream.v_offset + stream->pos <= sstream->write_peak);
	if (stream->istream.v_offset + stream->pos == sstream->write_peak) {
		/* need to read more */
		if (sstream->cur_input == NULL ||
		    i_stream_get_data_size(sstream->cur_input) == 0) {
			ret = read_more(sstream);
			if (ret == -1 || ret == 0)
				return ret;
		}

		/* save to our file */
		data = i_stream_get_data(sstream->cur_input, &size);
		ret = write(sstream->fd, data, size);
		if (ret <= 0) {
			if (ret < 0 && !ENOSPACE(errno)) {
				i_error("istream-seekable: write_full(%s) failed: %m",
					sstream->temp_path);
			}
			if (i_stream_seekable_write_failed(sstream) < 0)
				return -1;
			if (!read_from_buffer(sstream, &ret))
				i_unreached();
			return ret;
		}
		i_stream_sync(sstream->fd_input);
		i_stream_skip(sstream->cur_input, ret);
		sstream->write_peak += ret;
	}

	i_stream_seek(sstream->fd_input, stream->istream.v_offset);
	ret = i_stream_read_memarea(sstream->fd_input);
	if (ret <= 0) {
		stream->istream.eof = sstream->fd_input->eof;
		stream->istream.stream_errno =
			sstream->fd_input->stream_errno;
	} else {
		ret = -2;
	}

	stream->buffer = i_stream_get_data(sstream->fd_input, &pos);
	stream->pos -= stream->skip;
	stream->skip = 0;

	ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : ret;
	stream->pos = pos;
	return ret;
}
コード例 #2
0
static gboolean
begin_link_temporary_if_exists (GkmTransaction *self, const gchar *filename, gboolean *exists)
{
	guint i = 0;

	g_assert (GKM_IS_TRANSACTION (self));
	g_assert (!gkm_transaction_get_failed (self));
	g_assert (filename);
	g_assert (exists);

	for (i = 0; i < MAX_TRIES; ++i) {
		struct stat sb;
		unsigned int nlink;
		int stat_failed = 0;

		*exists = TRUE;

		/* Try to link to random temporary file names.  We try
		 * to use a hardlink to create a copy but if that
		 * fails (i.e. not supported by the FS), we copy the
		 * entire file.  The result should be the same except
		 * that the file times will change if we need to
		 * rollback the transaction. */
		if (stat (filename, &sb)) {
			stat_failed = 1;
		} else {
			gchar *result;

			result = g_strdup_printf ("%s.temp-%d", filename,
			                          g_random_int_range (0, G_MAXINT));
			nlink = (unsigned int)sb.st_nlink;
			/* The result code of link(2) is not reliable.
			 * Unless it fails with EEXIST we stat the
			 * file to check for success.  Note that there
			 * is a race here: If another process adds a
			 * link to the source file between link and
			 * stat, the check on the increased link count
			 * will fail.  Fortunately the case for
			 * hardlinks are not working solves it.  */
			if (link (filename, result) && errno == EEXIST) {
				/* This is probably a valid error.
				 * Let us try another temporary file.  */
			} else if (stat (filename, &sb)) {
				stat_failed = 1;
			} else {
				if ((sb.st_nlink == nlink + 1)
				    || !copy_to_temp_file (result, filename)) {
					/* Either the link worked or
					 * the copy succeeded.  */
					gkm_transaction_add (self, NULL,
					                     complete_link_temporary,
					                     result);
					return TRUE;
				}
			}

			g_free (result);
		}

		if (stat_failed && (errno == ENOENT || errno == ENOTDIR)) {
			/* The original file does not exist */
			*exists = FALSE;
			return TRUE;
		}

		/* If exists, try again, otherwise fail */
		if (errno != EEXIST) {
			g_warning ("couldn't create temporary file for: %s: %s",
			           filename, g_strerror (errno));
			gkm_transaction_fail (self, CKR_DEVICE_ERROR);
			return FALSE;
		}
	}

	g_assert_not_reached ();
}