00001
00006 #include "system.h"
00007
00008 #ifdef WITH_NEON
00009
00010 #include "ne_alloc.h"
00011 #include "ne_auth.h"
00012 #include "ne_basic.h"
00013 #include "ne_dates.h"
00014 #include "ne_locks.h"
00015
00016 #define NEONBLOWSCHUNKS
00017 #ifndef NEONBLOWSCHUNKS
00018
00019 #include "../neon/src/ne_private.h"
00020 #endif
00021
00022 #include "ne_props.h"
00023 #include "ne_request.h"
00024 #include "ne_socket.h"
00025 #include "ne_string.h"
00026
00027 #include "ne_utils.h"
00028 #if !defined(HEADER_ERR_H)
00029
00030
00031 extern void ERR_remove_state(int foo);
00032 extern void ENGINE_cleanup(void);
00033 extern void CONF_modules_unload(int foo);
00034 extern void ERR_free_strings(void);
00035 extern void EVP_cleanup(void);
00036 extern void CRYPTO_cleanup_all_ex_data(void);
00037 extern void CRYPTO_mem_leaks(void * ptr);
00038
00039 #endif
00040
00041 #include "ne_md5.h"
00042
00043
00044 #if defined(NE_MD5_H)
00045 #define WITH_NEON_MIN_VERSION 0x002700
00046 #elif defined(NE_FEATURE_I18N)
00047 #define WITH_NEON_MIN_VERSION 0x002600
00048 #else
00049 #define WITH_NEON_MIN_VERSION 0x002500
00050 #endif
00051
00052
00053 #if WITH_NEON_MIN_VERSION >= 0x002600
00054 #define ne_propfind_set_private(_pfh, _create_item, NULL) \
00055 ne_propfind_set_private(_pfh, _create_item, NULL, NULL)
00056 #endif
00057
00058 #endif
00059
00060 #include <rpmio_internal.h>
00061
00062 #include <rpmhash.h>
00063 #include <rpmmacro.h>
00064 #include <ugid.h>
00065
00066 #define _RPMAV_INTERNAL
00067 #define _RPMDAV_INTERNAL
00068 #include <rpmdav.h>
00069 #include <mire.h>
00070
00071 #include "debug.h"
00072
00073
00074
00075
00076
00077
00078
00079 #if 0
00080 #define TIMEOUT_SECS 60
00081 #else
00082 #define TIMEOUT_SECS 5
00083 #endif
00084
00085
00086 static const char _rpmioHttpUserAgent[] = PACKAGE "/" PACKAGE_VERSION;
00087
00088
00089 static int rpmioHttpPersist = 1;
00090
00091 int rpmioHttpReadTimeoutSecs = TIMEOUT_SECS;
00092
00093 int rpmioHttpConnectTimeoutSecs = TIMEOUT_SECS;
00094 #ifdef NOTYET
00095 int rpmioHttpRetries = 20;
00096 int rpmioHttpRecurseMax = 5;
00097 int rpmioHttpMaxRedirect = 20;
00098 #endif
00099
00100
00101 const char * rpmioHttpAccept;
00102
00103 const char * rpmioHttpUserAgent;
00104
00105
00106 void * avContextDestroy(avContext ctx)
00107 {
00108 if (ctx == NULL)
00109 return NULL;
00110 if (ctx->av != NULL)
00111 ctx->av = argvFree(ctx->av);
00112 ctx->modes = _free(ctx->modes);
00113 ctx->sizes = _free(ctx->sizes);
00114 ctx->mtimes = _free(ctx->mtimes);
00115 ctx->u = urlFree(ctx->u, "avContextDestroy");
00116 ctx->uri = _free(ctx->uri);
00117 memset(ctx, 0, sizeof(*ctx));
00118 ctx = _free(ctx);
00119 return NULL;
00120 }
00121
00122 void * avContextCreate(const char *uri, struct stat *st)
00123 {
00124 avContext ctx;
00125 urlinfo u;
00126
00127
00128 if (urlSplit(uri, &u))
00129 return NULL;
00130
00131
00132 ctx = xcalloc(1, sizeof(*ctx));
00133 ctx->uri = xstrdup(uri);
00134 ctx->u = urlLink(u, "avContextCreate");
00135
00136 if ((ctx->st = st) != NULL)
00137 memset(ctx->st, 0, sizeof(*ctx->st));
00138
00139 return ctx;
00140 }
00141
00142 int avContextAdd(avContext ctx, const char * path,
00143 mode_t mode, size_t size, time_t mtime)
00144 {
00145 int xx;
00146
00147 if (_av_debug < 0)
00148 fprintf(stderr, "*** avContextAdd(%p,\"%s\", %06o, 0x%x, 0x%x)\n", ctx, path, (unsigned)mode, (unsigned)size, (unsigned)mtime);
00149
00150 xx = argvAdd(&ctx->av, path);
00151
00152 while (ctx->ac >= ctx->nalloced) {
00153 if (ctx->nalloced <= 0)
00154 ctx->nalloced = 1;
00155 ctx->nalloced *= 2;
00156 ctx->modes = xrealloc(ctx->modes,
00157 (sizeof(*ctx->modes) * ctx->nalloced));
00158 ctx->sizes = xrealloc(ctx->sizes,
00159 (sizeof(*ctx->sizes) * ctx->nalloced));
00160 ctx->mtimes = xrealloc(ctx->mtimes,
00161 (sizeof(*ctx->mtimes) * ctx->nalloced));
00162 }
00163
00164 ctx->modes[ctx->ac] = (rpmuint16_t)mode;
00165 ctx->sizes[ctx->ac] = size;
00166 ctx->mtimes[ctx->ac] = mtime;
00167 ctx->ac++;
00168 return 0;
00169 }
00170
00171 int avClosedir( DIR * dir)
00172 {
00173 AVDIR avdir = (AVDIR)dir;
00174
00175 if (_av_debug)
00176 fprintf(stderr, "*** avClosedir(%p)\n", avdir);
00177
00178 #if defined(WITH_PTHREADS)
00179
00180 (void) pthread_mutex_destroy(&avdir->lock);
00181
00182 #endif
00183
00184 avdir = _free(avdir);
00185 return 0;
00186 }
00187
00188 struct dirent * avReaddir(DIR * dir)
00189 {
00190 AVDIR avdir = (AVDIR)dir;
00191 struct dirent * dp;
00192 const char ** av;
00193 unsigned char * dt;
00194 int ac;
00195 int i;
00196
00197 if (avdir == NULL || !ISAVMAGIC(avdir) || avdir->data == NULL) {
00198
00199 return NULL;
00200 }
00201
00202 dp = (struct dirent *) avdir->data;
00203 av = (const char **) (dp + 1);
00204 ac = (int)avdir->size;
00205 dt = (unsigned char *) (av + (ac + 1));
00206 i = avdir->offset + 1;
00207
00208 if (i < 0 || i >= ac || av[i] == NULL)
00209 return NULL;
00210
00211 avdir->offset = i;
00212
00213
00214
00215
00216 dp->d_ino = hashFunctionString(avdir->filepos, dp->d_name, 0);
00217
00218 #if !defined(__DragonFly__) && !defined(__CYGWIN__)
00219 dp->d_reclen = 0;
00220 #endif
00221
00222 #if !(defined(hpux) || defined(__hpux) || defined(sun) || defined(RPM_OS_AIX) || defined(__CYGWIN__) || defined(__QNXNTO__))
00223 #if !defined(__APPLE__) && !defined(__FreeBSD_kernel__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
00224 dp->d_off = 0;
00225 #endif
00226 dp->d_type = dt[i];
00227 #endif
00228
00229
00230 strncpy(dp->d_name, av[i], sizeof(dp->d_name));
00231 if (_av_debug)
00232 fprintf(stderr, "*** avReaddir(%p) %p %s\n", (void *)avdir, dp, dp->d_name);
00233
00234 return dp;
00235 }
00236
00237 DIR * avOpendir(const char * path, const char ** av, rpmuint16_t * modes)
00238 {
00239 AVDIR avdir;
00240 struct dirent * dp;
00241 size_t nb;
00242 const char ** nav;
00243 unsigned char * dt;
00244 char * t;
00245 int ac, nac;
00246
00247 if (_av_debug)
00248 fprintf(stderr, "*** avOpendir(%s, %p, %p)\n", path, av, modes);
00249
00250 nb = 0;
00251 ac = 0;
00252 if (av != NULL)
00253 while (av[ac] != NULL)
00254 nb += strlen(av[ac++]) + 1;
00255 ac += 2;
00256 nb += sizeof(".") + sizeof("..");
00257
00258 nb += sizeof(*avdir) + sizeof(*dp) + ((ac + 1) * sizeof(*av)) + (ac + 1);
00259 avdir = xcalloc(1, nb);
00260
00261 dp = (struct dirent *) (avdir + 1);
00262 nav = (const char **) (dp + 1);
00263 dt = (unsigned char *) (nav + (ac + 1));
00264 t = (char *) (dt + ac + 1);
00265
00266
00267 avdir->fd = avmagicdir;
00268
00269 avdir->data = (char *) dp;
00270
00271 avdir->allocation = nb;
00272 avdir->size = ac;
00273 avdir->offset = -1;
00274
00275 avdir->filepos = hashFunctionString(0, path, 0);
00276
00277 #if defined(WITH_PTHREADS)
00278
00279 (void) pthread_mutex_init(&avdir->lock, NULL);
00280
00281 #endif
00282
00283 nac = 0;
00284
00285 dt[nac] = (unsigned char)DT_DIR; nav[nac++] = t; t = stpcpy(t, "."); t++;
00286 dt[nac] = (unsigned char)DT_DIR; nav[nac++] = t; t = stpcpy(t, ".."); t++;
00287
00288
00289
00290 ac = 0;
00291 if (av != NULL)
00292 while (av[ac] != NULL) {
00293 if (modes != NULL)
00294 switch (modes[ac] & S_IFMT) {
00295 case S_IFIFO: dt[nac]=(unsigned char)DT_FIFO;break;
00296 case S_IFCHR: dt[nac]=(unsigned char)DT_CHR; break;
00297 case S_IFDIR: dt[nac]=(unsigned char)DT_DIR; break;
00298 case S_IFBLK: dt[nac]=(unsigned char)DT_BLK; break;
00299 case S_IFREG: dt[nac]=(unsigned char)DT_REG; break;
00300 case S_IFLNK: dt[nac]=(unsigned char)DT_LNK; break;
00301
00302 case S_IFSOCK:dt[nac]=(unsigned char)DT_SOCK;break;
00303
00304 default: dt[nac]=(unsigned char)DT_UNKNOWN;break;
00305 }
00306 else
00307 dt[nac] = (unsigned char)DT_UNKNOWN;
00308
00309 nav[nac++] = t;
00310
00311 t = stpcpy(t, av[ac++]);
00312 t++;
00313 }
00314 nav[nac] = NULL;
00315
00316
00317 return (DIR *) avdir;
00318
00319 }
00320
00321 #ifdef WITH_NEON
00322
00323
00324 int davDisconnect( void * _u)
00325 {
00326 #ifdef NOTYET
00327 urlinfo u = (urlinfo)_u;
00328 int rc;
00329
00330 #if WITH_NEON_MIN_VERSION >= 0x002700
00331 rc = (u->info.status == ne_status_sending || u->info.status == ne_status_recving);
00332 #else
00333 rc = 0;
00334 #endif
00335 if (u != NULL && rc != 0) {
00336 if (u->ctrl->req != NULL) {
00337 if (u->ctrl && u->ctrl->req) {
00338 ne_request_destroy(u->ctrl->req);
00339 u->ctrl->req = NULL;
00340 }
00341 if (u->data && u->data->req) {
00342 ne_request_destroy(u->data->req);
00343 u->data->req = NULL;
00344 }
00345 }
00346 }
00347 if (_dav_debug < 0)
00348 fprintf(stderr, "*** davDisconnect(%p) active %d\n", u, rc);
00349
00350 #endif
00351 return 0;
00352 }
00353
00354
00355 int davFree(urlinfo u)
00356 {
00357 if (u != NULL) {
00358 if (u->sess != NULL) {
00359 ne_session_destroy(u->sess);
00360 u->sess = NULL;
00361 }
00362 switch (u->urltype) {
00363 default:
00364 break;
00365 case URL_IS_HTTPS:
00366 case URL_IS_HTTP:
00367 case URL_IS_HKP:
00368 u->capabilities = _free(u->capabilities);
00369 if (u->lockstore != NULL)
00370 ne_lockstore_destroy(u->lockstore);
00371 u->lockstore = NULL;
00372 u->info.status = 0;
00373 ne_sock_exit();
00374 break;
00375 }
00376 }
00377 if (_dav_debug < 0)
00378 fprintf(stderr, "*** davFree(%p)\n", u);
00379 return 0;
00380 }
00381
00382 void davDestroy(void)
00383 {
00384 #ifdef NE_FEATURE_SSL
00385 if (ne_has_support(NE_FEATURE_SSL)) {
00386
00387 ENGINE_cleanup();
00388 CRYPTO_cleanup_all_ex_data();
00389 ERR_free_strings();
00390 ERR_remove_state(0);
00391 EVP_cleanup();
00392 CRYPTO_mem_leaks(NULL);
00393 CONF_modules_unload(1);
00394 }
00395 #endif
00396 if (_dav_debug < 0)
00397 fprintf(stderr, "*** davDestroy()\n");
00398 }
00399
00400 static void davProgress(void * userdata, off_t progress, off_t total)
00401
00402 {
00403 urlinfo u = userdata;
00404 ne_session * sess;
00405
00406 assert(u != NULL);
00407 sess = u->sess;
00408 assert(sess != NULL);
00409
00410 assert(u == ne_get_session_private(sess, "urlinfo"));
00411
00412
00413 u->info.progress = progress;
00414 u->info.total = total;
00415
00416 if (_dav_debug < 0)
00417 fprintf(stderr, "*** davProgress(%p,0x%x:0x%x) sess %p u %p\n", userdata, (unsigned int)progress, (unsigned int)total, sess, u);
00418 }
00419
00420 #if WITH_NEON_MIN_VERSION >= 0x002700
00421 static void davNotify(void * userdata,
00422 ne_session_status status, const ne_session_status_info *info)
00423 #else
00424 static void davNotify(void * userdata,
00425 ne_conn_status status, const char * info)
00426 #endif
00427
00428 {
00429 char buf[64];
00430 urlinfo u = userdata;
00431 ne_session * sess;
00432
00433 assert(u != NULL);
00434 sess = u->sess;
00435 assert(sess != NULL);
00436
00437 assert(u == ne_get_session_private(sess, "urlinfo"));
00438
00439
00440 u->info.hostname = NULL;
00441 u->info.address = NULL;
00442 u->info.progress = 0;
00443 u->info.total = 0;
00444
00445 #if WITH_NEON_MIN_VERSION >= 0x002700
00446 #ifdef REFERENCE
00447 typedef enum {
00448 ne_status_lookup = 0,
00449 ne_status_connecting,
00450 ne_status_connected,
00451 ne_status_sending,
00452 ne_status_recving,
00453 ne_status_disconnected
00454 } ne_session_status;
00455 #endif
00456 switch (status) {
00457 default:
00458 break;
00459 case ne_status_lookup:
00460 u->info.hostname = info->ci.hostname;
00461 break;
00462 case ne_status_connecting:
00463 u->info.hostname = info->ci.hostname;
00464 (void) ne_iaddr_print(info->ci.address, buf, sizeof(buf));
00465 buf[sizeof(buf)-1] = '\0';
00466 u->info.address = buf;
00467 break;
00468 case ne_status_connected:
00469 u->info.hostname = info->ci.hostname;
00470 break;
00471 case ne_status_sending:
00472 u->info.progress = info->sr.progress;
00473 u->info.total = info->sr.total;
00474 break;
00475 case ne_status_recving:
00476 u->info.progress = info->sr.progress;
00477 u->info.total = info->sr.total;
00478 break;
00479 case ne_status_disconnected:
00480 u->info.hostname = info->ci.hostname;
00481 break;
00482 }
00483
00484 if (u->notify != NULL)
00485 (void) (*u->notify) (u, status);
00486
00487 #else
00488 #ifdef REFERENCE
00489 typedef enum {
00490 ne_conn_namelookup,
00491 ne_conn_connecting,
00492 ne_conn_connected,
00493 ne_conn_secure
00494 } ne_conn_status;
00495 #endif
00496
00497 if (_dav_debug < 0) {
00498
00499 static const char * connstates[] = {
00500 "namelookup",
00501 "connecting",
00502 "connected",
00503 "secure",
00504 "unknown"
00505 };
00506
00507 fprintf(stderr, "*** davNotify(%p,%d,%p) sess %p u %p %s\n", userdata, status, info, sess, u, connstates[ (status < 4 ? status : 4)]);
00508 }
00509 #endif
00510
00511 u->info.status = status;
00512 u->info.hostname = NULL;
00513 u->info.address = NULL;
00514 u->info.progress = 0;
00515 u->info.total = 0;
00516 }
00517
00518 static void davCreateRequest(ne_request * req, void * userdata,
00519 const char * method, const char * uri)
00520
00521 {
00522 urlinfo u = userdata;
00523 ne_session * sess;
00524 void * private = NULL;
00525 const char * id = "urlinfo";
00526
00527 assert(u != NULL);
00528 assert(u->sess != NULL);
00529 assert(req != NULL);
00530 sess = ne_get_session(req);
00531 assert(sess == u->sess);
00532
00533 assert(u == ne_get_session_private(sess, "urlinfo"));
00534
00535
00536 assert(sess != NULL);
00537 private = ne_get_session_private(sess, id);
00538 assert(u == private);
00539
00540 if (_dav_debug < 0)
00541 fprintf(stderr, "*** davCreateRequest(%p,%p,%s,%s) %s:%p\n", req, userdata, method, uri, id, private);
00542 }
00543
00544 static void davPreSend(ne_request * req, void * userdata, ne_buffer * buf)
00545 {
00546 urlinfo u = userdata;
00547 ne_session * sess;
00548 const char * id = "fd";
00549 FD_t fd = NULL;
00550
00551
00552 assert(u != NULL);
00553 assert(u->sess != NULL);
00554 assert(req != NULL);
00555 sess = ne_get_session(req);
00556 assert(sess == u->sess);
00557
00558 assert(u == ne_get_session_private(sess, "urlinfo"));
00559
00560
00561 fd = ne_get_request_private(req, id);
00562
00563
00564 if (_dav_debug < 0)
00565 fprintf(stderr, "*** davPreSend(%p,%p,%p) sess %p %s %p\n", req, userdata, buf, sess, id, fd);
00566 if (_dav_debug)
00567 fprintf(stderr, "-> %s\n", buf->data);
00568
00569 }
00570
00571 static int davPostSend(ne_request * req, void * userdata, const ne_status * status)
00572
00573 {
00574 urlinfo u = userdata;
00575 ne_session * sess;
00576 const char * id = "fd";
00577 FD_t fd = NULL;
00578
00579 assert(u != NULL);
00580 assert(u->sess != NULL);
00581 assert(req != NULL);
00582 sess = ne_get_session(req);
00583 assert(sess == u->sess);
00584
00585 assert(u == ne_get_session_private(sess, "urlinfo"));
00586
00587
00588 fd = ne_get_request_private(req, id);
00589
00590
00591 if (_dav_debug < 0)
00592 fprintf(stderr, "*** davPostSend(%p,%p,%p) sess %p %s %p %s\n", req, userdata, status, sess, id, fd, ne_get_error(sess));
00593
00594 return NE_OK;
00595 }
00596
00597 static void davDestroyRequest(ne_request * req, void * userdata)
00598
00599 {
00600 urlinfo u = userdata;
00601 ne_session * sess;
00602 const char * id = "fd";
00603 FD_t fd = NULL;
00604
00605 assert(u != NULL);
00606 assert(u->sess != NULL);
00607 assert(req != NULL);
00608 sess = ne_get_session(req);
00609 assert(sess == u->sess);
00610
00611 assert(u == ne_get_session_private(sess, "urlinfo"));
00612
00613
00614 fd = ne_get_request_private(req, id);
00615
00616 if (_dav_debug < 0)
00617 fprintf(stderr, "*** davDestroyRequest(%p,%p) sess %p %s %p\n", req, userdata, sess, id, fd);
00618 }
00619
00620 static void davDestroySession(void * userdata)
00621
00622 {
00623 urlinfo u = userdata;
00624 ne_session * sess;
00625 void * private = NULL;
00626 const char * id = "urlinfo";
00627
00628 assert(u != NULL);
00629 assert(u->sess != NULL);
00630 sess = u->sess;
00631
00632 assert(u == ne_get_session_private(sess, "urlinfo"));
00633
00634
00635 assert(sess != NULL);
00636 private = ne_get_session_private(sess, id);
00637 assert(u == private);
00638
00639 if (_dav_debug < 0)
00640 fprintf(stderr, "*** davDestroySession(%p) sess %p %s %p\n", userdata, sess, id, private);
00641 }
00642
00643 static int
00644 davVerifyCert(void *userdata, int failures, const ne_ssl_certificate *cert)
00645
00646 {
00647 const char *hostname = userdata;
00648
00649 if (_dav_debug < 0)
00650 fprintf(stderr, "*** davVerifyCert(%p,%d,%p) %s\n", userdata, failures, cert, hostname);
00651
00652 return 0;
00653 }
00654
00655 static int davConnect(urlinfo u)
00656
00657
00658 {
00659 const char * path = NULL;
00660 int rc;
00661
00662
00663 if (!(u->urltype == URL_IS_HTTP || u->urltype == URL_IS_HTTPS))
00664 return 0;
00665
00666
00667 (void) urlPath(u->url, &path);
00668 if (path == NULL || *path == '\0')
00669 path = "/";
00670
00671 #ifdef NOTYET
00672
00673 if (path != NULL && path[strlen(path)-1] == '/')
00674 u->allow &= ~RPMURL_SERVER_OPTIONSDONE;
00675 #endif
00676
00677 if (u->allow & RPMURL_SERVER_OPTIONSDONE)
00678 return 0;
00679
00680 u->allow &= ~(RPMURL_SERVER_HASDAVCLASS1 |
00681 RPMURL_SERVER_HASDAVCLASS2 |
00682 RPMURL_SERVER_HASDAVEXEC);
00683
00684
00685
00686 rc = ne_options(u->sess, path, u->capabilities);
00687 switch (rc) {
00688 case NE_OK:
00689 u->allow |= RPMURL_SERVER_OPTIONSDONE;
00690 { ne_server_capabilities *cap = u->capabilities;
00691 if (cap->dav_class1)
00692 u->allow |= RPMURL_SERVER_HASDAVCLASS1;
00693 else
00694 u->allow &= ~RPMURL_SERVER_HASDAVCLASS1;
00695 if (cap->dav_class2)
00696 u->allow |= RPMURL_SERVER_HASDAVCLASS2;
00697 else
00698 u->allow &= ~RPMURL_SERVER_HASDAVCLASS2;
00699 if (cap->dav_executable)
00700 u->allow |= RPMURL_SERVER_HASDAVEXEC;
00701 else
00702 u->allow &= ~RPMURL_SERVER_HASDAVEXEC;
00703 } break;
00704 case NE_ERROR:
00705
00706 if (!strncmp("501 ", ne_get_error(u->sess), sizeof("501 ")-1)) {
00707 u->allow |= RPMURL_SERVER_OPTIONSDONE;
00708 rc = NE_OK;
00709 break;
00710 }
00711
00712 if (!strncmp("301 ", ne_get_error(u->sess), sizeof("301 ")-1))
00713 break;
00714 #ifdef HACK
00715
00716 if (!strncmp("302 ", ne_get_error(u->sess), sizeof("302 ")-1)) {
00717 char * t;
00718 if ((t = strchr(u->url, '\0')) != NULL)
00719 *t = '/';
00720 break;
00721 }
00722 #endif
00723 errno = EIO;
00724 goto bottom;
00725 case NE_LOOKUP:
00726 errno = ENOENT;
00727 goto bottom;
00728 case NE_CONNECT:
00729 default:
00730 bottom:
00731
00732 if (_dav_debug)
00733 fprintf(stderr, "*** Connect to %s:%d failed(%d):\n\t%s\n",
00734 u->host, u->port, rc, ne_get_error(u->sess));
00735
00736 break;
00737 }
00738
00739
00740 u->httpVersion = (ne_version_pre_http11(u->sess) ? 0 : 1);
00741
00742 return rc;
00743 }
00744
00745 static int davInit(const char * url, urlinfo * uret)
00746
00747
00748 {
00749 urlinfo u = NULL;
00750 int rc = 0;
00751
00752
00753 if (urlSplit(url, &u))
00754 return -1;
00755
00756
00757 if (u->url != NULL && u->sess == NULL)
00758 switch (u->urltype) {
00759 default:
00760 assert(u->urltype != u->urltype);
00761 break;
00762 case URL_IS_HTTPS:
00763 case URL_IS_HTTP:
00764 case URL_IS_HKP:
00765 { ne_server_capabilities * capabilities;
00766
00767
00768
00769 rc = ((_dav_debug < 0) ? NE_DBG_HTTP : 0);
00770 ne_debug_init(stderr, rc);
00771
00772 rc = ne_sock_init();
00773
00774 u->lockstore = ne_lockstore_create();
00775
00776 u->capabilities = capabilities = xcalloc(1, sizeof(*capabilities));
00777 u->sess = ne_session_create(u->scheme, u->host, u->port);
00778
00779 ne_lockstore_register(u->lockstore, u->sess);
00780
00781 if (u->proxyh != NULL)
00782 ne_session_proxy(u->sess, u->proxyh, u->proxyp);
00783
00784 #if 0
00785 { const ne_inet_addr ** addrs;
00786 unsigned int n;
00787 ne_set_addrlist(u->sess, addrs, n);
00788 }
00789 #endif
00790
00791 ne_set_progress(u->sess, davProgress, u);
00792 #if WITH_NEON_MIN_VERSION >= 0x002700
00793 ne_set_notifier(u->sess, davNotify, u);
00794 #else
00795 ne_set_status(u->sess, davNotify, u);
00796 #endif
00797
00798 #if WITH_NEON_MIN_VERSION >= 0x002600
00799 ne_set_session_flag(u->sess, NE_SESSFLAG_PERSIST, rpmioHttpPersist);
00800 #else
00801 ne_set_persist(u->sess, rpmioHttpPersist);
00802 #endif
00803 ne_set_read_timeout(u->sess, rpmioHttpReadTimeoutSecs);
00804 ne_set_useragent(u->sess,
00805 (rpmioHttpUserAgent ? rpmioHttpUserAgent : _rpmioHttpUserAgent));
00806
00807
00808 if (!strcasecmp(u->scheme, "https"))
00809 ne_ssl_set_verify(u->sess, davVerifyCert, (char *)u->host);
00810
00811 ne_set_session_private(u->sess, "urlinfo", u);
00812
00813 ne_hook_destroy_session(u->sess, davDestroySession, u);
00814
00815 ne_hook_create_request(u->sess, davCreateRequest, u);
00816 ne_hook_pre_send(u->sess, davPreSend, u);
00817 ne_hook_post_send(u->sess, davPostSend, u);
00818 ne_hook_destroy_request(u->sess, davDestroyRequest, u);
00819
00820
00821 rc = davConnect(u);
00822 if (rc)
00823 goto exit;
00824 } break;
00825 }
00826
00827 exit:
00828 if (uret != NULL)
00829 *uret = urlLink(u, "davInit");
00830 u = urlFree(u, "urlSplit (davInit)");
00831
00832 return rc;
00833 }
00834
00835
00836 enum fetch_rtype_e {
00837 resr_normal = 0,
00838 resr_collection,
00839 resr_reference,
00840 resr_error
00841 };
00842
00843 struct fetch_resource_s {
00844
00845 struct fetch_resource_s *next;
00846 char *uri;
00847
00848 char *displayname;
00849 enum fetch_rtype_e type;
00850 size_t size;
00851 time_t modtime;
00852 int is_executable;
00853 int is_vcr;
00854 char *error_reason;
00855 int error_status;
00856 };
00857
00858
00859 static void *fetch_destroy_item( struct fetch_resource_s *res)
00860
00861 {
00862 ne_free(res->uri);
00863 ne_free(res->error_reason);
00864 res = _free(res);
00865 return NULL;
00866 }
00867
00868 #ifdef NOTUSED
00869
00870 static void *fetch_destroy_list( struct fetch_resource_s *res)
00871
00872 {
00873 struct fetch_resource_s *next;
00874 for (; res != NULL; res = next) {
00875 next = res->next;
00876 res = fetch_destroy_item(res);
00877 }
00878 return NULL;
00879 }
00880 #endif
00881
00882 #if WITH_NEON_MIN_VERSION >= 0x002600
00883 static void *fetch_create_item( void *userdata, const ne_uri *uri)
00884 #else
00885 static void *fetch_create_item( void *userdata, const char *uri)
00886 #endif
00887
00888 {
00889 struct fetch_resource_s * res = ne_calloc(sizeof(*res));
00890 return res;
00891 }
00892
00893
00894
00895
00896
00897 static const ne_propname fetch_props[] = {
00898 { "DAV:", "getcontentlength" },
00899 { "DAV:", "getlastmodified" },
00900 { "http://apache.org/dav/props/", "executable" },
00901 { "DAV:", "resourcetype" },
00902 { "DAV:", "checked-in" },
00903 { "DAV:", "checked-out" },
00904 { NULL, NULL }
00905 };
00906
00907
00908 #define ELM_resourcetype (NE_PROPS_STATE_TOP + 1)
00909 #define ELM_collection (NE_PROPS_STATE_TOP + 2)
00910
00911
00912
00913 static const struct ne_xml_idmap fetch_idmap[] = {
00914 { "DAV:", "resourcetype", ELM_resourcetype },
00915 { "DAV:", "collection", ELM_collection }
00916 };
00917
00918
00919 static int fetch_startelm(void *userdata, int parent,
00920 const char *nspace, const char *name,
00921 const char **atts)
00922
00923 {
00924 ne_propfind_handler *pfh = userdata;
00925 struct fetch_resource_s *r = ne_propfind_current_private(pfh);
00926
00927 int state = ne_xml_mapid(fetch_idmap, NE_XML_MAPLEN(fetch_idmap),
00928 nspace, name);
00929
00930
00931 if (r == NULL ||
00932 !((parent == NE_207_STATE_PROP && state == ELM_resourcetype) ||
00933 (parent == ELM_resourcetype && state == ELM_collection)))
00934 return NE_XML_DECLINE;
00935
00936 if (state == ELM_collection) {
00937 r->type = resr_collection;
00938 }
00939
00940 return state;
00941 }
00942
00943 static int fetch_compare(const struct fetch_resource_s *r1,
00944 const struct fetch_resource_s *r2)
00945
00946 {
00947
00948 if (r1->type == resr_error) {
00949 return -1;
00950 } else if (r2->type == resr_error) {
00951 return 1;
00952 } else if (r1->type == resr_collection) {
00953 if (r2->type != resr_collection) {
00954 return -1;
00955 } else {
00956 return strcmp(r1->uri, r2->uri);
00957 }
00958 } else {
00959 if (r2->type != resr_collection) {
00960 return strcmp(r1->uri, r2->uri);
00961 } else {
00962 return 1;
00963 }
00964 }
00965 }
00966
00967 #if WITH_NEON_MIN_VERSION >= 0x002600
00968 static void fetch_results(void *userdata, const ne_uri *uarg,
00969 const ne_prop_result_set *set)
00970 #else
00971 static void fetch_results(void *userdata, void *uarg,
00972 const ne_prop_result_set *set)
00973 #endif
00974
00975 {
00976 avContext ctx = userdata;
00977 struct fetch_resource_s *current, *previous, *newres;
00978 const char *clength, *modtime, *isexec;
00979 const char *checkin, *checkout;
00980 const ne_status *status = NULL;
00981 const char * path = NULL;
00982
00983 #if WITH_NEON_MIN_VERSION >= 0x002600
00984 const ne_uri * uri = uarg;
00985 (void) urlPath(uri->path, &path);
00986 #else
00987 const char * uri = uarg;
00988 (void) urlPath(uri, &path);
00989 #endif
00990 if (path == NULL)
00991 return;
00992
00993 newres = ne_propset_private(set);
00994
00995 if (_dav_debug < 0)
00996 fprintf(stderr, "==> %s in uri %s\n", path, ctx->uri);
00997
00998 if (ne_path_compare(ctx->uri, path) == 0) {
00999
01000 if (_dav_debug < 0)
01001 fprintf(stderr, "==> %s skipping target resource.\n", path);
01002
01003
01004 free(newres);
01005
01006 return;
01007 }
01008
01009 newres->uri = ne_strdup(path);
01010
01011 clength = ne_propset_value(set, &fetch_props[0]);
01012 modtime = ne_propset_value(set, &fetch_props[1]);
01013 isexec = ne_propset_value(set, &fetch_props[2]);
01014 checkin = ne_propset_value(set, &fetch_props[4]);
01015 checkout = ne_propset_value(set, &fetch_props[5]);
01016
01017 if (clength == NULL)
01018 status = ne_propset_status(set, &fetch_props[0]);
01019 if (modtime == NULL)
01020 status = ne_propset_status(set, &fetch_props[1]);
01021
01022 if (newres->type == resr_normal && status != NULL) {
01023
01024 newres->error_status = status->code;
01025
01026
01027 if (strcmp(status->reason_phrase, "status text goes here") == 0) {
01028 const char *desc;
01029 if (status->code == 401) {
01030 desc = _("Authorization Required");
01031 } else if (status->klass == 3) {
01032 desc = _("Redirect");
01033 } else if (status->klass == 5) {
01034 desc = _("Server Error");
01035 } else {
01036 desc = _("Unknown Error");
01037 }
01038 newres->error_reason = ne_strdup(desc);
01039 } else {
01040 newres->error_reason = ne_strdup(status->reason_phrase);
01041 }
01042 newres->type = resr_error;
01043 }
01044
01045 if (isexec && strcasecmp(isexec, "T") == 0) {
01046 newres->is_executable = 1;
01047 } else {
01048 newres->is_executable = 0;
01049 }
01050
01051 if (modtime)
01052 newres->modtime = ne_httpdate_parse(modtime);
01053
01054 if (clength)
01055 newres->size = atoi(clength);
01056
01057
01058 if (checkin) {
01059 newres->is_vcr = 1;
01060 } else if (checkout) {
01061 newres->is_vcr = 2;
01062 } else {
01063 newres->is_vcr = 0;
01064 }
01065
01066 current = *(struct fetch_resource_s **)ctx->resrock;
01067 for (current = *ctx->resrock, previous = NULL; current != NULL;
01068 previous = current, current = current->next)
01069 {
01070 if (fetch_compare(current, newres) >= 0) {
01071 break;
01072 }
01073 }
01074 if (previous) {
01075 previous->next = newres;
01076 } else {
01077
01078 *(struct fetch_resource_s **)ctx->resrock = newres;
01079
01080 }
01081 newres->next = current;
01082 }
01083
01084 static int davFetch(const urlinfo u, avContext ctx)
01085
01086
01087 {
01088 const char * path = NULL;
01089 int depth = 1;
01090 struct fetch_resource_s * resitem = NULL;
01091 ne_propfind_handler *pfh;
01092 struct fetch_resource_s *current, *next;
01093 mode_t st_mode;
01094 int rc = 0;
01095 int xx;
01096
01097 (void) urlPath(u->url, &path);
01098 pfh = ne_propfind_create(u->sess, ctx->uri, depth);
01099
01100
01101
01102 ctx->resrock = (void **) &resitem;
01103
01104 ne_xml_push_handler(ne_propfind_get_parser(pfh),
01105 fetch_startelm, NULL, NULL, pfh);
01106
01107 ne_propfind_set_private(pfh, fetch_create_item, NULL);
01108
01109 rc = ne_propfind_named(pfh, fetch_props, fetch_results, ctx);
01110
01111 ne_propfind_destroy(pfh);
01112
01113 for (current = resitem; current != NULL; current = next) {
01114 const char *s, *se;
01115 char * val;
01116
01117 next = current->next;
01118
01119
01120
01121 se = current->uri + strlen(current->uri);
01122 if (se[-1] == '/') {
01123 if (strlen(current->uri) <= strlen(path)) {
01124 current = fetch_destroy_item(current);
01125 continue;
01126 }
01127 se--;
01128 }
01129 s = se;
01130 while (s > current->uri && s[-1] != '/')
01131 s--;
01132
01133 val = ne_strndup(s, (se - s));
01134
01135
01136 val = ne_path_unescape(val);
01137
01138
01139 switch (current->type) {
01140 case resr_normal:
01141 st_mode = S_IFREG;
01142 break;
01143 case resr_collection:
01144 st_mode = S_IFDIR;
01145 break;
01146 case resr_reference:
01147 case resr_error:
01148 default:
01149 st_mode = 0;
01150 break;
01151 }
01152
01153 xx = avContextAdd(ctx, val, st_mode, current->size, current->modtime);
01154 ne_free(val);
01155
01156 current = fetch_destroy_item(current);
01157 }
01158 ctx->resrock = NULL;
01159
01160
01161 return rc;
01162 }
01163
01164
01165 static int davHEAD(urlinfo u, struct stat *st)
01166
01167 {
01168 ne_request *req;
01169 const ne_status *status = NULL;
01170 const char *htag;
01171 const char *value = NULL;
01172 int rc;
01173 int printing = 0;
01174
01175
01176 { size_t nb = strlen(u->url);
01177 st->st_mode = (u->url[nb-1] == '/' ? S_IFDIR : S_IFREG);
01178 }
01179 st->st_blksize = 4 * 1024;
01180 st->st_size = -1;
01181 st->st_atime = -1;
01182 st->st_mtime = -1;
01183 st->st_ctime = -1;
01184
01185 req = ne_request_create(u->sess, "HEAD", u->url);
01186 if (rpmioHttpAccept != NULL)
01187 ne_add_request_header(req, "Accept", rpmioHttpAccept);
01188
01189
01190
01191 rc = ne_request_dispatch(req);
01192 status = ne_get_status(req);
01193
01194
01195 if (_dav_debug) {
01196 fprintf(stderr, "HTTP request sent, awaiting response... %d %s\n", status->code, status->reason_phrase);
01197 }
01198
01199 switch (rc) {
01200 default:
01201 goto exit;
01202 break;
01203 case NE_OK:
01204 if (status->klass != 2)
01205 rc = NE_ERROR;
01206 break;
01207 }
01208
01209 #if defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
01210 htag = "ETag";
01211 value = ne_get_response_header(req, htag);
01212 if (value) {
01213
01214 u->etag = _free(u->etag);
01215 u->etag = xstrdup(value);
01216 }
01217
01218
01219 htag = "Location";
01220 value = ne_get_response_header(req, htag);
01221 if (value) {
01222 u->location = _free(u->location);
01223 u->location = xstrdup(value);
01224 }
01225
01226 htag = "Content-Length";
01227 value = ne_get_response_header(req, htag);
01228 if (value) {
01229
01230 if (_dav_debug && ++printing)
01231 fprintf(stderr, "Length: %s", value);
01232
01233
01234 st->st_size = strtoll(value, NULL, 10);
01235
01236 st->st_blocks = (st->st_size + 511)/512;
01237 }
01238
01239 htag = "Content-Type";
01240 value = ne_get_response_header(req, htag);
01241 if (value) {
01242 if (_dav_debug && printing)
01243 fprintf(stderr, " [%s]", value);
01244 if (!strcmp(value, "text/html")
01245 || !strcmp(value, "application/xhtml+xml"))
01246 st->st_blksize = 2 * 1024;
01247 }
01248
01249 htag = "Last-Modified";
01250 value = ne_get_response_header(req, htag);
01251 if (value) {
01252 if (_dav_debug && printing)
01253 fprintf(stderr, " [%s]", value);
01254 st->st_mtime = ne_httpdate_parse(value);
01255 st->st_atime = st->st_ctime = st->st_mtime;
01256 }
01257
01258 if (_dav_debug && printing)
01259 fprintf(stderr, "\n");
01260 #endif
01261
01262 exit:
01263 ne_request_destroy(req);
01264 return rc;
01265 }
01266
01267 static int my_result(const char * msg, int ret, FILE * fp)
01268
01269 {
01270
01271 if (_dav_debug >= 0)
01272 return ret;
01273 if (fp == NULL)
01274 fp = stderr;
01275 if (msg != NULL)
01276 fprintf(fp, "*** %s: ", msg);
01277
01278
01279 #ifdef HACK
01280 fprintf(fp, "%s: %s\n", ftpStrerror(-ret), ne_get_error(sess));
01281 #else
01282 fprintf(fp, "%s\n", ftpStrerror(-ret));
01283 #endif
01284 return ret;
01285 }
01286
01287
01290 typedef struct rpmhtml_s * rpmhtml;
01291
01294 struct rpmhtml_s {
01295
01296 avContext ctx;
01297 ne_request *req;
01298
01299
01300 const char * pattern;
01301
01302 miRE mires;
01303 int nmires;
01304
01305 char * buf;
01306 size_t nbuf;
01307
01308 char * b;
01309 size_t nb;
01310 };
01311
01314 static
01315 rpmhtml htmlFree( rpmhtml html)
01316
01317 {
01318 if (html != NULL) {
01319 if (html->req != NULL) {
01320 ne_request_destroy(html->req);
01321 html->req = NULL;
01322 }
01323 html->buf = _free(html->buf);
01324 html->nbuf = 0;
01325 html->ctx = NULL;
01326 }
01327 return NULL;
01328 }
01329
01332 static
01333 rpmhtml htmlNew(urlinfo u, avContext ctx)
01334
01335 {
01336 rpmhtml html = xcalloc(1, sizeof(*html));
01337 html->ctx = ctx;
01338 html->nbuf = BUFSIZ;
01339 html->buf = xmalloc(html->nbuf + 1 + 1);
01340 html->req = ne_request_create(u->sess, "GET", u->url);
01341 return html;
01342 }
01343
01346 static ssize_t htmlFill(rpmhtml html)
01347
01348 {
01349 char * b = html->buf;
01350 size_t nb = html->nbuf;
01351 ssize_t rc;
01352
01353 if (_dav_debug < 0)
01354 fprintf(stderr, "*** htmlFill(%p) %p[%u]\n", html, b, (unsigned)nb);
01355 if (html->b != NULL && html->nb > 0 && html->b > html->buf) {
01356 memmove(html->buf, html->b, html->nb);
01357 b += html->nb;
01358 nb -= html->nb;
01359 }
01360
01361
01362 rc = ne_read_response_block(html->req, b, nb) ;
01363 if (rc > 0)
01364 html->nb += rc;
01365 html->b = html->buf;
01366
01367 return rc;
01368 }
01369
01375 static
01376 unsigned char nibble(char c)
01377
01378 {
01379 if (c >= '0' && c <= '9')
01380 return (unsigned char) (c - '0');
01381 if (c >= 'A' && c <= 'F')
01382 return (unsigned char)((int)(c - 'A') + 10);
01383 if (c >= 'a' && c <= 'f')
01384 return (unsigned char)((int)(c - 'a') + 10);
01385 return (unsigned char) '\0';
01386 }
01387
01388
01389 static const char * hrefpat = "(?i)<a(?:\\s+[a-z][a-z0-9_]*(?:=(?:\"[^\"]*\"|\\S+))?)*?\\s+href=(?:\"([^\"]*)\"|(\\S+))";
01390
01393 static int htmlParse(rpmhtml html)
01394
01395
01396 {
01397 miRE mire;
01398 int noffsets = 3;
01399 int offsets[3];
01400 ssize_t nr = (html->b != NULL ? (ssize_t)html->nb : htmlFill(html));
01401 int rc = 0;
01402 int xx;
01403
01404 if (_dav_debug < 0)
01405 fprintf(stderr, "*** htmlParse(%p) %p[%u]\n", html, html->buf, (unsigned)html->nbuf);
01406 html->pattern = hrefpat;
01407 xx = mireAppend(RPMMIRE_PCRE, 0, html->pattern, NULL, &html->mires, &html->nmires);
01408 mire = html->mires;
01409
01410 xx = mireSetEOptions(mire, offsets, noffsets);
01411
01412 while (html->nb > 0) {
01413 char * gbn, * href;
01414 const char * hbn, * lpath;
01415 char * f, * fe;
01416 char * g, * ge;
01417 size_t ng;
01418 char * h, * he;
01419 size_t nh;
01420 char * t;
01421 mode_t st_mode;
01422 int ut;
01423
01424 assert(html->b != NULL);
01425 offsets[0] = offsets[1] = -1;
01426 xx = mireRegexec(mire, html->b, html->nb);
01427 if (xx == 0 && offsets[0] != -1 && offsets[1] != -1) {
01428
01429
01430 f = html->b + offsets[0];
01431 fe = html->b + offsets[1];
01432
01433 he = fe;
01434 if (he[-1] == '"') he--;
01435 h = he;
01436 while (h > f && h[-1] != '"')
01437 h--;
01438
01439 nh = (size_t)(he - h);
01440 href = t = xmalloc(nh + 1 + 1);
01441 while (h < he) {
01442 char c = *h++;
01443 switch (c) {
01444 default:
01445 break;
01446 case '%':
01447 if (isxdigit((int)h[0]) && isxdigit((int)h[1])) {
01448 c = (char) (nibble(h[0]) << 4) | nibble(h[1]);
01449 h += 2;
01450 }
01451 break;
01452 }
01453 *t++ = c;
01454 }
01455 *t = '\0';
01456
01457
01458 switch ((ut = urlPath(href, &lpath))) {
01459 case URL_IS_UNKNOWN:
01460 default:
01461
01462 if (href[nh-1] == '/') {
01463 st_mode = S_IFDIR | 0755;
01464 href[nh-1] = '\0';
01465 } else
01466 st_mode = S_IFREG | 0644;
01467 break;
01468 case URL_IS_FTP:
01469 case URL_IS_HTTPS:
01470 case URL_IS_HTTP:
01471 #ifdef NOTYET
01472 st_mode = S_IFLNK | 0755;
01473 break;
01474 #endif
01475 case URL_IS_PATH:
01476 case URL_IS_DASH:
01477 case URL_IS_HKP:
01478 href[0] = '\0';
01479 break;
01480 }
01481 if ((hbn = strrchr(href, '/')) != NULL)
01482 hbn++;
01483 else
01484 hbn = href;
01485 assert(hbn != NULL);
01486
01487
01488 g = fe;
01489 while (*g != '>')
01490 g++;
01491 ge = ++g;
01492 while (*ge != '<')
01493 ge++;
01494
01495 ng = (size_t)(ge - g);
01496 gbn = t = xmalloc(ng + 1 + 1);
01497 while (g < ge && *g != '/')
01498 *t++ = *g++;
01499 *t = '\0';
01500
01501 if (_dav_debug)
01502 if (*hbn != '\0' && *gbn != '\0' && strcasecmp(hbn, gbn))
01503 fprintf(stderr, "\t[%s] != [%s]\n", hbn, gbn);
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513 if (*hbn != '\0' && *gbn != '\0')
01514 if (strcmp(hbn, ".") && strcmp(hbn, ".."))
01515 if (!strcasecmp(hbn, gbn)) {
01516 size_t _st_size = (size_t)0;
01517 time_t _st_mtime = (time_t)0;
01518 xx = avContextAdd(html->ctx, gbn, st_mode, _st_size, _st_mtime);
01519 }
01520
01521 gbn = _free(gbn);
01522 href = _free(href);
01523
01524 offsets[1] += (ge - fe);
01525 html->b += offsets[1];
01526 html->nb -= offsets[1];
01527 } else {
01528 size_t nb = html->nb;
01529 if (nr > 0) nb -= 128;
01530 html->b += nb;
01531 html->nb -= nb;
01532 }
01533
01534 if (nr > 0)
01535 nr = htmlFill(html);
01536 }
01537
01538 xx = mireSetEOptions(mire, NULL, 0);
01539
01540 html->mires = mireFreeAll(html->mires, html->nmires);
01541 html->nmires = 0;
01542
01543 if (_dav_debug < 0)
01544 fprintf(stderr, "*** htmlParse(%p) rc %d\n", html, rc);
01545 return rc;
01546 }
01547
01548
01549
01550 static int htmlNLST(urlinfo u, avContext ctx)
01551
01552
01553 {
01554 rpmhtml html = htmlNew(u, ctx);
01555 int rc = 0;
01556
01557 if (_dav_debug < 0)
01558 fprintf(stderr, "*** htmlNLST(%p, %p) html %p\n", u, ctx, html);
01559
01560 do {
01561 rc = ne_begin_request(html->req);
01562 rc = my_result("ne_begin_req(html->req)", rc, NULL);
01563 if (rc != NE_OK) goto exit;
01564
01565 (void) htmlParse(html);
01566
01567 rc = ne_end_request(html->req);
01568 rc = my_result("ne_end_req(html->req)", rc, NULL);
01569 } while (rc == NE_RETRY);
01570
01571 exit:
01572 html = htmlFree(html);
01573 return rc;
01574 }
01575
01576
01577 static int davNLST(avContext ctx)
01578
01579
01580 {
01581 urlinfo u = NULL;
01582 int rc;
01583 int xx;
01584
01585 retry:
01586 rc = davInit(ctx->uri, &u);
01587 if (rc || u == NULL)
01588 goto exit;
01589
01590
01591
01592
01593
01594
01595 if (u->allow & RPMURL_SERVER_HASDAV)
01596 rc = davFetch(u, ctx);
01597 else {
01598
01599 rc = davHEAD(u, ctx->st);
01600
01601
01602 if (rc == NE_OK && S_ISDIR(ctx->st->st_mode))
01603 rc = htmlNLST(u, ctx);
01604 }
01605
01606 switch (rc) {
01607 case NE_OK:
01608 break;
01609 case NE_ERROR:
01610
01611
01612
01613
01614
01615 if (!strncmp("301 ", ne_get_error(u->sess), sizeof("301 ")-1))
01616 break;
01617
01618
01619 if (!strncmp("302 ", ne_get_error(u->sess), sizeof("302 ")-1)) {
01620 const char * path = NULL;
01621 int ut = urlPath(u->url, &path);
01622 size_t nb = strlen(path);
01623 ut = ut;
01624 if (u->location != NULL && !strncmp(path, u->location, nb)
01625 && u->location[nb] == '/' && u->location[nb+1] == '\0')
01626 {
01627 char * te = strchr(u->url, '\0');
01628
01629 if (te != NULL && te[-1] != '/') {
01630
01631 *te++ = '/';
01632 *te = '\0';
01633 u->location = _free(u->location);
01634
01635 xx = davFree(u);
01636 goto retry;
01637 break;
01638 }
01639 }
01640 }
01641
01642 default:
01643
01644 if (_dav_debug)
01645 fprintf(stderr, "*** Fetch from %s:%d failed:\n\t%s\n",
01646 u->host, u->port, ne_get_error(u->sess));
01647
01648 break;
01649 }
01650
01651 exit:
01652 xx = davFree(u);
01653 return rc;
01654 }
01655
01656
01657
01658 static void davAcceptRanges(void * userdata, const char * value)
01659
01660 {
01661 urlinfo u = userdata;
01662
01663 if (!(u != NULL && value != NULL)) return;
01664 if (_dav_debug < 0)
01665 fprintf(stderr, "*** u %p Accept-Ranges: %s\n", u, value);
01666 if (!strcmp(value, "bytes"))
01667 u->allow |= RPMURL_SERVER_HASRANGE;
01668 if (!strcmp(value, "none"))
01669 u->allow &= ~RPMURL_SERVER_HASRANGE;
01670 }
01671
01672
01673 #if !defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
01674 static void davAllHeaders(void * userdata, const char * value)
01675 {
01676 FD_t ctrl = userdata;
01677
01678 if (!(ctrl != NULL && value != NULL)) return;
01679 if (_dav_debug)
01680 fprintf(stderr, "<- %s\n", value);
01681 }
01682 #endif
01683
01684
01685 static void davContentLength(void * userdata, const char * value)
01686
01687 {
01688 FD_t ctrl = userdata;
01689
01690 if (!(ctrl != NULL && value != NULL)) return;
01691 if (_dav_debug < 0)
01692 fprintf(stderr, "*** fd %p Content-Length: %s\n", ctrl, value);
01693
01694 ctrl->contentLength = strtoll(value, NULL, 10);
01695
01696 }
01697
01698
01699
01700 static void davContentType(void * userdata, const char * value)
01701
01702 {
01703 FD_t ctrl = userdata;
01704
01705 if (!(ctrl != NULL && value != NULL)) return;
01706 if (_dav_debug < 0)
01707 fprintf(stderr, "*** fd %p Content-Type: %s\n", ctrl, value);
01708 ctrl->contentType = _free(ctrl->contentType);
01709 ctrl->contentType = xstrdup(value);
01710 }
01711
01712
01713
01714 static void davContentDisposition(void * userdata, const char * value)
01715
01716 {
01717 FD_t ctrl = userdata;
01718
01719 if (!(ctrl != NULL && value != NULL)) return;
01720 if (_dav_debug < 0)
01721 fprintf(stderr, "*** fd %p Content-Disposition: %s\n", ctrl, value);
01722 ctrl->contentDisposition = _free(ctrl->contentDisposition);
01723 ctrl->contentDisposition = xstrdup(value);
01724 }
01725
01726
01727
01728 static void davLastModified(void * userdata, const char * value)
01729
01730 {
01731 FD_t ctrl = userdata;
01732
01733 if (!(ctrl != NULL && value != NULL)) return;
01734 if (_dav_debug < 0)
01735 fprintf(stderr, "*** fd %p Last-Modified: %s\n", ctrl, value);
01736
01737 ctrl->lastModified = ne_httpdate_parse(value);
01738
01739 }
01740
01741
01742
01743 static void davConnection(void * userdata, const char * value)
01744
01745 {
01746 FD_t ctrl = userdata;
01747
01748 if (!(ctrl != NULL && value != NULL)) return;
01749 if (_dav_debug < 0)
01750 fprintf(stderr, "*** fd %p Connection: %s\n", ctrl, value);
01751 if (!strcasecmp(value, "close"))
01752 ctrl->persist = 0;
01753 else if (!strcasecmp(value, "Keep-Alive"))
01754 ctrl->persist = 1;
01755 }
01756
01757
01758
01759 int davResp(urlinfo u, FD_t ctrl, char *const * str)
01760 {
01761 int rc = 0;
01762
01763 rc = ne_begin_request(ctrl->req);
01764 rc = my_result("ne_begin_req(ctrl->req)", rc, NULL);
01765
01766 if (_dav_debug < 0)
01767 fprintf(stderr, "*** davResp(%p,%p,%p) sess %p req %p rc %d\n", u, ctrl, str, u->sess, ctrl->req, rc);
01768
01769
01770
01771 if (rc)
01772 fdSetSyserrno(ctrl, errno, ftpStrerror(-rc));
01773
01774
01775 return rc;
01776 }
01777
01778
01779 int davReq(FD_t ctrl, const char * httpCmd, const char * httpArg)
01780 {
01781 urlinfo u;
01782 int rc = 0;
01783
01784 assert(ctrl != NULL);
01785 u = ctrl->url;
01786 URLSANE(u);
01787
01788 if (_dav_debug < 0)
01789 fprintf(stderr, "*** davReq(%p,%s,\"%s\") entry sess %p req %p\n", ctrl, httpCmd, (httpArg ? httpArg : ""), u->sess, ctrl->req);
01790
01791 ctrl->persist = (u->httpVersion > 0 ? 1 : 0);
01792 ctrl = fdLink(ctrl, "open ctrl (davReq)");
01793 assert(ctrl != NULL);
01794
01795 assert(u->sess != NULL);
01796
01797 if (ctrl->req == (void *)-1)
01798 ctrl->req = NULL;
01799
01800 assert(ctrl->req == NULL);
01801
01802
01803 ctrl->req = ne_request_create(u->sess, httpCmd, httpArg);
01804
01805 assert(ctrl->req != NULL);
01806
01807 ne_set_request_private(ctrl->req, "fd", ctrl);
01808
01809 #if !defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
01810 ne_add_response_header_catcher(ctrl->req, davAllHeaders, ctrl);
01811
01812 ne_add_response_header_handler(ctrl->req, "Content-Length",
01813 davContentLength, ctrl);
01814 ne_add_response_header_handler(ctrl->req, "Content-Type",
01815 davContentType, ctrl);
01816 ne_add_response_header_handler(ctrl->req, "Content-Disposition",
01817 davContentDisposition, ctrl);
01818 ne_add_response_header_handler(ctrl->req, "Last-Modified",
01819 davLastModified, ctrl);
01820 ne_add_response_header_handler(ctrl->req, "Connection",
01821 davConnection, ctrl);
01822 #endif
01823
01824 if (!strcmp(httpCmd, "PUT")) {
01825 #if defined(HAVE_NEON_NE_SEND_REQUEST_CHUNK)
01826 ctrl->wr_chunked = 1;
01827 ne_add_request_header(ctrl->req, "Transfer-Encoding", "chunked");
01828 ne_set_request_chunked(ctrl->req, 1);
01829
01830 rc = davResp(u, ctrl, NULL);
01831 #else
01832 rc = FTPERR_SERVER_IO_ERROR;
01833 #endif
01834 } else {
01835
01836 #if !defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
01837 ne_add_response_header_handler(ctrl->req, "Accept-Ranges",
01838 davAcceptRanges, u);
01839 #endif
01840
01841
01842
01843
01844
01845 do {
01846 rc = davResp(u, ctrl, NULL);
01847 } while (rc == NE_RETRY);
01848 }
01849
01850
01851 if (_dav_debug) {
01852 const ne_status *status = ne_get_status(ctrl->req);
01853 fprintf(stderr, "HTTP request sent, awaiting response... %d %s\n", status->code, status->reason_phrase);
01854 }
01855
01856 if (rc)
01857 goto errxit;
01858
01859 if (_dav_debug < 0)
01860 fprintf(stderr, "*** davReq(%p,%s,\"%s\") exit sess %p req %p rc %d\n", ctrl, httpCmd, (httpArg ? httpArg : ""), u->sess, ctrl->req, rc);
01861
01862 #if defined(HAVE_NEON_NE_GET_RESPONSE_HEADER)
01863 davContentLength(ctrl,
01864 ne_get_response_header(ctrl->req, "Content-Length"));
01865 davContentType(ctrl,
01866 ne_get_response_header(ctrl->req, "Content-Type"));
01867 davContentDisposition(ctrl,
01868 ne_get_response_header(ctrl->req, "Content-Disposition"));
01869 davLastModified(ctrl,
01870 ne_get_response_header(ctrl->req, "Last-Modified"));
01871 davConnection(ctrl,
01872 ne_get_response_header(ctrl->req, "Connection"));
01873 if (strcmp(httpCmd, "PUT"))
01874 davAcceptRanges(u,
01875 ne_get_response_header(ctrl->req, "Accept-Ranges"));
01876 #endif
01877
01878 ctrl = fdLink(ctrl, "open data (davReq)");
01879 return 0;
01880
01881 errxit:
01882
01883 fdSetSyserrno(ctrl, errno, ftpStrerror(rc));
01884
01885
01886
01887 ctrl = fdLink(ctrl, "error data (davReq)");
01888
01889 return rc;
01890 }
01891
01892 FD_t davOpen(const char * url, int flags,
01893 mode_t mode, urlinfo * uret)
01894 {
01895 const char * path = NULL;
01896 urltype urlType = urlPath(url, &path);
01897 urlinfo u = NULL;
01898 FD_t fd = NULL;
01899 int rc;
01900
01901 #if 0
01902 assert(!(flags & O_RDWR));
01903 #endif
01904
01905 if (_dav_debug < 0)
01906 fprintf(stderr, "*** davOpen(%s,0x%x,0%o,%p)\n", url, flags, (unsigned)mode, uret);
01907 rc = davInit(url, &u);
01908 if (rc || u == NULL || u->sess == NULL)
01909 goto exit;
01910
01911 if (u->ctrl == NULL)
01912 u->ctrl = fdNew("persist ctrl (davOpen)");
01913 else {
01914 yarnLock use = u->ctrl->_item.use;
01915 yarnPossess(use);
01916 if (yarnPeekLock(use) > 2L && u->data == NULL)
01917 u->data = fdNew("persist data (davOpen)");
01918 yarnRelease(use);
01919 }
01920
01921 if (u->ctrl->url == NULL)
01922 fd = u->ctrl = fdLink(u->ctrl, "grab ctrl (davOpen persist ctrl)");
01923 else if (u->data->url == NULL)
01924 fd = u->data = fdLink(u->data, "grab ctrl (davOpen persist data)");
01925 else
01926 fd = fdNew("grab ctrl (davOpen)");
01927
01928 if (fd) {
01929 fdSetOpen(fd, url, flags, mode);
01930 fdSetIo(fd, ufdio);
01931
01932 fd->ftpFileDoneNeeded = 0;
01933 fd->rd_timeoutsecs = rpmioHttpReadTimeoutSecs;
01934 fd->contentLength = fd->bytesRemain = -1;
01935 assert(urlType == URL_IS_HTTPS || urlType == URL_IS_HTTP || urlType == URL_IS_HKP);
01936 fd->urlType = urlType;
01937 fd->url = urlLink(u, "url (davOpen)");
01938 fd = fdLink(fd, "grab data (davOpen)");
01939 }
01940
01941 exit:
01942 if (uret)
01943 *uret = u;
01944
01945 return fd;
01946
01947 }
01948
01949
01950 ssize_t davRead(void * cookie, char * buf, size_t count)
01951 {
01952 FD_t fd = cookie;
01953 ssize_t rc;
01954
01955 #if WITH_NEON_MIN_VERSION >= 0x002700
01956 { urlinfo u = NULL;
01957 u = urlLink(fd->url, "url (davRead)");
01958 if (u->info.status == ne_status_recving)
01959 rc = ne_read_response_block(fd->req, buf, count);
01960 else {
01961
01962 if (u->info.status == ne_status_disconnected) {
01963 int xx;
01964 xx = ne_end_request(fd->req);
01965 xx = my_result("davRead: ne_end_request(req)", xx, NULL);
01966 ne_request_destroy(fd->req);
01967 fd->req = (void *)-1;
01968 }
01969 errno = EIO;
01970 rc = -1;
01971 }
01972 u = urlFree(u, "url (davRead)");
01973 }
01974 #else
01975 rc = ne_read_response_block(fd->req, buf, count);
01976 #endif
01977
01978 if (_dav_debug < 0) {
01979 fprintf(stderr, "*** davRead(%p,%p,0x%x) rc 0x%x\n", cookie, buf, (unsigned)count, (unsigned)rc);
01980 }
01981
01982 return rc;
01983 }
01984
01985
01986 ssize_t davWrite(void * cookie, const char * buf, size_t count)
01987 {
01988 #if !defined(NEONBLOWSCHUNKS) || defined(HAVE_NEON_NE_SEND_REQUEST_CHUNK) || defined(__LCLINT__)
01989 FD_t fd = cookie;
01990 #endif
01991 ssize_t rc;
01992 int xx = -1;
01993
01994 #if !defined(NEONBLOWSCHUNKS)
01995 ne_session * sess;
01996
01997 assert(fd->req != NULL);
01998 sess = ne_get_session(fd->req);
01999 assert(sess != NULL);
02000
02001
02002 xx = ne_sock_fullwrite(sess->socket, buf, count);
02003 #else
02004 #if defined(HAVE_NEON_NE_SEND_REQUEST_CHUNK) || defined(__LCLINT__)
02005 assert(fd->req != NULL);
02006
02007 xx = ne_send_request_chunk(fd->req, buf, count);
02008
02009 #else
02010 errno = EIO;
02011 return -1;
02012 #endif
02013 #endif
02014
02015
02016 rc = (xx == 0 ? (ssize_t)count : -1);
02017
02018 if (_dav_debug < 0)
02019 fprintf(stderr, "*** davWrite(%p,%p,0x%x) rc 0x%x\n", cookie, buf, (unsigned)count, (unsigned)rc);
02020
02021 return rc;
02022 }
02023
02024 int davSeek(void * cookie, _libio_pos_t pos, int whence)
02025 {
02026 if (_dav_debug < 0)
02027 fprintf(stderr, "*** davSeek(%p,pos,%d)\n", cookie, whence);
02028 return -1;
02029 }
02030
02031
02032 int davClose(void * cookie)
02033 {
02034
02035 FD_t fd = cookie;
02036
02037 int rc = 0;
02038
02039 assert(fd->req != NULL);
02040 if (fd->req != (void *)-1) {
02041 rc = ne_end_request(fd->req);
02042 rc = my_result("ne_end_request(req)", rc, NULL);
02043
02044 ne_request_destroy(fd->req);
02045 }
02046 fd->req = NULL;
02047
02048 if (_dav_debug < 0)
02049 fprintf(stderr, "*** davClose(%p) rc %d\n", fd, rc);
02050 return rc;
02051 }
02052
02053
02054
02055 int davMkdir(const char * path, mode_t mode)
02056 {
02057 urlinfo u = NULL;
02058 const char * src = NULL;
02059 int rc;
02060
02061 rc = davInit(path, &u);
02062 if (rc)
02063 goto exit;
02064 assert(u != NULL);
02065
02066 (void) urlPath(path, &src);
02067
02068 rc = ne_mkcol(u->sess, path);
02069
02070 if (rc) rc = -1;
02071
02072
02073
02074 exit:
02075 if (_dav_debug)
02076 fprintf(stderr, "*** davMkdir(%s,0%o) rc %d\n", path, (unsigned)mode, rc);
02077 return rc;
02078 }
02079
02080 int davRmdir(const char * path)
02081 {
02082 urlinfo u = NULL;
02083 const char * src = NULL;
02084 int rc;
02085
02086 rc = davInit(path, &u);
02087 if (rc)
02088 goto exit;
02089 assert(u != NULL);
02090
02091 (void) urlPath(path, &src);
02092
02093
02094
02095 rc = ne_delete(u->sess, path);
02096
02097 if (rc) rc = -1;
02098
02099 exit:
02100 if (_dav_debug)
02101 fprintf(stderr, "*** davRmdir(%s) rc %d\n", path, rc);
02102 return rc;
02103 }
02104
02105 int davRename(const char * oldpath, const char * newpath)
02106 {
02107 urlinfo u = NULL;
02108 const char * src = NULL;
02109 const char * dst = NULL;
02110 int overwrite = 1;
02111 int rc;
02112
02113 rc = davInit(oldpath, &u);
02114 if (rc)
02115 goto exit;
02116 assert(u != NULL);
02117
02118 (void) urlPath(oldpath, &src);
02119 (void) urlPath(newpath, &dst);
02120
02121
02122
02123 rc = ne_move(u->sess, overwrite, src, dst);
02124
02125 if (rc) rc = -1;
02126
02127 exit:
02128 if (_dav_debug)
02129 fprintf(stderr, "*** davRename(%s,%s) rc %d\n", oldpath, newpath, rc);
02130 return rc;
02131 }
02132
02133 int davUnlink(const char * path)
02134 {
02135 urlinfo u = NULL;
02136 const char * src = NULL;
02137 int rc;
02138
02139 rc = davInit(path, &u);
02140 if (rc)
02141 goto exit;
02142 assert(u != NULL);
02143
02144 (void) urlPath(path, &src);
02145
02146
02147
02148 rc = ne_delete(u->sess, src);
02149
02150 exit:
02151 if (rc) rc = -1;
02152
02153 if (_dav_debug)
02154 fprintf(stderr, "*** davUnlink(%s) rc %d\n", path, rc);
02155 return rc;
02156 }
02157
02158 #ifdef NOTYET
02159 static int davChdir(const char * path)
02160
02161
02162 {
02163 return davCommand("CWD", path, NULL);
02164 }
02165 #endif
02166
02167
02168
02169 static const char * statstr(const struct stat * st,
02170 char * buf)
02171
02172 {
02173 sprintf(buf,
02174 "*** dev %x ino %x mode %0o nlink %d uid %d gid %d rdev %x size %x\n",
02175 (unsigned)st->st_dev,
02176 (unsigned)st->st_ino,
02177 (unsigned)st->st_mode,
02178 (unsigned)st->st_nlink,
02179 (unsigned)st->st_uid,
02180 (unsigned)st->st_gid,
02181 (unsigned)st->st_rdev,
02182 (unsigned)st->st_size);
02183 return buf;
02184 }
02185
02186 int davStat(const char * path, struct stat *st)
02187
02188
02189 {
02190 avContext ctx = NULL;
02191 char buf[1024];
02192 int rc = -1;
02193
02194 if (path == NULL || *path == '\0') {
02195 errno = ENOENT;
02196 goto exit;
02197 }
02198 ctx = avContextCreate(path, st);
02199 if (ctx == NULL) {
02200 errno = ENOENT;
02201 goto exit;
02202 }
02203 rc = davNLST(ctx);
02204 if (rc) {
02205
02206 goto exit;
02207 }
02208
02209 if (st->st_mode == 0)
02210 st->st_mode = (ctx->ac > 1 ? S_IFDIR : S_IFREG);
02211 st->st_size = (ctx->sizes ? ctx->sizes[0] : (size_t)st->st_size);
02212 st->st_mtime = (ctx->mtimes ? ctx->mtimes[0] : st->st_mtime);
02213 st->st_atime = st->st_ctime = st->st_mtime;
02214 if (S_ISDIR(st->st_mode)) {
02215 st->st_nlink = 2;
02216 st->st_mode |= 0755;
02217 } else
02218 if (S_ISREG(st->st_mode)) {
02219 st->st_nlink = 1;
02220 st->st_mode |= 0644;
02221 }
02222
02223
02224
02225 if (st->st_ino == 0)
02226 st->st_ino = hashFunctionString(0, path, 0);
02227
02228 exit:
02229 if (_dav_debug < 0)
02230 fprintf(stderr, "*** davStat(%s) rc %d\n%s", path, rc, statstr(st, buf));
02231 ctx = avContextDestroy(ctx);
02232 return rc;
02233 }
02234
02235 int davLstat(const char * path, struct stat *st)
02236
02237
02238 {
02239 avContext ctx = NULL;
02240 char buf[1024];
02241 int rc = -1;
02242
02243 if (path == NULL || *path == '\0') {
02244 errno = ENOENT;
02245 goto exit;
02246 }
02247 ctx = avContextCreate(path, st);
02248 if (ctx == NULL) {
02249 errno = ENOENT;
02250 goto exit;
02251 }
02252 rc = davNLST(ctx);
02253 if (rc) {
02254
02255 goto exit;
02256 }
02257
02258 if (st->st_mode == 0)
02259 st->st_mode = (ctx->ac > 1 ? S_IFDIR : S_IFREG);
02260 st->st_size = (ctx->sizes ? ctx->sizes[0] : (size_t)st->st_size);
02261 st->st_mtime = (ctx->mtimes ? ctx->mtimes[0] : st->st_mtime);
02262 st->st_atime = st->st_ctime = st->st_mtime;
02263 if (S_ISDIR(st->st_mode)) {
02264 st->st_nlink = 2;
02265 st->st_mode |= 0755;
02266 } else
02267 if (S_ISREG(st->st_mode)) {
02268 st->st_nlink = 1;
02269 st->st_mode |= 0644;
02270 }
02271
02272
02273
02274 if (st->st_ino == 0)
02275 st->st_ino = hashFunctionString(0, path, 0);
02276
02277 if (_dav_debug < 0)
02278 fprintf(stderr, "*** davLstat(%s) rc %d\n%s\n", path, rc, statstr(st, buf));
02279 exit:
02280 ctx = avContextDestroy(ctx);
02281 return rc;
02282 }
02283
02284 #ifdef NOTYET
02285 static int davReadlink(const char * path, char * buf, size_t bufsiz)
02286
02287
02288 {
02289 int rc;
02290 rc = davNLST(path, DO_FTP_READLINK, NULL, buf, bufsiz);
02291 if (_dav_debug < 0)
02292 fprintf(stderr, "*** davReadlink(%s) rc %d\n", path, rc);
02293 return rc;
02294 }
02295 #endif
02296
02297 #endif
02298
02299
02300
02301 int avmagicdir = 0x3607113;
02302
02303 #ifndef WITH_NEON
02304
02305 FD_t httpOpen(const char * url, int flags,
02306 mode_t mode, urlinfo * uret)
02307
02308
02309 {
02310 urlinfo u = NULL;
02311 FD_t fd = NULL;
02312
02313 #if 0
02314 assert(!(flags & O_RDWR));
02315 #endif
02316 if (urlSplit(url, &u))
02317 goto exit;
02318
02319 if (u->ctrl == NULL)
02320 u->ctrl = fdNew("persist ctrl (httpOpen)");
02321 if (u->ctrl != NULL) {
02322 yarnLock use = u->ctrl->_item.use;
02323 yarnPossess(use);
02324 if (yarnPeekLock(use) > 2L && u->data == NULL)
02325 u->data = fdNew("persist data (httpOpen)");
02326 yarnRelease(use);
02327 }
02328
02329 if (u->ctrl->url == NULL)
02330 fd = fdLink(u->ctrl, "grab ctrl (httpOpen persist ctrl)");
02331 else if (u->data->url == NULL)
02332 fd = fdLink(u->data, "grab ctrl (httpOpen persist data)");
02333 else
02334 fd = fdNew("grab ctrl (httpOpen)");
02335
02336 if (fd) {
02337 fdSetIo(fd, ufdio);
02338 fd->ftpFileDoneNeeded = 0;
02339 fd->rd_timeoutsecs = rpmioHttpReadTimeoutSecs;
02340 fd->contentLength = fd->bytesRemain = -1;
02341 fd->url = urlLink(u, "url (httpOpen)");
02342 fd = fdLink(fd, "grab data (httpOpen)");
02343 fd->urlType = URL_IS_HTTP;
02344 }
02345
02346 exit:
02347 if (uret)
02348 *uret = u;
02349
02350 return fd;
02351
02352 }
02353
02354 #endif
02355
02356 #ifdef WITH_NEON
02357
02358 int davClosedir( DIR * dir)
02359 {
02360 return avClosedir(dir);
02361 }
02362
02363 struct dirent * davReaddir(DIR * dir)
02364 {
02365 return avReaddir(dir);
02366 }
02367
02368 DIR * davOpendir(const char * path)
02369
02370 {
02371 AVDIR avdir = NULL;
02372 avContext ctx = NULL;
02373 struct stat sb, *st = &sb;
02374 const char * uri = NULL;
02375 int rc;
02376
02377 if (_dav_debug < 0)
02378 fprintf(stderr, "*** davOpendir(%s)\n", path);
02379
02380 if (path == NULL || *path == '\0') {
02381 errno = ENOENT;
02382 goto exit;
02383 }
02384
02385
02386
02387 if (path[strlen(path)-1] != '/')
02388 uri = rpmExpand(path, "/", NULL);
02389 else
02390 uri = xstrdup(path);
02391
02392
02393
02394
02395 ctx = avContextCreate(uri, st);
02396 if (ctx == NULL) {
02397 errno = ENOENT;
02398 goto exit;
02399 }
02400
02401 rc = davNLST(ctx);
02402 if (rc) {
02403
02404 goto exit;
02405 } else
02406 avdir = (AVDIR) avOpendir(uri, ctx->av, ctx->modes);
02407
02408 exit:
02409 uri = _free(uri);
02410 ctx = avContextDestroy(ctx);
02411
02412 return (DIR *) avdir;
02413
02414 }
02415
02416
02417
02418 char * davRealpath(const char * path, char * resolved_path)
02419 {
02420 assert(resolved_path == NULL);
02421
02422 return xstrdup(path);
02423 }
02424
02425
02426 #endif