rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 }