Imported Upstream version 2.1.2
[platform/upstream/fdupes.git] / log.c
1 /* Copyright (c) 2018 Adrian Lopez
2
3    This software is provided 'as-is', without any express or implied
4    warranty. In no event will the authors be held liable for any damages
5    arising from the use of this software.
6
7    Permission is granted to anyone to use this software for any purpose,
8    including commercial applications, and to alter it and redistribute it
9    freely, subject to the following restrictions:
10
11    1. The origin of this software must not be misrepresented; you must not
12       claim that you wrote the original software. If you use this software
13       in a product, an acknowledgment in the product documentation would be
14       appreciated but is not required.
15    2. Altered source versions must be plainly marked as such, and must not be
16       misrepresented as being the original software.
17    3. This notice may not be removed or altered from any source distribution. */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include "fmatch.h"
23 #include "dir.h"
24 #include "log.h"
25
26 #define LOG_HEADER "[fdupes log]\n"
27
28 /* Open log file in append mode. If file exists, make sure it is a valid fdupes log file. 
29 */
30 struct log_info *log_open(char *filename, int *error)
31 {
32   struct log_info *info;
33   int is_match;
34   size_t read;
35
36   info = (struct log_info*) malloc(sizeof(struct log_info));
37   if (info == 0)
38   {
39     if (error != 0)
40       *error = LOG_ERROR_OUT_OF_MEMORY;
41
42     return 0;
43   }
44
45   info->file = fopen(filename, "a+");
46   if (info->file == 0)
47   {
48     if (error != 0)
49       *error = LOG_ERROR_FOPEN_FAILED;
50
51     free(info);
52     return 0;
53   }
54
55   fmatch(info->file, LOG_HEADER, &is_match, &read);
56   if (!is_match && read > 0)
57   {
58     if (error != 0)
59       *error = LOG_ERROR_NOT_A_LOG_FILE;
60
61     free(info);
62     return 0;
63   }
64
65   info->append = read > 0;
66
67   info->log_start = 1;
68   info->deleted = 0;
69   info->remaining = 0;
70
71   if (error != 0)
72     *error = LOG_ERROR_NONE;
73
74   return info;
75 }
76
77 /* Free linked lists holding set of deleted and remaining files.
78 */
79 void log_free_set(struct log_info *info)
80 {
81   struct log_file *f;
82   struct log_file *next;
83
84   f = info->deleted;
85   while (f != 0)
86   {
87     next = f->next;
88
89     free(f);
90
91     f = next;
92   }
93
94   f = info->remaining;
95   while (f != 0)
96   {
97     next = f->next;
98
99     free(f);
100
101     f = next;
102   }
103
104   info->deleted = 0;
105   info->remaining = 0;
106 }
107
108 /* Signal beginning of duplicate set.
109 */
110 void log_begin_set(struct log_info *info)
111 {
112   log_free_set(info);
113 }
114
115 /* Add deleted file to log.
116 */
117 int log_file_deleted(struct log_info *info, char *name)
118 {
119   struct log_file *file;
120
121   file = (struct log_file*) malloc(sizeof(struct log_file));
122   if (file == 0)
123     return 0;
124
125   file->next = info->deleted;
126   file->filename = name;
127
128   info->deleted = file;
129
130   return 1;
131 }
132
133 /* Add remaining file to log.
134 */
135 int log_file_remaining(struct log_info *info, char *name)
136 {
137   struct log_file *file;
138
139   file = (struct log_file*) malloc(sizeof(struct log_file));
140   if (file == 0)
141     return 0;
142
143   file->next = info->remaining;
144   file->filename = name;
145
146   info->remaining = file;
147
148   return 1;
149 }
150
151 /* Output log header.
152 */
153 void log_header(FILE *file)
154 {
155   fprintf(file, "%s\n", LOG_HEADER);
156 }
157
158 /* Output log timestamp.
159 */
160 void log_timestamp(FILE *file)
161 {
162   time_t t = time(NULL);
163   struct tm tm = *localtime(&t);
164
165   fprintf(file, "Log entry for %d-%02d-%02d %02d:%02d:%02d\n\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
166 }
167
168 /* Output current working directory.
169 */
170 void log_cwd(FILE *file)
171 {
172   char *cwd = getworkingdirectory();
173
174   fprintf(file, "working directory:\n  %s\n\n", cwd);
175
176   free(cwd);
177 }
178
179 /* Signal the end of a duplicate set.
180 */
181 void log_end_set(struct log_info *info)
182 {
183   struct log_file *f;
184
185   if (info->deleted == 0)
186     return;
187
188   if (info->log_start)
189   {
190     if (info->append)
191       fprintf(info->file, "---\n\n");
192     else
193       log_header(info->file);
194
195     log_timestamp(info->file);
196     log_cwd(info->file);
197
198     info->log_start = 0;
199   }
200
201   f = info->deleted;
202   do
203   {
204     fprintf(info->file, "deleted %s\n", f->filename);
205     f = f->next;
206   } while (f != 0);
207
208   f = info->remaining;
209   while (f != 0)
210   {
211     fprintf(info->file, "   left %s\n", f->filename);
212     f = f->next;
213   }
214
215   fprintf(info->file, "\n");
216
217   fflush(info->file);
218 }
219
220 /* Close log and free all memory.
221 */
222 void log_close(struct log_info *info)
223 {
224   fclose(info->file);
225
226   log_free_set(info);
227
228   free(info);
229 }