Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2020-2023 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : *
4 : : * Redistribution and use in source and binary forms, with or without
5 : : * modification, are permitted provided that the following conditions
6 : : * are met:
7 : : * 1. Redistributions of source code must retain the above copyright
8 : : * notice, this list of conditions and the following disclaimer
9 : : * in this position and unchanged.
10 : : * 2. Redistributions in binary form must reproduce the above copyright
11 : : * notice, this list of conditions and the following disclaimer in the
12 : : * documentation and/or other materials provided with the distribution.
13 : : *
14 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 : : */
25 : :
26 : : #include <sys/stat.h>
27 : : #include <sys/param.h>
28 : :
29 : : #include <stdio.h>
30 : : #include <errno.h>
31 : :
32 : : #include "pkg.h"
33 : : #include "private/pkg.h"
34 : : #include "private/event.h"
35 : : #include "private/utils.h"
36 : : #include "private/fetch.h"
37 : :
38 : : int
39 : 289 : file_open(struct pkg_repo *repo, struct fetch_item *fi)
40 : : {
41 : : struct stat st;
42 : 289 : const char *u = fi->url;
43 : 289 : size_t len = strlen(u);
44 : :
45 [ - + ]: 289 : if (len > 5)
46 : 289 : u += 5; /* file: */
47 [ - + ]: 289 : if (len < 8) {
48 : 0 : pkg_emit_error("Invalid url: %s'\n', "
49 : 0 : "file://<absolutepath> expected", fi->url);
50 : 0 : return (EPKG_FATAL);
51 : : }
52 [ + + ]: 289 : if (strncmp(u, "//", 2) != 0) {
53 : 6 : pkg_emit_error("invalid url: '%s'\n", fi->url);
54 : 6 : return (EPKG_FATAL);
55 : : }
56 : 283 : u+=2;
57 : : /* if we don't have a '/' it means we have a host FQDN component, otherwise just proceed */
58 : : /* we can fetch local files only, so we accept the localhost FQDN */
59 : : /* TODO: consider accepting gethostname/getdomainname and combinations of these. */
60 : : /* TODO: delegate to curl to fetch any URL, btw. curl bails on this as well. */
61 [ + + ]: 283 : if (*u != '/') {
62 : 29 : char fqdn[256]="";
63 : 29 : char *path = strchr(u+1, '/');
64 [ + - ]: 29 : if (path == NULL) {
65 : 0 : pkg_emit_error("Invalid url: '%s',\n"
66 : 0 : "file:///<path> or file://localhost/<path> expected.", fi->url);
67 : 0 : return (EPKG_FATAL);
68 : : }
69 [ - + ]: 29 : strncat(fqdn, u, MIN(255, path-u));
70 [ + + ]: 29 : if (0 != strncmp("localhost", fqdn, sizeof(fqdn))) {
71 : 24 : pkg_emit_error("Invalid url: '%s'\n"
72 : 24 : "file:///<path> or file://localhost/<path> expected.", fi->url);
73 : 24 : return (EPKG_FATAL);
74 : : }
75 : 5 : u = path;
76 : 5 : }
77 [ + + ]: 259 : if (stat(u, &st) == -1) {
78 [ - + ]: 12 : if (!repo->silent)
79 : 24 : pkg_emit_error("%s: %s", fi->url,
80 : 12 : strerror(errno));
81 : 12 : return (EPKG_FATAL);
82 : : }
83 : 247 : fi->size = st.st_size;
84 [ + + ]: 247 : if (st.st_mtime <= fi->mtime)
85 : 104 : return (EPKG_UPTODATE);
86 : :
87 : 143 : pkg_dbg(PKG_DBG_FETCH, 1, "mtime: local %ld, remote %ld", st.st_mtime, fi->mtime);
88 : 143 : repo->fh = fopen(u, "re");
89 [ + - ]: 143 : if (repo->fh == NULL)
90 : 0 : return (EPKG_FATAL);
91 : 143 : fi->mtime = st.st_mtime;
92 : 143 : return (EPKG_OK);
93 : 289 : }
94 : :
95 : : void
96 : 289 : fh_close(struct pkg_repo *repo)
97 : : {
98 [ + + ]: 289 : if (repo->fh != NULL)
99 : 143 : fclose(repo->fh);
100 : 289 : repo->fh = NULL;
101 : 289 : }
102 : :
103 : : int
104 : 143 : stdio_fetch(struct pkg_repo *repo, int dest, struct fetch_item *fi)
105 : : {
106 : : char buf[8192];
107 : 143 : size_t buflen = 0, left = 0;
108 : 143 : off_t done = 0, r;
109 : :
110 : 143 : pkg_emit_fetch_begin(fi->url);
111 : 143 : pkg_emit_progress_start(NULL);
112 [ + - ]: 143 : if (fi->offset > 0)
113 : 0 : done += fi->offset;
114 : 143 : buflen = sizeof(buf);
115 : 143 : left = sizeof(buf);
116 [ + + ]: 143 : if (fi->size > 0)
117 : 140 : left = fi->size - done;
118 : :
119 [ + + + + ]: 289 : while ((r = fread(buf, 1, left < buflen ? left : buflen, repo->fh)) > 0) {
120 [ - + ]: 146 : if (write(dest, buf, r) != r) {
121 : 0 : pkg_emit_errno("write", "");
122 : 0 : return (EPKG_FATAL);
123 : : }
124 : 146 : done += r;
125 [ + - ]: 146 : if (fi->size > 0) {
126 : 146 : left -= r;
127 : 146 : pkg_dbg(PKG_DBG_FETCH, 1, "Read status: %jd over %jd", (intmax_t)done, (intmax_t)fi->size);
128 : 146 : } else
129 : 0 : pkg_dbg(PKG_DBG_FETCH, 1, "Read status: %jd", (intmax_t)done);
130 [ + + ]: 146 : if (fi->size > 0)
131 : 140 : pkg_emit_progress_tick(done, fi->size);
132 : : }
133 [ + + + + ]: 429 : if (ferror(repo->fh)) {
134 : 286 : pkg_emit_error("An error occurred while fetching package");
135 : 286 : return(EPKG_FATAL);
136 : : }
137 : 143 : return (EPKG_OK);
138 : 143 : }
|