Skip to content

Commit ed5e9fa

Browse files
committed
Fix issue #95: Avoid hang on 404 directory access
- Refactor LinkTable_uninitialised_fill to avoid infinite loops and duplicate requests. - Handle curl errors in curl_process_msgs for metadata requests. - Add NULL checks in path_to_Link_recursive and path_to_LinkTable.
1 parent 08a7987 commit ed5e9fa

2 files changed

Lines changed: 69 additions & 14 deletions

File tree

src/link.c

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,33 +234,70 @@ static void LinkTable_uninitialised_fill(LinkTable *linktbl)
234234
int u;
235235
char s[STATUS_LEN];
236236
lprintf(debug, " ... ");
237+
238+
/*
239+
* Start all uninitialized requests once
240+
*/
241+
int total_uninitialized = 0;
242+
for (int i = 0; i < linktbl->num; i++) {
243+
Link *this_link = linktbl->links[i];
244+
if (this_link->type == LINK_UNINITIALISED_FILE
245+
|| this_link->type == LINK_UNINITIALISED_DIR) {
246+
Link_req_file_stat(linktbl->links[i]);
247+
total_uninitialized++;
248+
}
249+
}
250+
251+
if (total_uninitialized == 0) {
252+
lprintf(debug, "Done!\n");
253+
return;
254+
}
255+
256+
int n = total_uninitialized;
257+
int j = 0;
237258
do {
238259
u = 0;
239260
for (int i = 0; i < linktbl->num; i++) {
240261
Link *this_link = linktbl->links[i];
241262
if (this_link->type == LINK_UNINITIALISED_FILE
242263
|| this_link->type == LINK_UNINITIALISED_DIR) {
243-
Link_req_file_stat(linktbl->links[i]);
244264
u++;
245265
}
246266
}
247-
/*
248-
* Block until the gaps are filled
249-
*/
250-
int n = curl_multi_perform_once();
251-
int i = 0;
252-
int j = 0;
253-
while ((i = curl_multi_perform_once())) {
267+
268+
if (u > 0) {
254269
if (CONFIG.log_type & debug) {
255270
if (j) {
256271
erase_string(stderr, STATUS_LEN, s);
257272
}
258-
snprintf(s, STATUS_LEN, "%d / %d", n - i, n);
273+
snprintf(s, STATUS_LEN, "%d / %d", n - u, n);
259274
fprintf(stderr, "%s", s);
260275
j++;
261276
}
277+
278+
/*
279+
* Block until some handles are processed
280+
*/
281+
int n_running = curl_multi_perform_once();
282+
283+
/*
284+
* If no handles are running but u > 0, we have an error
285+
* and we must break to avoid infinite loop.
286+
*/
287+
if (n_running == 0 && u > 0) {
288+
lprintf(error, "Some links failed to initialize.\n");
289+
for (int i = 0; i < linktbl->num; i++) {
290+
Link *this_link = linktbl->links[i];
291+
if (this_link->type == LINK_UNINITIALISED_FILE
292+
|| this_link->type == LINK_UNINITIALISED_DIR) {
293+
this_link->type = LINK_INVALID;
294+
}
295+
}
296+
break;
297+
}
262298
}
263-
} while (u);
299+
} while (u > 0);
300+
264301
if (CONFIG.log_type & debug) {
265302
erase_string(stderr, STATUS_LEN, s);
266303
fprintf(stderr, "... Done!\n");
@@ -802,6 +839,9 @@ LinkTable *path_to_LinkTable(const char *path)
802839
tmp_link = &link_cpy;
803840
} else {
804841
link = path_to_Link(path);
842+
if (!link) {
843+
return NULL;
844+
}
805845
tmp_link = link;
806846
}
807847

@@ -837,6 +877,10 @@ LinkTable *path_to_LinkTable(const char *path)
837877

838878
static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
839879
{
880+
if (!linktbl || !path || path[0] == '\0') {
881+
return NULL;
882+
}
883+
840884
/*
841885
* skip the leading '/' if it exists
842886
*/
@@ -847,12 +891,15 @@ static Link *path_to_Link_recursive(char *path, LinkTable *linktbl)
847891
/*
848892
* remove the last '/' if it exists
849893
*/
850-
char *slash = &(path[strnlen(path, MAX_PATH_LEN) - 1]);
851-
if (*slash == '/') {
852-
*slash = '\0';
894+
size_t path_len = strnlen(path, MAX_PATH_LEN);
895+
if (path_len > 0) {
896+
char *slash = &(path[path_len - 1]);
897+
if (*slash == '/') {
898+
*slash = '\0';
899+
}
853900
}
854901

855-
slash = strchr(path, '/');
902+
char *slash = strchr(path, '/');
856903
if (slash == NULL) {
857904
/*
858905
* We cannot find another '/', we have reached the last level

src/network.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
135135
} else {
136136
lprintf(error, "%d - %s <%s>\n", curl_msg->data.result,
137137
curl_easy_strerror(curl_msg->data.result), url);
138+
/*
139+
* If the transfer failed, and we are querying the file size,
140+
* we must mark the link as invalid so that the link table
141+
* fill function can proceed.
142+
*/
143+
if (ts->type == FILESTAT) {
144+
ts->link->type = LINK_INVALID;
145+
}
138146
}
139147
curl_multi_remove_handle(curl_multi, curl);
140148
/*

0 commit comments

Comments
 (0)