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