touch.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. /*
  3. * Copyright (C) 2022, 2023 Ferass El Hafidi <vitali64pmemail@protonmail.com>
  4. */
  5. #define _XOPEN_SOURCE /* WHY???? */
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <stdint.h>
  13. #include <errno.h>
  14. #include <time.h>
  15. /* Requirements in common.h */
  16. #define REQ_PRINT_USAGE
  17. #define REQ_ERRPRINT
  18. #include "../common/common.h"
  19. #define DESCRIPTION "Change file access and modification times."
  20. #define OPERANDS "[-acm] [-t [[CC]YY]MMDDhhmm[.SS]] file..."
  21. int main(int argc, char *argv[]) {
  22. int file, i, argument;
  23. struct timespec times[2];
  24. struct tm time_tm = { 0 }; /* Used by strptime() */
  25. char param[256], *argv0 = strdup(argv[0]), *datefmt, *date_string;
  26. for (i = 0; i < 256 && (param[i] = 0); i++);
  27. while ((argument = getopt(argc, argv, "acmt:")) != -1) {
  28. if (argument == '?')
  29. return print_usage(argv0, DESCRIPTION, OPERANDS, VERSION);
  30. else if (argument == 't') {
  31. switch (strlen(optarg)) {
  32. case 8: /* MMDDhhmm */
  33. datefmt = "%m%d%H%M";
  34. break;
  35. case 10: /* YYMMDDhhmm */
  36. datefmt = "%y%m%d%H%M";
  37. break;
  38. case 12: /* CCYYMMDDhhmm */
  39. datefmt = "%C%y%m%d%H%M";
  40. break;
  41. case 13: /* MMDDhhmm.SS */
  42. datefmt = "%m%d%H%M.%S";
  43. break;
  44. case 15: /* YYMMDDhhmm.SS */
  45. datefmt = "%y%m%d%H%M.%S";
  46. break;
  47. case 17: /* CCYYMMDDhhmm.SS */
  48. datefmt = "%C%y%m%d%H%M.%S";
  49. break;
  50. default:
  51. return print_usage(argv0, DESCRIPTION, OPERANDS, VERSION);
  52. }
  53. date_string = optarg;
  54. }
  55. param[(uint8_t)argument] = 1;
  56. } argc -= optind; argv += optind;
  57. if (argc < 1) return print_usage(argv0, DESCRIPTION, OPERANDS, VERSION);
  58. if (param['t']) {
  59. strptime(date_string, datefmt, &time_tm);
  60. if (errno) return errprint(argv0, "strptime()", errno);
  61. if (param['a'])
  62. times[0].tv_sec = mktime(&time_tm);
  63. if (param['m'])
  64. times[1].tv_sec = mktime(&time_tm);
  65. times[0].tv_nsec = 0; times[1].tv_nsec = 0;
  66. } else {
  67. times[0].tv_sec = time(NULL); times[1].tv_sec = time(NULL);
  68. times[0].tv_nsec = 0; times[1].tv_nsec = 0;
  69. }
  70. for (i = 0; i < argc; i++) {
  71. if (access(argv[i], F_OK) == -1 && errno == ENOENT && !param['c']) {
  72. /* File does not exist */
  73. file = creat(argv[i],
  74. S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
  75. futimens(file, times);
  76. } else if (access(argv[i], F_OK) != -1)
  77. /* File exists */
  78. utimensat(AT_FDCWD, argv[i], times, 0);
  79. else if (errno != ENOENT) return errprint(argv0, argv[i], errno);
  80. }
  81. return errprint(argv0, NULL, errno);
  82. }