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