rpm 5.3.7

rpmio/rpmrpc.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio_internal.h>
00008 #include <rpmmacro.h>
00009 
00010 #define _RPMDIR_INTERNAL
00011 #include <rpmdir.h>
00012 #define _RPMDAV_INTERNAL
00013 #include <rpmdav.h>
00014 
00015 #include <rpmhash.h>
00016 #include <ugid.h>
00017 
00018 #include "debug.h"
00019 
00020 /*@access DIR @*/
00021 /*@access FD_t @*/
00022 /*@access urlinfo @*/
00023 
00024 /* =============================================================== */
00025 static int ftpMkdir(const char * path, /*@unused@*/ mode_t mode)
00026         /*@globals h_errno, fileSystem, internalState @*/
00027         /*@modifies fileSystem, internalState @*/
00028 {
00029     int rc;
00030     if ((rc = ftpCmd("MKD", path, NULL)) != 0)
00031         return rc;
00032 #if NOTYET
00033     {   char buf[20];
00034         sprintf(buf, " 0%o", mode);
00035         (void) ftpCmd("SITE CHMOD", path, buf);
00036     }
00037 #endif
00038     return rc;
00039 }
00040 
00041 static int ftpChdir(const char * path)
00042         /*@globals h_errno, fileSystem, internalState @*/
00043         /*@modifies fileSystem, internalState @*/
00044 {
00045     return ftpCmd("CWD", path, NULL);
00046 }
00047 
00048 static int ftpRmdir(const char * path)
00049         /*@globals h_errno, fileSystem, internalState @*/
00050         /*@modifies fileSystem, internalState @*/
00051 {
00052     return ftpCmd("RMD", path, NULL);
00053 }
00054 
00055 static int ftpRename(const char * oldpath, const char * newpath)
00056         /*@globals h_errno, fileSystem, internalState @*/
00057         /*@modifies fileSystem, internalState @*/
00058 {
00059     int rc;
00060     if ((rc = ftpCmd("RNFR", oldpath, NULL)) != 0)
00061         return rc;
00062     return ftpCmd("RNTO", newpath, NULL);
00063 }
00064 
00065 static int ftpUnlink(const char * path)
00066         /*@globals h_errno, fileSystem, internalState @*/
00067         /*@modifies fileSystem, internalState @*/
00068 {
00069     return ftpCmd("DELE", path, NULL);
00070 }
00071 
00072 /* =============================================================== */
00073 int Mkdir (const char * path, mode_t mode)
00074 {
00075     const char * lpath;
00076     int ut = urlPath(path, &lpath);
00077 
00078 if (_rpmio_debug)
00079 fprintf(stderr, "*** Mkdir(%s, 0%o)\n", path, (unsigned)mode);
00080     switch (ut) {
00081     case URL_IS_FTP:
00082         return ftpMkdir(path, mode);
00083         /*@notreached@*/ break;
00084     case URL_IS_HTTPS:
00085     case URL_IS_HTTP:
00086 #ifdef WITH_NEON
00087         return davMkdir(path, mode);
00088 #endif
00089         /*@notreached@*/ break;
00090     case URL_IS_PATH:
00091         path = lpath;
00092         /*@fallthrough@*/
00093     case URL_IS_UNKNOWN:
00094         break;
00095     case URL_IS_DASH:
00096     case URL_IS_HKP:
00097     default:
00098         return -2;
00099         /*@notreached@*/ break;
00100     }
00101     return mkdir(path, mode);
00102 }
00103 
00104 int Chdir (const char * path)
00105 {
00106     const char * lpath;
00107     int ut = urlPath(path, &lpath);
00108 
00109 if (_rpmio_debug)
00110 fprintf(stderr, "*** Chdir(%s)\n", path);
00111     switch (ut) {
00112     case URL_IS_FTP:
00113         return ftpChdir(path);
00114         /*@notreached@*/ break;
00115     case URL_IS_HTTPS:
00116     case URL_IS_HTTP:
00117 #ifdef  NOTYET
00118         return davChdir(path);
00119 #else
00120         errno = EINVAL;         /* XXX W2DO? */
00121         return -2;
00122 #endif
00123         /*@notreached@*/ break;
00124     case URL_IS_PATH:
00125         path = lpath;
00126         /*@fallthrough@*/
00127     case URL_IS_UNKNOWN:
00128         break;
00129     case URL_IS_DASH:
00130     case URL_IS_HKP:
00131     default:
00132         errno = EINVAL;         /* XXX W2DO? */
00133         return -2;
00134         /*@notreached@*/ break;
00135     }
00136     return chdir(path);
00137 }
00138 
00139 int Rmdir (const char * path)
00140 {
00141     const char * lpath;
00142     int ut = urlPath(path, &lpath);
00143 
00144 if (_rpmio_debug)
00145 fprintf(stderr, "*** Rmdir(%s)\n", path);
00146     switch (ut) {
00147     case URL_IS_FTP:
00148         return ftpRmdir(path);
00149         /*@notreached@*/ break;
00150     case URL_IS_HTTPS:
00151     case URL_IS_HTTP:
00152 #ifdef WITH_NEON
00153         return davRmdir(path);
00154 #endif
00155         /*@notreached@*/ break;
00156     case URL_IS_PATH:
00157         path = lpath;
00158         /*@fallthrough@*/
00159     case URL_IS_UNKNOWN:
00160         break;
00161     case URL_IS_DASH:
00162     case URL_IS_HKP:
00163     default:
00164         return -2;
00165         /*@notreached@*/ break;
00166     }
00167     return rmdir(path);
00168 }
00169 
00170 /*@unchecked@*/
00171 const char * _chroot_prefix = NULL;
00172 
00173 int Chroot(const char * path)
00174 {
00175     const char * lpath;
00176     int ut = urlPath(path, &lpath);
00177     int rc;
00178 
00179     switch (ut) {
00180     case URL_IS_PATH:
00181         path = lpath;
00182         /*@fallthrough@*/
00183     case URL_IS_UNKNOWN:
00184         break;
00185     case URL_IS_DASH:
00186     case URL_IS_HKP:
00187     case URL_IS_FTP:            /* XXX TODO: implement. */
00188     case URL_IS_HTTPS:          /* XXX TODO: implement. */
00189     case URL_IS_HTTP:           /* XXX TODO: implement. */
00190     default:
00191         errno = EINVAL;         /* XXX W2DO? */
00192         return -2;
00193         /*@notreached@*/ break;
00194     }
00195 
00196 /*@-dependenttrans -modobserver -observertrans @*/
00197     _chroot_prefix = _free(_chroot_prefix);
00198 /*@=dependenttrans =modobserver =observertrans @*/
00199 /*@-globs -mods@*/      /* XXX hide rpmGlobalMacroContext mods for now. */
00200     if (strcmp(path, "."))
00201         _chroot_prefix = rpmGetPath(path, NULL);
00202 /*@=globs =mods@*/
00203 
00204 /*@-superuser@*/
00205     rc = chroot(path);
00206 /*@=superuser@*/
00207 
00208 if (_rpmio_debug)
00209 fprintf(stderr, "<-- %s(%s) prefix %s rc %d\n", __FUNCTION__, path, _chroot_prefix, rc);
00210 
00211     return rc;
00212 }
00213 /*@=mods@*/
00214 
00215 int Open(const char * path, int flags, mode_t mode)
00216 {
00217     const char * lpath;
00218     int ut = urlPath(path, &lpath);
00219     int fdno;
00220 
00221     switch (ut) {
00222     case URL_IS_PATH:
00223         path = lpath;
00224         /*@fallthrough@*/
00225     case URL_IS_UNKNOWN:
00226         break;
00227     case URL_IS_DASH:
00228     case URL_IS_HKP:
00229     case URL_IS_FTP:            /* XXX TODO: implement. */
00230     case URL_IS_HTTPS:          /* XXX TODO: implement. */
00231     case URL_IS_HTTP:           /* XXX TODO: implement. */
00232     default:
00233         errno = EINVAL;         /* XXX W2DO? */
00234         return -2;
00235         /*@notreached@*/ break;
00236     }
00237 
00238     if (_chroot_prefix && _chroot_prefix[0] == '/' && _chroot_prefix[1] != '\0')
00239     {
00240         size_t nb = strlen(_chroot_prefix);
00241         size_t ob = strlen(path);
00242         while (nb > 0 && _chroot_prefix[nb-1] == '/')
00243             nb--;
00244         if (ob > nb && !strncmp(path, _chroot_prefix, nb) && path[nb] == '/')
00245             path += nb;
00246     }
00247 #ifdef  NOTYET  /* XXX likely sane default. */
00248     if (mode == 0)
00249         mode = 0644;
00250 #endif
00251     fdno = open(path, flags, mode);
00252     /* XXX if the open(2) fails, try to strip a possible chroot(2) prefix. */
00253     if (fdno < 0 && errno == ENOENT) {
00254         const char *dbpath = rpmExpand("%{?_dbpath}/", NULL);
00255         const char * fn = strstr(path + 1, dbpath);
00256         if (fn)
00257             fdno = open(fn, flags, mode);
00258         dbpath = _free(dbpath);
00259     }
00260     if (fdno >= 0) {
00261         if (fcntl(fdno, F_SETFD, FD_CLOEXEC) < 0) {
00262             (void) close(fdno);
00263             fdno = -1;
00264         }
00265     }
00266 
00267 #ifdef  NOTYET  /* XXX db-5.0.26 is slower using POSIX_FADV_RANDOM. */
00268 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_RANDOM)
00269     (void) posix_fadvise(fdno, 0, 0, POSIX_FADV_RANDOM);
00270 #endif
00271 #endif
00272 
00273 if (_rpmio_debug)
00274 fprintf(stderr, "<-- %s(%s, 0x%x, 0%o) prefix %s fdno %d\n", __FUNCTION__, path, flags, (unsigned)mode, _chroot_prefix, fdno);
00275 
00276     return fdno;
00277 }
00278 
00279 /* XXX rpmdb.c: analogue to rename(2). */
00280 
00281 int Rename (const char * oldpath, const char * newpath)
00282 {
00283     const char *oe = NULL;
00284     const char *ne = NULL;
00285     int oldut, newut;
00286 
00287 if (_rpmio_debug)
00288 fprintf(stderr, "*** Rename(%s, %s)\n", oldpath, newpath);
00289     /* XXX lib/install.c used to rely on this behavior. */
00290     if (!strcmp(oldpath, newpath)) return 0;
00291 
00292     oldut = urlPath(oldpath, &oe);
00293     switch (oldut) {
00294     case URL_IS_HTTPS:
00295     case URL_IS_HTTP:
00296 #ifdef WITH_NEON
00297         return davRename(oldpath, newpath);
00298 #endif
00299         /*@notreached@*/ break;
00300     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
00301     case URL_IS_PATH:
00302     case URL_IS_UNKNOWN:
00303         break;
00304     case URL_IS_DASH:
00305     case URL_IS_HKP:
00306     default:
00307         return -2;
00308         /*@notreached@*/ break;
00309     }
00310 
00311     newut = urlPath(newpath, &ne);
00312     switch (newut) {
00313     case URL_IS_FTP:
00314 if (_rpmio_debug)
00315 fprintf(stderr, "*** rename old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
00316         if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
00317             !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
00318             return -2;
00319         return ftpRename(oldpath, newpath);
00320         /*@notreached@*/ break;
00321     case URL_IS_HTTPS:          /* XXX WRONG WRONG WRONG */
00322     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
00323     case URL_IS_PATH:
00324         oldpath = oe;
00325         newpath = ne;
00326         break;
00327     case URL_IS_UNKNOWN:
00328         break;
00329     case URL_IS_DASH:
00330     case URL_IS_HKP:
00331     default:
00332         return -2;
00333         /*@notreached@*/ break;
00334     }
00335     return rename(oldpath, newpath);
00336 }
00337 
00338 int Link (const char * oldpath, const char * newpath)
00339 {
00340     const char *oe = NULL;
00341     const char *ne = NULL;
00342     int oldut, newut;
00343 
00344 if (_rpmio_debug)
00345 fprintf(stderr, "*** Link(%s, %s)\n", oldpath, newpath);
00346     oldut = urlPath(oldpath, &oe);
00347     switch (oldut) {
00348     case URL_IS_HTTPS:          /* XXX WRONG WRONG WRONG */
00349     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
00350     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
00351     case URL_IS_PATH:
00352     case URL_IS_UNKNOWN:
00353         break;
00354     case URL_IS_DASH:
00355     case URL_IS_HKP:
00356     default:
00357         return -2;
00358         /*@notreached@*/ break;
00359     }
00360 
00361     newut = urlPath(newpath, &ne);
00362     switch (newut) {
00363     case URL_IS_HTTPS:          /* XXX WRONG WRONG WRONG */
00364     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
00365     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
00366     case URL_IS_PATH:
00367 if (_rpmio_debug)
00368 fprintf(stderr, "*** link old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
00369         if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
00370             !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
00371             return -2;
00372         oldpath = oe;
00373         newpath = ne;
00374         break;
00375     case URL_IS_UNKNOWN:
00376         break;
00377     case URL_IS_DASH:
00378     case URL_IS_HKP:
00379     default:
00380         return -2;
00381         /*@notreached@*/ break;
00382     }
00383     return link(oldpath, newpath);
00384 }
00385 
00386 /* XXX build/build.c: analogue to unlink(2). */
00387 
00388 int Unlink(const char * path) {
00389     const char * lpath;
00390     int ut = urlPath(path, &lpath);
00391     int rc = -2;
00392 
00393     switch (ut) {
00394     case URL_IS_FTP:
00395         rc = ftpUnlink(path);
00396         /*@notreached@*/ break;
00397     case URL_IS_HTTPS:
00398     case URL_IS_HTTP:
00399 #ifdef WITH_NEON
00400         rc = davUnlink(path);
00401 #endif
00402         /*@notreached@*/ break;
00403     case URL_IS_PATH:
00404         path = lpath;
00405         /*@fallthrough@*/
00406     case URL_IS_UNKNOWN:
00407         break;
00408     case URL_IS_DASH:
00409     case URL_IS_HKP:
00410     default:
00411         errno = EINVAL;
00412         goto exit;
00413         /*@notreached@*/ break;
00414     }
00415     rc = unlink(path);
00416 exit:
00417 if (_rpmio_debug)
00418 fprintf(stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, path, rc);
00419     return rc;
00420 }
00421 
00422 /* XXX swiped from mc-4.5.39-pre9 vfs/ftpfs.c */
00423 
00424 #define g_strdup        xstrdup
00425 #define g_free          free
00426 
00427 /*
00428  * FIXME: this is broken. It depends on mc not crossing border on month!
00429  */
00430 /*@unchecked@*/
00431 static int current_mday;
00432 /*@unchecked@*/
00433 static int current_mon;
00434 /*@unchecked@*/
00435 static int current_year;
00436 
00437 /* Following stuff (parse_ls_lga) is used by ftpfs and extfs */
00438 #define MAXCOLS         30
00439 
00440 /*@unchecked@*/
00441 static char *columns [MAXCOLS]; /* Points to the string in column n */
00442 /*@unchecked@*/
00443 static int   column_ptr [MAXCOLS]; /* Index from 0 to the starting positions of the columns */
00444 
00445 static int
00446 vfs_split_text (char *p)
00447         /*@globals columns, column_ptr @*/
00448         /*@modifies *p, columns, column_ptr @*/
00449 {
00450     char *original = p;
00451     int  numcols;
00452 
00453 
00454     for (numcols = 0; *p && numcols < MAXCOLS; numcols++){
00455         while (*p == ' ' || *p == '\r' || *p == '\n'){
00456             *p = '\0';
00457             p++;
00458         }
00459         columns [numcols] = p;
00460         column_ptr [numcols] = p - original;
00461         while (*p && *p != ' ' && *p != '\r' && *p != '\n')
00462             p++;
00463     }
00464     return numcols;
00465 }
00466 
00467 static int
00468 is_num (int idx)
00469         /*@*/
00470 {
00471     if (!columns [idx] || columns [idx][0] < '0' || columns [idx][0] > '9')
00472         return 0;
00473     return 1;
00474 }
00475 
00476 static int
00477 is_dos_date(/*@null@*/ const char *str)
00478         /*@*/
00479 {
00480     if (str != NULL && strlen(str) == 8 &&
00481                 str[2] == str[5] && strchr("\\-/", (int)str[2]) != NULL)
00482         return 1;
00483     return 0;
00484 }
00485 
00486 static int
00487 is_week (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
00488         /*@modifies *tim @*/
00489 {
00490 /*@observer@*/ static const char * week = "SunMonTueWedThuFriSat";
00491     const char * pos;
00492 
00493     /*@-observertrans -mayaliasunique@*/
00494     if (str != NULL && (pos=strstr(week, str)) != NULL) {
00495     /*@=observertrans =mayaliasunique@*/
00496         if (tim != NULL)
00497             tim->tm_wday = (pos - week)/3;
00498         return 1;
00499     }
00500     return 0;
00501 }
00502 
00503 static int
00504 is_month (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
00505         /*@modifies *tim @*/
00506 {
00507 /*@observer@*/ static const char * month = "JanFebMarAprMayJunJulAugSepOctNovDec";
00508     const char * pos;
00509 
00510     /*@-observertrans -mayaliasunique@*/
00511     if (str != NULL && (pos = strstr(month, str)) != NULL) {
00512     /*@=observertrans -mayaliasunique@*/
00513         if (tim != NULL)
00514             tim->tm_mon = (pos - month)/3;
00515         return 1;
00516     }
00517     return 0;
00518 }
00519 
00520 static int
00521 is_time (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
00522         /*@modifies *tim @*/
00523 {
00524     const char * p, * p2;
00525 
00526     if (str != NULL && (p = strchr(str, ':')) && (p2 = strrchr(str, ':'))) {
00527         if (p != p2) {
00528             if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
00529                 return 0;
00530         } else {
00531             if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
00532                 return 0;
00533         }
00534     } else
00535         return 0;
00536 
00537     return 1;
00538 }
00539 
00540 static int is_year(/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
00541         /*@modifies *tim @*/
00542 {
00543     long year;
00544 
00545     if (str == NULL)
00546         return 0;
00547 
00548     if (strchr(str,':'))
00549         return 0;
00550 
00551     if (strlen(str) != 4)
00552         return 0;
00553 
00554     if (sscanf(str, "%ld", &year) != 1)
00555         return 0;
00556 
00557     if (year < 1900 || year > 3000)
00558         return 0;
00559 
00560     tim->tm_year = (int) (year - 1900);
00561 
00562     return 1;
00563 }
00564 
00565 /*
00566  * FIXME: this is broken. Consider following entry:
00567  * -rwx------   1 root     root            1 Aug 31 10:04 2904 1234
00568  * where "2904 1234" is filename. Well, this code decodes it as year :-(.
00569  */
00570 
00571 static int
00572 vfs_parse_filetype (char c)
00573         /*@*/
00574 {
00575     switch (c) {
00576         case 'd': return (int)S_IFDIR;
00577         case 'b': return (int)S_IFBLK;
00578         case 'c': return (int)S_IFCHR;
00579         case 'l': return (int)S_IFLNK;
00580         case 's':
00581 #ifdef IS_IFSOCK /* And if not, we fall through to IFIFO, which is pretty close */
00582                   return (int)S_IFSOCK;
00583 #endif
00584         case 'p': return (int)S_IFIFO;
00585         case 'm': case 'n':             /* Don't know what these are :-) */
00586         case '-': case '?': return (int)S_IFREG;
00587         default: return -1;
00588     }
00589 }
00590 
00591 static int vfs_parse_filemode (const char *p)
00592         /*@*/
00593 {       /* converts rw-rw-rw- into 0666 */
00594     int res = 0;
00595     switch (*(p++)) {
00596         case 'r': res |= 0400; break;
00597         case '-': break;
00598         default: return -1;
00599     }
00600     switch (*(p++)) {
00601         case 'w': res |= 0200; break;
00602         case '-': break;
00603         default: return -1;
00604     }
00605     switch (*(p++)) {
00606         case 'x': res |= 0100; break;
00607         case 's': res |= 0100 | S_ISUID; break;
00608         case 'S': res |= S_ISUID; break;
00609         case '-': break;
00610         default: return -1;
00611     }
00612     switch (*(p++)) {
00613         case 'r': res |= 0040; break;
00614         case '-': break;
00615         default: return -1;
00616     }
00617     switch (*(p++)) {
00618         case 'w': res |= 0020; break;
00619         case '-': break;
00620         default: return -1;
00621     }
00622     switch (*(p++)) {
00623         case 'x': res |= 0010; break;
00624         case 's': res |= 0010 | S_ISGID; break;
00625         case 'l': /* Solaris produces these */
00626         case 'S': res |= S_ISGID; break;
00627         case '-': break;
00628         default: return -1;
00629     }
00630     switch (*(p++)) {
00631         case 'r': res |= 0004; break;
00632         case '-': break;
00633         default: return -1;
00634     }
00635     switch (*(p++)) {
00636         case 'w': res |= 0002; break;
00637         case '-': break;
00638         default: return -1;
00639     }
00640     switch (*(p++)) {
00641         case 'x': res |= 0001; break;
00642         case 't': res |= 0001 | S_ISVTX; break;
00643         case 'T': res |= S_ISVTX; break;
00644         case '-': break;
00645         default: return -1;
00646     }
00647     return res;
00648 }
00649 
00650 static int vfs_parse_filedate(int idx, /*@out@*/ time_t *t)
00651         /*@modifies *t @*/
00652 {       /* This thing parses from idx in columns[] array */
00653 
00654     char *p;
00655     struct tm tim;
00656     int d[3];
00657     int got_year = 0;
00658 
00659     /* Let's setup default time values */
00660     tim.tm_year = current_year;
00661     tim.tm_mon  = current_mon;
00662     tim.tm_mday = current_mday;
00663     tim.tm_hour = 0;
00664     tim.tm_min  = 0;
00665     tim.tm_sec  = 0;
00666     tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
00667 
00668     p = columns [idx++];
00669 
00670     /* We eat weekday name in case of extfs */
00671     if(is_week(p, &tim))
00672         p = columns [idx++];
00673 
00674     /* Month name */
00675     if(is_month(p, &tim)){
00676         /* And we expect, it followed by day number */
00677         if (is_num (idx))
00678             tim.tm_mday = (int)atol (columns [idx++]);
00679         else
00680             return 0; /* No day */
00681 
00682     } else {
00683         /* We usually expect:
00684            Mon DD hh:mm
00685            Mon DD  YYYY
00686            But in case of extfs we allow these date formats:
00687            Mon DD YYYY hh:mm
00688            Mon DD hh:mm YYYY
00689            Wek Mon DD hh:mm:ss YYYY
00690            MM-DD-YY hh:mm
00691            where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
00692            YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
00693 
00694         /* Here just this special case with MM-DD-YY */
00695         if (is_dos_date(p)){
00696 /*@-mods@*/
00697             p[2] = p[5] = '-';
00698 /*@=mods@*/
00699 
00700             memset(d, 0, sizeof(d));
00701             if (sscanf(p, "%2d-%2d-%2d", &d[0], &d[1], &d[2]) == 3){
00702             /*  We expect to get:
00703                 1. MM-DD-YY
00704                 2. DD-MM-YY
00705                 3. YY-MM-DD
00706                 4. YY-DD-MM  */
00707                 
00708                 /* Hmm... maybe, next time :)*/
00709                 
00710                 /* At last, MM-DD-YY */
00711                 d[0]--; /* Months are zerobased */
00712                 /* Y2K madness */
00713                 if(d[2] < 70)
00714                     d[2] += 100;
00715 
00716                 tim.tm_mon  = d[0];
00717                 tim.tm_mday = d[1];
00718                 tim.tm_year = d[2];
00719                 got_year = 1;
00720             } else
00721                 return 0; /* sscanf failed */
00722         } else
00723             return 0; /* unsupported format */
00724     }
00725 
00726     /* Here we expect to find time and/or year */
00727 
00728     if (is_num (idx)) {
00729         if(is_time(columns[idx], &tim) || (got_year = is_year(columns[idx], &tim))) {
00730         idx++;
00731 
00732         /* This is a special case for ctime() or Mon DD YYYY hh:mm */
00733         if(is_num (idx) &&
00734             ((got_year = is_year(columns[idx], &tim)) || is_time(columns[idx], &tim)))
00735                 idx++; /* time & year or reverse */
00736         } /* only time or date */
00737     }
00738     else
00739         return 0; /* Nor time or date */
00740 
00741     /*
00742      * If the date is less than 6 months in the past, it is shown without year
00743      * other dates in the past or future are shown with year but without time
00744      * This does not check for years before 1900 ... I don't know, how
00745      * to represent them at all
00746      */
00747     if (!got_year &&
00748         current_mon < 6 && current_mon < tim.tm_mon &&
00749         tim.tm_mon - current_mon >= 6)
00750 
00751         tim.tm_year--;
00752 
00753     if ((*t = mktime(&tim)) < 0)
00754         *t = 0;
00755     return idx;
00756 }
00757 
00758 static int
00759 vfs_parse_ls_lga (char * p, /*@out@*/ struct stat * st,
00760                 /*@out@*/ const char ** filename,
00761                 /*@out@*/ const char ** linkname)
00762         /*@modifies *p, *st, *filename, *linkname @*/
00763 {
00764     int idx, idx2, num_cols;
00765     int i;
00766     char *p_copy;
00767     long n;
00768 
00769     if (strncmp (p, "total", 5) == 0)
00770         return 0;
00771 
00772     p_copy = g_strdup(p);
00773 /* XXX FIXME: parse out inode number from "NLST -lai ." */
00774 /* XXX FIXME: parse out sizein blocks from "NLST -lais ." */
00775 
00776     if ((i = vfs_parse_filetype(*(p++))) == -1)
00777         goto error;
00778 
00779     st->st_mode = i;
00780     if (*p == ' ')      /* Notwell 4 */
00781         p++;
00782     if (*p == '['){
00783         if (strlen (p) <= 8 || p [8] != ']')
00784             goto error;
00785         /* Should parse here the Notwell permissions :) */
00786         /*@-unrecog@*/
00787         if (S_ISDIR (st->st_mode))
00788             st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
00789         else
00790             st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
00791         p += 9;
00792         /*@=unrecog@*/
00793     } else {
00794         if ((i = vfs_parse_filemode(p)) == -1)
00795             goto error;
00796         st->st_mode |= i;
00797         p += 9;
00798 
00799         /* This is for an extra ACL attribute (HP-UX) */
00800         if (*p == '+')
00801             p++;
00802     }
00803 
00804     g_free(p_copy);
00805     p_copy = g_strdup(p);
00806     num_cols = vfs_split_text (p);
00807 
00808     n = atol(columns[0]);
00809     st->st_nlink = n;
00810     if (n < 0)
00811         goto error;
00812 
00813     if (!is_num (1))
00814 #ifdef  HACK
00815         st->st_uid = finduid (columns [1]);
00816 #else
00817         (void) unameToUid (columns [1], &st->st_uid);
00818 #endif
00819     else
00820         st->st_uid = (uid_t) atol (columns [1]);
00821 
00822     /* Mhm, the ls -lg did not produce a group field */
00823     for (idx = 3; idx <= 5; idx++)
00824         if (is_month(columns [idx], NULL) || is_week(columns [idx], NULL) || is_dos_date(columns[idx]))
00825             break;
00826 
00827     if (idx == 6 || (idx == 5 && !S_ISCHR (st->st_mode) && !S_ISBLK (st->st_mode)))
00828         goto error;
00829 
00830     /* We don't have gid */     
00831     if (idx == 3 || (idx == 4 && (S_ISCHR(st->st_mode) || S_ISBLK (st->st_mode))))
00832         idx2 = 2;
00833     else {
00834         /* We have gid field */
00835         if (is_num (2))
00836             st->st_gid = (gid_t) atol (columns [2]);
00837         else
00838 #ifdef  HACK
00839             st->st_gid = findgid (columns [2]);
00840 #else
00841             (void) gnameToGid (columns [1], &st->st_gid);
00842 #endif
00843         idx2 = 3;
00844     }
00845 
00846     /* This is device */
00847     if (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode)){
00848         unsigned maj, min;
00849         
00850         if (!is_num (idx2) || sscanf(columns [idx2], " %d,", &maj) != 1)
00851             goto error;
00852         
00853         if (!is_num (++idx2) || sscanf(columns [idx2], " %d", &min) != 1)
00854             goto error;
00855         
00856 #ifdef HAVE_ST_RDEV
00857         st->st_rdev = ((maj & 0x000000ffU) << 8) | (min & 0x000000ffU);
00858 #endif
00859         st->st_size = 0;
00860         
00861     } else {
00862         /* Common file size */
00863         if (!is_num (idx2))
00864             goto error;
00865         
00866         st->st_size = (size_t) atol (columns [idx2]);
00867 #ifdef HAVE_ST_RDEV
00868         st->st_rdev = 0;
00869 #endif
00870     }
00871 
00872     idx = vfs_parse_filedate(idx, &st->st_mtime);
00873     if (!idx)
00874         goto error;
00875     /* Use resulting time value */
00876     st->st_atime = st->st_ctime = st->st_mtime;
00877     st->st_dev = 0;
00878     st->st_ino = 0;
00879 #ifdef HAVE_ST_BLKSIZE
00880     st->st_blksize = 512;
00881 #endif
00882 #ifdef HAVE_ST_BLOCKS
00883     st->st_blocks = (st->st_size + 511) / 512;
00884 #endif
00885 
00886     for (i = idx + 1, idx2 = 0; i < num_cols; i++ )
00887         if (strcmp (columns [i], "->") == 0){
00888             idx2 = i;
00889             break;
00890         }
00891 
00892     if (((S_ISLNK (st->st_mode) ||
00893         (num_cols == idx + 3 && st->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
00894         && idx2)
00895     {
00896         size_t tlen;
00897         char *t;
00898 
00899         if (filename){
00900             size_t nb = column_ptr [idx2] - column_ptr [idx] - 1;
00901             t = strncpy(xcalloc(1, nb+1), p_copy + column_ptr [idx], nb);
00902             *filename = t;
00903         }
00904         if (linkname){
00905             t = g_strdup (p_copy + column_ptr [idx2+1]);
00906             tlen = strlen (t);
00907             if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
00908                 t [tlen-1] = '\0';
00909             if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
00910                 t [tlen-2] = '\0';
00911                 
00912             *linkname = t;
00913         }
00914     } else {
00915         /* Extract the filename from the string copy, not from the columns
00916          * this way we have a chance of entering hidden directories like ". ."
00917          */
00918         if (filename){
00919             /*
00920             *filename = g_strdup (columns [idx++]);
00921             */
00922             size_t tlen;
00923             char *t;
00924 
00925             t = g_strdup (p_copy + column_ptr [idx]); idx++;
00926             tlen = strlen (t);
00927             /* g_strchomp(); */
00928             if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
00929                 t [tlen-1] = '\0';
00930             if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
00931                 t [tlen-2] = '\0';
00932 
00933             *filename = t;
00934         }
00935         if (linkname)
00936             *linkname = NULL;
00937     }
00938     g_free (p_copy);
00939     return 1;
00940 
00941 error:
00942 #ifdef  HACK
00943     {
00944       static int errorcount = 0;
00945 
00946       if (++errorcount < 5) {
00947         message_1s (1, "Could not parse:", p_copy);
00948       } else if (errorcount == 5)
00949         message_1s (1, "More parsing errors will be ignored.", "(sorry)" );
00950     }
00951 #endif
00952 
00953     /*@-usereleased@*/
00954     if (p_copy != p)            /* Carefull! */
00955     /*@=usereleased@*/
00956         g_free (p_copy);
00957     return 0;
00958 }
00959 
00960 typedef enum {
00961         DO_FTP_STAT     = 1,
00962         DO_FTP_LSTAT    = 2,
00963         DO_FTP_READLINK = 3,
00964         DO_FTP_ACCESS   = 4,
00965         DO_FTP_GLOB     = 5
00966 } ftpSysCall_t;
00967 
00970 static size_t ftpBufAlloced;
00971 
00974 /*@only@*/ /*@relnull@*/
00975 static char * ftpBuf;
00976         
00977 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00978 
00979 static int ftpNLST(const char * url, ftpSysCall_t ftpSysCall,
00980                 /*@out@*/ /*@null@*/ struct stat * st,
00981                 /*@out@*/ /*@null@*/ char * rlbuf, size_t rlbufsiz)
00982         /*@globals ftpBufAlloced, ftpBuf,
00983                 h_errno, fileSystem, internalState @*/
00984         /*@modifies *st, *rlbuf, ftpBufAlloced, ftpBuf,
00985                 fileSystem, internalState @*/
00986 {
00987     FD_t fd;
00988     const char * path;
00989     int bufLength, moretodo;
00990     const char *n, *ne, *o, *oe;
00991     char * s;
00992     char * se;
00993     const char * urldn;
00994     char * bn = NULL;
00995     size_t nbn = 0;
00996     urlinfo u;
00997     int rc;
00998 
00999     n = ne = o = oe = NULL;
01000     (void) urlPath(url, &path);
01001     if (*path == '\0')
01002         return -2;
01003 
01004     switch (ftpSysCall) {
01005     case DO_FTP_GLOB:
01006         fd = ftpOpen(url, 0, 0, &u);
01007         if (fd == NULL || u == NULL)
01008             return -1;
01009 
01010         u->openError = ftpReq(fd, "LIST", path);
01011         break;
01012     default:
01013         urldn = alloca_strdup(url);
01014         if ((bn = strrchr(urldn, '/')) == NULL)
01015             return -2;
01016         else if (bn == path)
01017             bn = ".";
01018         else
01019             *bn++ = '\0';
01020         nbn = strlen(bn);
01021 
01022         rc = ftpChdir(urldn);           /* XXX don't care about CWD */
01023         if (rc < 0)
01024             return rc;
01025 
01026         fd = ftpOpen(url, 0, 0, &u);
01027         if (fd == NULL || u == NULL)
01028             return -1;
01029 
01030         /* XXX possibly should do "NLST -lais" to get st_ino/st_blocks also */
01031         u->openError = ftpReq(fd, "NLST", "-la");
01032 
01033         if (bn == NULL || nbn == 0) {
01034             rc = -2;
01035             goto exit;
01036         }
01037         break;
01038     }
01039 
01040     if (u->openError < 0) {
01041         fd = fdLink(fd, "error data (ftpStat)");
01042         rc = -2;
01043         goto exit;
01044     }
01045 
01046     if (ftpBufAlloced == 0 || ftpBuf == NULL) {
01047         ftpBufAlloced = _url_iobuf_size;
01048         ftpBuf = xcalloc(ftpBufAlloced, sizeof(ftpBuf[0]));
01049     }
01050     *ftpBuf = '\0';
01051 
01052     bufLength = 0;
01053     moretodo = 1;
01054 
01055     do {
01056 
01057         /* XXX FIXME: realloc ftpBuf if < ~128 chars remain */
01058         if ((ftpBufAlloced - bufLength) < (1024+80)) {
01059             ftpBufAlloced <<= 2;
01060             assert(ftpBufAlloced < (8*1024*1024));
01061             ftpBuf = xrealloc(ftpBuf, ftpBufAlloced);
01062         }
01063         s = se = ftpBuf + bufLength;
01064         *se = '\0';
01065 
01066         rc = fdFgets(fd, se, (ftpBufAlloced - bufLength));
01067         if (rc <= 0) {
01068             moretodo = 0;
01069             break;
01070         }
01071         if (ftpSysCall == DO_FTP_GLOB) {        /* XXX HACK */
01072             bufLength += strlen(se);
01073             continue;
01074         }
01075 
01076         for (s = se; *s != '\0'; s = se) {
01077             int bingo;
01078 
01079             while (*se && *se != '\n') se++;
01080             if (se > s && se[-1] == '\r') se[-1] = '\0';
01081             if (*se == '\0')
01082                 /*@innerbreak@*/ break;
01083             *se++ = '\0';
01084 
01085             if (!strncmp(s, "total ", sizeof("total ")-1))
01086                 /*@innercontinue@*/ continue;
01087 
01088             o = NULL;
01089             for (bingo = 0, n = se; n >= s; n--) {
01090                 switch (*n) {
01091                 case '\0':
01092                     oe = ne = n;
01093                     /*@switchbreak@*/ break;
01094                 case ' ':
01095                     if (o || !(n[-3] == ' ' && n[-2] == '-' && n[-1] == '>')) {
01096                         while (*(++n) == ' ')
01097                             {};
01098                         bingo++;
01099                         /*@switchbreak@*/ break;
01100                     }
01101                     for (o = n + 1; *o == ' '; o++)
01102                         {};
01103                     n -= 3;
01104                     ne = n;
01105                     /*@switchbreak@*/ break;
01106                 default:
01107                     /*@switchbreak@*/ break;
01108                 }
01109                 if (bingo)
01110                     /*@innerbreak@*/ break;
01111             }
01112 
01113             if (nbn != (size_t)(ne - n))        /* Same name length? */
01114                 /*@innercontinue@*/ continue;
01115             if (strncmp(n, bn, nbn))    /* Same name? */
01116                 /*@innercontinue@*/ continue;
01117 
01118             moretodo = 0;
01119             /*@innerbreak@*/ break;
01120         }
01121 
01122         if (moretodo && se > s) {
01123             bufLength = se - s - 1;
01124             if (s != ftpBuf)
01125                 memmove(ftpBuf, s, bufLength);
01126         } else {
01127             bufLength = 0;
01128         }
01129     } while (moretodo);
01130 
01131     switch (ftpSysCall) {
01132     case DO_FTP_STAT:
01133         if (o && oe) {
01134             /* XXX FIXME: symlink, replace urldn/bn from [o,oe) and restart */
01135         }
01136         /*@fallthrough@*/
01137     case DO_FTP_LSTAT:
01138         if (st == NULL || !(n && ne)) {
01139             rc = -1;
01140         } else {
01141             rc = ((vfs_parse_ls_lga(s, st, NULL, NULL) > 0) ? 0 : -1);
01142         }
01143         break;
01144     case DO_FTP_READLINK:
01145         if (rlbuf == NULL || !(o && oe)) {
01146             rc = -1;
01147         } else {
01148             rc = oe - o;
01149 assert(rc >= 0);
01150             if (rc > (int)rlbufsiz)
01151                 rc = (int)rlbufsiz;
01152             memcpy(rlbuf, o, (size_t)rc);
01153             if (rc < (int)rlbufsiz)
01154                 rlbuf[rc] = '\0';
01155         }
01156         break;
01157     case DO_FTP_ACCESS:
01158         rc = 0;         /* XXX WRONG WRONG WRONG */
01159         break;
01160     case DO_FTP_GLOB:
01161         rc = 0;         /* XXX WRONG WRONG WRONG */
01162         break;
01163     }
01164 
01165 exit:
01166     (void) ufdClose(fd);
01167     return rc;
01168 }
01169 
01170 static const char * statstr(const struct stat * st,
01171                 /*@returned@*/ /*@out@*/ char * buf)
01172         /*@modifies *buf @*/
01173 {
01174     char * t = buf;
01175     sprintf(t, "*** dev %x", (unsigned int)st->st_dev);
01176         t += strlen(t);
01177     sprintf(t, " ino %x", (unsigned int)st->st_ino);
01178         t += strlen(t);
01179     sprintf(t, " mode %0o", (unsigned int)st->st_mode);
01180         t += strlen(t);
01181     sprintf(t, " nlink %d", (unsigned int)st->st_nlink);
01182         t += strlen(t);
01183     sprintf(t, " uid %d", (unsigned int)st->st_uid);
01184         t += strlen(t);
01185     sprintf(t, " gid %d", (unsigned int)st->st_gid);
01186         t += strlen(t);
01187     sprintf(t, " rdev %x", (unsigned int)st->st_rdev);
01188         t += strlen(t);
01189     sprintf(t, " size %x", (unsigned int)st->st_size);
01190         t += strlen(t);
01191     sprintf(t, "\n");
01192     return buf;
01193 }
01194 
01195 /* FIXME: borked for path with trailing '/' */
01196 static int ftpStat(const char * path, /*@out@*/ struct stat *st)
01197         /*@globals ftpBufAlloced, ftpBuf, h_errno, fileSystem, internalState @*/
01198         /*@modifies ftpBufAlloced, ftpBuf, *st, fileSystem, internalState @*/
01199 {
01200     char buf[1024];
01201     int rc;
01202     rc = ftpNLST(path, DO_FTP_STAT, st, NULL, 0);
01203 
01204     /* XXX fts(3) needs/uses st_ino. */
01205     /* Hash the path to generate a st_ino analogue. */
01206     if (st->st_ino == 0)
01207         st->st_ino = hashFunctionString(0, path, 0);
01208 
01209 if (_ftp_debug)
01210 fprintf(stderr, "<-- %s(%s) rc %d\n%s", __FUNCTION__, path, rc, statstr(st, buf));
01211     return rc;
01212 }
01213 
01214 /* FIXME: borked for path with trailing '/' */
01215 static int ftpLstat(const char * path, /*@out@*/ struct stat *st)
01216         /*@globals ftpBufAlloced, ftpBuf, h_errno, fileSystem, internalState @*/
01217         /*@modifies ftpBufAlloced, ftpBuf, *st, fileSystem, internalState @*/
01218 {
01219     char buf[1024];
01220     int rc;
01221     rc = ftpNLST(path, DO_FTP_LSTAT, st, NULL, 0);
01222 
01223     /* XXX fts(3) needs/uses st_ino. */
01224     /* Hash the path to generate a st_ino analogue. */
01225     if (st->st_ino == 0)
01226         st->st_ino = hashFunctionString(0, path, 0);
01227 
01228 if (_ftp_debug)
01229 fprintf(stderr, "<-- %s(%s) rc %d\n%s\n", __FUNCTION__, path, rc, statstr(st, buf));
01230     return rc;
01231 }
01232 
01233 static int ftpReadlink(const char * path, /*@out@*/ char * buf, size_t bufsiz)
01234         /*@globals ftpBufAlloced, ftpBuf, h_errno, fileSystem, internalState @*/
01235         /*@modifies ftpBufAlloced, ftpBuf, *buf, fileSystem, internalState @*/
01236 {
01237     int rc;
01238     rc = ftpNLST(path, DO_FTP_READLINK, NULL, buf, bufsiz);
01239 if (_ftp_debug)
01240 fprintf(stderr, "<-- %s(%s) rc %d\n", __FUNCTION__, path, rc);
01241     return rc;
01242 }
01243 
01244 DIR * ftpOpendir(const char * path)
01245         /*@globals ftpBufAlloced, ftpBuf @*/
01246         /*@modifies ftpBufAlloced, ftpBuf @*/
01247 {
01248     AVDIR avdir;
01249     rpmavx avx;
01250     struct stat * st = NULL;
01251     const char * s, * sb, * se;
01252     int nac;
01253     int c;
01254     int rc;
01255 
01256 if (_ftp_debug)
01257 fprintf(stderr, "*** ftpOpendir(%s)\n", path);
01258 
01259     /* Load FTP collection into argv. */
01260     avx = rpmavxNew(path, st);
01261     if (avx == NULL) {
01262         errno = ENOENT;         /* Note: avx is NULL iff urlSplit() fails. */
01263         return NULL;
01264     }
01265 
01266     rc = ftpNLST(path, DO_FTP_GLOB, NULL, NULL, 0);
01267     if (rc)
01268         return NULL;
01269 
01270     nac = 0;
01271     sb = NULL;
01272     s = se = ftpBuf;
01273     while ((c = (int) *se++) != (int) '\0') {
01274         switch (c) {
01275         case '/':
01276             sb = se;
01277             /*@switchbreak@*/ break;
01278         case '\r':
01279             if (sb == NULL) {
01280                 for (sb = se; sb > s && sb[-1] != ' '; sb--)
01281                     {};
01282             }
01283             nac++;
01284 
01285             if (*se == '\n') se++;
01286             sb = NULL;
01287             s = se;
01288             /*@switchbreak@*/ break;
01289         default:
01290             /*@switchbreak@*/ break;
01291         }
01292     }
01293 
01294     avx->av = xcalloc(nac+1, sizeof(*avx->av));
01295     avx->modes = xcalloc(nac, sizeof(*avx->modes));
01296 
01297     nac = 0;
01298     sb = NULL;
01299     s = se = ftpBuf;
01300     while ((c = (int) *se) != (int) '\0') {
01301         se++;
01302         switch (c) {
01303         case '/':
01304             sb = se;
01305             /*@switchbreak@*/ break;
01306         case '\r':
01307             if (sb == NULL) {
01308                 avx->modes[nac] = (*s == 'd' ? 0755 : 0644);
01309                 /*@-unrecog@*/
01310                 switch(*s) {
01311                 case 'p': avx->modes[nac] |= S_IFIFO; /*@innerbreak@*/ break;
01312                 case 'c': avx->modes[nac] |= S_IFCHR; /*@innerbreak@*/ break;
01313                 case 'd': avx->modes[nac] |= S_IFDIR; /*@innerbreak@*/ break;
01314                 case 'b': avx->modes[nac] |= S_IFBLK; /*@innerbreak@*/ break;
01315                 case '-': avx->modes[nac] |= S_IFREG; /*@innerbreak@*/ break;
01316                 case 'l': avx->modes[nac] |= S_IFLNK; /*@innerbreak@*/ break;
01317                 case 's': avx->modes[nac] |= S_IFSOCK; /*@innerbreak@*/ break;
01318                 default:  avx->modes[nac] |= S_IFREG; /*@innerbreak@*/ break;
01319                 }
01320                 /*@=unrecog@*/
01321                 for (sb = se; sb > s && sb[-1] != ' '; sb--)
01322                     {};
01323             }
01324             avx->av[nac++] = strncpy(xcalloc(1, (se-sb-1)+1), sb, (se-sb-1));
01325             if (*se == '\n') se++;
01326             sb = NULL;
01327             s = se;
01328             /*@switchbreak@*/ break;
01329         default:
01330             /*@switchbreak@*/ break;
01331         }
01332     }
01333 
01334     avdir = (AVDIR) avOpendir(path, avx->av, avx->modes);
01335 
01336     avx = rpmavxFree(avx);
01337 
01338 /*@-kepttrans@*/
01339     return (DIR *) avdir;
01340 /*@=kepttrans@*/
01341 }
01342 
01343 static char * ftpRealpath(const char * path, /*@null@*/ char * resolved_path)
01344         /*@*/
01345 {
01346 assert(resolved_path == NULL);  /* XXX no POSIXly broken realpath(3) here. */
01347     /* XXX TODO: handle redirects. For now, just dupe the path. */
01348     return xstrdup(path);
01349 }
01350 
01351 int Stat(const char * path, struct stat * st)
01352         /*@globals ftpBufAlloced, ftpBuf @*/
01353         /*@modifies ftpBufAlloced, ftpBuf @*/
01354 {
01355     const char * lpath;
01356     int ut = urlPath(path, &lpath);
01357     int rc = -2;
01358 
01359     switch (ut) {
01360     case URL_IS_FTP:
01361         rc = ftpStat(path, st);
01362         goto exit;
01363         /*@notreached@*/ break;
01364     case URL_IS_HTTPS:
01365     case URL_IS_HTTP:
01366 #ifdef WITH_NEON
01367         rc = davStat(path, st);
01368 #endif
01369         goto exit;
01370         /*@notreached@*/ break;
01371     case URL_IS_PATH:
01372         path = lpath;
01373         /*@fallthrough@*/
01374     case URL_IS_UNKNOWN:
01375         break;
01376     case URL_IS_DASH:
01377     case URL_IS_HKP:
01378     default:
01379         errno = ENOENT; 
01380         goto exit;
01381         /*@notreached@*/ break;
01382     }
01383     rc = stat(path, st);
01384 exit:
01385 if (_rpmio_debug)
01386 fprintf(stderr, "<-- %s(%s,%p) rc %d\n", __FUNCTION__, path, st, rc);
01387     return rc;
01388 }
01389 
01390 int Lstat(const char * path, struct stat * st)
01391         /*@globals ftpBufAlloced, ftpBuf @*/
01392         /*@modifies ftpBufAlloced, ftpBuf @*/
01393 {
01394     const char * lpath;
01395     int ut = urlPath(path, &lpath);
01396     int rc = -2;
01397 
01398     switch (ut) {
01399     case URL_IS_FTP:
01400         rc = ftpLstat(path, st);
01401         goto exit;
01402         /*@notreached@*/ break;
01403     case URL_IS_HTTPS:
01404     case URL_IS_HTTP:
01405 #ifdef WITH_NEON
01406         rc = davLstat(path, st);
01407 #endif
01408         goto exit;
01409         /*@notreached@*/ break;
01410     case URL_IS_PATH:
01411         path = lpath;
01412         /*@fallthrough@*/
01413     case URL_IS_UNKNOWN:
01414         break;
01415     case URL_IS_DASH:
01416     case URL_IS_HKP:
01417     default:
01418         errno = ENOENT; 
01419         goto exit;
01420         /*@notreached@*/ break;
01421     }
01422     rc = lstat(path, st);
01423 exit:
01424 if (_rpmio_debug)
01425 fprintf(stderr, "<-- %s(%s,%p) rc %d\n", __FUNCTION__, path, st, rc);
01426     return rc;
01427 }
01428 
01429 int Fstat(FD_t fd, struct stat * st)
01430 {
01431     const char * path = fdGetOPath(fd);
01432     const char * lpath;
01433     int ut = urlPath(path, &lpath);
01434     int rc = -2;
01435 
01436     if (fd == NULL || path == NULL || *path == '\0' || st == NULL) {
01437         errno = ENOENT;
01438         goto exit;
01439     }
01440 
01441     switch (ut) {
01442     case URL_IS_DASH:
01443     case URL_IS_PATH:
01444     case URL_IS_UNKNOWN:
01445         break;
01446     case URL_IS_FTP:
01447     case URL_IS_HTTPS:
01448     case URL_IS_HTTP:
01449     case URL_IS_HKP:
01450         if (fd->contentLength < 0) {
01451             errno = ENOENT;
01452             goto exit;
01453         }
01454         memset(st, 0, sizeof(*st));
01455         if (path[strlen(path)-1] == '/') {
01456             st->st_nlink = 2;
01457             st->st_mode = (S_IFDIR | 0755);
01458         } else {
01459             st->st_nlink = 1;
01460             st->st_mode = (S_IFREG | 0644);
01461         }
01462         st->st_ino = hashFunctionString(0, path, 0);;
01463         st->st_size = fd->contentLength;
01464         st->st_mtime = fd->lastModified;
01465 
01466         st->st_atime = st->st_ctime = st->st_mtime;
01467         st->st_blksize = 4 * 1024;  /* HACK correct for linux ext */
01468         st->st_blocks = (st->st_size + 511)/512;
01469         break;
01470     default:
01471         errno = ENOENT; 
01472         goto exit;
01473         /*@notreached@*/ break;
01474     }
01475     rc = fstat(Fileno(fd), st);
01476 exit:
01477 if (_rpmio_debug)
01478 fprintf(stderr, "<-- %s(%p,%p) path %s rc %d\n", __FUNCTION__, fd, st, path, rc);
01479     return rc;
01480 }
01481 
01482 int Fadvise(FD_t fd, off_t offset, off_t len, int advice)
01483 {
01484     const char * path = fdGetOPath(fd);
01485     const char * lpath;
01486     int ut = urlPath(path, &lpath);
01487     int fdno = Fileno(fd);
01488     int rc;
01489 
01490 if (_rpmio_debug)
01491 fprintf(stderr, "*** %s(%p,0x%x,0x%x,0x%x) fdno %d path %s\n", __FUNCTION__, fd, (unsigned)offset, (unsigned)len, advice, fdno, path);
01492 
01493     /* XXX errno is not set by fallocate/posix_fallocate */
01494     if (fd == NULL || fdno < 0) {
01495         rc = EBADF;
01496         return rc;
01497     }
01498 
01499     switch (ut) {
01500     case URL_IS_PATH:
01501     case URL_IS_UNKNOWN:
01502         break;
01503     default:
01504         rc = ENODEV;    
01505         return rc;
01506         /*@notreached@*/ break;
01507     }
01508 
01509     switch (advice) {
01510 #if defined(HAVE_POSIX_FADVISE)
01511     case POSIX_FADV_NORMAL:
01512     case POSIX_FADV_SEQUENTIAL:
01513     case POSIX_FADV_RANDOM:
01514     case POSIX_FADV_NOREUSE:
01515     case POSIX_FADV_WILLNEED:
01516     case POSIX_FADV_DONTNEED:
01517         rc = posix_fadvise(fdno, offset, len, advice);
01518 #else
01519         rc = ENOSYS;
01520 #endif
01521         break;
01522     default:
01523         rc = EINVAL;
01524         break;
01525     }
01526 
01527     if (rc != 0)
01528         rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x,0x%x) failed: rc %d\n"),
01529                 __FUNCTION__, fdno, (unsigned)offset, (unsigned)len, rc);
01530 
01531     return rc;
01532 }
01533 
01534 #undef  HAVE_FALLOCATE  /* XXX hmmm, fallocate64 is AWOL in F11. */
01535 int Fallocate(FD_t fd, off_t offset, off_t len)
01536 {
01537     const char * path = fdGetOPath(fd);
01538     const char * lpath;
01539     int ut = urlPath(path, &lpath);
01540     int fdno = Fileno(fd);
01541     int rc;
01542 
01543 if (_rpmio_debug)
01544 fprintf(stderr, "*** %s(%p,0x%x,0x%x) fdno %d path %s\n", __FUNCTION__, fd, (unsigned)offset, (unsigned)len, fdno, path);
01545 
01546     /* XXX errno is not set by fallocate/posix_fallocate */
01547     if (fd == NULL || fdno < 0) {
01548         rc = EBADF;
01549         return rc;
01550     }
01551 
01552     switch (ut) {
01553     case URL_IS_PATH:
01554     case URL_IS_UNKNOWN:
01555         break;
01556     default:
01557         rc = ENODEV;    
01558         return rc;
01559         /*@notreached@*/ break;
01560     }
01561 
01562 #if defined(HAVE_FALLOCATE)
01563     /* XXX linux FALLOC_FL_KEEP_SIZE zeroes allocated blocks */
01564     rc = (int) fallocate(fdno, 0, (loff_t)offset, (loff_t)len);
01565 #elif defined(HAVE_POSIX_FALLOCATE)
01566     rc = posix_fallocate(fdno, offset, len);
01567 #else
01568     rc = ENOSYS;
01569 #endif
01570 
01571     if (rc != 0)
01572         rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x,0x%x) failed: rc %d\n"),
01573                 __FUNCTION__, fdno, (unsigned)offset, (unsigned)len, rc);
01574 
01575     return rc;
01576 }
01577 
01578 #ifdef  NOTYET  /* XXX figger mmap or posix_memalign first */
01579 void *Mmap(void *addr, size_t length, int prot, int flags,
01580                   FD_t fd, off_t offset)
01581 {
01582     int fdno = (fd ? Fileno(fd) : -1);
01583     void * ret = mmap(addr, length, prot, flags, fdno, offset);
01584     if (ret == NULL || ret == (void *)-1)
01585         rpmlog(RPMLOG_ERR, _("%s(%p[%u],0x%x,0x%x,%p,0x%x) failed: %m\n"),
01586                 __FUNCTION__, addr, (unsigned)len, prot, flags, fd,
01587                 (unsigned)offset);
01588 if (_rpmio_debug)
01589 fprintf(stderr, "<-- %s(%p[%u],0x%x,0x%x,%p,0x%x) ret %p\n", __FUNCTION__, addr, (unsigned)len, prot, flags, fd, (unsigned)offset, ret);
01590     return ret;
01591 }
01592 
01593 int Munmap(const void * addr, size_t len)
01594 {
01595     int rc = munmap(addr, len);
01596     if (rc < 0)
01597         rpmlog(RPMLOG_ERR, _("%s(%p[%u]) failed: %m\n"),
01598                 __FUNCTION__, addr, (unsigned)len);
01599 if (_rpmio_debug)
01600 fprintf(stderr, "<-- %s(%p[%u]) rc %d\n", __FUNCTION__, addr, (unsigned)len, rc);
01601     return rc;
01602 }
01603 
01604 int Mprotect(const void * addr, size_t len, int prot)
01605 {
01606     int rc = mprotect(addr, len, prot);
01607     if (rc < 0)
01608         rpmlog(RPMLOG_ERR, _("%s(%p[%u],%d) failed: %m\n"),
01609                 __FUNCTION__, addr, (unsigned)len, prot);
01610 if (_rpmio_debug)
01611 fprintf(stderr, "<-- %s(%p[%u],%d) rc %d\n", __FUNCTION__, addr, len, prot, rc);
01612     return rc;
01613 }
01614 #endif
01615 
01616 #ifdef  NOTYET  /* XXX figger posix_fadvise or posix_madvise first */
01617 int Madvise(void *addr, size_t len, int advice)
01618 {
01619     int rc = madvise(addr, len, advice);
01620     if (rc < 0)
01621         rpmlog(RPMLOG_ERR, _("%s(%p[%u],%d) failed: %m\n"),
01622                 __FUNCTION__, addr, (unsigned)len, advice);
01623 if (_rpmio_debug)
01624 fprintf(stderr, "<-- %s(%p[%u],%d) rc %d\n", __FUNCTION__, addr, len, advice, rc);
01625     return rc;
01626 }
01627 
01628 int Fadvise(FD_t fd, off_t offset, off_t len, int advice)
01629 {
01630     const char * path = fdGetOPath(fd);
01631     const char * lpath;
01632     int ut = urlPath(path, &lpath);
01633     int fdno = Fileno(fd);
01634     int rc = -2;
01635 
01636     if (fd == NULL || fdno < 0) {
01637         errno = EBADF;
01638         goto exit;
01639     }
01640 
01641     switch (ut) {
01642     case URL_IS_PATH:
01643     case URL_IS_UNKNOWN:
01644         break;
01645     default:
01646         errno = EINVAL; 
01647         goto exit;
01648         /*@notreached@*/ break;
01649     }
01650     rc = posix_fadvise(fdno, offset, len, advice);
01651     if (rc != 0)
01652         rpmlog(RPMLOG_ERR, _("%s(%d,%d,0x%x,0x%x) failed: %m\n"),
01653                 __FUNCTION__, fdno, (unsigned)offset, (unsigned)len, advice);
01654 exit:
01655 if (_rpmio_debug)
01656 fprintf(stderr, "<-- %s(%p,0x%x,0x%x,%d) fdno %d path %s rc %d\n", __FUNCTION__, fd, (unsigned)offset, (unsigned)len, advice, fdno, path, rc);
01657     return rc;
01658 }
01659 #endif
01660 
01661 int Chown(const char * path, uid_t owner, gid_t group)
01662 {
01663     const char * lpath;
01664     int ut = urlPath(path, &lpath);
01665     int rc = -2;
01666 
01667     switch (ut) {
01668     case URL_IS_PATH:
01669         path = lpath;
01670         /*@fallthrough@*/
01671     case URL_IS_UNKNOWN:
01672         break;
01673     case URL_IS_DASH:
01674     case URL_IS_HKP:
01675     case URL_IS_FTP:            /* XXX TODO: implement. */
01676     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01677     case URL_IS_HTTP:           /* XXX TODO: implement. */
01678     default:
01679         errno = EINVAL;         /* XXX W2DO? */
01680         goto exit;
01681         /*@notreached@*/ break;
01682     }
01683     rc = chown(path, owner, group);
01684 exit:
01685 if (_rpmio_debug)
01686 fprintf(stderr, "<-- %s(%s,%u,%u) rc %d\n", __FUNCTION__, path, (unsigned)owner, (unsigned)group, rc);
01687     return rc;
01688 }
01689 
01690 int Fchown(FD_t fd, uid_t owner, gid_t group)
01691 {
01692     const char * path = fdGetOPath(fd);
01693     const char * lpath;
01694     int ut = urlPath(path, &lpath);
01695     int rc = -2;
01696 
01697     switch (ut) {
01698     case URL_IS_PATH:
01699         path = lpath;
01700         /*@fallthrough@*/
01701     case URL_IS_UNKNOWN:
01702         break;
01703     case URL_IS_DASH:
01704     case URL_IS_HKP:
01705     case URL_IS_FTP:            /* XXX TODO: implement. */
01706     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01707     case URL_IS_HTTP:           /* XXX TODO: implement. */
01708     default:
01709         errno = EINVAL;         /* XXX W2DO? */
01710         goto exit;
01711         /*@notreached@*/ break;
01712     }
01713     rc = fchown(Fileno(fd), owner, group);
01714 exit:
01715 if (_rpmio_debug)
01716 fprintf(stderr, "<-- %s(%p,%u,%u) path %s rc %d\n", __FUNCTION__, fd, (unsigned)owner, (unsigned)group, path, rc);
01717     return rc;
01718 }
01719 
01720 int Lchown(const char * path, uid_t owner, gid_t group)
01721 {
01722     const char * lpath;
01723     int ut = urlPath(path, &lpath);
01724     int rc = -2;
01725 
01726     switch (ut) {
01727     case URL_IS_PATH:
01728         path = lpath;
01729         /*@fallthrough@*/
01730     case URL_IS_UNKNOWN:
01731         break;
01732     case URL_IS_DASH:
01733     case URL_IS_HKP:
01734     case URL_IS_FTP:            /* XXX TODO: implement. */
01735     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01736     case URL_IS_HTTP:           /* XXX TODO: implement. */
01737     default:
01738         errno = EINVAL;         /* XXX W2DO? */
01739         goto exit;
01740         /*@notreached@*/ break;
01741     }
01742     rc = lchown(path, owner, group);
01743 exit:
01744 if (_rpmio_debug)
01745 fprintf(stderr, "*** %s(%s,%u,%u)\n", __FUNCTION__, path, (unsigned)owner, (unsigned)group);
01746     return rc;
01747 }
01748 
01749 int Chmod(const char * path, mode_t mode)
01750 {
01751     const char * lpath;
01752     int ut = urlPath(path, &lpath);
01753     int rc = -2;
01754 
01755     switch (ut) {
01756     case URL_IS_PATH:
01757         path = lpath;
01758         /*@fallthrough@*/
01759     case URL_IS_UNKNOWN:
01760         break;
01761     case URL_IS_DASH:
01762     case URL_IS_HKP:
01763     case URL_IS_FTP:            /* XXX TODO: implement. */
01764     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01765     case URL_IS_HTTP:           /* XXX TODO: implement. */
01766     default:
01767         errno = EINVAL;         /* XXX W2DO? */
01768         goto exit;
01769         /*@notreached@*/ break;
01770     }
01771     rc = chmod(path, mode);
01772 exit:
01773 if (_rpmio_debug)
01774 fprintf(stderr, "<-- %s(%s,%0o) rc %d\n", __FUNCTION__, path, (int)mode, rc);
01775     return rc;
01776 }
01777 
01778 int Lchmod(const char * path, mode_t mode)
01779 {
01780 #if defined(HAVE_LCHMOD)
01781     const char * lpath;
01782     int ut = urlPath(path, &lpath);
01783     int rc = -2;
01784 
01785     switch (ut) {
01786     case URL_IS_PATH:
01787         path = lpath;
01788         /*@fallthrough@*/
01789     case URL_IS_UNKNOWN:
01790         break;
01791     case URL_IS_DASH:
01792     case URL_IS_HKP:
01793     case URL_IS_FTP:            /* XXX TODO: implement. */
01794     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01795     case URL_IS_HTTP:           /* XXX TODO: implement. */
01796     default:
01797         errno = EINVAL;         /* XXX W2DO? */
01798         goto exit;
01799         /*@notreached@*/ break;
01800     }
01801     rc = lchmod(path, mode);
01802 exit:
01803 if (_rpmio_debug)
01804 fprintf(stderr, "<-- %s(%s,%0o) rc %d\n", __FUNCTION__, path, (int)mode, rc);
01805     return rc;
01806 #else
01807     errno = ENOSYS;
01808     return -2;
01809 #endif
01810 }
01811 
01812 int Fchmod(FD_t fd, mode_t mode)
01813 {
01814     const char * path = fdGetOPath(fd);
01815     const char * lpath;
01816     int ut = urlPath(path, &lpath);
01817     int rc = -2;
01818 
01819     switch (ut) {
01820     case URL_IS_PATH:
01821         path = lpath;
01822         /*@fallthrough@*/
01823     case URL_IS_UNKNOWN:
01824         break;
01825     case URL_IS_DASH:
01826     case URL_IS_HKP:
01827     case URL_IS_FTP:            /* XXX TODO: implement. */
01828     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01829     case URL_IS_HTTP:           /* XXX TODO: implement. */
01830     default:
01831         errno = EINVAL;         /* XXX W2DO? */
01832         goto exit;
01833         /*@notreached@*/ break;
01834     }
01835     rc = fchmod(Fileno(fd), mode);
01836 exit:
01837 if (_rpmio_debug)
01838 fprintf(stderr, "*** %s(%p,%0o) path %s rc %d\n", __FUNCTION__, fd, (int)mode, path, rc);
01839     return rc;
01840 }
01841 
01842 int Chflags(const char * path, unsigned int flags)
01843 {
01844 #if defined(HAVE_CHFLAGS)
01845     const char * lpath;
01846     int ut = urlPath(path, &lpath);
01847 
01848 if (_rpmio_debug)
01849 fprintf(stderr, "*** Chflags(%s,0x%x)\n", path, flags);
01850     switch (ut) {
01851     case URL_IS_PATH:
01852         path = lpath;
01853         /*@fallthrough@*/
01854     case URL_IS_UNKNOWN:
01855         break;
01856     case URL_IS_DASH:
01857     case URL_IS_HKP:
01858     case URL_IS_FTP:            /* XXX TODO: implement. */
01859     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01860     case URL_IS_HTTP:           /* XXX TODO: implement. */
01861     default:
01862         errno = EINVAL;         /* XXX W2DO? */
01863         return -2;
01864         /*@notreached@*/ break;
01865     }
01866     return chflags(path, flags);
01867 #else
01868     errno = ENOSYS;
01869     return -2;
01870 #endif
01871 }
01872 
01873 int Lchflags(const char * path, unsigned int flags)
01874 {
01875     const char * lpath;
01876     int ut = urlPath(path, &lpath);
01877     int rc = -2;
01878 
01879 #if defined(HAVE_LCHFLAGS)
01880 if (_rpmio_debug)
01881 fprintf(stderr, "*** Lchflags(%s,0x%x)\n", path, flags);
01882     switch (ut) {
01883     case URL_IS_PATH:
01884         path = lpath;
01885         /*@fallthrough@*/
01886     case URL_IS_UNKNOWN:
01887         break;
01888     case URL_IS_DASH:
01889     case URL_IS_HKP:
01890     case URL_IS_FTP:            /* XXX TODO: implement. */
01891     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01892     case URL_IS_HTTP:           /* XXX TODO: implement. */
01893     default:
01894         errno = EINVAL;         /* XXX W2DO? */
01895         return -2;
01896         /*@notreached@*/ break;
01897     }
01898     return lchflags(path, flags);
01899 #else
01900     ut = ut;    /* keep gcc happy */
01901     errno = ENOSYS;
01902 #endif
01903     return rc;
01904 }
01905 
01906 int Fchflags(FD_t fd, unsigned int flags)
01907 {
01908 #if defined(HAVE_FCHFLAGS)
01909     const char * path = fdGetOPath(fd);
01910     const char * lpath;
01911     int ut = urlPath(path, &lpath);
01912 
01913 if (_rpmio_debug)
01914 fprintf(stderr, "*** Fchflags(%p,0x%x) path %s\n", fd, flags, path);
01915     switch (ut) {
01916     case URL_IS_PATH:
01917         path = lpath;
01918         /*@fallthrough@*/
01919     case URL_IS_UNKNOWN:
01920         break;
01921     case URL_IS_DASH:
01922     case URL_IS_HKP:
01923     case URL_IS_FTP:            /* XXX TODO: implement. */
01924     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01925     case URL_IS_HTTP:           /* XXX TODO: implement. */
01926     default:
01927         errno = EINVAL;         /* XXX W2DO? */
01928         return -2;
01929         /*@notreached@*/ break;
01930     }
01931     return fchflags(Fileno(fd), flags);
01932 #else
01933     errno = ENOSYS;
01934     return -2;
01935 #endif
01936 }
01937 int Mkfifo(const char * path, mode_t mode)
01938 {
01939     const char * lpath;
01940     int ut = urlPath(path, &lpath);
01941     int rc = -2;
01942 
01943     switch (ut) {
01944     case URL_IS_PATH:
01945         path = lpath;
01946         /*@fallthrough@*/
01947     case URL_IS_UNKNOWN:
01948         break;
01949     case URL_IS_DASH:
01950     case URL_IS_HKP:
01951     case URL_IS_FTP:            /* XXX TODO: implement. */
01952     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01953     case URL_IS_HTTP:           /* XXX TODO: implement. */
01954     default:
01955         errno = EINVAL;         /* XXX W2DO? */
01956         goto exit;
01957         /*@notreached@*/ break;
01958     }
01959     rc = mkfifo(path, mode);
01960 exit:
01961 if (_rpmio_debug)
01962 fprintf(stderr, "<-- %s(%s,%0o) rc %d\n", __FUNCTION__, path, (int)mode, rc);
01963     return rc;
01964 }
01965 
01966 int Mknod(const char * path, mode_t mode, dev_t dev)
01967 {
01968     const char * lpath;
01969     int ut = urlPath(path, &lpath);
01970     int rc = -2;
01971 
01972     switch (ut) {
01973     case URL_IS_PATH:
01974         path = lpath;
01975         /*@fallthrough@*/
01976     case URL_IS_UNKNOWN:
01977         break;
01978     case URL_IS_DASH:
01979     case URL_IS_HKP:
01980     case URL_IS_FTP:            /* XXX TODO: implement. */
01981     case URL_IS_HTTPS:          /* XXX TODO: implement. */
01982     case URL_IS_HTTP:           /* XXX TODO: implement. */
01983     default:
01984         errno = EINVAL;         /* XXX W2DO? */
01985         goto exit;
01986         /*@notreached@*/ break;
01987     }
01988 /*@-portability@*/
01989     rc = mknod(path, mode, dev);
01990 /*@=portability@*/
01991 exit:
01992 if (_rpmio_debug)
01993 fprintf(stderr, "<-- %s(%s,%0o, 0x%x) rc %d\n", __FUNCTION__, path, (int)mode, (int)dev, rc);
01994     return rc;
01995 }
01996 
01997 int Utime(const char * path, const struct utimbuf *buf)
01998 {
01999     const char * lpath;
02000     int ut = urlPath(path, &lpath);
02001     int rc = -2;
02002 
02003     switch (ut) {
02004     case URL_IS_PATH:
02005         path = lpath;
02006         /*@fallthrough@*/
02007     case URL_IS_UNKNOWN:
02008         break;
02009     case URL_IS_DASH:
02010     case URL_IS_HKP:
02011     case URL_IS_FTP:            /* XXX TODO: implement. */
02012     case URL_IS_HTTPS:          /* XXX TODO: implement. */
02013     case URL_IS_HTTP:           /* XXX TODO: implement. */
02014     default:
02015         errno = EINVAL;         /* XXX W2DO? */
02016         goto exit;
02017         /*@notreached@*/ break;
02018     }
02019     rc = utime(path, buf);
02020 exit:
02021 if (_rpmio_debug)
02022 fprintf(stderr, "<-- %s(%s,%p) rc %d\n", __FUNCTION__, path, buf, rc);
02023     return rc;
02024 }
02025 
02026 /*@-fixedformalarray@*/
02027 int Utimes(const char * path, const struct timeval times[2])
02028 {
02029     const char * lpath;
02030     int ut = urlPath(path, &lpath);
02031     int rc = -2;
02032 
02033     switch (ut) {
02034     case URL_IS_PATH:
02035         path = lpath;
02036         /*@fallthrough@*/
02037     case URL_IS_UNKNOWN:
02038         break;
02039     case URL_IS_DASH:
02040     case URL_IS_HKP:
02041     case URL_IS_FTP:            /* XXX TODO: implement. */
02042     case URL_IS_HTTPS:          /* XXX TODO: implement. */
02043     case URL_IS_HTTP:           /* XXX TODO: implement. */
02044     default:
02045         errno = EINVAL;         /* XXX W2DO? */
02046         goto exit;
02047         /*@notreached@*/ break;
02048     }
02049     rc = utimes(path, times);
02050 exit:
02051 if (_rpmio_debug)
02052 fprintf(stderr, "<-- %s(%s,%p) rc %d\n", __FUNCTION__, path, times, rc);
02053     return rc;
02054 }
02055 /*@=fixedformalarray@*/
02056 
02057 /*@-fixedformalarray@*/
02058 int Lutimes(const char * path, const struct timeval times[2])
02059 {
02060 #ifdef HAVE_LUTIMES
02061     const char * lpath;
02062     int ut = urlPath(path, &lpath);
02063     int rc = -2;
02064 
02065     switch (ut) {
02066     case URL_IS_PATH:
02067         path = lpath;
02068         /*@fallthrough@*/
02069     case URL_IS_UNKNOWN:
02070         break;
02071     case URL_IS_DASH:
02072     case URL_IS_HKP:
02073     case URL_IS_FTP:            /* XXX TODO: implement. */
02074     case URL_IS_HTTPS:          /* XXX TODO: implement. */
02075     case URL_IS_HTTP:           /* XXX TODO: implement. */
02076     default:
02077         errno = EINVAL;         /* XXX W2DO? */
02078         goto exit;
02079         /*@notreached@*/ break;
02080     }
02081     rc = lutimes(path, times);
02082 exit:
02083 if (_rpmio_debug)
02084 fprintf(stderr, "<-- %s(%s,%p) rc %d\n", __FUNCTION__, path, times, rc);
02085     return rc;
02086 #else
02087     errno = ENOSYS;
02088     return -2;
02089 #endif
02090 }
02091 /*@=fixedformalarray@*/
02092 
02093 int Symlink(const char * oldpath, const char * newpath)
02094 {
02095     const char * opath;
02096     int out = urlPath(oldpath, &opath);
02097     const char * npath;
02098     int nut = urlPath(newpath, &npath);
02099     int rc = -2;
02100 
02101     nut = nut;  /* XXX keep gcc quiet. */
02102     switch (out) {
02103     case URL_IS_PATH:
02104         oldpath = opath;
02105         newpath = npath;
02106         /*@fallthrough@*/
02107     case URL_IS_UNKNOWN:
02108         break;
02109     case URL_IS_DASH:
02110     case URL_IS_HKP:
02111     case URL_IS_FTP:            /* XXX TODO: implement. */
02112     case URL_IS_HTTPS:          /* XXX TODO: implement. */
02113     case URL_IS_HTTP:           /* XXX TODO: implement. */
02114     default:
02115         errno = EINVAL;         /* XXX W2DO? */
02116         goto exit;
02117         /*@notreached@*/ break;
02118     }
02119     rc = symlink(oldpath, newpath);
02120 exit:
02121 if (_rpmio_debug)
02122 fprintf(stderr, "<-- %s(%s,%s) rc %d\n", __FUNCTION__, oldpath, newpath, rc);
02123     return rc;
02124 }
02125 
02126 int Readlink(const char * path, char * buf, size_t bufsiz)
02127         /*@globals ftpBufAlloced, ftpBuf @*/
02128         /*@modifies ftpBufAlloced, ftpBuf @*/
02129 {
02130     const char * lpath;
02131     int ut = urlPath(path, &lpath);
02132     int rc = -2;
02133 
02134     switch (ut) {
02135     case URL_IS_FTP:
02136         rc = ftpReadlink(path, buf, bufsiz);
02137         goto exit;
02138         /*@notreached@*/ break;
02139     case URL_IS_HTTPS:
02140     case URL_IS_HTTP:
02141 #ifdef  NOTYET
02142         rc = davReadlink(path, buf, bufsiz);
02143 #endif
02144         goto exit;
02145         /*@notreached@*/ break;
02146     case URL_IS_PATH:
02147         path = lpath;
02148         /*@fallthrough@*/
02149     case URL_IS_UNKNOWN:
02150         break;
02151     case URL_IS_DASH:
02152     case URL_IS_HKP:
02153     default:
02154         errno = EINVAL;         /* XXX W2DO? */
02155         goto exit;
02156         /*@notreached@*/ break;
02157     }
02158 /*@-compdef@*/ /* FIX: *buf is undefined */
02159     rc = readlink(path, buf, bufsiz);
02160 /*@=compdef@*/
02161 exit:
02162 if (_rpmio_debug)
02163 fprintf(stderr, "<-- %s(%s,%p[%u]) rc %d\n", __FUNCTION__, path, buf, (unsigned)bufsiz, rc);
02164     return rc;
02165 }
02166 
02167 int Access(const char * path, int amode)
02168 {
02169     const char * lpath;
02170     int ut = urlPath(path, &lpath);
02171     int rc = -2;
02172 
02173     switch (ut) {
02174     case URL_IS_PATH:
02175         path = lpath;
02176         /*@fallthrough@*/
02177     case URL_IS_UNKNOWN:
02178         break;
02179     case URL_IS_DASH:
02180     case URL_IS_HKP:
02181     case URL_IS_HTTPS:          /* XXX TODO: implement. */
02182     case URL_IS_HTTP:           /* XXX TODO: implement. */
02183     case URL_IS_FTP:            /* XXX TODO: implement. */
02184     default:
02185         errno = EINVAL;         /* XXX W2DO? */
02186         goto exit;
02187         /*@notreached@*/ break;
02188     }
02189     rc = access(path, amode);
02190 exit:
02191 if (_rpmio_debug)
02192 fprintf(stderr, "<-- %s(%s,%d) rc %d\n", __FUNCTION__, path, amode, rc);
02193     return rc;
02194 }
02195 
02196 /* glob_pattern_p() taken from bash
02197  * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
02198  *
02199  * Return nonzero if PATTERN has any special globbing chars in it.
02200  */
02201 int Glob_pattern_p (const char * pattern, int quote)
02202 {
02203     const char *p;
02204     int ut = urlPath(pattern, &p);
02205     int open = 0;
02206     char c;
02207 
02208     while ((c = *p++) != '\0')
02209         switch (c) {
02210         case '?':
02211             /* Don't treat '?' as a glob char in HTTP URL's */
02212             if (ut == URL_IS_HTTPS || ut == URL_IS_HTTP || ut == URL_IS_HKP)
02213                 continue;
02214             /*@fallthrough@*/
02215         case '*':
02216             return (1);
02217         case '\\':
02218             if (quote && *p != '\0')
02219                 p++;
02220             continue;
02221 
02222         case '[':
02223             open = 1;
02224             continue;
02225         case ']':
02226             if (open)
02227                 return (1);
02228             continue;
02229 
02230         case '+':
02231         case '@':
02232         case '!':
02233             if (*p == '(')
02234                 return (1);
02235             continue;
02236         }
02237 
02238     return (0);
02239 }
02240 
02241 int Glob_error(/*@unused@*/ const char * epath,
02242                 /*@unused@*/ int eerrno)
02243 {
02244     return 1;
02245 }
02246 
02247 int Glob(const char *pattern, int flags,
02248         int errfunc(const char * epath, int eerrno), void *_pglob)
02249 {
02250     glob_t *pglob = _pglob;
02251     const char * lpath;
02252     int ut = urlPath(pattern, &lpath);
02253     const char *home = getenv("HOME");
02254 
02255 /*@-castfcnptr@*/
02256 if (_rpmio_debug)
02257 fprintf(stderr, "*** Glob(%s,0x%x,%p,%p)\n", pattern, (unsigned)flags, (void *)errfunc, pglob);
02258 /*@=castfcnptr@*/
02259     switch (ut) {
02260     case URL_IS_HTTPS:
02261     case URL_IS_HTTP:
02262     case URL_IS_FTP:
02263 /*@-type@*/
02264         pglob->gl_closedir = (void *) Closedir;
02265         pglob->gl_readdir = (void *) Readdir;
02266         pglob->gl_opendir = (void *) Opendir;
02267         pglob->gl_lstat = Lstat;
02268         pglob->gl_stat = Stat;
02269 /*@=type@*/
02270         flags |= GLOB_ALTDIRFUNC;
02271         flags &= ~GLOB_TILDE;
02272         break;
02273     case URL_IS_PATH:
02274         pattern = lpath;
02275         /*@fallthrough@*/
02276     case URL_IS_UNKNOWN:
02277         if (home && home[0])
02278             flags |= GLOB_TILDE;
02279         else
02280             flags &= ~GLOB_TILDE;
02281         break;
02282     case URL_IS_DASH:
02283     case URL_IS_HKP:
02284     default:
02285         return -2;
02286         /*@notreached@*/ break;
02287     }
02288     return glob(pattern, flags, errfunc, pglob);
02289 }
02290 
02291 void Globfree(void *_pglob)
02292 {
02293     glob_t *pglob = _pglob;
02294 if (_rpmio_debug)
02295 fprintf(stderr, "*** Globfree(%p)\n", pglob);
02296     globfree(pglob);
02297 }
02298 
02299 char * Realpath(const char * path, /*@null@*/ char * resolved_path)
02300 {
02301     const char * lpath;
02302     int ut = urlPath(path, &lpath);
02303     char * rpath = NULL;
02304 
02305 if (_rpmio_debug)
02306 fprintf(stderr, "*** Realpath(%s, %s)\n", path, (resolved_path ? resolved_path : "NULL"));
02307 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */
02308 /*@-nullpass@*/
02309     /* XXX if POSIXly broken realpath(3) is desired, do that. */
02310     /* XXX note: preserves current rpmlib realpath(3) usage cases. */
02311     if (path == NULL || resolved_path != NULL)
02312         return realpath(path, resolved_path);
02313 /*@=nullpass@*/
02314 #endif  /* !__LCLINT__ */
02315 
02316     switch (ut) {
02317     case URL_IS_FTP:
02318         return ftpRealpath(path, resolved_path);
02319         /*@notreached@*/ break;
02320     case URL_IS_HTTPS:  
02321     case URL_IS_HTTP:
02322     case URL_IS_HKP:
02323 #ifdef WITH_NEON
02324         return davRealpath(path, resolved_path);
02325         /*@notreached@*/ break;
02326 #endif
02327         /*@fallthrough@*/
02328     default:
02329         return xstrdup(path);
02330         /*@notreached@*/ break;
02331     case URL_IS_DASH:
02332         /* non-GLIBC systems => EINVAL. non-linux systems => EINVAL */
02333 #if defined(__linux__)
02334         lpath = "/dev/stdin";
02335 #else
02336         lpath = NULL;
02337 #endif
02338         break;
02339     case URL_IS_PATH:           /* XXX note: file:/// prefix is dropped. */
02340     case URL_IS_UNKNOWN:
02341         path = lpath;
02342         break;
02343     }
02344 
02345 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */
02346     if (lpath == NULL || *lpath == '/')
02347 /*@-nullpass@*/ /* XXX glibc extension */
02348         rpath = realpath(lpath, resolved_path);
02349 /*@=nullpass@*/
02350     else {
02351         char * t;
02352 #if defined(__GLIBC__)
02353         char * dn = NULL;
02354 #else
02355         char dn[PATH_MAX];
02356         dn[0] = '\0';
02357 #endif
02358         /*
02359          * Using realpath on lpath isn't correct if the lpath is a symlink,
02360          * especially if the symlink is a dangling link.  What we 
02361          * do instead is use realpath() on `.' and then append lpath to
02362          * the result.
02363          */
02364         if ((t = realpath(".", dn)) != NULL) {
02365 /*@-globs -mods@*/      /* XXX no rpmGlobalMacroContext mods please. */
02366             rpath = (char *) rpmGetPath(t, "/", lpath, NULL);
02367             /* XXX preserve the pesky trailing '/' */
02368             if (lpath[strlen(lpath)-1] == '/') {
02369                 char * s = rpath;
02370                 rpath = rpmExpand(s, "/", NULL);
02371                 s = _free(s);
02372             }
02373 /*@=globs =mods@*/
02374         } else
02375             rpath = NULL;
02376 #if defined(__GLIBC__)
02377         t = _free(t);
02378 #endif
02379     }
02380 #endif  /* !__LCLINT__ */
02381 
02382     return rpath;
02383 }
02384 
02385 off_t Lseek(int fdno, off_t offset, int whence)
02386 {
02387 if (_rpmio_debug)
02388 fprintf(stderr, "*** Lseek(%d,0x%lx,%d)\n", fdno, (long)offset, whence);
02389     return lseek(fdno, offset, whence);
02390 }