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 get 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 :
|