1 | #include <glib/glib.h> |
2 | #include <glib/gstdio.h> |
3 | #include <gio/gio.h> |
4 | #include <string.h> |
5 | |
6 | #ifdef G_OS_UNIX |
7 | #include <unistd.h> |
8 | #endif |
9 | #ifdef G_OS_WIN32 |
10 | #include <io.h> /* for close() */ |
11 | #endif |
12 | |
13 | static const char *original_data = "This is some test data that we can put in a file..." ; |
14 | static const char *new_data = "new data.." ; |
15 | |
16 | static void |
17 | verify_pos (GIOStream *iostream, goffset expected_pos) |
18 | { |
19 | goffset pos; |
20 | |
21 | pos = g_seekable_tell (G_SEEKABLE (iostream)); |
22 | g_assert_cmpint (pos, ==, expected_pos); |
23 | |
24 | pos = g_seekable_tell (G_SEEKABLE (g_io_stream_get_input_stream (iostream))); |
25 | g_assert_cmpint (pos, ==, expected_pos); |
26 | |
27 | pos = g_seekable_tell (G_SEEKABLE (g_io_stream_get_output_stream (iostream))); |
28 | g_assert_cmpint (pos, ==, expected_pos); |
29 | } |
30 | |
31 | static void |
32 | verify_iostream (GFileIOStream *file_iostream) |
33 | { |
34 | gboolean res; |
35 | GIOStream *iostream; |
36 | GError *error; |
37 | GInputStream *in; |
38 | GOutputStream *out; |
39 | char buffer[1024]; |
40 | gsize n_bytes; |
41 | char *modified_data; |
42 | |
43 | iostream = G_IO_STREAM (file_iostream); |
44 | |
45 | verify_pos (iostream, expected_pos: 0); |
46 | |
47 | in = g_io_stream_get_input_stream (stream: iostream); |
48 | out = g_io_stream_get_output_stream (stream: iostream); |
49 | |
50 | res = g_input_stream_read_all (stream: in, buffer, count: 20, bytes_read: &n_bytes, NULL, NULL); |
51 | g_assert (res); |
52 | g_assert_cmpmem (buffer, n_bytes, original_data, 20); |
53 | |
54 | verify_pos (iostream, expected_pos: 20); |
55 | |
56 | res = g_seekable_seek (G_SEEKABLE (iostream), |
57 | offset: -10, type: G_SEEK_END, |
58 | NULL, NULL); |
59 | g_assert (res); |
60 | verify_pos (iostream, expected_pos: strlen (s: original_data) - 10); |
61 | |
62 | res = g_input_stream_read_all (stream: in, buffer, count: 20, bytes_read: &n_bytes, NULL, NULL); |
63 | g_assert (res); |
64 | g_assert_cmpmem (buffer, n_bytes, original_data + strlen (original_data) - 10, 10); |
65 | |
66 | verify_pos (iostream, expected_pos: strlen (s: original_data)); |
67 | |
68 | res = g_seekable_seek (G_SEEKABLE (iostream), |
69 | offset: 10, type: G_SEEK_SET, |
70 | NULL, NULL); |
71 | |
72 | res = g_input_stream_skip (stream: in, count: 5, NULL, NULL); |
73 | g_assert (res == 5); |
74 | verify_pos (iostream, expected_pos: 15); |
75 | |
76 | res = g_input_stream_skip (stream: in, count: 10000, NULL, NULL); |
77 | g_assert (res == strlen (original_data) - 15); |
78 | verify_pos (iostream, expected_pos: strlen (s: original_data)); |
79 | |
80 | res = g_seekable_seek (G_SEEKABLE (iostream), |
81 | offset: 10, type: G_SEEK_SET, |
82 | NULL, NULL); |
83 | |
84 | verify_pos (iostream, expected_pos: 10); |
85 | |
86 | res = g_output_stream_write_all (stream: out, buffer: new_data, count: strlen (s: new_data), |
87 | bytes_written: &n_bytes, NULL, NULL); |
88 | g_assert (res); |
89 | g_assert_cmpint (n_bytes, ==, strlen (new_data)); |
90 | |
91 | verify_pos (iostream, expected_pos: 10 + strlen (s: new_data)); |
92 | |
93 | res = g_seekable_seek (G_SEEKABLE (iostream), |
94 | offset: 0, type: G_SEEK_SET, |
95 | NULL, NULL); |
96 | g_assert (res); |
97 | verify_pos (iostream, expected_pos: 0); |
98 | |
99 | res = g_input_stream_read_all (stream: in, buffer, count: strlen (s: original_data), bytes_read: &n_bytes, NULL, NULL); |
100 | g_assert (res); |
101 | g_assert_cmpint ((int)n_bytes, ==, strlen (original_data)); |
102 | buffer[n_bytes] = 0; |
103 | |
104 | modified_data = g_strdup (str: original_data); |
105 | memcpy (dest: modified_data + 10, src: new_data, n: strlen (s: new_data)); |
106 | g_assert_cmpstr (buffer, ==, modified_data); |
107 | |
108 | verify_pos (iostream, expected_pos: strlen (s: original_data)); |
109 | |
110 | res = g_seekable_seek (G_SEEKABLE (iostream), |
111 | offset: 0, type: G_SEEK_SET, |
112 | NULL, NULL); |
113 | g_assert (res); |
114 | verify_pos (iostream, expected_pos: 0); |
115 | |
116 | res = g_output_stream_close (stream: out, NULL, NULL); |
117 | g_assert (res); |
118 | |
119 | res = g_input_stream_read_all (stream: in, buffer, count: 15, bytes_read: &n_bytes, NULL, NULL); |
120 | g_assert (res); |
121 | g_assert_cmpmem (buffer, n_bytes, modified_data, 15); |
122 | |
123 | error = NULL; |
124 | res = g_output_stream_write_all (stream: out, buffer: new_data, count: strlen (s: new_data), |
125 | bytes_written: &n_bytes, NULL, error: &error); |
126 | g_assert (!res); |
127 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); |
128 | g_error_free (error); |
129 | |
130 | error = NULL; |
131 | res = g_io_stream_close (stream: iostream, NULL, error: &error); |
132 | g_assert (res); |
133 | g_assert_no_error (error); |
134 | |
135 | g_free (mem: modified_data); |
136 | } |
137 | |
138 | static void |
139 | test_g_file_open_readwrite (void) |
140 | { |
141 | char *tmp_file; |
142 | int fd; |
143 | gboolean res; |
144 | GFileIOStream *file_iostream; |
145 | char *path; |
146 | GFile *file; |
147 | GError *error; |
148 | |
149 | fd = g_file_open_tmp (tmpl: "readwrite_XXXXXX" , |
150 | name_used: &tmp_file, NULL); |
151 | g_assert (fd != -1); |
152 | close (fd: fd); |
153 | |
154 | res = g_file_set_contents (filename: tmp_file, |
155 | contents: original_data, length: -1, NULL); |
156 | g_assert (res); |
157 | |
158 | path = g_build_filename (first_element: g_get_tmp_dir (), "g-a-nonexisting-file" , NULL); |
159 | file = g_file_new_for_path (path); |
160 | g_free (mem: path); |
161 | error = NULL; |
162 | file_iostream = g_file_open_readwrite (file, NULL, error: &error); |
163 | g_assert (file_iostream == NULL); |
164 | g_assert (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)); |
165 | g_error_free (error); |
166 | g_object_unref (object: file); |
167 | |
168 | file = g_file_new_for_path (path: tmp_file); |
169 | error = NULL; |
170 | file_iostream = g_file_open_readwrite (file, NULL, error: &error); |
171 | g_assert (file_iostream != NULL); |
172 | g_object_unref (object: file); |
173 | |
174 | verify_iostream (file_iostream); |
175 | |
176 | g_object_unref (object: file_iostream); |
177 | |
178 | g_unlink (filename: tmp_file); |
179 | g_free (mem: tmp_file); |
180 | } |
181 | |
182 | static void |
183 | test_g_file_create_readwrite (void) |
184 | { |
185 | char *tmp_file; |
186 | int fd; |
187 | gboolean res; |
188 | GFileIOStream *file_iostream; |
189 | GOutputStream *out; |
190 | GFile *file; |
191 | GError *error; |
192 | gsize n_bytes; |
193 | |
194 | fd = g_file_open_tmp (tmpl: "readwrite_XXXXXX" , |
195 | name_used: &tmp_file, NULL); |
196 | g_assert (fd != -1); |
197 | close (fd: fd); |
198 | |
199 | file = g_file_new_for_path (path: tmp_file); |
200 | error = NULL; |
201 | file_iostream = g_file_create_readwrite (file, flags: 0, NULL, error: &error); |
202 | g_assert (file_iostream == NULL); |
203 | g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS); |
204 | g_error_free (error); |
205 | |
206 | g_unlink (filename: tmp_file); |
207 | file_iostream = g_file_create_readwrite (file, flags: 0, NULL, error: &error); |
208 | g_assert (file_iostream != NULL); |
209 | |
210 | out = g_io_stream_get_output_stream (G_IO_STREAM (file_iostream)); |
211 | res = g_output_stream_write_all (stream: out, buffer: original_data, count: strlen (s: original_data), |
212 | bytes_written: &n_bytes, NULL, NULL); |
213 | g_assert (res); |
214 | g_assert_cmpint (n_bytes, ==, strlen (original_data)); |
215 | |
216 | res = g_seekable_seek (G_SEEKABLE (file_iostream), |
217 | offset: 0, type: G_SEEK_SET, |
218 | NULL, NULL); |
219 | g_assert (res); |
220 | |
221 | verify_iostream (file_iostream); |
222 | |
223 | g_object_unref (object: file_iostream); |
224 | g_object_unref (object: file); |
225 | |
226 | g_unlink (filename: tmp_file); |
227 | g_free (mem: tmp_file); |
228 | } |
229 | |
230 | static void |
231 | test_g_file_replace_readwrite (void) |
232 | { |
233 | char *tmp_file, *backup, *data; |
234 | int fd; |
235 | gboolean res; |
236 | GFileIOStream *file_iostream; |
237 | GInputStream *in; |
238 | GOutputStream *out; |
239 | GFile *file; |
240 | GError *error; |
241 | char buffer[1024]; |
242 | gsize n_bytes; |
243 | |
244 | fd = g_file_open_tmp (tmpl: "readwrite_XXXXXX" , |
245 | name_used: &tmp_file, NULL); |
246 | g_assert (fd != -1); |
247 | close (fd: fd); |
248 | |
249 | res = g_file_set_contents (filename: tmp_file, |
250 | contents: new_data, length: -1, NULL); |
251 | g_assert (res); |
252 | |
253 | file = g_file_new_for_path (path: tmp_file); |
254 | error = NULL; |
255 | file_iostream = g_file_replace_readwrite (file, NULL, |
256 | TRUE, flags: 0, NULL, error: &error); |
257 | g_assert (file_iostream != NULL); |
258 | |
259 | in = g_io_stream_get_input_stream (G_IO_STREAM (file_iostream)); |
260 | |
261 | /* Ensure its empty */ |
262 | res = g_input_stream_read_all (stream: in, buffer, count: sizeof buffer, bytes_read: &n_bytes, NULL, NULL); |
263 | g_assert (res); |
264 | g_assert_cmpint ((int)n_bytes, ==, 0); |
265 | |
266 | out = g_io_stream_get_output_stream (G_IO_STREAM (file_iostream)); |
267 | res = g_output_stream_write_all (stream: out, buffer: original_data, count: strlen (s: original_data), |
268 | bytes_written: &n_bytes, NULL, NULL); |
269 | g_assert (res); |
270 | g_assert_cmpint (n_bytes, ==, strlen (original_data)); |
271 | |
272 | res = g_seekable_seek (G_SEEKABLE (file_iostream), |
273 | offset: 0, type: G_SEEK_SET, |
274 | NULL, NULL); |
275 | g_assert (res); |
276 | |
277 | verify_iostream (file_iostream); |
278 | |
279 | g_object_unref (object: file_iostream); |
280 | g_object_unref (object: file); |
281 | |
282 | backup = g_strconcat (string1: tmp_file, "~" , NULL); |
283 | res = g_file_get_contents (filename: backup, |
284 | contents: &data, |
285 | NULL, NULL); |
286 | g_assert (res); |
287 | g_assert_cmpstr (data, ==, new_data); |
288 | g_free (mem: data); |
289 | g_unlink (filename: backup); |
290 | g_free (mem: backup); |
291 | |
292 | g_unlink (filename: tmp_file); |
293 | g_free (mem: tmp_file); |
294 | } |
295 | |
296 | |
297 | int |
298 | main (int argc, |
299 | char *argv[]) |
300 | { |
301 | g_test_init (argc: &argc, argv: &argv, NULL); |
302 | |
303 | g_test_add_func (testpath: "/readwrite/test_g_file_open_readwrite" , |
304 | test_func: test_g_file_open_readwrite); |
305 | g_test_add_func (testpath: "/readwrite/test_g_file_create_readwrite" , |
306 | test_func: test_g_file_create_readwrite); |
307 | g_test_add_func (testpath: "/readwrite/test_g_file_replace_readwrite" , |
308 | test_func: test_g_file_replace_readwrite); |
309 | |
310 | return g_test_run(); |
311 | } |
312 | |