-
Notifications
You must be signed in to change notification settings - Fork 1
/
site_index.c
124 lines (105 loc) · 3.11 KB
/
site_index.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#define _POSIX_C_SOURCE 200809L // for fdopen()
#define _BSD_SOURCE // for scandir() and alphasort()
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#define MAX_PATH_LEN 4096
const char* index_file_ext = ".idx";
static void free_dents(struct dirent **dents, int num_dents)
{
for (int i = 0; i < num_dents; ++i) {
free(dents[i]);
}
free(dents);
}
static int ends_with(const char *s, const char *end)
{
size_t slen = strlen(s);
size_t endlen = strlen(end);
return slen >= endlen && strcmp(&s[slen - endlen], end) == 0;
}
static int filter_dents(const struct dirent *dent)
{
return ends_with(dent->d_name, index_file_ext);
}
int write_site_index(const char *dirname)
{
char temp_path[MAX_PATH_LEN];
char actual_path[MAX_PATH_LEN];
int tempfile_exists = 0;
int fd = -1;
FILE *f = NULL;
struct dirent **dents = NULL;
int num_dents = 0;
if (
snprintf(actual_path, MAX_PATH_LEN, "%s/index.txt", dirname) >= MAX_PATH_LEN ||
snprintf(temp_path, MAX_PATH_LEN, "%s/.index.txt.tmp.XXXXXX", dirname) >= MAX_PATH_LEN
) {
fprintf(stderr, "Cannot write site index - path name too long.\n");
goto fail;
}
fd = mkstemp(temp_path);
if (fd == -1) {
perror("Failed to open temporary site index file");
goto fail;
}
tempfile_exists = 1;
f = fdopen(fd, "wb");
if (f == NULL) {
perror("Failed to write site index - fdopen() failed");
goto fail;
}
fd = -1; // Now owned by `f`
num_dents = scandir(dirname, &dents, &filter_dents, &alphasort);
if (num_dents == -1) {
perror("Failed to write site index - directory scan failed");
goto fail;
}
for (int i = 0; i < num_dents; ++i) {
char entry[MAX_PATH_LEN];
size_t len = strlen(dents[i]->d_name);
if (len < MAX_PATH_LEN && len > strlen(index_file_ext)) {
strncpy(entry, dents[i]->d_name, MAX_PATH_LEN);
entry[strlen(entry) - strlen(index_file_ext)] = '\0';
if (fprintf(f, "%s\n", entry) < 0) {
perror("Failed to write site index - fprintf() failed");
goto fail;
}
} else {
fprintf(stderr, "Skipping weird file name while writing site index: %s\n", dents[i]->d_name);
}
}
free_dents(dents, num_dents);
dents = NULL;
int close_ok = (fclose(f) == 0);
f = NULL;
if (!close_ok) {
perror("Failed to write site index - fclose() failed");
goto fail;
}
if (rename(temp_path, actual_path) == -1) {
perror("Failed to write site index - rename() failed");
goto fail;
}
tempfile_exists = 0;
return 1;
fail:
if (tempfile_exists) {
if (unlink(temp_path) == -1) {
perror("Failed to delete temporary file while writing site index");
}
}
if (f != NULL) {
fclose(f);
}
if (fd != -1) {
close(fd);
}
if (dents != NULL) {
free_dents(dents, num_dents);
}
return 0;
}