00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "config.h"
00021
00022 #include <stdlib.h>
00023 #include <errno.h>
00024 #include <time.h>
00025 #include <string.h>
00026 #include <limits.h>
00027 #include <stdio.h>
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #include <unistd.h>
00031 #include <download.h>
00032
00033
00034 #include "server.h"
00035 #include "alpm_list.h"
00036 #include "error.h"
00037 #include "log.h"
00038 #include "alpm.h"
00039 #include "util.h"
00040 #include "handle.h"
00041 #include "package.h"
00042
00043 pmserver_t *_alpm_server_new(const char *url)
00044 {
00045 struct url *u;
00046 pmserver_t *server;
00047
00048 ALPM_LOG_FUNC;
00049
00050 CALLOC(server, 1, sizeof(pmserver_t), RET_ERR(PM_ERR_MEMORY, NULL));
00051
00052 u = downloadParseURL(url);
00053 if(!u) {
00054 _alpm_log(PM_LOG_ERROR, _("url '%s' is invalid, ignoring\n"), url);
00055 RET_ERR(PM_ERR_SERVER_BAD_URL, NULL);
00056 }
00057 if(strlen(u->scheme) == 0) {
00058 _alpm_log(PM_LOG_WARNING, _("url scheme not specified, assuming http\n"));
00059 strcpy(u->scheme, "http");
00060 }
00061
00062 if(strcmp(u->scheme,"ftp") == 0 && strlen(u->user) == 0) {
00063 strcpy(u->user, "anonymous");
00064 strcpy(u->pwd, "libalpm@guest");
00065 }
00066
00067
00068 for(int i = strlen(u->doc) - 1; u->doc[i] == '/'; --i)
00069 u->doc[i] = '\0';
00070
00071 server->s_url = u;
00072
00073 return server;
00074 }
00075
00076 void _alpm_server_free(pmserver_t *server)
00077 {
00078 ALPM_LOG_FUNC;
00079
00080 if(server == NULL) {
00081 return;
00082 }
00083
00084
00085 downloadFreeURL(server->s_url);
00086 FREE(server);
00087 }
00088
00089
00090 static char *strip_filename(pmserver_t *server)
00091 {
00092 char *p = NULL, *fname = NULL;
00093 if(!server) {
00094 return(NULL);
00095 }
00096
00097 p = strrchr(server->s_url->doc, '/');
00098 if(p && *(++p)) {
00099 fname = strdup(p);
00100 _alpm_log(PM_LOG_DEBUG, "stripping '%s' from '%s'\n",
00101 fname, server->s_url->doc);
00102 *p = 0;
00103 }
00104
00105
00106
00107 return(fname);
00108 }
00109
00110
00111 static struct url *url_for_file(pmserver_t *server, const char *filename)
00112 {
00113 struct url *ret = NULL;
00114 char *doc = NULL;
00115 int doclen = 0;
00116
00117 doclen = strlen(server->s_url->doc) + strlen(filename) + 2;
00118 CALLOC(doc, doclen, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL));
00119
00120 snprintf(doc, doclen, "%s/%s", server->s_url->doc, filename);
00121 ret = downloadMakeURL(server->s_url->scheme,
00122 server->s_url->host,
00123 server->s_url->port,
00124 doc,
00125 server->s_url->user,
00126 server->s_url->pwd);
00127 FREE(doc);
00128 return(ret);
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 int _alpm_downloadfiles(alpm_list_t *servers, const char *localpath,
00143 alpm_list_t *files, int *dl_total, unsigned long totalsize)
00144 {
00145 return(_alpm_downloadfiles_forreal(servers, localpath, files, 0, NULL,
00146 dl_total, totalsize));
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 int _alpm_downloadfiles_forreal(alpm_list_t *servers, const char *localpath,
00167 alpm_list_t *files, time_t mtime1, time_t *mtime2, int *dl_total,
00168 unsigned long totalsize)
00169 {
00170 int dl_thisfile = 0;
00171 alpm_list_t *lp;
00172 int done = 0;
00173 alpm_list_t *complete = NULL;
00174 alpm_list_t *i;
00175
00176 ALPM_LOG_FUNC;
00177
00178 if(files == NULL) {
00179 return(0);
00180 }
00181
00182 for(i = servers; i && !done; i = i->next) {
00183 pmserver_t *server = i->data;
00184
00185
00186 for(lp = files; lp; lp = lp->next) {
00187 struct url *fileurl = NULL;
00188 char realfile[PATH_MAX];
00189 char output[PATH_MAX];
00190 char *fn = (char *)lp->data;
00191 char *pkgname;
00192
00193 fileurl = url_for_file(server, fn);
00194 if(!fileurl) {
00195 return(-1);
00196 }
00197
00198
00199 STRDUP(pkgname, fn, (void)0);
00200 _alpm_log(PM_LOG_DEBUG, "using '%s' for download progress\n", pkgname);
00201
00202 snprintf(realfile, PATH_MAX, "%s%s", localpath, fn);
00203 snprintf(output, PATH_MAX, "%s%s.part", localpath, fn);
00204
00205 if(alpm_list_find_str(complete, fn)) {
00206 continue;
00207 }
00208
00209 if(!handle->xfercommand || !strcmp(fileurl->scheme, "file")) {
00210 FILE *dlf, *localf = NULL;
00211 struct url_stat ust;
00212 struct stat st;
00213 int chk_resume = 0;
00214
00215 if(stat(output, &st) == 0 && st.st_size > 0) {
00216 _alpm_log(PM_LOG_DEBUG, "existing file found, using it\n");
00217 fileurl->offset = (off_t)st.st_size;
00218 dl_thisfile = st.st_size;
00219 if (dl_total != NULL) {
00220 *dl_total += st.st_size;
00221 }
00222 localf = fopen(output, "a");
00223 chk_resume = 1;
00224 } else {
00225 fileurl->offset = (off_t)0;
00226 dl_thisfile = 0;
00227 }
00228
00229
00230
00231 downloadLastErrCode = 0;
00232
00233
00234 downloadTimeout = 10000;
00235
00236 dlf = downloadXGet(fileurl, &ust, (handle->nopassiveftp ? "" : "p"));
00237
00238 if(downloadLastErrCode != 0 || dlf == NULL) {
00239 const char *host = _("disk");
00240 if(strcmp(SCHEME_FILE, fileurl->scheme) != 0) {
00241 host = fileurl->host;
00242 }
00243 _alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"),
00244 fn, host, downloadLastErrString);
00245 if(localf != NULL) {
00246 fclose(localf);
00247 }
00248
00249 downloadFreeURL(fileurl);
00250 continue;
00251 } else {
00252 _alpm_log(PM_LOG_DEBUG, "connected to %s successfully\n", fileurl->host);
00253 }
00254
00255 if(ust.mtime && mtime1 && ust.mtime == mtime1) {
00256 _alpm_log(PM_LOG_DEBUG, "mtimes are identical, skipping %s\n", fn);
00257 complete = alpm_list_add(complete, fn);
00258 if(localf != NULL) {
00259 fclose(localf);
00260 }
00261 if(dlf != NULL) {
00262 fclose(dlf);
00263 }
00264 downloadFreeURL(fileurl);
00265 return(1);
00266 }
00267
00268 if(ust.mtime && mtime2) {
00269 *mtime2 = ust.mtime;
00270 }
00271
00272 if(chk_resume && fileurl->offset == 0) {
00273 _alpm_log(PM_LOG_WARNING, _("cannot resume download, starting over\n"));
00274 if(localf != NULL) {
00275 fclose(localf);
00276 localf = NULL;
00277 }
00278 }
00279
00280 if(localf == NULL) {
00281 _alpm_rmrf(output);
00282 fileurl->offset = (off_t)0;
00283 dl_thisfile = 0;
00284 localf = fopen(output, "w");
00285 if(localf == NULL) {
00286 _alpm_log(PM_LOG_ERROR, _("cannot write to file '%s'\n"), output);
00287 if(dlf != NULL) {
00288 fclose(dlf);
00289 }
00290 downloadFreeURL(fileurl);
00291 return(-1);
00292 }
00293 }
00294
00295
00296 if(handle->dlcb) {
00297 handle->dlcb(pkgname, 0, ust.size, dl_total ? *dl_total : 0,
00298 totalsize);
00299 }
00300
00301 int nread = 0;
00302 char buffer[PM_DLBUF_LEN];
00303 while((nread = fread(buffer, 1, PM_DLBUF_LEN, dlf)) > 0) {
00304 if(ferror(dlf)) {
00305 _alpm_log(PM_LOG_ERROR, _("error downloading '%s': %s\n"),
00306 fn, downloadLastErrString);
00307 fclose(localf);
00308 fclose(dlf);
00309 downloadFreeURL(fileurl);
00310 return(-1);
00311 }
00312
00313 int nwritten = 0;
00314 while(nwritten < nread) {
00315 nwritten += fwrite(buffer, 1, (nread - nwritten), localf);
00316 if(ferror(localf)) {
00317 _alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"),
00318 realfile, strerror(errno));
00319 fclose(localf);
00320 fclose(dlf);
00321 downloadFreeURL(fileurl);
00322 return(-1);
00323 }
00324 }
00325
00326 if(nwritten != nread) {
00327
00328 }
00329 dl_thisfile += nread;
00330 if (dl_total != NULL) {
00331 *dl_total += nread;
00332 }
00333
00334 if(handle->dlcb) {
00335 handle->dlcb(pkgname, dl_thisfile, ust.size,
00336 dl_total ? *dl_total : 0, totalsize);
00337 }
00338 }
00339
00340 downloadFreeURL(fileurl);
00341 fclose(localf);
00342 fclose(dlf);
00343 rename(output, realfile);
00344 complete = alpm_list_add(complete, fn);
00345 } else {
00346 int ret;
00347 int usepart = 0;
00348 char *ptr1, *ptr2;
00349 char origCmd[PATH_MAX];
00350 char parsedCmd[PATH_MAX] = "";
00351 char url[PATH_MAX];
00352 char cwd[PATH_MAX];
00353
00354
00355 snprintf(url, PATH_MAX, "%s://%s%s", fileurl->scheme,
00356 fileurl->host, fileurl->doc);
00357
00358 downloadFreeURL(fileurl);
00359
00360
00361 strncpy(origCmd, handle->xfercommand, sizeof(origCmd));
00362 ptr1 = origCmd;
00363 while((ptr2 = strstr(ptr1, "%o"))) {
00364 usepart = 1;
00365 ptr2[0] = '\0';
00366 strcat(parsedCmd, ptr1);
00367 strcat(parsedCmd, output);
00368 ptr1 = ptr2 + 2;
00369 }
00370 strcat(parsedCmd, ptr1);
00371
00372 strncpy(origCmd, parsedCmd, sizeof(origCmd));
00373 parsedCmd[0] = '\0';
00374 ptr1 = origCmd;
00375 while((ptr2 = strstr(ptr1, "%u"))) {
00376 ptr2[0] = '\0';
00377 strcat(parsedCmd, ptr1);
00378 strcat(parsedCmd, url);
00379 ptr1 = ptr2 + 2;
00380 }
00381 strcat(parsedCmd, ptr1);
00382
00383 getcwd(cwd, PATH_MAX);
00384 if(chdir(localpath)) {
00385 _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), localpath);
00386 return(PM_ERR_CONNECT_FAILED);
00387 }
00388
00389 _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd);
00390 ret = system(parsedCmd);
00391 if(ret == -1) {
00392 _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!\n"));
00393 return(PM_ERR_FORK_FAILED);
00394 } else if(ret != 0) {
00395
00396 _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero status code (%d)\n", ret);
00397 } else {
00398
00399 complete = alpm_list_add(complete, fn);
00400 if(usepart) {
00401 rename(output, realfile);
00402 }
00403 }
00404 chdir(cwd);
00405 }
00406 FREE(pkgname);
00407 }
00408
00409 if(alpm_list_count(complete) == alpm_list_count(files)) {
00410 done = 1;
00411 }
00412 }
00413 alpm_list_free(complete);
00414
00415 return(done ? 0 : -1);
00416 }
00417
00418
00419
00420
00421
00422
00423 char SYMEXPORT *alpm_fetch_pkgurl(const char *url)
00424 {
00425 pmserver_t *server;
00426 char *filename, *filepath;
00427 const char *cachedir;
00428
00429 ALPM_LOG_FUNC;
00430
00431 if(strstr(url, "://") == NULL) {
00432 _alpm_log(PM_LOG_DEBUG, "Invalid URL passed to alpm_fetch_pkgurl\n");
00433 return(NULL);
00434 }
00435
00436 server = _alpm_server_new(url);
00437 if(!server) {
00438 return(NULL);
00439 }
00440
00441
00442 filename = strip_filename(server);
00443 if(!filename) {
00444 _alpm_log(PM_LOG_ERROR, _("URL does not contain a file for download\n"));
00445 return(NULL);
00446 }
00447
00448
00449 cachedir = _alpm_filecache_setup();
00450
00451
00452 alpm_list_t *servers = alpm_list_add(NULL, server);
00453 alpm_list_t *files = alpm_list_add(NULL, filename);
00454
00455
00456 if(_alpm_downloadfiles(servers, cachedir, files, NULL, 0)) {
00457 _alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url);
00458 return(NULL);
00459 }
00460 _alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", filename);
00461 alpm_list_free(files);
00462 alpm_list_free(servers);
00463 _alpm_server_free(server);
00464
00465
00466 filepath = _alpm_filecache_find(filename);
00467 return(filepath);
00468 }
00469
00470