]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/file.c
libpakfire: filelist: Refactor filelist
[people/stevee/pakfire.git] / src / libpakfire / file.c
CommitLineData
221cc3ce
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2014 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
21#include <assert.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <tar.h>
28#include <time.h>
29
30#include <pakfire/constants.h>
31#include <pakfire/file.h>
9f953e68 32#include <pakfire/private.h>
221cc3ce
MT
33#include <pakfire/util.h>
34
9f953e68 35PAKFIRE_EXPORT PakfireFile pakfire_file_create() {
221cc3ce
MT
36 PakfireFile file = pakfire_calloc(1, sizeof(*file));
37 if (file) {
38 file->name = NULL;
39
40 file->prev = NULL;
41 file->next = NULL;
42 }
43
44 return file;
45}
46
d03fa9a3
MT
47PAKFIRE_EXPORT PakfireFile pakfire_file_ref(PakfireFile file) {
48 return file;
49}
50
51PAKFIRE_EXPORT PakfireFile pakfire_file_unref(PakfireFile file) {
52 return file;
53}
54
9f953e68 55PAKFIRE_EXPORT void pakfire_file_free(PakfireFile file) {
221cc3ce
MT
56 if (file->name)
57 pakfire_free(file->name);
58
59 if (file->user)
60 pakfire_free(file->user);
61 if (file->group)
62 pakfire_free(file->group);
63
64 // Update pointers in the previous and next element in the list.
65 if (file->next)
66 file->next->prev = NULL;
67 if (file->prev)
68 file->prev->next = NULL;
69
70 pakfire_free(file);
71}
72
9f953e68 73PAKFIRE_EXPORT void pakfire_file_free_all(PakfireFile file) {
221cc3ce
MT
74 file = pakfire_file_get_first(file);
75
76 while (file) {
77 PakfireFile next = file->next;
78 pakfire_file_free(file);
79
80 file = next;
81 }
82}
83
9f953e68 84PAKFIRE_EXPORT int pakfire_file_cmp(PakfireFile file1, PakfireFile file2) {
221cc3ce
MT
85 const char* name1 = pakfire_file_get_name(file1);
86 const char* name2 = pakfire_file_get_name(file2);
87
88 return strcmp(name1, name2);
89}
90
9f953e68 91PAKFIRE_EXPORT void pakfire_file_swap(PakfireFile file1, PakfireFile file2) {
221cc3ce
MT
92 PakfireFile file_prev = file1->prev;
93 PakfireFile file_next = file2->next;
94
95 if (file_prev)
96 file_prev->next = file2;
97 file2->prev = file_prev;
98
99 if (file_next)
100 file_next->prev = file1;
101 file1->next = file_next;
102
103 file2->next = file1;
104 file1->prev = file2;
105}
106
9f953e68 107PAKFIRE_EXPORT PakfireFile pakfire_file_sort(PakfireFile head) {
221cc3ce
MT
108 unsigned int count = pakfire_file_count(head);
109
110 for (unsigned int i = 0; i < count; i++) {
111 PakfireFile file = head;
112 PakfireFile next = pakfire_file_get_next(file);
113
114 while (next) {
115 if (pakfire_file_cmp(file, next) > 0) {
116 if (head == file)
117 head = next;
118
119 pakfire_file_swap(file, next);
120 }
121
122 file = next;
123 next = pakfire_file_get_next(file);
124 }
125 }
126
127 return head;
128}
129
9f953e68 130PAKFIRE_EXPORT PakfireFile pakfire_file_get_prev(PakfireFile file) {
221cc3ce
MT
131 return file->prev;
132}
133
9f953e68 134PAKFIRE_EXPORT PakfireFile pakfire_file_get_next(PakfireFile file) {
221cc3ce
MT
135 return file->next;
136}
137
9f953e68 138PAKFIRE_EXPORT PakfireFile pakfire_file_get_first(PakfireFile file) {
221cc3ce
MT
139 if (file->prev)
140 return pakfire_file_get_first(file->prev);
141
142 return file;
143}
144
9f953e68 145PAKFIRE_EXPORT PakfireFile pakfire_file_get_last(PakfireFile file) {
221cc3ce
MT
146 if (file->next)
147 return pakfire_file_get_last(file->next);
148
149 return file;
150}
151
152static PakfireFile __pakfire_file_append(PakfireFile file, PakfireFile appended_file) {
153 // Get the last file in the queue.
154 file = pakfire_file_get_last(file);
155
156 // Set the links.
157 file->next = appended_file;
158 appended_file->prev = file;
159
160 return appended_file;
161}
162
9f953e68 163PAKFIRE_EXPORT PakfireFile pakfire_file_append(PakfireFile file) {
221cc3ce
MT
164 // Create a new file object.
165 PakfireFile appended_file = pakfire_file_create();
166
167 return __pakfire_file_append(file, appended_file);
168}
169
9f953e68 170PAKFIRE_EXPORT unsigned int pakfire_file_count(PakfireFile file) {
221cc3ce
MT
171 unsigned int counter = 0;
172
173 while (file) {
174 file = pakfire_file_get_next(file);
175 ++counter;
176 }
177
178 return counter;
179}
180
181static char pakfire_file_sprintf_type(PakfireFile file) {
182 if (pakfire_file_is_dir(file))
183 return 'd';
184
185 if (pakfire_file_is_symlink(file))
186 return 'l';
187
188 if (pakfire_file_is_char(file))
189 return 'c';
190
191 return '-';
192}
193
194static char* pakfire_file_format_perms(PakfireFile file) {
195 char buffer[11];
196
197 mode_t mode = pakfire_file_get_mode(file);
198
199 buffer[0] = pakfire_file_sprintf_type(file);
200 buffer[1] = (S_IRUSR & mode) ? 'r' : '-';
201 buffer[2] = (S_IWUSR & mode) ? 'w' : '-';
202 buffer[3] = (S_IXUSR & mode) ? 'x' : '-';
203 buffer[4] = (S_IRGRP & mode) ? 'r' : '-';
204 buffer[5] = (S_IWGRP & mode) ? 'w' : '-';
205 buffer[6] = (S_IXGRP & mode) ? 'x' : '-';
206 buffer[7] = (S_IROTH & mode) ? 'r' : '-';
207 buffer[8] = (S_IWOTH & mode) ? 'w' : '-';
208 buffer[9] = (S_IXOTH & mode) ? 'x' : '-';
209 buffer[10] = '\0';
210
211 #warning TODO SUID bits, etc...
212
213 return pakfire_strdup(buffer);
214}
215
216static char* pakfire_file_format_mtime(PakfireFile file) {
217 struct tm* timer = gmtime((time_t *)&file->time);
218
219 char buffer[STRING_SIZE];
220 strftime(buffer, sizeof(buffer), "%d %b %Y %T", timer);
221
222 return pakfire_strdup(buffer);
223}
224
9f953e68 225PAKFIRE_EXPORT void pakfire_file_sprintf(PakfireFile file, char* str, size_t len) {
221cc3ce
MT
226 const char* name = pakfire_file_get_name(file);
227 ssize_t size = pakfire_file_get_size(file);
228
229 const char* user = pakfire_file_get_user(file);
230 const char* group = pakfire_file_get_group(file);
231
232 char* perms = pakfire_file_format_perms(file);
233 char* mtime = pakfire_file_format_mtime(file);
234
235 snprintf(str, len, "%s %-8s %-8s %8d %s %s", perms, user, group,
236 (int)size, mtime, name);
237
238 pakfire_free(perms);
239 pakfire_free(mtime);
240}
241
9f953e68 242PAKFIRE_EXPORT const char* pakfire_file_get_name(PakfireFile file) {
221cc3ce
MT
243 return file->name;
244}
245
9f953e68 246PAKFIRE_EXPORT void pakfire_file_set_name(PakfireFile file, const char* name) {
221cc3ce
MT
247 if (file->name)
248 pakfire_free(file->name);
249
250 if (*name == '/') {
251 file->name = pakfire_strdup(name);
252 } else {
253 asprintf(&file->name, "/%s", name);
254 }
255}
256
9f953e68 257PAKFIRE_EXPORT char pakfire_file_get_type(PakfireFile file) {
221cc3ce
MT
258 return file->type;
259}
260
9f953e68 261PAKFIRE_EXPORT void pakfire_file_set_type(PakfireFile file, char type) {
221cc3ce
MT
262 file->type = type;
263}
264
9f953e68 265PAKFIRE_EXPORT int pakfire_file_is_file(PakfireFile file) {
221cc3ce
MT
266 return (file->type == REGTYPE) || (file->type == AREGTYPE);
267}
268
9f953e68 269PAKFIRE_EXPORT int pakfire_file_is_link(PakfireFile file) {
221cc3ce
MT
270 return (file->type == LNKTYPE);
271}
272
9f953e68 273PAKFIRE_EXPORT int pakfire_file_is_symlink(PakfireFile file) {
221cc3ce
MT
274 return (file->type == SYMTYPE);
275}
276
9f953e68 277PAKFIRE_EXPORT int pakfire_file_is_char(PakfireFile file) {
221cc3ce
MT
278 return (file->type == CHRTYPE);
279}
280
9f953e68 281PAKFIRE_EXPORT int pakfire_file_is_block(PakfireFile file) {
221cc3ce
MT
282 return (file->type == BLKTYPE);
283}
284
9f953e68 285PAKFIRE_EXPORT int pakfire_file_is_dir(PakfireFile file) {
221cc3ce
MT
286 return (file->type == DIRTYPE);
287}
288
9f953e68 289PAKFIRE_EXPORT ssize_t pakfire_file_get_size(PakfireFile file) {
221cc3ce
MT
290 return file->size;
291}
292
9f953e68 293PAKFIRE_EXPORT void pakfire_file_set_size(PakfireFile file, ssize_t size) {
221cc3ce
MT
294 file->size = size;
295}
296
9f953e68 297PAKFIRE_EXPORT const char* pakfire_file_get_user(PakfireFile file) {
221cc3ce
MT
298 return file->user;
299}
300
9f953e68 301PAKFIRE_EXPORT void pakfire_file_set_user(PakfireFile file, const char* user) {
221cc3ce
MT
302 file->user = pakfire_strdup(user);
303}
304
9f953e68 305PAKFIRE_EXPORT const char* pakfire_file_get_group(PakfireFile file) {
221cc3ce
MT
306 return file->group;
307}
308
9f953e68 309PAKFIRE_EXPORT void pakfire_file_set_group(PakfireFile file, const char* group) {
221cc3ce
MT
310 file->group = pakfire_strdup(group);
311}
312
9f953e68 313PAKFIRE_EXPORT mode_t pakfire_file_get_mode(PakfireFile file) {
221cc3ce
MT
314 return file->mode;
315}
316
9f953e68 317PAKFIRE_EXPORT void pakfire_file_set_mode(PakfireFile file, mode_t mode) {
221cc3ce
MT
318 file->mode = mode;
319}
320
9f953e68 321PAKFIRE_EXPORT time_t pakfire_file_get_time(PakfireFile file) {
221cc3ce
MT
322 return file->time;
323}
324
9f953e68 325PAKFIRE_EXPORT void pakfire_file_set_time(PakfireFile file, time_t time) {
221cc3ce
MT
326 file->time = time;
327}
328
9f953e68 329PAKFIRE_EXPORT const char* pakfire_file_get_chksum(PakfireFile file) {
221cc3ce
MT
330 return file->chksum;
331}
332
9f953e68 333PAKFIRE_EXPORT void pakfire_file_set_chksum(PakfireFile file, const char* chksum) {
221cc3ce
MT
334 file->chksum = pakfire_strdup(chksum);
335}
336
337static PakfireFile pakfire_file_parse_line(char* line, unsigned int format) {
338 unsigned int i = 0;
339
340 PakfireFile file = pakfire_file_create();
341 ssize_t size;
342 mode_t mode;
343 time_t time;
344
345 unsigned int bytes_read = 0;
346
347 char* word = strtok(line, " ");
348 while (word) {
349 if (format >= 4) {
350 switch (i) {
351 // type
352 case 0:
353 pakfire_file_set_type(file, *word);
354 break;
355
356 // size
357 case 1:
358 size = atoi(word);
359 pakfire_file_set_size(file, size);
360 break;
361
362 // user
363 case 2:
364 pakfire_file_set_user(file, word);
365 break;
366
367 // group
368 case 3:
369 pakfire_file_set_group(file, word);
370 break;
371
372 // mode
373 case 4:
374 mode = atoi(word);
375 pakfire_file_set_mode(file, mode);
376 break;
377
378 // time
379 case 5:
380 time = atoi(word);
381 pakfire_file_set_time(file, time);
382 break;
383
384 // checksum
385 case 6:
386 pakfire_file_set_chksum(file, word);
387 break;
388
389 // name
390 #warning handle filenames with spaces
391 case 8:
392 pakfire_file_set_name(file, line + bytes_read);
393 break;
394 }
395
396 } else if (format >= 3) {
397 switch (i) {
398 // name
399 case 0:
400 pakfire_file_set_name(file, word);
401 break;
402
403 // type
404 case 1:
405 pakfire_file_set_type(file, *word);
406 break;
407
408 // size
409 case 2:
410 size = atoi(word);
411 pakfire_file_set_size(file, size);
412 break;
413
414 // user
415 case 3:
416 pakfire_file_set_user(file, word);
417 break;
418
419 // group
420 case 4:
421 pakfire_file_set_group(file, word);
422 break;
423
424 // mode
425 case 5:
426 mode = atoi(word);
427 pakfire_file_set_mode(file, mode);
428 break;
429
430 // time
431 case 6:
432 time = atoi(word);
433 pakfire_file_set_time(file, time);
434 break;
435
436 // checksum
437 case 7:
438 pakfire_file_set_chksum(file, word);
439 break;
440 }
441 }
442
443 // Count the bytes of the line that have been processed so far
444 // (Skip all padding spaces)
445 bytes_read += strlen(word) + 1;
446 while (*(line + bytes_read) == ' ')
447 bytes_read += 1;
448
449 word = strtok(NULL, " ");
450 ++i;
451 }
452
453 return file;
454}
455
9f953e68 456PAKFIRE_EXPORT PakfireFile pakfire_file_parse_from_file(const char* list, unsigned int format) {
221cc3ce
MT
457 PakfireFile head = NULL;
458
459 char* plist = (char *)list;
460 char line[32 * 1024];
461
462 for (;;) {
463 line[0] = '\0';
464
465 pakfire_sgets(line, sizeof(line), &plist);
466 pakfire_remove_trailing_newline(line);
467
468 if (*line == '\0')
469 break;
470
471 PakfireFile file = pakfire_file_parse_line(line, format);
472
473 if (!file)
474 continue;
475
476 if (head)
477 file = __pakfire_file_append(head, file);
478 else
479 head = file;
480 }
481
482 return head;
483}