NetSurf
file.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010 Vincent Sanders <vince@netsurf-browser.org>
3  *
4  * This file is part of NetSurf.
5  *
6  * NetSurf 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; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * \file
21  *
22  * file scheme URL handling. Based on the data fetcher by Rob Kendrick
23  *
24  * output dates and directory ordering are affected by the current locale
25  */
26 
27 #include "utils/config.h"
28 
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <stdbool.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <time.h>
40 #include <stdio.h>
41 #include <stdarg.h>
42 #ifdef HAVE_MMAP
43 #include <sys/mman.h>
44 #endif
45 #include <libwapcaplet/libwapcaplet.h>
46 
47 #include "netsurf/inttypes.h"
48 #include "utils/nsurl.h"
49 #include "utils/dirent.h"
50 #include "utils/corestrings.h"
51 #include "utils/messages.h"
52 #include "utils/utils.h"
53 #include "utils/log.h"
54 #include "utils/time.h"
55 #include "utils/ring.h"
56 #include "utils/file.h"
57 #include "netsurf/fetch.h"
58 #include "desktop/gui_internal.h"
59 
60 #include "content/dirlist.h"
61 #include "content/fetch.h"
62 #include "content/fetchers.h"
63 #include "content/fetchers/file.h"
64 
65 /* Maximum size of read buffer */
66 #define FETCH_FILE_MAX_BUF_SIZE (1024 * 1024)
67 
68 /** Context for a fetch */
71 
72  struct fetch *fetchh; /**< Handle for this fetch */
73 
74  bool aborted; /**< Flag indicating fetch has been aborted */
75  bool locked; /**< Flag indicating entry is already entered */
76 
77  nsurl *url; /**< The full url the fetch refers to */
78  char *path; /**< The actual path to be used with open() */
79 
80  time_t file_etag; /**< Request etag for file (previous st.m_time) */
81 };
82 
83 static struct fetch_file_context *ring = NULL;
84 
85 /** issue fetch callbacks with locking */
86 static inline bool fetch_file_send_callback(const fetch_msg *msg,
87  struct fetch_file_context *ctx)
88 {
89  ctx->locked = true;
90  fetch_send_callback(msg, ctx->fetchh);
91  ctx->locked = false;
92 
93  return ctx->aborted;
94 }
95 
97  const char *fmt, ...)
98 {
99  fetch_msg msg;
100  char header[64];
101  va_list ap;
102  int len;
103 
104  va_start(ap, fmt);
105  len = vsnprintf(header, sizeof header, fmt, ap);
106  va_end(ap);
107 
108  if (len >= (int)sizeof(header) || len < 0) {
109  return false;
110  }
111 
112  msg.type = FETCH_HEADER;
113  msg.data.header_or_data.buf = (const uint8_t *) header;
114  msg.data.header_or_data.len = len;
115 
116  return fetch_file_send_callback(&msg, ctx);
117 }
118 
119 /** callback to initialise the file fetcher. */
120 static bool fetch_file_initialise(lwc_string *scheme)
121 {
122  return true;
123 }
124 
125 /** callback to initialise the file fetcher. */
126 static void fetch_file_finalise(lwc_string *scheme)
127 {
128 }
129 
130 static bool fetch_file_can_fetch(const nsurl *url)
131 {
132  return true;
133 }
134 
135 /** callback to set up a file fetch context. */
136 static void *
138  nsurl *url,
139  bool only_2xx,
140  bool downgrade_tls,
141  const char *post_urlenc,
142  const struct fetch_multipart_data *post_multipart,
143  const char **headers)
144 {
145  struct fetch_file_context *ctx;
146  int i;
147  nserror ret;
148 
149  ctx = calloc(1, sizeof(*ctx));
150  if (ctx == NULL)
151  return NULL;
152 
153  ret = guit->file->nsurl_to_path(url, &ctx->path);
154  if (ret != NSERROR_OK) {
155  free(ctx);
156  return NULL;
157  }
158 
159  ctx->url = nsurl_ref(url);
160 
161  /* Scan request headers looking for If-None-Match */
162  for (i = 0; headers[i] != NULL; i++) {
163  if (strncasecmp(headers[i], "If-None-Match:",
164  SLEN("If-None-Match:")) != 0) {
165  continue;
166  }
167 
168  /* If-None-Match: "12345678" */
169  const char *d = headers[i] + SLEN("If-None-Match:");
170 
171  /* Scan to first digit, if any */
172  while (*d != '\0' && (*d < '0' || '9' < *d))
173  d++;
174 
175  /* Convert to time_t */
176  if (*d != '\0') {
177  ret = nsc_snptimet(d, strlen(d), &ctx->file_etag);
178  if (ret != NSERROR_OK) {
179  NSLOG(fetch, WARNING,
180  "Bad If-None-Match value");
181  }
182  }
183  }
184 
185  ctx->fetchh = fetchh;
186 
187  RING_INSERT(ring, ctx);
188 
189  return ctx;
190 }
191 
192 /** callback to free a file fetch */
193 static void fetch_file_free(void *ctx)
194 {
195  struct fetch_file_context *c = ctx;
196  nsurl_unref(c->url);
197  free(c->path);
198  free(ctx);
199 }
200 
201 /** callback to start a file fetch */
202 static bool fetch_file_start(void *ctx)
203 {
204  return true;
205 }
206 
207 /** callback to abort a file fetch */
208 static void fetch_file_abort(void *ctx)
209 {
210  struct fetch_file_context *c = ctx;
211 
212  /* To avoid the poll loop having to deal with the fetch context
213  * disappearing from under it, we simply flag the abort here.
214  * The poll loop itself will perform the appropriate cleanup.
215  */
216  c->aborted = true;
217 }
218 
219 static int fetch_file_errno_to_http_code(int error_no)
220 {
221  switch (error_no) {
222  case ENAMETOOLONG:
223  return 400;
224  case EACCES:
225  return 403;
226  case ENOENT:
227  return 404;
228  default:
229  break;
230  }
231 
232  return 500;
233 }
234 
235 static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
236 {
237  fetch_msg msg;
238  char buffer[1024];
239  const char *title;
240  char key[8];
241 
242  /* content is going to return error code */
243  fetch_set_http_code(ctx->fetchh, code);
244 
245  /* content type */
246  if (fetch_file_send_header(ctx, "Content-Type: text/html"))
247  goto fetch_file_process_error_aborted;
248 
249  snprintf(key, sizeof key, "HTTP%03d", code);
250  title = messages_get(key);
251 
252  snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>"
253  "<body><h1>%s</h1>"
254  "<p>Error %d while fetching file %s</p></body></html>",
255  title, title, code, nsurl_access(ctx->url));
256 
257  msg.type = FETCH_DATA;
258  msg.data.header_or_data.buf = (const uint8_t *) buffer;
259  msg.data.header_or_data.len = strlen(buffer);
260  if (fetch_file_send_callback(&msg, ctx))
261  goto fetch_file_process_error_aborted;
262 
263  msg.type = FETCH_FINISHED;
264  fetch_file_send_callback(&msg, ctx);
265 
266 fetch_file_process_error_aborted:
267  return;
268 }
269 
270 
271 /** Process object as a regular file */
273  struct stat *fdstat)
274 {
275 #ifdef HAVE_MMAP
276  fetch_msg msg;
277  char *buf = NULL;
278  size_t buf_size;
279 
280  int fd; /**< The file descriptor of the object */
281 
282  /* Check if we can just return not modified */
283  if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
284  fetch_set_http_code(ctx->fetchh, 304);
285  msg.type = FETCH_NOTMODIFIED;
286  fetch_file_send_callback(&msg, ctx);
287  return;
288  }
289 
290  fd = open(ctx->path, O_RDONLY);
291  if (fd < 0) {
292  /* process errors as appropriate */
295  return;
296  }
297 
298  /* set buffer size */
299  buf_size = fdstat->st_size;
300 
301  /* allocate the buffer storage */
302  if (buf_size > 0) {
303  buf = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, fd, 0);
304  if (buf == MAP_FAILED) {
305  msg.type = FETCH_ERROR;
306  msg.data.error = "Unable to map memory for file data buffer";
307  fetch_file_send_callback(&msg, ctx);
308  close(fd);
309  return;
310  }
311  }
312 
313  /* fetch is going to be successful */
314  fetch_set_http_code(ctx->fetchh, 200);
315 
316  /* Any callback can result in the fetch being aborted.
317  * Therefore, we _must_ check for this after _every_ call to
318  * fetch_file_send_callback().
319  */
320 
321  /* content type */
322  if (fetch_file_send_header(ctx, "Content-Type: %s",
323  guit->fetch->filetype(ctx->path))) {
324  goto fetch_file_process_aborted;
325  }
326 
327  /* content length */
328  if (fetch_file_send_header(ctx, "Content-Length: %" PRIsizet,
329  fdstat->st_size)) {
330  goto fetch_file_process_aborted;
331  }
332 
333  /* create etag */
334  if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
335  (int64_t) fdstat->st_mtime)) {
336  goto fetch_file_process_aborted;
337  }
338 
339  msg.type = FETCH_DATA;
340  msg.data.header_or_data.buf = (const uint8_t *) buf;
341  msg.data.header_or_data.len = buf_size;
342  fetch_file_send_callback(&msg, ctx);
343 
344  if (ctx->aborted == false) {
345  msg.type = FETCH_FINISHED;
346  fetch_file_send_callback(&msg, ctx);
347  }
348 
349 fetch_file_process_aborted:
350 
351  if (buf != NULL)
352  munmap(buf, buf_size);
353  close(fd);
354 #else
355  fetch_msg msg;
356  char *buf;
357  size_t buf_size;
358 
359  ssize_t tot_read = 0;
360  ssize_t res;
361 
362  FILE *infile;
363 
364  /* Check if we can just return not modified */
365  if (ctx->file_etag != 0 && ctx->file_etag == fdstat->st_mtime) {
366  fetch_set_http_code(ctx->fetchh, 304);
367  msg.type = FETCH_NOTMODIFIED;
368  fetch_file_send_callback(&msg, ctx);
369  return;
370  }
371 
372  infile = fopen(ctx->path, "rb");
373  if (infile == NULL) {
374  /* process errors as appropriate */
377  return;
378  }
379 
380  /* set buffer size */
381  buf_size = fdstat->st_size;
382  if (buf_size > FETCH_FILE_MAX_BUF_SIZE)
383  buf_size = FETCH_FILE_MAX_BUF_SIZE;
384 
385  /* allocate the buffer storage */
386  buf = malloc(buf_size);
387  if (buf == NULL) {
388  msg.type = FETCH_ERROR;
389  msg.data.error =
390  "Unable to allocate memory for file data buffer";
391  fetch_file_send_callback(&msg, ctx);
392  fclose(infile);
393  return;
394  }
395 
396  /* fetch is going to be successful */
397  fetch_set_http_code(ctx->fetchh, 200);
398 
399  /* Any callback can result in the fetch being aborted.
400  * Therefore, we _must_ check for this after _every_ call to
401  * fetch_file_send_callback().
402  */
403 
404  /* content type */
405  if (fetch_file_send_header(ctx, "Content-Type: %s",
406  guit->fetch->filetype(ctx->path))) {
407  goto fetch_file_process_aborted;
408  }
409 
410  /* content length */
411  if (fetch_file_send_header(ctx, "Content-Length: %" PRIsizet,
412  fdstat->st_size)) {
413  goto fetch_file_process_aborted;
414  }
415 
416  /* create etag */
417  if (fetch_file_send_header(ctx, "ETag: \"%10" PRId64 "\"",
418  (int64_t) fdstat->st_mtime)) {
419  goto fetch_file_process_aborted;
420  }
421 
422  /* main data loop */
423  while (tot_read < fdstat->st_size) {
424  res = fread(buf, 1, buf_size, infile);
425  if (res == 0) {
426  if (feof(infile)) {
427  msg.type = FETCH_ERROR;
428  msg.data.error = "Unexpected EOF reading file";
429  fetch_file_send_callback(&msg, ctx);
430  goto fetch_file_process_aborted;
431  } else {
432  msg.type = FETCH_ERROR;
433  msg.data.error = "Error reading file";
434  fetch_file_send_callback(&msg, ctx);
435  goto fetch_file_process_aborted;
436  }
437  }
438  tot_read += res;
439 
440  msg.type = FETCH_DATA;
441  msg.data.header_or_data.buf = (const uint8_t *) buf;
442  msg.data.header_or_data.len = res;
443  if (fetch_file_send_callback(&msg, ctx))
444  break;
445  }
446 
447  if (ctx->aborted == false) {
448  msg.type = FETCH_FINISHED;
449  fetch_file_send_callback(&msg, ctx);
450  }
451 
452 fetch_file_process_aborted:
453 
454  fclose(infile);
455  free(buf);
456 #endif
457  return;
458 }
459 
460 static char *gen_nice_title(char *path)
461 {
462  char *nice_path, *cnv, *tmp;
463  char *title;
464  int title_length;
465 
466  /* Convert path for display */
467  nice_path = malloc(strlen(path) * SLEN("&amp;") + 1);
468  if (nice_path == NULL) {
469  return NULL;
470  }
471 
472  /* Escape special HTML characters */
473  for (cnv = nice_path, tmp = path; *tmp != '\0'; tmp++) {
474  if (*tmp == '<') {
475  *cnv++ = '&';
476  *cnv++ = 'l';
477  *cnv++ = 't';
478  *cnv++ = ';';
479  } else if (*tmp == '>') {
480  *cnv++ = '&';
481  *cnv++ = 'g';
482  *cnv++ = 't';
483  *cnv++ = ';';
484  } else if (*tmp == '&') {
485  *cnv++ = '&';
486  *cnv++ = 'a';
487  *cnv++ = 'm';
488  *cnv++ = 'p';
489  *cnv++ = ';';
490  } else {
491  *cnv++ = *tmp;
492  }
493  }
494  *cnv = '\0';
495 
496  /* Construct a localised title string */
497  title_length = (cnv - nice_path) + strlen(messages_get("FileIndex"));
498  title = malloc(title_length + 1);
499 
500  if (title == NULL) {
501  free(nice_path);
502  return NULL;
503  }
504 
505  /* Set title to localised "Index of <nice_path>" */
506  snprintf(title, title_length, messages_get("FileIndex"), nice_path);
507 
508  free(nice_path);
509 
510  return title;
511 }
512 
513 /**
514  * Generate an output row of the directory listing.
515  *
516  * \param ctx The file fetching context.
517  * \param ent current directory entry.
518  * \param even is the row an even row.
519  * \param buffer The output buffer.
520  * \param buffer_len The space available in the output buffer.
521  * \return NSERROR_OK or error code on faliure.
522  */
523 static nserror
525  struct dirent *ent,
526  bool even,
527  char *buffer,
528  size_t buffer_len)
529 {
530  nserror ret;
531  char *urlpath = NULL; /* buffer for leaf entry path */
532  struct stat ent_stat; /* stat result of leaf entry */
533  char datebuf[64]; /* buffer for date text */
534  char timebuf[64]; /* buffer for time text */
535  nsurl *url;
536 
537  /* skip hidden files */
538  if (ent->d_name[0] == '.') {
539  return NSERROR_BAD_PARAMETER;
540  }
541 
542  ret = netsurf_mkpath(&urlpath, NULL, 2, ctx->path, ent->d_name);
543  if (ret != NSERROR_OK) {
544  return ret;
545  }
546 
547  if (stat(urlpath, &ent_stat) != 0) {
548  ent_stat.st_mode = 0;
549  datebuf[0] = 0;
550  timebuf[0] = 0;
551  } else {
552  /* Get date in output format. a (day of week) and b
553  * (month) are both affected by the locale
554  */
555  if (strftime((char *)&datebuf, sizeof datebuf, "%a %d %b %Y",
556  localtime(&ent_stat.st_mtime)) == 0) {
557  datebuf[0] = '-';
558  datebuf[1] = 0;
559  }
560 
561  /* Get time in output format */
562  if (strftime((char *)&timebuf, sizeof timebuf, "%H:%M",
563  localtime(&ent_stat.st_mtime)) == 0) {
564  timebuf[0] = '-';
565  timebuf[1] = 0;
566  }
567  }
568 
569  ret = guit->file->path_to_nsurl(urlpath, &url);
570  if (ret != NSERROR_OK) {
571  free(urlpath);
572  return ret;
573  }
574 
575  if (S_ISREG(ent_stat.st_mode)) {
576  /* regular file */
578  false,
579  url,
580  ent->d_name,
581  guit->fetch->filetype(urlpath),
582  ent_stat.st_size,
583  datebuf, timebuf,
584  buffer, buffer_len);
585  } else if (S_ISDIR(ent_stat.st_mode)) {
586  /* directory */
588  true,
589  url,
590  ent->d_name,
591  messages_get("FileDirectory"),
592  -1,
593  datebuf, timebuf,
594  buffer, buffer_len);
595  } else {
596  /* something else */
598  false,
599  url,
600  ent->d_name,
601  "",
602  -1,
603  datebuf, timebuf,
604  buffer, buffer_len);
605  }
606 
607  nsurl_unref(url);
608  free(urlpath);
609 
610  return NSERROR_OK;
611 }
612 
613 /**
614  * Comparison function for sorting directories.
615  *
616  * Correctly orders non zero-padded numerical parts.
617  * ie. produces "file1, file2, file10" rather than "file1, file10, file2".
618  *
619  * \param d1 first directory entry
620  * \param d2 second directory entry
621  */
622 static int dir_sort_alpha(const struct dirent **d1, const struct dirent **d2)
623 {
624  const char *s1 = (*d1)->d_name;
625  const char *s2 = (*d2)->d_name;
626 
627  while (*s1 != '\0' && *s2 != '\0') {
628  if ((*s1 >= '0' && *s1 <= '9') &&
629  (*s2 >= '0' && *s2 <= '9')) {
630  int n1 = 0, n2 = 0;
631  while (*s1 >= '0' && *s1 <= '9') {
632  n1 = n1 * 10 + (*s1) - '0';
633  s1++;
634  }
635  while (*s2 >= '0' && *s2 <= '9') {
636  n2 = n2 * 10 + (*s2) - '0';
637  s2++;
638  }
639  if (n1 != n2) {
640  return n1 - n2;
641  }
642  if (*s1 == '\0' || *s2 == '\0')
643  break;
644  }
645  if (tolower(*s1) != tolower(*s2))
646  break;
647 
648  s1++;
649  s2++;
650  }
651 
652  return tolower(*s1) - tolower(*s2);
653 }
654 
656  struct stat *fdstat)
657 {
658  fetch_msg msg;
659  char buffer[1024]; /* Output buffer */
660  bool even = false; /* formatting flag */
661  char *title; /* pretty printed title */
662  nserror err; /* result from url routines */
663  nsurl *up; /* url of parent */
664 
665  struct dirent **listing = NULL; /* directory entry listing */
666  int i; /* directory entry index */
667  int n; /* number of directory entries */
668 
669  n = scandir(ctx->path, &listing, 0, dir_sort_alpha);
670  if (n < 0) {
673  return;
674  }
675 
676  /* fetch is going to be successful */
677  fetch_set_http_code(ctx->fetchh, 200);
678 
679  /* force no-cache */
680  if (fetch_file_send_header(ctx, "Cache-Control: no-cache"))
681  goto fetch_file_process_dir_aborted;
682 
683  /* content type */
684  if (fetch_file_send_header(ctx, "Content-Type: text/html"))
685  goto fetch_file_process_dir_aborted;
686 
687  msg.type = FETCH_DATA;
688  msg.data.header_or_data.buf = (const uint8_t *) buffer;
689 
690  /* directory listing top */
691  dirlist_generate_top(buffer, sizeof buffer);
692  msg.data.header_or_data.len = strlen(buffer);
693  if (fetch_file_send_callback(&msg, ctx))
694  goto fetch_file_process_dir_aborted;
695 
696  /* directory listing title */
697  title = gen_nice_title(ctx->path);
698  dirlist_generate_title(title, buffer, sizeof buffer);
699  free(title);
700  msg.data.header_or_data.len = strlen(buffer);
701  if (fetch_file_send_callback(&msg, ctx))
702  goto fetch_file_process_dir_aborted;
703 
704  /* Print parent directory link */
705  err = nsurl_parent(ctx->url, &up);
706  if (err == NSERROR_OK) {
707  if (nsurl_compare(ctx->url, up, NSURL_COMPLETE) == false) {
708  /* different URL; have parent */
710  buffer, sizeof buffer);
711 
712  msg.data.header_or_data.len = strlen(buffer);
713  fetch_file_send_callback(&msg, ctx);
714  }
715  nsurl_unref(up);
716 
717  if (ctx->aborted)
718  goto fetch_file_process_dir_aborted;
719 
720  }
721 
722  /* directory list headings */
723  dirlist_generate_headings(buffer, sizeof buffer);
724  msg.data.header_or_data.len = strlen(buffer);
725  if (fetch_file_send_callback(&msg, ctx))
726  goto fetch_file_process_dir_aborted;
727 
728  for (i = 0; i < n; i++) {
729 
730  err = process_dir_ent(ctx, listing[i], even, buffer,
731  sizeof(buffer));
732 
733  if (err == NSERROR_OK) {
734  msg.data.header_or_data.len = strlen(buffer);
735  if (fetch_file_send_callback(&msg, ctx))
736  goto fetch_file_process_dir_aborted;
737 
738  even = !even;
739  }
740  }
741 
742  /* directory listing bottom */
743  dirlist_generate_bottom(buffer, sizeof buffer);
744  msg.data.header_or_data.len = strlen(buffer);
745  if (fetch_file_send_callback(&msg, ctx))
746  goto fetch_file_process_dir_aborted;
747 
748  msg.type = FETCH_FINISHED;
749  fetch_file_send_callback(&msg, ctx);
750 
751 fetch_file_process_dir_aborted:
752 
753  if (listing != NULL) {
754  for (i = 0; i < n; i++) {
755  free(listing[i]);
756  }
757  free(listing);
758  }
759 }
760 
761 
762 /* process a file fetch */
763 static void fetch_file_process(struct fetch_file_context *ctx)
764 {
765  struct stat fdstat; /**< The objects stat */
766 
767  if (stat(ctx->path, &fdstat) != 0) {
768  /* process errors as appropriate */
771  return;
772  }
773 
774  if (S_ISDIR(fdstat.st_mode)) {
775  /* directory listing */
776  fetch_file_process_dir(ctx, &fdstat);
777  return;
778  } else if (S_ISREG(fdstat.st_mode)) {
779  /* regular file */
780  fetch_file_process_plain(ctx, &fdstat);
781  return;
782  } else {
783  /* unhandled type of file */
784  fetch_file_process_error(ctx, 501);
785  }
786 
787  return;
788 }
789 
790 /** callback to poll for additional file fetch contents */
791 static void fetch_file_poll(lwc_string *scheme)
792 {
793  struct fetch_file_context *c, *save_ring = NULL;
794 
795  while (ring != NULL) {
796  /* Take the first entry from the ring */
797  c = ring;
798  RING_REMOVE(ring, c);
799 
800  /* Ignore fetches that have been flagged as locked.
801  * This allows safe re-entrant calls to this function.
802  * Re-entrancy can occur if, as a result of a callback,
803  * the interested party causes fetch_poll() to be called
804  * again.
805  */
806  if (c->locked == true) {
807  RING_INSERT(save_ring, c);
808  continue;
809  }
810 
811  /* Only process non-aborted fetches */
812  if (c->aborted == false) {
813  /* file fetches can be processed in one go */
815  }
816 
817  /* And now finish */
819  fetch_free(c->fetchh);
820 
821  }
822 
823  /* Finally, if we saved any fetches which were locked, put them back
824  * into the ring for next time
825  */
826  ring = save_ring;
827 }
828 
830 {
831  lwc_string *scheme = lwc_string_ref(corestring_lwc_file);
832  const struct fetcher_operation_table fetcher_ops = {
834  .acceptable = fetch_file_can_fetch,
835  .setup = fetch_file_setup,
836  .start = fetch_file_start,
837  .abort = fetch_file_abort,
838  .free = fetch_file_free,
839  .poll = fetch_file_poll,
840  .finalise = fetch_file_finalise
841  };
842 
843  return fetcher_add(scheme, &fetcher_ops);
844 }
static void * fetch_file_setup(struct fetch *fetchh, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers)
callback to set up a file fetch context.
Definition: file.c:137
nserror fetcher_add(lwc_string *scheme, const struct fetcher_operation_table *ops)
Register a fetcher for a scheme.
Definition: fetch.c:358
struct fetch * fetchh
Handle for this fetch.
Definition: file.c:72
Default operations table for files.
bool dirlist_generate_row(bool even, bool directory, nsurl *url, char *name, const char *mimetype, long long size, char *date, char *time, char *buffer, int buffer_length)
Generates the part of an HTML directory listing page that displays a row in the directory contents ta...
Definition: dirlist.c:288
nsurl * url
The full url the fetch refers to.
Definition: file.c:77
Interface to utility string handling.
bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
Compare two URLs.
Localised message support (interface).
static void fetch_file_free(void *ctx)
callback to free a file fetch
Definition: file.c:193
Interface to time operations.
static bool fetch_file_initialise(lwc_string *scheme)
callback to initialise the file fetcher.
Definition: file.c:120
file scheme fetcher handler interface.
bool locked
Flag indicating entry is already entered.
Definition: file.c:75
const char * error
Definition: fetch.h:83
static void fetch_file_poll(lwc_string *scheme)
callback to poll for additional file fetch contents
Definition: file.c:791
static bool fetch_file_can_fetch(const nsurl *url)
Definition: file.c:130
static void fetch_file_abort(void *ctx)
callback to abort a file fetch
Definition: file.c:208
bool aborted
Flag indicating fetch has been aborted.
Definition: file.c:74
static void fetch_file_process_dir(struct fetch_file_context *ctx, struct stat *fdstat)
Definition: file.c:655
nserror(* path_to_nsurl)(const char *path, struct nsurl **url)
Create a nsurl from a path.
Definition: file.h:108
Fetch POST multipart data.
Definition: fetch.h:99
bool dirlist_generate_top(char *buffer, int buffer_length)
Generates the top part of an HTML directory listing page.
Definition: dirlist.c:60
static bool fetch_file_start(void *ctx)
callback to start a file fetch
Definition: file.c:202
#define RING_INSERT(ring, element)
Insert the given item into the specified ring.
Definition: ring.h:40
bool dirlist_generate_bottom(char *buffer, int buffer_length)
Generates the bottom part of an HTML directory listing page.
Definition: dirlist.c:343
directory traversal and entry
Ring list structure.
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:84
nserror
Enumeration of error codes.
Definition: errors.h:29
struct gui_fetch_table * fetch
Fetcher table.
Definition: gui_table.h:85
Context for a fetch.
Definition: file.c:69
void fetch_remove_from_queues(struct fetch *fetch)
remove a queued fetch
Definition: fetch.c:808
int scandir(const char *dir, struct dirent ***namelist, int(*filter)(const struct dirent *), int(*compar)(const struct dirent **, const struct dirent **))
Definition: os3support.c:190
bool dirlist_generate_parent_link(const char *parent, char *buffer, int buffer_length)
Generates the part of an HTML directory listing page that links to the parent directory.
Definition: dirlist.c:201
const char *(* filetype)(const char *unix_path)
Determine the MIME type of a local file.
Definition: fetch.h:45
static char * gen_nice_title(char *path)
Definition: file.c:460
static void fetch_file_finalise(lwc_string *scheme)
callback to initialise the file fetcher.
Definition: file.c:126
nserror netsurf_mkpath(char **str, size_t *size, size_t nelm,...)
Generate a path from one or more component elemnts.
Definition: file.c:287
struct fetch_file_context * r_prev
Definition: file.c:70
Useful interned string pointers (interface).
Fetcher operations API.
Definition: fetchers.h:49
bool dirlist_generate_headings(char *buffer, int buffer_length)
Generates the part of an HTML directory listing page that displays the column headings.
Definition: dirlist.c:236
No error.
Definition: errors.h:30
#define PRIsizet
c99 standard printf formatting for size_t type
Definition: inttypes.h:53
bool(* initialise)(lwc_string *scheme)
The initialiser for the fetcher.
Definition: fetchers.h:55
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:115
struct fetch_file_context * r_next
Definition: file.c:70
#define RING_REMOVE(ring, element)
Remove the given element from the specified ring.
Definition: ring.h:53
union fetch_msg::@118 data
void fetch_set_http_code(struct fetch *fetch, long http_code)
set the http code of a fetch
Definition: fetch.c:835
void fetch_free(struct fetch *f)
Free a fetch structure and associated resources.
Definition: fetch.c:589
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
Bad Parameter.
Definition: errors.h:48
nserror nsc_snptimet(const char *str, size_t size, time_t *timep)
Parse time in seconds since epoc.
Definition: time.c:147
static bool fetch_file_send_header(struct fetch_file_context *ctx, const char *fmt,...)
Definition: file.c:96
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
static struct fetch_file_context * ring
Definition: file.c:83
Netsurf additional integer type formatting macros.
static int dir_sort_alpha(const struct dirent **d1, const struct dirent **d2)
Comparison function for sorting directories.
Definition: file.c:622
#define FETCH_FILE_MAX_BUF_SIZE
Definition: file.c:66
time_t file_etag
Request etag for file (previous st.m_time)
Definition: file.c:80
nserror nsurl_parent(const nsurl *url, nsurl **new_url)
Create a NetSurf URL object for URL with parent location of an existing URL.
char * path
The actual path to be used with open()
Definition: file.c:78
static void fetch_file_process_plain(struct fetch_file_context *ctx, struct stat *fdstat)
Process object as a regular file.
Definition: file.c:272
nserror fetch_file_register(void)
Register file scheme handler.
Definition: file.c:829
static void fetch_file_process(struct fetch_file_context *ctx)
Definition: file.c:763
static bool fetch_file_send_callback(const fetch_msg *msg, struct fetch_file_context *ctx)
issue fetch callbacks with locking
Definition: file.c:86
static nserror process_dir_ent(struct fetch_file_context *ctx, struct dirent *ent, bool even, char *buffer, size_t buffer_len)
Generate an output row of the directory listing.
Definition: file.c:524
Interface for fetchers factory.
nsurl * nsurl_ref(nsurl *url)
Increment the reference count to a NetSurf URL object.
static void fetch_file_process_error(struct fetch_file_context *ctx, int code)
Definition: file.c:235
Interface to a number of general purpose functionality.
static int fetch_file_errno_to_http_code(int error_no)
Definition: file.c:219
Information for a single fetch.
Definition: fetch.c:89
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
Fetcher message data.
Definition: fetch.h:72
Fetching of data from a URL (interface).
Generate HTML content for displaying directory listings (interface).
#define PRId64
Definition: inttypes.h:34
fetch_msg_type type
Definition: fetch.h:73
void fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
send message to fetch
Definition: fetch.c:798
nserror(* nsurl_to_path)(struct nsurl *url, char **path)
Create a path from a nsurl.
Definition: file.h:95
Interface to platform-specific fetcher operations.
struct gui_file_table * file
File table.
Definition: gui_table.h:95
Interface to core interface table.
struct fetch_msg::@118::@119 header_or_data
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:47
NetSurf URL handling (interface).
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
Generates the part of an HTML directory listing page that contains the title.
Definition: dirlist.c:142
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.