OLD | NEW |
1 /////////////////////////////////////////////////////////////////////////////// | 1 /////////////////////////////////////////////////////////////////////////////// |
2 // | 2 // |
3 /// \file file_io.c | 3 /// \file file_io.c |
4 /// \brief File opening, unlinking, and closing | 4 /// \brief File opening, unlinking, and closing |
5 // | 5 // |
6 // Author: Lasse Collin | 6 // Author: Lasse Collin |
7 // | 7 // |
8 // This file has been put into the public domain. | 8 // This file has been put into the public domain. |
9 // You can do whatever you want with this file. | 9 // You can do whatever you want with this file. |
10 // | 10 // |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 static int stdout_flags = 0; | 46 static int stdout_flags = 0; |
47 #endif | 47 #endif |
48 | 48 |
49 | 49 |
50 static bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size); | 50 static bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size); |
51 | 51 |
52 | 52 |
53 extern void | 53 extern void |
54 io_init(void) | 54 io_init(void) |
55 { | 55 { |
56 » // Make sure that stdin, stdout, and and stderr are connected to | 56 » // Make sure that stdin, stdout, and stderr are connected to |
57 // a valid file descriptor. Exit immediately with exit code ERROR | 57 // a valid file descriptor. Exit immediately with exit code ERROR |
58 // if we cannot make the file descriptors valid. Maybe we should | 58 // if we cannot make the file descriptors valid. Maybe we should |
59 // print an error message, but our stderr could be screwed anyway. | 59 // print an error message, but our stderr could be screwed anyway. |
60 tuklib_open_stdxxx(E_ERROR); | 60 tuklib_open_stdxxx(E_ERROR); |
61 | 61 |
62 #ifndef TUKLIB_DOSLIKE | 62 #ifndef TUKLIB_DOSLIKE |
63 // If fchown() fails setting the owner, we warn about it only if | 63 // If fchown() fails setting the owner, we warn about it only if |
64 // we are root. | 64 // we are root. |
65 warn_fchown = geteuid() == 0; | 65 warn_fchown = geteuid() == 0; |
66 #endif | 66 #endif |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 if (pair->src_fd == -1) { | 363 if (pair->src_fd == -1) { |
364 // If we were interrupted, don't display any error message. | 364 // If we were interrupted, don't display any error message. |
365 if (errno == EINTR) { | 365 if (errno == EINTR) { |
366 // All the signals that don't have SA_RESTART | 366 // All the signals that don't have SA_RESTART |
367 // set user_abort. | 367 // set user_abort. |
368 assert(user_abort); | 368 assert(user_abort); |
369 return true; | 369 return true; |
370 } | 370 } |
371 | 371 |
372 #ifdef O_NOFOLLOW | 372 #ifdef O_NOFOLLOW |
373 » » // Give an understandable error message in if reason | 373 » » // Give an understandable error message if the reason |
374 // for failing was that the file was a symbolic link. | 374 // for failing was that the file was a symbolic link. |
375 // | 375 // |
376 // Note that at least Linux, OpenBSD, Solaris, and Darwin | 376 // Note that at least Linux, OpenBSD, Solaris, and Darwin |
377 » » // use ELOOP to indicate if O_NOFOLLOW was the reason | 377 » » // use ELOOP to indicate that O_NOFOLLOW was the reason |
378 // that open() failed. Because there may be | 378 // that open() failed. Because there may be |
379 // directories in the pathname, ELOOP may occur also | 379 // directories in the pathname, ELOOP may occur also |
380 // because of a symlink loop in the directory part. | 380 // because of a symlink loop in the directory part. |
381 » » // So ELOOP doesn't tell us what actually went wrong. | 381 » » // So ELOOP doesn't tell us what actually went wrong, |
| 382 » » // and this stupidity went into POSIX-1.2008 too. |
382 // | 383 // |
383 // FreeBSD associates EMLINK with O_NOFOLLOW and | 384 // FreeBSD associates EMLINK with O_NOFOLLOW and |
384 // Tru64 uses ENOTSUP. We use these directly here | 385 // Tru64 uses ENOTSUP. We use these directly here |
385 // and skip the lstat() call and the associated race. | 386 // and skip the lstat() call and the associated race. |
386 // I want to hear if there are other kernels that | 387 // I want to hear if there are other kernels that |
387 // fail with something else than ELOOP with O_NOFOLLOW. | 388 // fail with something else than ELOOP with O_NOFOLLOW. |
388 bool was_symlink = false; | 389 bool was_symlink = false; |
389 | 390 |
390 # if defined(__FreeBSD__) || defined(__DragonFly__) | 391 # if defined(__FreeBSD__) || defined(__DragonFly__) |
391 if (errno == EMLINK) | 392 if (errno == EMLINK) |
392 was_symlink = true; | 393 was_symlink = true; |
393 | 394 |
394 # elif defined(__digital__) && defined(__unix__) | 395 # elif defined(__digital__) && defined(__unix__) |
395 if (errno == ENOTSUP) | 396 if (errno == ENOTSUP) |
396 was_symlink = true; | 397 was_symlink = true; |
397 | 398 |
398 # elif defined(__NetBSD__) | 399 # elif defined(__NetBSD__) |
399 » » // FIXME? As of 2008-11-20, NetBSD doesn't document what | 400 » » // As of 2010-09-05, NetBSD doesn't document what errno is |
400 » » // errno is used with O_NOFOLLOW. It seems to be EFTYPE, | 401 » » // used with O_NOFOLLOW. It is EFTYPE though, and I |
401 » » // but since it isn't documented, it may be wrong to rely | 402 » » // understood that is very unlikely to change even though |
402 » » // on it here. | 403 » » // it is undocumented. |
403 if (errno == EFTYPE) | 404 if (errno == EFTYPE) |
404 was_symlink = true; | 405 was_symlink = true; |
405 | 406 |
406 # else | 407 # else |
407 if (errno == ELOOP && !follow_symlinks) { | 408 if (errno == ELOOP && !follow_symlinks) { |
408 const int saved_errno = errno; | 409 const int saved_errno = errno; |
409 struct stat st; | 410 struct stat st; |
410 if (lstat(pair->src_name, &st) == 0 | 411 if (lstat(pair->src_name, &st) == 0 |
411 && S_ISLNK(st.st_mode)) | 412 && S_ISLNK(st.st_mode)) |
412 was_symlink = true; | 413 was_symlink = true; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 // the permissions, and when unlinking. | 450 // the permissions, and when unlinking. |
450 if (fstat(pair->src_fd, &pair->src_st)) | 451 if (fstat(pair->src_fd, &pair->src_st)) |
451 goto error_msg; | 452 goto error_msg; |
452 | 453 |
453 if (S_ISDIR(pair->src_st.st_mode)) { | 454 if (S_ISDIR(pair->src_st.st_mode)) { |
454 message_warning(_("%s: Is a directory, skipping"), | 455 message_warning(_("%s: Is a directory, skipping"), |
455 pair->src_name); | 456 pair->src_name); |
456 goto error; | 457 goto error; |
457 } | 458 } |
458 | 459 |
459 » if (reg_files_only) { | 460 » if (reg_files_only && !S_ISREG(pair->src_st.st_mode)) { |
460 » » if (!S_ISREG(pair->src_st.st_mode)) { | 461 » » message_warning(_("%s: Not a regular file, skipping"), |
461 » » » message_warning(_("%s: Not a regular file, " | 462 » » » » pair->src_name); |
462 » » » » » "skipping"), pair->src_name); | 463 » » goto error; |
463 » » » goto error; | 464 » } |
464 » » } | |
465 | 465 |
466 // These are meaningless on Windows. | |
467 #ifndef TUKLIB_DOSLIKE | 466 #ifndef TUKLIB_DOSLIKE |
| 467 if (reg_files_only && !opt_force) { |
468 if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) { | 468 if (pair->src_st.st_mode & (S_ISUID | S_ISGID)) { |
469 // gzip rejects setuid and setgid files even | 469 // gzip rejects setuid and setgid files even |
470 // when --force was used. bzip2 doesn't check | 470 // when --force was used. bzip2 doesn't check |
471 // for them, but calls fchown() after fchmod(), | 471 // for them, but calls fchown() after fchmod(), |
472 // and many systems automatically drop setuid | 472 // and many systems automatically drop setuid |
473 // and setgid bits there. | 473 // and setgid bits there. |
474 // | 474 // |
475 // We accept setuid and setgid files if | 475 // We accept setuid and setgid files if |
476 // --force was used. We drop these bits | 476 // --force was used. We drop these bits |
477 // explicitly in io_copy_attr(). | 477 // explicitly in io_copy_attr(). |
478 message_warning(_("%s: File has setuid or " | 478 message_warning(_("%s: File has setuid or " |
479 "setgid bit set, skipping"), | 479 "setgid bit set, skipping"), |
480 pair->src_name); | 480 pair->src_name); |
481 goto error; | 481 goto error; |
482 } | 482 } |
483 | 483 |
484 if (pair->src_st.st_mode & S_ISVTX) { | 484 if (pair->src_st.st_mode & S_ISVTX) { |
485 message_warning(_("%s: File has sticky bit " | 485 message_warning(_("%s: File has sticky bit " |
486 "set, skipping"), | 486 "set, skipping"), |
487 pair->src_name); | 487 pair->src_name); |
488 goto error; | 488 goto error; |
489 } | 489 } |
490 | 490 |
491 if (pair->src_st.st_nlink > 1) { | 491 if (pair->src_st.st_nlink > 1) { |
492 message_warning(_("%s: Input file has more " | 492 message_warning(_("%s: Input file has more " |
493 "than one hard link, " | 493 "than one hard link, " |
494 "skipping"), pair->src_name); | 494 "skipping"), pair->src_name); |
495 goto error; | 495 goto error; |
496 } | 496 } |
| 497 } |
497 #endif | 498 #endif |
498 } | |
499 | 499 |
500 return false; | 500 return false; |
501 | 501 |
502 error_msg: | 502 error_msg: |
503 message_error("%s: %s", pair->src_name, strerror(errno)); | 503 message_error("%s: %s", pair->src_name, strerror(errno)); |
504 error: | 504 error: |
505 (void)close(pair->src_fd); | 505 (void)close(pair->src_fd); |
506 return true; | 506 return true; |
507 } | 507 } |
508 | 508 |
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
948 strerror(errno)); | 948 strerror(errno)); |
949 return true; | 949 return true; |
950 } | 950 } |
951 | 951 |
952 pair->dest_pending_sparse = 0; | 952 pair->dest_pending_sparse = 0; |
953 } | 953 } |
954 } | 954 } |
955 | 955 |
956 return io_write_buf(pair, buf->u8, size); | 956 return io_write_buf(pair, buf->u8, size); |
957 } | 957 } |
OLD | NEW |