Line data Source code
1 : /* 2 : * Copyright (C) 2014 Andrea Mazzoleni 3 : * 4 : * This program is free software: you can redistribute it and/or modify 5 : * it under the terms of the GNU General Public License as published by 6 : * the Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This program is distributed in the hope that it will be useful, 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 : * GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License 15 : * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 : */ 17 : 18 : #include "portable.h" 19 : 20 : #include "support.h" 21 : #include "elem.h" 22 : #include "state.h" 23 : #include "handle.h" 24 : 25 1 : void state_touch(struct snapraid_state* state) 26 : { 27 : tommy_node* i; 28 : char esc_buffer[ESC_MAX]; 29 : 30 1 : msg_progress("Setting sub-second timestamps...\n"); 31 : 32 : /* for all disks */ 33 7 : for (i = state->disklist; i != 0; i = i->next) { 34 6 : struct snapraid_disk* disk = i->data; 35 : tommy_node* j; 36 : 37 : /* for all files */ 38 5734 : for (j = disk->filelist; j != 0; j = j->next) { 39 5728 : struct snapraid_file* file = j->data; 40 : 41 : /* if the file has a zero nanosecond timestamp */ 42 : /* note that symbolic links are not in the file list */ 43 : /* and then are not processed */ 44 5728 : if (file->mtime_nsec == 0) { 45 : char path[PATH_MAX]; 46 : struct stat st; 47 : int f; 48 : int ret; 49 : int nsec; 50 : int flags; 51 : 52 16 : pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub); 53 : 54 : /* set a new nanosecond timestamp different than 0 */ 55 : do { 56 : uint32_t nano; 57 : 58 : /* get a random nanosecond value */ 59 16 : if (randomize(&nano, sizeof(nano)) != 0) { 60 : /* LCOV_EXCL_START */ 61 : log_fatal("Failed to retrieve random values.\n"); 62 : exit(EXIT_FAILURE); 63 : /* LCOV_EXCL_STOP */ 64 : } 65 : 66 16 : nsec = nano % 1000000000; 67 16 : } while (nsec == 0); 68 : 69 : /* O_BINARY: open as binary file (Windows only) */ 70 : /* O_NOFOLLOW: do not follow links to ensure to open the real file */ 71 16 : flags = O_BINARY | O_NOFOLLOW; 72 : #ifdef _WIN32 73 : /* in Windows we must have write access at the file */ 74 : flags |= O_RDWR; 75 : #else 76 : /* in all others platforms, read access is enough */ 77 16 : flags |= O_RDONLY; 78 : #endif 79 : 80 : /* open it */ 81 16 : f = open(path, flags); 82 16 : if (f == -1) { 83 : /* LCOV_EXCL_START */ 84 : log_fatal("Error opening file '%s'. %s.\n", path, strerror(errno)); 85 : continue; 86 : /* LCOV_EXCL_STOP */ 87 : } 88 : 89 : /* get the present timestamp, that may be different than the one */ 90 : /* in the content file */ 91 16 : ret = fstat(f, &st); 92 16 : if (ret == -1) { 93 : /* LCOV_EXCL_START */ 94 : close(f); 95 : log_fatal("Error accessing file '%s'. %s.\n", path, strerror(errno)); 96 : continue; 97 : /* LCOV_EXCL_STOP */ 98 : } 99 : 100 : /* set the tweaked modification time, with new nano seconds */ 101 16 : ret = fmtime(f, st.st_mtime, nsec); 102 16 : if (ret != 0) { 103 : /* LCOV_EXCL_START */ 104 : close(f); 105 : log_fatal("Error timing file '%s'. %s.\n", path, strerror(errno)); 106 : continue; 107 : /* LCOV_EXCL_STOP */ 108 : } 109 : 110 : /* uses fstat again to get the present timestamp */ 111 : /* this is needed because the value read */ 112 : /* may be different than the written one */ 113 16 : ret = fstat(f, &st); 114 16 : if (ret == -1) { 115 : /* LCOV_EXCL_START */ 116 : close(f); 117 : log_fatal("Error accessing file '%s'. %s.\n", path, strerror(errno)); 118 : continue; 119 : /* LCOV_EXCL_STOP */ 120 : } 121 : 122 : /* close it */ 123 16 : ret = close(f); 124 16 : if (ret != 0) { 125 : /* LCOV_EXCL_START */ 126 : log_fatal("Error closing file '%s'. %s.\n", path, strerror(errno)); 127 : continue; 128 : /* LCOV_EXCL_STOP */ 129 : } 130 : 131 : /* set the same nanosecond value in the content file */ 132 : /* note that if the seconds value is already matching */ 133 : /* the file won't be synced because the content file will */ 134 : /* contain the new updated timestamp */ 135 16 : file->mtime_nsec = STAT_NSEC(&st); 136 : 137 : /* state changed, we need to update it */ 138 16 : state->need_write = 1; 139 : 140 16 : log_tag("touch:%s:%s: %" PRIu64 ".%d\n", disk->name, esc_tag(file->sub, esc_buffer), (uint64_t)st.st_mtime, STAT_NSEC(&st)); 141 16 : msg_info("touch %s\n", fmt_term(disk, file->sub, esc_buffer)); 142 : } 143 : } 144 : } 145 1 : } 146 :