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
4 : * be 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 0 : 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 : size_t bytes_written;
46 : ssize_t written;
47 102 : int num_errors = 0;
48 :
49 102 : for (bytes_written = 0;
50 306 : 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 : }
60 : }
61 102 : return num_errors;
62 : }
63 :
64 68 : int ReadAll(struct Gio *src, char *buffer, size_t nbytes) {
65 : size_t bytes_read;
66 : ssize_t readden; /* for parallelism :-) */
67 68 : int num_errors = 0;
68 :
69 68 : for (bytes_read = 0;
70 204 : 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 : }
80 : }
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 : char buffer[COPY_CHUNKSIZE];
89 : 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 : }
100 1 : return num_errors;
101 : }
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 : int byte;
108 : 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 : }
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 : }
123 2 : if (EOF != getc(f2)) {
124 0 : fprintf(stderr, "file length differs (%s short)\n", file1);
125 0 : ++num_errors;
126 : }
127 2 : if (0 != num_errors) {
128 0 : fprintf(stderr, "files %s and %s differ\n", file1, file2);
129 : }
130 2 : return num_errors;
131 : }
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 : off_t file_size;
143 : char buffer[COPY_CHUNKSIZE];
144 : off_t start_offset;
145 2 : int num_errors = 0;
146 : 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 : }
152 :
153 2 : start_offset = file_size;
154 : 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 : }
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 68 : } while (start_offset > 0);
176 :
177 2 : return num_errors;
178 : }
179 :
180 : int main(int ac,
181 1 : char **av) {
182 : struct NaClDescIoDesc *src;
183 : struct NaClDescIoDesc *dst;
184 : struct NaClGioNaClDesc gsrc;
185 : 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 1 : num_errors += GioCopy((struct Gio *) &gsrc, (struct Gio *) &gdst);
224 1 : num_errors += ComparePosixFiles(av[1], av[2]);
225 :
226 1 : (*NACL_VTBL(Gio, &gdst)->Close)(&gdst.base);
227 1 : (*NACL_VTBL(Gio, &gdst)->Dtor)(&gdst.base);
228 :
229 1 : if (0 < num_errors) {
230 0 : return num_errors;
231 : }
232 :
233 1 : RemoveFile(av[2]);
234 :
235 : /* reverse copy; reuse gsrc */
236 :
237 1 : dst = NaClDescIoDescOpen(av[2],
238 : NACL_ABI_O_WRONLY|
239 : NACL_ABI_O_TRUNC|
240 : NACL_ABI_O_CREAT,
241 : 0666);
242 1 : if (NULL == dst) {
243 0 : fprintf(stderr, "could not open %s for write\n", av[2]);
244 0 : Usage();
245 0 : return -6;
246 : }
247 1 : if (!NaClGioNaClDescCtor(&gdst, (struct NaClDesc *) dst)) {
248 0 : fprintf(stderr, "NaClGioNaClDescCtor faied for destination file\n");
249 0 : return -7;
250 : }
251 :
252 : /*
253 : * We run GioRevCopy twice because if Seek failed to move the file
254 : * pointer but reported the file size correctly, it would still
255 : * result in a correct output. By running it twice, the destination
256 : * data is just overwritten if the implementation is correct, and if
257 : * it isn't, we would end up with a file that is twice the source
258 : * file size.
259 : */
260 1 : num_errors += GioRevCopy((struct Gio *) &gsrc, (struct Gio *) &gdst);
261 1 : num_errors += GioRevCopy((struct Gio *) &gsrc, (struct Gio *) &gdst);
262 1 : num_errors += ComparePosixFiles(av[1], av[2]);
263 :
264 1 : (*NACL_VTBL(Gio, &gdst)->Close)((struct Gio *) &gdst);
265 1 : (*NACL_VTBL(Gio, &gdst)->Dtor)((struct Gio *) &gdst);
266 :
267 1 : (*NACL_VTBL(Gio, &gsrc)->Close)((struct Gio *) &gsrc);
268 1 : (*NACL_VTBL(Gio, &gsrc)->Dtor)((struct Gio *) &gsrc);
269 :
270 1 : if (0 < num_errors) {
271 0 : return num_errors;
272 : }
273 :
274 1 : RemoveFile(av[2]);
275 :
276 1 : return num_errors;
277 : }
|