1 /* librepo - A library providing (libcURL like) API to downloading repository
2  * Copyright (C) 2013  Tomas Mlcoch
3  *
4  * Licensed under the GNU Lesser General Public License Version 2.1
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <glib.h>
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib/gprintf.h>
26 
27 #include "util.h"
28 #include "downloadtarget.h"
29 #include "downloadtarget_internal.h"
30 #include "cleanup.h"
31 #include "handle_internal.h"
32 
33 LrDownloadTargetChecksum *
lr_downloadtargetchecksum_new(LrChecksumType type,const gchar * value)34 lr_downloadtargetchecksum_new(LrChecksumType type, const gchar *value)
35 {
36     LrDownloadTargetChecksum *dtch = lr_malloc0(sizeof(*dtch));
37     dtch->type = type;
38     dtch->value = g_strdup(value);
39     return dtch;
40 }
41 
42 void
lr_downloadtargetchecksum_free(LrDownloadTargetChecksum * dtch)43 lr_downloadtargetchecksum_free(LrDownloadTargetChecksum *dtch)
44 {
45     if (!dtch) return;
46     g_free(dtch->value);
47     g_free(dtch);
48 }
49 
50 LrDownloadTarget *
lr_downloadtarget_new(LrHandle * handle,const char * path,const char * baseurl,int fd,const char * fn,GSList * possiblechecksums,gint64 expectedsize,gboolean resume,LrProgressCb progresscb,void * cbdata,LrEndCb endcb,LrMirrorFailureCb mirrorfailurecb,void * userdata,gint64 byterangestart,gint64 byterangeend,char * range,gboolean no_cache,gboolean is_zchunk)51 lr_downloadtarget_new(LrHandle *handle,
52                       const char *path,
53                       const char *baseurl,
54                       int fd,
55                       const char *fn,
56                       GSList *possiblechecksums,
57                       gint64 expectedsize,
58                       gboolean resume,
59                       LrProgressCb progresscb,
60                       void *cbdata,
61                       LrEndCb endcb,
62                       LrMirrorFailureCb mirrorfailurecb,
63                       void *userdata,
64                       gint64 byterangestart,
65                       gint64 byterangeend,
66                       char *range,
67                       gboolean no_cache,
68                       gboolean is_zchunk)
69 {
70     LrDownloadTarget *target;
71     _cleanup_free_ gchar *final_path = NULL;
72     _cleanup_free_ gchar *final_baseurl = NULL;
73 
74     assert(path);
75     assert((fd >= 0 && !fn) || (fd < 0 && fn));
76 
77     if (byterangestart && resume) {
78         g_warning("Cannot specify byterangestart and set resume to TRUE at the same time");
79         return NULL;
80     }
81 
82     // Substitute variables in URLs
83     if (handle && handle->urlvars) {
84         final_path      = lr_url_substitute(path, handle->urlvars);
85         final_baseurl   = lr_url_substitute(baseurl, handle->urlvars);
86     } else {
87         final_path      = g_strdup(path);
88         final_baseurl   = g_strdup(baseurl);
89     }
90 
91 
92     target = lr_malloc0(sizeof(*target));
93 
94     target->handle          = handle;
95     target->chunk           = g_string_chunk_new(0);
96     target->path            = g_string_chunk_insert(target->chunk, final_path);
97     target->baseurl         = lr_string_chunk_insert(target->chunk, final_baseurl);
98     target->fd              = fd;
99     target->fn              = lr_string_chunk_insert(target->chunk, fn);
100     target->checksums       = possiblechecksums;
101     target->expectedsize    = expectedsize;
102     target->origsize        = expectedsize;
103     target->resume          = resume;
104     target->progresscb      = progresscb;
105     target->cbdata          = cbdata;
106     target->endcb           = endcb;
107     target->mirrorfailurecb = mirrorfailurecb;
108     target->rcode           = LRE_UNFINISHED;
109     target->userdata        = userdata;
110     target->byterangestart  = byterangestart;
111     target->byterangeend    = byterangeend;
112     target->range           = range;
113     target->no_cache        = no_cache;
114     target->is_zchunk       = is_zchunk;
115 
116     return target;
117 }
118 
119 void
lr_downloadtarget_reset(LrDownloadTarget * target)120 lr_downloadtarget_reset(LrDownloadTarget *target)
121 {
122     if (!target)
123         return;
124 
125     target->usedmirror = NULL;
126     target->effectiveurl = NULL;
127     target->rcode = LRE_OK;
128     target->err = NULL;
129 }
130 
131 void
lr_downloadtarget_free(LrDownloadTarget * target)132 lr_downloadtarget_free(LrDownloadTarget *target)
133 {
134     if (!target)
135         return;
136 
137     g_slist_free_full(target->checksums,
138                       (GDestroyNotify) lr_downloadtargetchecksum_free);
139     g_string_chunk_free(target->chunk);
140     lr_free(target);
141 }
142 
143 void
lr_downloadtarget_set_error(LrDownloadTarget * target,LrRc code,const char * format,...)144 lr_downloadtarget_set_error(LrDownloadTarget *target,
145                             LrRc code,
146                             const char *format,
147                             ...)
148 {
149     assert(target);
150     assert(code == LRE_OK || format);
151 
152     if (format) {
153         int ret;
154         va_list vl;
155         gchar *message = NULL;
156 
157         va_start(vl, format);
158         ret = g_vasprintf(&message, format, vl);
159         va_end(vl);
160 
161         if (ret < 0) {
162             assert(0);
163             target->err = "";
164             return;
165         }
166 
167         target->err = lr_string_chunk_insert(target->chunk, message);
168         g_free(message);
169     } else {
170         target->err = NULL;
171     }
172 
173     target->rcode = code;
174 }
175 
176 void
lr_downloadtarget_set_usedmirror(LrDownloadTarget * target,const char * url)177 lr_downloadtarget_set_usedmirror(LrDownloadTarget *target, const char *url)
178 {
179     assert(target);
180     target->usedmirror = lr_string_chunk_insert(target->chunk, url);
181 }
182 
183 void
lr_downloadtarget_set_effectiveurl(LrDownloadTarget * target,const char * url)184 lr_downloadtarget_set_effectiveurl(LrDownloadTarget *target, const char *url)
185 {
186     assert(target);
187     target->effectiveurl = lr_string_chunk_insert(target->chunk, url);
188 }
189