| OLD | NEW |
| (Empty) |
| 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 fprintf(stderr, "Usage: gio_nacl_desc_test src_file dst_file\n"); | |
| 42 } | |
| 43 | |
| 44 int WriteAll(struct Gio *dst, char *buffer, size_t nbytes) { | |
| 45 size_t bytes_written; | |
| 46 ssize_t written; | |
| 47 int num_errors = 0; | |
| 48 | |
| 49 for (bytes_written = 0; | |
| 50 bytes_written < nbytes; | |
| 51 bytes_written += written) { | |
| 52 written = (*NACL_VTBL(Gio, dst)->Write)(dst, | |
| 53 buffer + bytes_written, | |
| 54 nbytes - bytes_written); | |
| 55 if (written < 0) { | |
| 56 written = 0; | |
| 57 ++num_errors; | |
| 58 fprintf(stderr, "Write error\n"); | |
| 59 } | |
| 60 } | |
| 61 return num_errors; | |
| 62 } | |
| 63 | |
| 64 int ReadAll(struct Gio *src, char *buffer, size_t nbytes) { | |
| 65 size_t bytes_read; | |
| 66 ssize_t readden; /* for parallelism :-) */ | |
| 67 int num_errors = 0; | |
| 68 | |
| 69 for (bytes_read = 0; | |
| 70 bytes_read < nbytes; | |
| 71 bytes_read += readden) { | |
| 72 readden = (*NACL_VTBL(Gio, src)->Read)(src, | |
| 73 buffer + bytes_read, | |
| 74 nbytes - bytes_read); | |
| 75 if (readden < 0) { | |
| 76 readden = 0; | |
| 77 ++num_errors; | |
| 78 fprintf(stderr, "read error\n"); | |
| 79 } | |
| 80 } | |
| 81 return num_errors; | |
| 82 } | |
| 83 | |
| 84 /* | |
| 85 * Returns number of detected but correctable errors. | |
| 86 */ | |
| 87 int GioCopy(struct Gio *src, struct Gio *dst) { | |
| 88 char buffer[COPY_CHUNKSIZE]; | |
| 89 ssize_t bytes_read; | |
| 90 int num_errors = 0; | |
| 91 | |
| 92 while (0 != (bytes_read = (*NACL_VTBL(Gio, src)-> | |
| 93 Read)(src, buffer, sizeof buffer))) { | |
| 94 if (bytes_read < 0) { | |
| 95 fprintf(stderr, "negative read?!?\n"); | |
| 96 return ++num_errors; | |
| 97 } | |
| 98 num_errors += WriteAll(dst, buffer, (size_t) bytes_read); | |
| 99 } | |
| 100 return num_errors; | |
| 101 } | |
| 102 | |
| 103 int ComparePosixFiles(char *file1, char *file2) { | |
| 104 FILE *f1 = fopen(file1, "r"); | |
| 105 FILE *f2 = fopen(file2, "r"); | |
| 106 int num_errors = 0; | |
| 107 int byte; | |
| 108 int byte2; | |
| 109 | |
| 110 if (NULL == f1) return 1; | |
| 111 if (NULL == f2) return 1; | |
| 112 | |
| 113 while (EOF != (byte = getc(f1))) { | |
| 114 if (byte != (byte2 = getc(f2))) { | |
| 115 ++num_errors; | |
| 116 } | |
| 117 if (EOF == byte2) { | |
| 118 fprintf(stderr, "file length differs (%s short)\n", file2); | |
| 119 /* num_errors already incremented above */ | |
| 120 break; | |
| 121 } | |
| 122 } | |
| 123 if (EOF != getc(f2)) { | |
| 124 fprintf(stderr, "file length differs (%s short)\n", file1); | |
| 125 ++num_errors; | |
| 126 } | |
| 127 if (0 != num_errors) { | |
| 128 fprintf(stderr, "files %s and %s differ\n", file1, file2); | |
| 129 } | |
| 130 return num_errors; | |
| 131 } | |
| 132 | |
| 133 void RemoveFile(char *fname) { | |
| 134 #if NACL_WINDOWS | |
| 135 _unlink(fname); | |
| 136 #else | |
| 137 unlink(fname); | |
| 138 #endif | |
| 139 } | |
| 140 | |
| 141 int GioRevCopy(struct Gio *src, struct Gio *dst) { | |
| 142 off_t file_size; | |
| 143 char buffer[COPY_CHUNKSIZE]; | |
| 144 off_t start_offset; | |
| 145 int num_errors = 0; | |
| 146 size_t expected_bytes; | |
| 147 | |
| 148 file_size = (*NACL_VTBL(Gio, src)->Seek)(src, 0, SEEK_END); | |
| 149 if (file_size <= 0) { | |
| 150 fprintf(stderr, "non-positive file size?!?\n"); | |
| 151 } | |
| 152 | |
| 153 start_offset = file_size; | |
| 154 do { | |
| 155 start_offset -= COPY_CHUNKSIZE; | |
| 156 expected_bytes = COPY_CHUNKSIZE; | |
| 157 if (start_offset < 0) { | |
| 158 expected_bytes = start_offset + COPY_CHUNKSIZE; | |
| 159 start_offset = 0; | |
| 160 } | |
| 161 if (start_offset != (*NACL_VTBL(Gio, src)-> | |
| 162 Seek)(src, start_offset, SEEK_SET)) { | |
| 163 fprintf(stderr, "seek in source file failed, offset %"NACL_PRId64"\n", | |
| 164 (int64_t) start_offset); | |
| 165 return ++num_errors; | |
| 166 } | |
| 167 num_errors += ReadAll(src, buffer, expected_bytes); | |
| 168 if (start_offset != (*NACL_VTBL(Gio, dst)-> | |
| 169 Seek)(dst, start_offset, SEEK_SET)) { | |
| 170 fprintf(stderr, "seek in destination file failed, offset" | |
| 171 " %"NACL_PRId64"\n", (int64_t) start_offset); | |
| 172 return ++num_errors; | |
| 173 } | |
| 174 num_errors += WriteAll(dst, buffer, expected_bytes); | |
| 175 } while (start_offset > 0); | |
| 176 | |
| 177 return num_errors; | |
| 178 } | |
| 179 | |
| 180 int main(int ac, | |
| 181 char **av) { | |
| 182 struct NaClDescIoDesc *src; | |
| 183 struct NaClDescIoDesc *dst; | |
| 184 struct NaClGioNaClDesc gsrc; | |
| 185 struct NaClGioNaClDesc gdst; | |
| 186 int num_errors = 0; | |
| 187 | |
| 188 if (ac != 3) { | |
| 189 Usage(); | |
| 190 return -1; | |
| 191 } | |
| 192 | |
| 193 NaClLogModuleInit(); | |
| 194 NaClTimeInit(); | |
| 195 NaClSecureRngModuleInit(); | |
| 196 NaClGlobalSecureRngInit(); | |
| 197 | |
| 198 src = NaClDescIoDescOpen(av[1], NACL_ABI_O_RDONLY, 0); | |
| 199 if (NULL == src) { | |
| 200 fprintf(stderr, "could not open %s for read\n", av[1]); | |
| 201 Usage(); | |
| 202 return -2; | |
| 203 } | |
| 204 dst = NaClDescIoDescOpen(av[2], | |
| 205 NACL_ABI_O_WRONLY| | |
| 206 NACL_ABI_O_TRUNC| | |
| 207 NACL_ABI_O_CREAT, | |
| 208 0666); | |
| 209 if (NULL == dst) { | |
| 210 fprintf(stderr, "could not open %s for write\n", av[2]); | |
| 211 Usage(); | |
| 212 return -3; | |
| 213 } | |
| 214 if (!NaClGioNaClDescCtor(&gsrc, (struct NaClDesc *) src)) { | |
| 215 fprintf(stderr, "NaClGioNaClDescCtor failed for source file\n"); | |
| 216 return -4; | |
| 217 } | |
| 218 if (!NaClGioNaClDescCtor(&gdst, (struct NaClDesc *) dst)) { | |
| 219 fprintf(stderr, "NaClGioNaClDescCtor failed for destination file\n"); | |
| 220 return -5; | |
| 221 } | |
| 222 | |
| 223 /* | |
| 224 * The NaClGioNaClDesc now owns the NaClDescIoDesc. | |
| 225 */ | |
| 226 NaClDescUnref(&src->base); | |
| 227 NaClDescUnref(&dst->base); | |
| 228 | |
| 229 num_errors += GioCopy((struct Gio *) &gsrc, (struct Gio *) &gdst); | |
| 230 num_errors += ComparePosixFiles(av[1], av[2]); | |
| 231 | |
| 232 (*NACL_VTBL(Gio, &gdst)->Close)(&gdst.base); | |
| 233 (*NACL_VTBL(Gio, &gdst)->Dtor)(&gdst.base); | |
| 234 | |
| 235 if (0 < num_errors) { | |
| 236 return num_errors; | |
| 237 } | |
| 238 | |
| 239 RemoveFile(av[2]); | |
| 240 | |
| 241 /* reverse copy; reuse gsrc */ | |
| 242 | |
| 243 dst = NaClDescIoDescOpen(av[2], | |
| 244 NACL_ABI_O_WRONLY| | |
| 245 NACL_ABI_O_TRUNC| | |
| 246 NACL_ABI_O_CREAT, | |
| 247 0666); | |
| 248 if (NULL == dst) { | |
| 249 fprintf(stderr, "could not open %s for write\n", av[2]); | |
| 250 Usage(); | |
| 251 return -6; | |
| 252 } | |
| 253 if (!NaClGioNaClDescCtor(&gdst, (struct NaClDesc *) dst)) { | |
| 254 fprintf(stderr, "NaClGioNaClDescCtor faied for destination file\n"); | |
| 255 return -7; | |
| 256 } | |
| 257 | |
| 258 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 num_errors += GioRevCopy((struct Gio *) &gsrc, (struct Gio *) &gdst); | |
| 269 num_errors += GioRevCopy((struct Gio *) &gsrc, (struct Gio *) &gdst); | |
| 270 num_errors += ComparePosixFiles(av[1], av[2]); | |
| 271 | |
| 272 (*NACL_VTBL(Gio, &gdst)->Close)((struct Gio *) &gdst); | |
| 273 (*NACL_VTBL(Gio, &gdst)->Dtor)((struct Gio *) &gdst); | |
| 274 | |
| 275 (*NACL_VTBL(Gio, &gsrc)->Close)((struct Gio *) &gsrc); | |
| 276 (*NACL_VTBL(Gio, &gsrc)->Dtor)((struct Gio *) &gsrc); | |
| 277 | |
| 278 if (0 < num_errors) { | |
| 279 return num_errors; | |
| 280 } | |
| 281 | |
| 282 RemoveFile(av[2]); | |
| 283 | |
| 284 return num_errors; | |
| 285 } | |
| OLD | NEW |