Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/fetch_file.c
2065 views
1
/*-
2
* Copyright (c) 2020-2023 Baptiste Daroussin <[email protected]>
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
file_open(struct pkg_repo *repo, struct fetch_item *fi)
40
{
41
struct stat st;
42
const char *u = fi->url;
43
size_t len = strlen(u);
44
45
if (len > 5)
46
u += 5; /* file: */
47
if (len < 8) {
48
pkg_emit_error("Invalid url: %s'\n', "
49
"file://<absolutepath> expected", fi->url);
50
return (EPKG_FATAL);
51
}
52
if (strncmp(u, "//", 2) != 0) {
53
pkg_emit_error("invalid url: '%s'\n", fi->url);
54
return (EPKG_FATAL);
55
}
56
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
if (*u != '/') {
62
char fqdn[256]="";
63
char *path = strchr(u+1, '/');
64
if (path == NULL) {
65
pkg_emit_error("Invalid url: '%s',\n"
66
"file:///<path> or file://localhost/<path> expected.", fi->url);
67
return (EPKG_FATAL);
68
}
69
strncat(fqdn, u, MIN(255, path-u));
70
if (0 != strncmp("localhost", fqdn, sizeof(fqdn))) {
71
pkg_emit_error("Invalid url: '%s'\n"
72
"file:///<path> or file://localhost/<path> expected.", fi->url);
73
return (EPKG_FATAL);
74
}
75
u = path;
76
}
77
if (stat(u, &st) == -1) {
78
if (!repo->silent)
79
pkg_emit_error("%s: %s", fi->url,
80
strerror(errno));
81
return (EPKG_FATAL);
82
}
83
fi->size = st.st_size;
84
if (st.st_mtime <= fi->mtime)
85
return (EPKG_UPTODATE);
86
87
pkg_dbg(PKG_DBG_FETCH, 1, "mtime: local %ld, remote %ld", st.st_mtime, fi->mtime);
88
repo->fh = fopen(u, "re");
89
if (repo->fh == NULL)
90
return (EPKG_FATAL);
91
fi->mtime = st.st_mtime;
92
return (EPKG_OK);
93
}
94
95
void
96
fh_close(struct pkg_repo *repo)
97
{
98
if (repo->fh != NULL)
99
fclose(repo->fh);
100
repo->fh = NULL;
101
}
102
103
int
104
stdio_fetch(struct pkg_repo *repo, int dest, struct fetch_item *fi)
105
{
106
char buf[8192];
107
size_t buflen = 0, left = 0;
108
off_t done = 0, r;
109
110
pkg_emit_fetch_begin(fi->url);
111
pkg_emit_progress_start(NULL);
112
if (fi->offset > 0)
113
done += fi->offset;
114
buflen = sizeof(buf);
115
left = sizeof(buf);
116
if (fi->size > 0)
117
left = fi->size - done;
118
119
while ((r = fread(buf, 1, left < buflen ? left : buflen, repo->fh)) > 0) {
120
if (write(dest, buf, r) != r) {
121
pkg_emit_errno("write", "");
122
return (EPKG_FATAL);
123
}
124
done += r;
125
if (fi->size > 0) {
126
left -= r;
127
pkg_dbg(PKG_DBG_FETCH, 1, "Read status: %jd over %jd", (intmax_t)done, (intmax_t)fi->size);
128
} else
129
pkg_dbg(PKG_DBG_FETCH, 1, "Read status: %jd", (intmax_t)done);
130
if (fi->size > 0)
131
pkg_emit_progress_tick(done, fi->size);
132
}
133
if (ferror(repo->fh)) {
134
pkg_emit_error("An error occurred while fetching package");
135
return(EPKG_FATAL);
136
}
137
return (EPKG_OK);
138
}
139
140