1 /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "test-lib.h"
4 #include "istream.h"
5 #include "ostream.h"
6 #include "iostream-temp.h"
7 
8 #include <unistd.h>
9 #include <fcntl.h>
10 
test_iostream_temp_create_sized_memory(void)11 static void test_iostream_temp_create_sized_memory(void)
12 {
13 	struct ostream *output;
14 
15 	test_begin("iostream_temp_create_sized() memory");
16 	output = iostream_temp_create_sized(".intentional-nonexistent-error/", 0, "test", 4);
17 	test_assert(o_stream_send(output, "123", 3) == 3);
18 	test_assert(output->offset == 3);
19 	test_assert(o_stream_send(output, "4", 1) == 1);
20 	test_assert(output->offset == 4);
21 	test_assert(o_stream_get_fd(output) == -1);
22 
23 	/* now we'll try to switch to writing to a file, but it'll fail */
24 	test_expect_error_string("safe_mkstemp");
25 	test_assert(o_stream_send(output, "5", 1) == 1);
26 	test_expect_no_more_errors();
27 
28 	test_assert(o_stream_get_fd(output) == -1);
29 	o_stream_destroy(&output);
30 	test_end();
31 }
32 
test_iostream_temp_create_sized_disk(void)33 static void test_iostream_temp_create_sized_disk(void)
34 {
35 	struct ostream *output;
36 
37 	test_begin("iostream_temp_create_sized() disk");
38 	output = iostream_temp_create_sized(".", 0, "test", 4);
39 	test_assert(o_stream_send(output, "123", 3) == 3);
40 	test_assert(output->offset == 3);
41 	test_assert(o_stream_send(output, "4", 1) == 1);
42 	test_assert(output->offset == 4);
43 	test_assert(o_stream_get_fd(output) == -1);
44 	test_assert(o_stream_send(output, "5", 1) == 1);
45 	test_assert(output->offset == 5);
46 	test_assert(o_stream_get_fd(output) != -1);
47 	o_stream_destroy(&output);
48 	test_end();
49 }
50 
test_iostream_temp_create_write_error(void)51 static void test_iostream_temp_create_write_error(void)
52 {
53 	struct ostream *output;
54 
55 	test_begin("iostream_temp_create_sized() write error");
56 	output = iostream_temp_create_sized(".", 0, "test", 1);
57 
58 	test_assert(o_stream_send(output, "123", 3) == 3);
59 	test_assert(o_stream_get_fd(output) != -1);
60 	test_assert(output->offset == 3);
61 	test_assert(o_stream_temp_move_to_memory(output) == 0);
62 	test_assert(o_stream_get_fd(output) == -1);
63 	test_assert(o_stream_send(output, "45", 2) == 2);
64 	test_assert(output->offset == 5);
65 
66 	const unsigned char *data;
67 	size_t size;
68 	struct istream *input = iostream_temp_finish(&output, 128);
69 	test_assert(i_stream_read_bytes(input, &data, &size, 5) == 1 &&
70 		    memcmp(data, "12345", 5) == 0);
71 	i_stream_destroy(&input);
72 
73 	test_end();
74 }
75 
test_iostream_temp_istream(void)76 static void test_iostream_temp_istream(void)
77 {
78 	struct istream *input, *input2, *temp_input;
79 	struct ostream *output;
80 	int fd;
81 
82 	test_begin("iostream_temp istream");
83 
84 	fd = open(".temp.istream", O_RDWR | O_CREAT | O_TRUNC, 0600);
85 	if (fd == -1)
86 		i_fatal("create(.temp.istream) failed: %m");
87 	test_assert(write(fd, "foobar", 6) == 6);
88 	test_assert(lseek(fd, 0, SEEK_SET) == 0);
89 
90 	input = i_stream_create_fd_autoclose(&fd, 1024);
91 	/* a working fd-dup */
92 	output = iostream_temp_create_sized(".nonexistent/",
93 		IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 1);
94 	test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
95 	test_assert(output->offset == 6);
96 	temp_input = iostream_temp_finish(&output, 128);
97 	test_assert(i_stream_read(temp_input) == 6);
98 	i_stream_destroy(&temp_input);
99 
100 	/* non-working fd-dup: write data before sending istream */
101 	i_stream_seek(input, 0);
102 	output = iostream_temp_create_sized(".intentional-nonexistent-error/",
103 		IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4);
104 	test_assert(o_stream_send(output, "1234", 4) == 4);
105 	test_assert(output->offset == 4);
106 	test_expect_error_string("safe_mkstemp");
107 	test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
108 	test_assert(output->offset == 10);
109 	test_expect_no_more_errors();
110 	o_stream_destroy(&output);
111 
112 	/* non-working fd-dup: write data after sending istream */
113 	i_stream_seek(input, 0);
114 	output = iostream_temp_create_sized(".intentional-nonexistent-error/",
115 		IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4);
116 	test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
117 	test_assert(output->offset == 6);
118 	test_expect_error_string("safe_mkstemp");
119 	test_assert(o_stream_send(output, "1", 1) == 1);
120 	test_assert(output->offset == 7);
121 	test_expect_no_more_errors();
122 	o_stream_destroy(&output);
123 
124 	/* non-working fd-dup: send two istreams */
125 	i_stream_seek(input, 0);
126 	input2 = i_stream_create_limit(input, UOFF_T_MAX);
127 	output = iostream_temp_create_sized(".intentional-nonexistent-error/",
128 		IOSTREAM_TEMP_FLAG_TRY_FD_DUP, "test", 4);
129 	test_assert(o_stream_send_istream(output, input) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
130 	test_assert(output->offset == 6);
131 	test_expect_error_string("safe_mkstemp");
132 	test_assert(o_stream_send_istream(output, input2) == OSTREAM_SEND_ISTREAM_RESULT_FINISHED);
133 	test_assert(output->offset == 12);
134 	test_expect_no_more_errors();
135 	o_stream_destroy(&output);
136 	i_stream_unref(&input2);
137 
138 	i_stream_destroy(&input);
139 
140 	i_unlink(".temp.istream");
141 	test_end();
142 }
143 
test_iostream_temp(void)144 void test_iostream_temp(void)
145 {
146 	test_iostream_temp_create_sized_memory();
147 	test_iostream_temp_create_sized_disk();
148 	test_iostream_temp_create_write_error();
149 	test_iostream_temp_istream();
150 }
151