1 : /*
2 : * Copyright 2010 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <stdio.h>
8 : #include <stdlib.h>
9 :
10 : #if NACL_WINDOWS
11 : # include "io.h"
12 : # include "fcntl.h"
13 : #endif
14 :
15 : #define COPY_CHUNKSIZE (4 * 4096)
16 :
17 :
18 : /*
19 : * cp via gio on top of NaClDescIoDesc, as a test.
20 : */
21 :
22 : #include "native_client/src/include/portability.h"
23 :
24 : #include "native_client/src/shared/platform/nacl_check.h"
25 : #include "native_client/src/shared/platform/nacl_log.h"
26 : #include "native_client/src/shared/platform/nacl_time.h"
27 : #include "native_client/src/shared/platform/nacl_secure_random.h"
28 : #include "native_client/src/shared/platform/nacl_global_secure_random.h"
29 :
30 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
31 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
32 :
33 : #include "native_client/src/trusted/nacl_base/nacl_refcount.h"
34 :
35 : #include "native_client/src/trusted/desc/nrd_all_modules.h"
36 : #include "native_client/src/trusted/gio/gio_nacl_desc.h"
37 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
38 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
39 :
40 : void Usage(void) {
41 0 : fprintf(stderr, "Usage: gio_nacl_desc_test src_file dst_file\n");
42 0 : }
43 :
44 102 : int WriteAll(struct Gio *dst, char *buffer, size_t nbytes) {
45 102 : size_t bytes_written;
46 102 : ssize_t written;
47 102 : int num_errors = 0;
48 :
49 306 : for (bytes_written = 0;
50 : bytes_written < nbytes;
51 102 : bytes_written += written) {
52 102 : written = (*NACL_VTBL(Gio, dst)->Write)(dst,
53 : buffer + bytes_written,
54 : nbytes - bytes_written);
55 102 : if (written < 0) {
56 0 : written = 0;
57 0 : ++num_errors;
58 0 : fprintf(stderr, "Write error\n");
59 0 : }
60 102 : }
61 102 : return num_errors;
62 : }
63 :
64 68 : int ReadAll(struct Gio *src, char *buffer, size_t nbytes) {
65 68 : size_t bytes_read;
66 68 : ssize_t readden; /* for parallelism :-) */
67 68 : int num_errors = 0;
68 :
69 204 : for (bytes_read = 0;
70 : bytes_read < nbytes;
71 68 : bytes_read += readden) {
72 68 : readden = (*NACL_VTBL(Gio, src)->Read)(src,
73 : buffer + bytes_read,
74 : nbytes - bytes_read);
75 68 : if (readden < 0) {
76 0 : readden = 0;
77 0 : ++num_errors;
78 0 : fprintf(stderr, "read error\n");
79 0 : }
80 68 : }
81 68 : return num_errors;
82 : }
83 :
84 : /*
85 : * Returns number of detected but correctable errors.
86 : */
87 1 : int GioCopy(struct Gio *src, struct Gio *dst) {
88 1 : char buffer[COPY_CHUNKSIZE];
89 1 : ssize_t bytes_read;
90 1 : int num_errors = 0;
91 :
92 36 : while (0 != (bytes_read = (*NACL_VTBL(Gio, src)->
93 : Read)(src, buffer, sizeof buffer))) {
94 34 : if (bytes_read < 0) {
95 0 : fprintf(stderr, "negative read?!?\n");
96 0 : return ++num_errors;
97 : }
98 34 : num_errors += WriteAll(dst, buffer, (size_t) bytes_read);
99 34 : }
100 1 : return num_errors;
101 1 : }
102 :
103 2 : int ComparePosixFiles(char *file1, char *file2) {
104 2 : FILE *f1 = fopen(file1, "r");
105 2 : FILE *f2 = fopen(file2, "r");
106 2 : int num_errors = 0;
107 2 : int byte;
108 2 : int byte2;
109 :
110 2 : if (NULL == f1) return 1;
111 2 : if (NULL == f2) return 1;
112 :
113 1099234 : while (EOF != (byte = getc(f1))) {
114 1099230 : if (byte != (byte2 = getc(f2))) {
115 0 : ++num_errors;
116 0 : }
117 1099230 : if (EOF == byte2) {
118 0 : fprintf(stderr, "file length differs (%s short)\n", file2);
119 : /* num_errors already incremented above */
120 0 : break;
121 : }
122 1099230 : }
123 2 : if (EOF != getc(f2)) {
124 0 : fprintf(stderr, "file length differs (%s short)\n", file1);
125 0 : ++num_errors;
126 0 : }
127 2 : if (0 != num_errors) {
128 0 : fprintf(stderr, "files %s and %s differ\n", file1, file2);
129 0 : }
130 2 : return num_errors;
131 2 : }
132 :
133 2 : void RemoveFile(char *fname) {
134 : #if NACL_WINDOWS
135 : _unlink(fname);
136 : #else
137 2 : unlink(fname);
138 : #endif
139 2 : }
140 :
141 2 : int GioRevCopy(struct Gio *src, struct Gio *dst) {
142 2 : off_t file_size;
143 2 : char buffer[COPY_CHUNKSIZE];
144 2 : off_t start_offset;
145 2 : int num_errors = 0;
146 2 : size_t expected_bytes;
147 :
148 2 : file_size = (*NACL_VTBL(Gio, src)->Seek)(src, 0, SEEK_END);
149 2 : if (file_size <= 0) {
150 0 : fprintf(stderr, "non-positive file size?!?\n");
151 0 : }
152 :
153 2 : start_offset = file_size;
154 2 : do {
155 68 : start_offset -= COPY_CHUNKSIZE;
156 68 : expected_bytes = COPY_CHUNKSIZE;
157 68 : if (start_offset < 0) {
158 2 : expected_bytes = start_offset + COPY_CHUNKSIZE;
159 2 : start_offset = 0;
160 2 : }
161 68 : if (start_offset != (*NACL_VTBL(Gio, src)->
162 : Seek)(src, start_offset, SEEK_SET)) {
163 0 : fprintf(stderr, "seek in source file failed, offset %"NACL_PRId64"\n",
164 : (int64_t) start_offset);
165 0 : return ++num_errors;
166 : }
167 68 : num_errors += ReadAll(src, buffer, expected_bytes);
168 68 : if (start_offset != (*NACL_VTBL(Gio, dst)->
169 : Seek)(dst, start_offset, SEEK_SET)) {
170 0 : fprintf(stderr, "seek in destination file failed, offset"
171 : " %"NACL_PRId64"\n", (int64_t) start_offset);
172 0 : return ++num_errors;
173 : }
174 68 : num_errors += WriteAll(dst, buffer, expected_bytes);
175 136 : } while (start_offset > 0);
176 :
177 2 : return num_errors;
178 2 : }
179 :
180 1 : int main(int ac,
181 1 : char **av) {
182 1 : struct NaClDescIoDesc *src;
183 1 : struct NaClDescIoDesc *dst;
184 1 : struct NaClGioNaClDesc gsrc;
185 1 : struct NaClGioNaClDesc gdst;
186 1 : int num_errors = 0;
187 :
188 1 : if (ac != 3) {
189 0 : Usage();
190 0 : return -1;
191 : }
192 :
193 1 : NaClLogModuleInit();
194 1 : NaClTimeInit();
195 1 : NaClSecureRngModuleInit();
196 1 : NaClGlobalSecureRngInit();
197 :
198 1 : src = NaClDescIoDescOpen(av[1], NACL_ABI_O_RDONLY, 0);
199 1 : if (NULL == src) {
200 0 : fprintf(stderr, "could not open %s for read\n", av[1]);
201 0 : Usage();
202 0 : return -2;
203 : }
204 1 : dst = NaClDescIoDescOpen(av[2],
205 : NACL_ABI_O_WRONLY|
206 : NACL_ABI_O_TRUNC|
207 : NACL_ABI_O_CREAT,
208 : 0666);
209 1 : if (NULL == dst) {
210 0 : fprintf(stderr, "could not open %s for write\n", av[2]);
211 0 : Usage();
212 0 : return -3;
213 : }
214 1 : if (!NaClGioNaClDescCtor(&gsrc, (struct NaClDesc *) src)) {
215 0 : fprintf(stderr, "NaClGioNaClDescCtor failed for source file\n");
216 0 : return -4;
217 : }
218 1 : if (!NaClGioNaClDescCtor(&gdst, (struct NaClDesc *) dst)) {
219 0 : fprintf(stderr, "NaClGioNaClDescCtor failed for destination file\n");
220 0 : return -5;
221 : }
222 :
223 : /*
224 : * The NaClGioNaClDesc now owns the NaClDescIoDesc.
225 : */
226 1 : NaClDescUnref(&src->base);
227 1 : NaClDescUnref(&dst->base);
228 :
229 1 : num_errors += GioCopy((struct Gio *) &gsrc, (struct Gio *) &gdst);
230 1 : num_errors += ComparePosixFiles(av[1], av[2]);
231 :
232 1 : (*NACL_VTBL(Gio, &gdst)->Close)(&gdst.base);
233 1 : (*NACL_VTBL(Gio, &gdst)->Dtor)(&gdst.base);
234 :
235 1 : if (0 < num_errors) {
236 0 : return num_errors;
237 : }
238 :
239 1 : RemoveFile(av[2]);
240 :
241 : /* reverse copy; reuse gsrc */
242 :
243 1 : dst = NaClDescIoDescOpen(av[2],
244 : NACL_ABI_O_WRONLY|
245 : NACL_ABI_O_TRUNC|
246 : NACL_ABI_O_CREAT,
247 : 0666);
248 1 : if (NULL == dst) {
249 0 : fprintf(stderr, "could not open %s for write\n", av[2]);
250 0 : Usage();
251 0 : return -6;
252 : }
253 1 : if (!NaClGioNaClDescCtor(&gdst, (struct NaClDesc *) dst)) {
254 0 : fprintf(stderr, "NaClGioNaClDescCtor faied for destination file\n");
255 0 : return -7;
256 : }
257 :
258 1 : NaClDescUnref(&dst->base);
259 :
260 : /*
261 : * We run GioRevCopy twice because if Seek failed to move the file
262 : * pointer but reported the file size correctly, it would still
263 : * result in a correct output. By running it twice, the destination
264 : * data is just overwritten if the implementation is correct, and if
265 : * it isn't, we would end up with a file that is twice the source
266 : * file size.
267 : */
268 1 : num_errors += GioRevCopy((struct Gio *) &gsrc, (struct Gio *) &gdst);
269 1 : num_errors += GioRevCopy((struct Gio *) &gsrc, (struct Gio *) &gdst);
270 1 : num_errors += ComparePosixFiles(av[1], av[2]);
271 :
272 1 : (*NACL_VTBL(Gio, &gdst)->Close)((struct Gio *) &gdst);
273 1 : (*NACL_VTBL(Gio, &gdst)->Dtor)((struct Gio *) &gdst);
274 :
275 1 : (*NACL_VTBL(Gio, &gsrc)->Close)((struct Gio *) &gsrc);
276 1 : (*NACL_VTBL(Gio, &gsrc)->Dtor)((struct Gio *) &gsrc);
277 :
278 1 : if (0 < num_errors) {
279 0 : return num_errors;
280 : }
281 :
282 1 : RemoveFile(av[2]);
283 :
284 1 : return num_errors;
285 1 : }
|