rpm 5.2.1

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