logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git

truncate.c (2726B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include "../lib/bitmasks.h" // FIELD_CLR
  6. #include "../lib/truncation.h" // parse_size
  7. #include <assert.h>
  8. #include <errno.h>
  9. #include <fcntl.h> // open
  10. #include <stdbool.h>
  11. #include <stdio.h> // fprintf
  12. #include <stdlib.h> // abort
  13. #include <string.h> // strerror
  14. #include <sys/stat.h>
  15. #include <unistd.h> // getopt
  16. const char *argv0 = "truncate";
  17. static void
  18. usage(void)
  19. {
  20. fprintf(stderr, "Usage: truncate [-co] [-r ref_file] [-s size] file...\n");
  21. }
  22. int
  23. main(int argc, char *argv[])
  24. {
  25. int open_flags = O_WRONLY | O_CREAT | O_NONBLOCK;
  26. bool size_set = false;
  27. struct truncation tr = {
  28. .op = OP_SET,
  29. .size = 0,
  30. };
  31. char *ref_file = NULL;
  32. int c = -1;
  33. while((c = getopt(argc, argv, ":cr:s:")) != -1)
  34. {
  35. switch(c)
  36. {
  37. case 'c':
  38. FIELD_CLR(open_flags, O_CREAT);
  39. break;
  40. case 'r':
  41. if(size_set)
  42. {
  43. fprintf(stderr, "truncate: error: Truncation size can only be set once\n");
  44. usage();
  45. return 1;
  46. }
  47. ref_file = optarg;
  48. size_set = true;
  49. break;
  50. case 's':
  51. if(size_set)
  52. {
  53. fprintf(stderr, "truncate: error: Truncation size can only be set once\n");
  54. usage();
  55. return 1;
  56. }
  57. if(parse_size(optarg, &tr) < 0)
  58. {
  59. usage();
  60. return 1;
  61. }
  62. size_set = true;
  63. break;
  64. case ':':
  65. fprintf(stderr, "truncate: error: Missing operand for option: '-%c'\n", optopt);
  66. usage();
  67. return 1;
  68. case '?':
  69. fprintf(stderr, "truncate: error: Unrecognised option: '-%c'\n", optopt);
  70. usage();
  71. return 1;
  72. default:
  73. abort();
  74. }
  75. }
  76. argc -= optind;
  77. argv += optind;
  78. if(argc < 1) usage();
  79. if(!size_set)
  80. {
  81. fprintf(stderr,
  82. "truncate: error: target size wasn't set, you need to pass one of -d / -r / -s\n");
  83. return 1;
  84. }
  85. if(ref_file != NULL)
  86. {
  87. assert(errno == 0);
  88. struct stat ref_stats;
  89. if(stat(optarg, &ref_stats) < 0)
  90. {
  91. fprintf(stderr,
  92. "truncate: error: Couldn't get status for file '%s': %s\n",
  93. optarg,
  94. strerror(errno));
  95. return 1;
  96. }
  97. tr.op = OP_SET;
  98. tr.size = ref_stats.st_size;
  99. }
  100. for(int argi = 0; argi < argc; argi++)
  101. {
  102. assert(errno == 0);
  103. char *arg = argv[argi];
  104. int fd = open(arg, open_flags);
  105. if(fd < 0)
  106. {
  107. fprintf(stderr, "truncate: error: Failed to open '%s': %s\n", arg, strerror(errno));
  108. return 1;
  109. }
  110. assert(errno == 0);
  111. if(apply_truncation(fd, tr, arg) < 0) return 1;
  112. if(close(fd) < 0)
  113. {
  114. fprintf(stderr, "truncate: error: Failed closing fd for '%s': %s\n", arg, strerror(errno));
  115. return 1;
  116. }
  117. }
  118. return 0;
  119. }