1 #include "compat.h" 2 #include "md4.h" 3 #include "net.h" 4 5 #ifndef O_LARGEFILE 6 #define O_LARGEFILE 0 7 #endif 8 9 uint64_t net_bytesout = 0; 10 uint64_t net_bytesin = 0; 11 12 extern char *optarg; 13 extern int optind, opterr, optopt; 14 15 static int print_help(int ret) { 16 fprintf(stderr, "Usage: file_sync -t <host> <port> <file>\n"); 17 fprintf(stderr, "Usage: file_sync -r <port> <file>\n"); 18 return(ret); 19 } 20 21 #if 0 22 static void print_hash(FILE *fp, const unsigned char *hash) { 23 int i; 24 25 for (i = 0; i < 16; i++) { 26 fprintf(fp, "%x", hash[i] >> 4); 27 fprintf(fp, "%x", hash[i] & 0xf); 28 } 29 30 return; 31 } 32 #endif 33 34 static ssize_t read_large(int fd, char *buf, size_t count) { 35 size_t bytestoread; 36 ssize_t read_ret; 37 ssize_t retval = 0; 38 39 while (count) { 40 bytestoread = count; 41 42 if (bytestoread >= INT_MAX) { 43 bytestoread = INT_MAX - 1; 44 } 45 46 read_ret = read(fd, buf, bytestoread); 47 if (read_ret < 0) { 48 /* 49 * Only indicate an error if we have not read anything 50 * into the buffer. Subsequent calls to read() should 51 * generate the error again. Hopefully. 52 */ 53 if (retval == 0) { 54 retval = -1; 55 } 56 break; 57 } 58 59 if (read_ret == 0) { 60 break; 61 } 62 63 count -= read_ret; 64 buf += read_ret; 65 retval += read_ret; 66 } 67 68 return(retval); 69 } 70 71 static ssize_t write_large(int fd, char *buf, size_t count) { 72 size_t bytestowrite; 73 ssize_t write_ret; 74 ssize_t retval = 0; 75 76 while (count) { 77 bytestowrite = count; 78 79 if (bytestowrite >= INT_MAX) { 80 bytestowrite = INT_MAX - 1; 81 } 82 83 write_ret = write(fd, buf, bytestowrite); 84 if (write_ret < 0) { 85 retval = -1; 86 break; 87 } 88 89 if (write_ret == 0) { 90 break; 91 } 92 93 count -= write_ret; 94 buf += write_ret; 95 retval += write_ret; 96 } 97 98 return(retval); 99 } 100 101 static ssize_t read_net(int fd, void *buf, size_t count) { 102 ssize_t retval; 103 104 retval = read(fd, buf, count); 105 106 if (retval > 0) { 107 net_bytesin += retval; 108 } 109 110 return(retval); 111 } 112 113 static ssize_t write_net(int fd, void *buf, size_t count) { 114 ssize_t retval; 115 116 retval = write(fd, buf, count); 117 if (retval > 0) { 118 net_bytesout += retval; 119 } 120 121 return(retval); 122 } 123 124 static ssize_t read_large_net(int fd, void *buf, size_t count) { 125 ssize_t retval; 126 127 retval = read_large(fd, buf, count); 128 129 if (retval > 0) { 130 net_bytesin += retval; 131 } 132 133 return(retval); 134 } 135 136 static ssize_t write_large_net(int fd, void *buf, size_t count) { 137 ssize_t retval; 138 139 retval = write_large(fd, buf, count); 140 if (retval > 0) { 141 net_bytesout += retval; 142 } 143 144 return(retval); 145 } 146 147 int sync_transmit(const char *host, int port, const char *file) { 148 rsaref_MD4_CTX mdctx; 149 unsigned char md4buf[16]; 150 uint64_t filesize; 151 uint32_t blocksize; 152 uint8_t blockok; 153 ssize_t read_ret, write_ret; 154 char *buf; 155 off_t lseek_ret; 156 int retval = 0; 157 int sockfd; 158 int fd; 159 160 fd = open(file, O_RDONLY | O_LARGEFILE); 161 if (fd < 0) { 162 CHECKPOINT; 163 return(-1); 164 165 } 166 167 lseek_ret = lseek(fd, 0, SEEK_END); 168 if (lseek_ret < 0) { 169 close(fd); 170 CHECKPOINT; 171 return(-1); 172 } 173 174 filesize = lseek_ret; 175 176 lseek(fd, 0, SEEK_SET); 177 178 sockfd = net_connect_tcp(host, port); 179 if (sockfd < 0) { 180 close(fd); 181 CHECKPOINT; 182 return(-1); 183 } 184 185 blocksize = (128 * 1024); 186 187 buf = calloc(blocksize, 1); 188 if (!buf) { 189 close(fd); 190 close(sockfd); 191 CHECKPOINT; 192 return(-1); 193 } 194 195 filesize = htonll(filesize); 196 blocksize = htonl(blocksize); 197 198 write_ret = write_net(sockfd, &filesize, sizeof(filesize)); 199 if (write_ret != sizeof(filesize)) { 200 close(fd); 201 close(sockfd); 202 CHECKPOINT; 203 return(-1); 204 } 205 206 write_ret = write_net(sockfd, &blocksize, sizeof(blocksize)); 207 if (write_ret != sizeof(blocksize)) { 208 close(fd); 209 close(sockfd); 210 CHECKPOINT; 211 return(-1); 212 } 213 214 blocksize = ntohl(blocksize); 215 216 while (1) { 217 read_ret = read_large(fd, buf, blocksize); 218 if (read_ret < 0) { 219 retval = -1; 220 CHECKPOINT; 221 break; 222 } 223 224 if (read_ret == 0) { 225 CHECKPOINT; 226 break; 227 } 228 229 rsaref_MD4Init(&mdctx); 230 rsaref_MD4Update(&mdctx, buf, read_ret); 231 rsaref_MD4Final(md4buf, &mdctx); 232 233 write_ret = write_net(sockfd, md4buf, sizeof(md4buf)); 234 if (write_ret != sizeof(md4buf)) { 235 retval = -1; 236 CHECKPOINT; 237 break; 238 } 239 240 read_ret = read_net(sockfd, &blockok, sizeof(blockok)); 241 if (read_ret != sizeof(blockok)) { 242 retval = -1; 243 CHECKPOINT; 244 break; 245 } 246 247 if (!blockok) { 248 write_ret = write_large_net(sockfd, buf, blocksize); 249 if (write_ret != blocksize) { 250 retval = -1; 251 CHECKPOINT; 252 break; 253 } 254 } 255 } 256 257 close(fd); 258 close(sockfd); 259 260 return(retval); 261 } 262 263 int sync_receive(int port, const char *file) { 264 rsaref_MD4_CTX mdctx; 265 unsigned char md4buf[16], check_md4buf[16]; 266 uint64_t filesize; 267 uint32_t blocksize; 268 uint8_t blockok; 269 ssize_t cur_read_ret, read_ret, write_ret; 270 size_t bytestowrite; 271 off_t lseek_ret; 272 char *buf; 273 int sockfd, master_sockfd; 274 int retval = 0; 275 int fd; 276 int skipbytes; 277 278 fd = open(file, O_RDWR | O_CREAT | O_LARGEFILE, 0600); 279 if (fd < 0) { 280 CHECKPOINT; 281 return(-1); 282 } 283 284 master_sockfd = net_listen(port); 285 if (master_sockfd < 0) { 286 close(fd); 287 CHECKPOINT; 288 return(-1); 289 } 290 291 sockfd = accept(master_sockfd, NULL, 0); 292 if (sockfd < 0) { 293 close(fd); 294 close(master_sockfd); 295 CHECKPOINT; 296 return(-1); 297 } 298 299 read_ret = read_net(sockfd, &filesize, sizeof(filesize)); 300 if (read_ret != sizeof(filesize)) { 301 close(fd); 302 close(sockfd); 303 close(master_sockfd); 304 CHECKPOINT; 305 return(-1); 306 } 307 308 read_ret = read_net(sockfd, &blocksize, sizeof(blocksize)); 309 if (read_ret != sizeof(blocksize)) { 310 close(fd); 311 close(sockfd); 312 close(master_sockfd); 313 CHECKPOINT; 314 return(-1); 315 } 316 317 filesize = ntohll(filesize); 318 blocksize = ntohl(blocksize); 319 320 buf = calloc(blocksize, 1); 321 if (!buf) { 322 close(fd); 323 close(sockfd); 324 close(master_sockfd); 325 CHECKPOINT; 326 return(-1); 327 } 328 329 while (filesize) { 330 cur_read_ret = read_ret = read_large(fd, buf, blocksize); 331 if (read_ret < 0) { 332 retval = -1; 333 CHECKPOINT; 334 break; 335 } 336 337 bytestowrite = blocksize; 338 if (bytestowrite > filesize) { 339 bytestowrite = filesize; 340 } 341 342 if (read_ret != blocksize) { 343 memset(buf, '\0', bytestowrite); 344 read_ret = bytestowrite; 345 skipbytes = bytestowrite; 346 } else { 347 skipbytes = 0; 348 } 349 350 rsaref_MD4Init(&mdctx); 351 rsaref_MD4Update(&mdctx, buf, read_ret); 352 rsaref_MD4Final(md4buf, &mdctx); 353 354 read_ret = read_net(sockfd, check_md4buf, sizeof(check_md4buf)); 355 if (read_ret != sizeof(check_md4buf)) { 356 retval = -1; 357 CHECKPOINT; 358 break; 359 } 360 361 if (memcmp(check_md4buf, md4buf, sizeof(md4buf)) == 0) { 362 blockok = 1; 363 } else { 364 blockok = 0; 365 } 366 367 write_ret = write_net(sockfd, &blockok, sizeof(blockok)); 368 if (write_ret != sizeof(blockok)) { 369 retval = -1; 370 CHECKPOINT; 371 break; 372 } 373 374 if (blockok && skipbytes > 0) { 375 lseek_ret = lseek(fd, skipbytes, SEEK_CUR); 376 if (lseek_ret < 0) { 377 retval = -1; 378 CHECKPOINT; 379 break; 380 } 381 } 382 383 if (!blockok) { 384 read_ret = read_large_net(sockfd, buf, blocksize); 385 if (read_ret != blocksize) { 386 retval = -1; 387 CHECKPOINT; 388 break; 389 } 390 391 if (cur_read_ret) { 392 lseek_ret = lseek(fd, ((off_t) cur_read_ret) * -1, SEEK_CUR); 393 if (lseek_ret < 0) { 394 retval = -1; 395 CHECKPOINT; 396 break; 397 } 398 } 399 400 write_ret = write(fd, buf, bytestowrite); 401 if (write_ret != bytestowrite) { 402 retval = -1; 403 CHECKPOINT; 404 break; 405 } 406 } 407 408 filesize -= bytestowrite; 409 } 410 411 close(fd); 412 close(sockfd); 413 close(master_sockfd); 414 415 return(retval); 416 } 417 418 int main(int argc, char **argv) { 419 char *mode, *host, *port_str, *file; 420 int func_ret; 421 int retval = EXIT_SUCCESS; 422 int port; 423 424 if (argc < 2) { 425 return(print_help(EXIT_FAILURE)); 426 } 427 428 429 430 mode = argv[1]; 431 if (strcmp(mode, "-t") == 0) { 432 if (argc != 5) { 433 return(print_help(EXIT_FAILURE)); 434 } 435 436 host = argv[2]; 437 port_str = argv[3]; 438 file = argv[4]; 439 440 port = strtoul(port_str, NULL, 10); 441 442 func_ret = sync_transmit(host, port, file); 443 if (func_ret < 0) { 444 fprintf(stderr, "Failed.\n"); 445 retval = 1; 446 } 447 } else if (strcmp(mode, "-r") == 0) { 448 if (argc != 4) { 449 return(print_help(EXIT_FAILURE)); 450 } 451 452 port_str = argv[2]; 453 file = argv[3]; 454 455 port = strtoul(port_str, NULL, 10); 456 457 func_ret = sync_receive(port, file); 458 if (func_ret < 0) { 459 fprintf(stderr, "Failed.\n"); 460 retval = 1; 461 } 462 } else { 463 return(print_help(EXIT_FAILURE)); 464 } 465 466 printf("Bytes In: %llu, Bytes Out: %llu\n", net_bytesin, net_bytesout); 467 468 return(retval); 469 } |