# rpmio/rpmrpc.c

Go to the documentation of this file.

    00001 /*@-type@*/ /* LCL: function typedefs */
    00006 #include "system.h"
    00007 #include <rpmio_internal.h>
    00008 #include <popt.h>
    00009 #include "ugid.h"
    00010 #include "debug.h"
    00011
    00012 /*@access FD_t@*/
    00013 /*@access urlinfo@*/
    00014
    00015 /*@-redecl@*/
    00016 extern int _rpmio_debug;
    00017 /*@=redecl@*/
    00018
    00019 /* =============================================================== */
    00020 static int ftpMkdir(const char * path, /*@unused@*/ mode_t mode)
    00021         /*@globals fileSystem @*/
    00022         /*@modifies fileSystem @*/
    00023 {
    00024     int rc;
    00025     if ((rc = ftpCmd("MKD", path, NULL)) != 0)
    00026         return rc;
    00027 #if NOTYET
    00028     {   char buf[20];
    00029         sprintf(buf, " 0%o", mode);
    00030         (void) ftpCmd("SITE CHMOD", path, buf);
    00031     }
    00032 #endif
    00033     return rc;
    00034 }
    00035
    00036 static int ftpChdir(const char * path)
    00037         /*@globals fileSystem @*/
    00038         /*@modifies fileSystem @*/
    00039 {
    00040     return ftpCmd("CWD", path, NULL);
    00041 }
    00042
    00043 static int ftpRmdir(const char * path)
    00044         /*@globals fileSystem @*/
    00045         /*@modifies fileSystem @*/
    00046 {
    00047     return ftpCmd("RMD", path, NULL);
    00048 }
    00049
    00050 static int ftpRename(const char * oldpath, const char * newpath)
    00051         /*@globals fileSystem @*/
    00052         /*@modifies fileSystem @*/
    00053 {
    00054     int rc;
    00055     if ((rc = ftpCmd("RNFR", oldpath, NULL)) != 0)
    00056         return rc;
    00057     return ftpCmd("RNTO", newpath, NULL);
    00058 }
    00059
    00060 static int ftpUnlink(const char * path)
    00061         /*@globals fileSystem @*/
    00062         /*@modifies fileSystem @*/
    00063 {
    00064     return ftpCmd("DELE", path, NULL);
    00065 }
    00066
    00067 /* =============================================================== */
    00068 /* XXX rebuilddb.c: analogues to mkdir(2)/rmdir(2). */
    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_HTTP:           /* XXX WRONG WRONG WRONG */
    00079     case URL_IS_PATH:
    00080         path = lpath;
    00081         /*@fallthrough@*/
    00082     case URL_IS_UNKNOWN:
    00083         break;
    00084     case URL_IS_DASH:
    00085     default:
    00086         return -2;
    00087         /*@notreached@*/ break;
    00088     }
    00089     return mkdir(path, mode);
    00090 }
    00091
    00092 int Chdir (const char * path)
    00093 {
    00094     const char * lpath;
    00095     int ut = urlPath(path, &lpath);
    00096
    00097     switch (ut) {
    00098     case URL_IS_FTP:
    00099         return ftpChdir(path);
    00100         /*@notreached@*/ break;
    00101     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00102     case URL_IS_PATH:
    00103         path = lpath;
    00104         /*@fallthrough@*/
    00105     case URL_IS_UNKNOWN:
    00106         break;
    00107     case URL_IS_DASH:
    00108     default:
    00109         return -2;
    00110         /*@notreached@*/ break;
    00111     }
    00112     return chdir(path);
    00113 }
    00114
    00115 int Rmdir (const char * path)
    00116 {
    00117     const char * lpath;
    00118     int ut = urlPath(path, &lpath);
    00119
    00120     switch (ut) {
    00121     case URL_IS_FTP:
    00122         return ftpRmdir(path);
    00123         /*@notreached@*/ break;
    00124     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00125     case URL_IS_PATH:
    00126         path = lpath;
    00127         /*@fallthrough@*/
    00128     case URL_IS_UNKNOWN:
    00129         break;
    00130     case URL_IS_DASH:
    00131     default:
    00132         return -2;
    00133         /*@notreached@*/ break;
    00134     }
    00135     return rmdir(path);
    00136 }
    00137
    00138 /* XXX rpmdb.c: analogue to rename(2). */
    00139
    00140 int Rename (const char * oldpath, const char * newpath)
    00141 {
    00142     const char *oe = NULL;
    00143     const char *ne = NULL;
    00144     int oldut, newut;
    00145
    00146     /* XXX lib/install.c used to rely on this behavior. */
    00147     if (!strcmp(oldpath, newpath)) return 0;
    00148
    00149     oldut = urlPath(oldpath, &oe);
    00150     switch (oldut) {
    00151     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
    00152     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00153     case URL_IS_PATH:
    00154     case URL_IS_UNKNOWN:
    00155         break;
    00156     case URL_IS_DASH:
    00157     default:
    00158         return -2;
    00159         /*@notreached@*/ break;
    00160     }
    00161
    00162     newut = urlPath(newpath, &ne);
    00163     switch (newut) {
    00164     case URL_IS_FTP:
    00165 if (_rpmio_debug)
    00166 fprintf(stderr, "*** rename old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
    00167         if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
    00168             !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
    00169             return -2;
    00170         return ftpRename(oldpath, newpath);
    00171         /*@notreached@*/ break;
    00172     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00173     case URL_IS_PATH:
    00174         oldpath = oe;
    00175         newpath = ne;
    00176         break;
    00177     case URL_IS_UNKNOWN:
    00178         break;
    00179     case URL_IS_DASH:
    00180     default:
    00181         return -2;
    00182         /*@notreached@*/ break;
    00183     }
    00184     return rename(oldpath, newpath);
    00185 }
    00186
    00187 int Link (const char * oldpath, const char * newpath)
    00188 {
    00189     const char *oe = NULL;
    00190     const char *ne = NULL;
    00191     int oldut, newut;
    00192
    00193     oldut = urlPath(oldpath, &oe);
    00194     switch (oldut) {
    00195     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
    00196     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00197     case URL_IS_PATH:
    00198     case URL_IS_UNKNOWN:
    00199         break;
    00200     case URL_IS_DASH:
    00201     default:
    00202         return -2;
    00203         /*@notreached@*/ break;
    00204     }
    00205
    00206     newut = urlPath(newpath, &ne);
    00207     switch (newut) {
    00208     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00209     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
    00210     case URL_IS_PATH:
    00211 if (_rpmio_debug)
    00212 fprintf(stderr, "*** link old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
    00213         if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
    00214             !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
    00215             return -2;
    00216         oldpath = oe;
    00217         newpath = ne;
    00218         break;
    00219     case URL_IS_UNKNOWN:
    00220         break;
    00221     case URL_IS_DASH:
    00222     default:
    00223         return -2;
    00224         /*@notreached@*/ break;
    00225     }
    00226     return link(oldpath, newpath);
    00227 }
    00228
    00229 /* XXX build/build.c: analogue to unlink(2). */
    00230
    00231 int Unlink(const char * path) {
    00232     const char * lpath;
    00233     int ut = urlPath(path, &lpath);
    00234
    00235     switch (ut) {
    00236     case URL_IS_FTP:
    00237         return ftpUnlink(path);
    00238         /*@notreached@*/ break;
    00239     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    00240     case URL_IS_PATH:
    00241         path = lpath;
    00242         /*@fallthrough@*/
    00243     case URL_IS_UNKNOWN:
    00244         break;
    00245     case URL_IS_DASH:
    00246     default:
    00247         return -2;
    00248         /*@notreached@*/ break;
    00249     }
    00250     return unlink(path);
    00251 }
    00252
    00253 /* XXX swiped from mc-4.5.39-pre9 vfs/ftpfs.c */
    00254
    00255 #define g_strdup        xstrdup
    00256 #define g_free          free
    00257
    00258 /*
    00259  * FIXME: this is broken. It depends on mc not crossing border on month!
    00260  */
    00261 /*@unchecked@*/
    00262 static int current_mday;
    00263 /*@unchecked@*/
    00264 static int current_mon;
    00265 /*@unchecked@*/
    00266 static int current_year;
    00267
    00268 /* Following stuff (parse_ls_lga) is used by ftpfs and extfs */
    00269 #define MAXCOLS         30
    00270
    00271 /*@unchecked@*/
    00272 static char *columns [MAXCOLS]; /* Points to the string in column n */
    00273 /*@unchecked@*/
    00274 static int   column_ptr [MAXCOLS]; /* Index from 0 to the starting positions of the columns */
    00275
    00276 static int
    00277 vfs_split_text (char *p)
    00278         /*@globals columns, column_ptr @*/
    00279         /*@modifies *p, columns, column_ptr @*/
    00280 {
    00281     char *original = p;
    00282     int  numcols;
    00283
    00284
    00285     for (numcols = 0; *p && numcols < MAXCOLS; numcols++){
    00286         while (*p == ' ' || *p == '\r' || *p == '\n'){
    00287             *p = 0;
    00288             p++;
    00289         }
    00290         columns [numcols] = p;
    00291         column_ptr [numcols] = p - original;
    00292         while (*p && *p != ' ' && *p != '\r' && *p != '\n')
    00293             p++;
    00294     }
    00295     return numcols;
    00296 }
    00297
    00298 static int
    00299 is_num (int idx)
    00300         /*@*/
    00301 {
    00302     if (!columns [idx] || columns [idx][0] < '0' || columns [idx][0] > '9')
    00303         return 0;
    00304     return 1;
    00305 }
    00306
    00307 static int
    00308 is_dos_date(/*@null@*/ const char *str)
    00309         /*@*/
    00310 {
    00311     if (str != NULL && strlen(str) == 8 &&
    00312                 str[2] == str[5] && strchr("\\-/", (int)str[2]) != NULL)
    00313         return 1;
    00314     return 0;
    00315 }
    00316
    00317 static int
    00318 is_week (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
    00319         /*@modifies *tim @*/
    00320 {
    00321 /*@observer@*/ static const char * week = "SunMonTueWedThuFriSat";
    00322     const char * pos;
    00323
    00324     /*@-observertrans -mayaliasunique@*/
    00325     if (str != NULL && (pos=strstr(week, str)) != NULL) {
    00326     /*@=observertrans =mayaliasunique@*/
    00327         if (tim != NULL)
    00328             tim->tm_wday = (pos - week)/3;
    00329         return 1;
    00330     }
    00331     return 0;
    00332 }
    00333
    00334 static int
    00335 is_month (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
    00336         /*@modifies *tim @*/
    00337 {
    00338 /*@observer@*/ static const char * month = "JanFebMarAprMayJunJulAugSepOctNovDec";
    00339     const char * pos;
    00340
    00341     /*@-observertrans -mayaliasunique@*/
    00342     if (str != NULL && (pos = strstr(month, str)) != NULL) {
    00343     /*@=observertrans -mayaliasunique@*/
    00344         if (tim != NULL)
    00345             tim->tm_mon = (pos - month)/3;
    00346         return 1;
    00347     }
    00348     return 0;
    00349 }
    00350
    00351 static int
    00352 is_time (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
    00353         /*@modifies *tim @*/
    00354 {
    00355     const char * p, * p2;
    00356
    00357     if (str != NULL && (p = strchr(str, ':')) && (p2 = strrchr(str, ':'))) {
    00358         if (p != p2) {
    00359             if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
    00360                 return 0;
    00361         } else {
    00362             if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
    00363                 return 0;
    00364         }
    00365     } else
    00366         return 0;
    00367
    00368     return 1;
    00369 }
    00370
    00371 static int is_year(/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
    00372         /*@modifies *tim @*/
    00373 {
    00374     long year;
    00375
    00376     if (str == NULL)
    00377         return 0;
    00378
    00379     if (strchr(str,':'))
    00380         return 0;
    00381
    00382     if (strlen(str) != 4)
    00383         return 0;
    00384
    00385     if (sscanf(str, "%ld", &year) != 1)
    00386         return 0;
    00387
    00388     if (year < 1900 || year > 3000)
    00389         return 0;
    00390
    00391     tim->tm_year = (int) (year - 1900);
    00392
    00393     return 1;
    00394 }
    00395
    00396 /*
    00397  * FIXME: this is broken. Consider following entry:
    00398  * -rwx------   1 root     root            1 Aug 31 10:04 2904 1234
    00399  * where "2904 1234" is filename. Well, this code decodes it as year :-(.
    00400  */
    00401
    00402 static int
    00403 vfs_parse_filetype (char c)
    00404         /*@*/
    00405 {
    00406     switch (c) {
    00407         case 'd': return S_IFDIR;
    00408         case 'b': return S_IFBLK;
    00409         case 'c': return S_IFCHR;
    00410         case 'l': return S_IFLNK;
    00411         case 's':
    00412 #ifdef IS_IFSOCK /* And if not, we fall through to IFIFO, which is pretty close */
    00413                   return S_IFSOCK;
    00414 #endif
    00415         case 'p': return S_IFIFO;
    00416         case 'm': case 'n':             /* Don't know what these are :-) */
    00417         case '-': case '?': return S_IFREG;
    00418         default: return -1;
    00419     }
    00420 }
    00421
    00422 static int vfs_parse_filemode (const char *p)
    00423         /*@*/
    00424 {       /* converts rw-rw-rw- into 0666 */
    00425     int res = 0;
    00426     switch (*(p++)) {
    00427         case 'r': res |= 0400; break;
    00428         case '-': break;
    00429         default: return -1;
    00430     }
    00431     switch (*(p++)) {
    00432         case 'w': res |= 0200; break;
    00433         case '-': break;
    00434         default: return -1;
    00435     }
    00436     switch (*(p++)) {
    00437         case 'x': res |= 0100; break;
    00438         case 's': res |= 0100 | S_ISUID; break;
    00439         case 'S': res |= S_ISUID; break;
    00440         case '-': break;
    00441         default: return -1;
    00442     }
    00443     switch (*(p++)) {
    00444         case 'r': res |= 0040; break;
    00445         case '-': break;
    00446         default: return -1;
    00447     }
    00448     switch (*(p++)) {
    00449         case 'w': res |= 0020; break;
    00450         case '-': break;
    00451         default: return -1;
    00452     }
    00453     switch (*(p++)) {
    00454         case 'x': res |= 0010; break;
    00455         case 's': res |= 0010 | S_ISGID; break;
    00456         case 'l': /* Solaris produces these */
    00457         case 'S': res |= S_ISGID; break;
    00458         case '-': break;
    00459         default: return -1;
    00460     }
    00461     switch (*(p++)) {
    00462         case 'r': res |= 0004; break;
    00463         case '-': break;
    00464         default: return -1;
    00465     }
    00466     switch (*(p++)) {
    00467         case 'w': res |= 0002; break;
    00468         case '-': break;
    00469         default: return -1;
    00470     }
    00471     switch (*(p++)) {
    00472         case 'x': res |= 0001; break;
    00473         case 't': res |= 0001 | S_ISVTX; break;
    00474         case 'T': res |= S_ISVTX; break;
    00475         case '-': break;
    00476         default: return -1;
    00477     }
    00478     return res;
    00479 }
    00480
    00481 static int vfs_parse_filedate(int idx, /*@out@*/ time_t *t)
    00482         /*@modifies *t @*/
    00483 {       /* This thing parses from idx in columns[] array */
    00484
    00485     char *p;
    00486     struct tm tim;
    00487     int d[3];
    00488     int got_year = 0;
    00489
    00490     /* Let's setup default time values */
    00491     tim.tm_year = current_year;
    00492     tim.tm_mon  = current_mon;
    00493     tim.tm_mday = current_mday;
    00494     tim.tm_hour = 0;
    00495     tim.tm_min  = 0;
    00496     tim.tm_sec  = 0;
    00497     tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
    00498
    00499     p = columns [idx++];
    00500
    00501     /* We eat weekday name in case of extfs */
    00502     if(is_week(p, &tim))
    00503         p = columns [idx++];
    00504
    00505     /* Month name */
    00506     if(is_month(p, &tim)){
    00507         /* And we expect, it followed by day number */
    00508         if (is_num (idx))
    00509             tim.tm_mday = (int)atol (columns [idx++]);
    00510         else
    00511             return 0; /* No day */
    00512
    00513     } else {
    00514         /* We usually expect:
    00515            Mon DD hh:mm
    00516            Mon DD  YYYY
    00517            But in case of extfs we allow these date formats:
    00518            Mon DD YYYY hh:mm
    00519            Mon DD hh:mm YYYY
    00520            Wek Mon DD hh:mm:ss YYYY
    00521            MM-DD-YY hh:mm
    00522            where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
    00523            YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
    00524
    00525         /* Here just this special case with MM-DD-YY */
    00526         if (is_dos_date(p)){
    00527             /*@-mods@*/
    00528             p[2] = p[5] = '-';
    00529             /*@=mods@*/
    00530
    00531             memset(d, 0, sizeof(d));
    00532             if (sscanf(p, "%2d-%2d-%2d", &d[0], &d[1], &d[2]) == 3){
    00533             /*  We expect to get:
    00534                 1. MM-DD-YY
    00535                 2. DD-MM-YY
    00536                 3. YY-MM-DD
    00537                 4. YY-DD-MM  */
    00538
    00539                 /* Hmm... maybe, next time :)*/
    00540
    00541                 /* At last, MM-DD-YY */
    00542                 d[0]--; /* Months are zerobased */
    00543                 /* Y2K madness */
    00544                 if(d[2] < 70)
    00545                     d[2] += 100;
    00546
    00547                 tim.tm_mon  = d[0];
    00548                 tim.tm_mday = d[1];
    00549                 tim.tm_year = d[2];
    00550                 got_year = 1;
    00551             } else
    00552                 return 0; /* sscanf failed */
    00553         } else
    00554             return 0; /* unsupported format */
    00555     }
    00556
    00557     /* Here we expect to find time and/or year */
    00558
    00559     if (is_num (idx)) {
    00560         if(is_time(columns[idx], &tim) || (got_year = is_year(columns[idx], &tim))) {
    00561         idx++;
    00562
    00563         /* This is a special case for ctime() or Mon DD YYYY hh:mm */
    00564         if(is_num (idx) &&
    00565             ((got_year = is_year(columns[idx], &tim)) || is_time(columns[idx], &tim)))
    00566                 idx++; /* time & year or reverse */
    00567         } /* only time or date */
    00568     }
    00569     else
    00570         return 0; /* Nor time or date */
    00571
    00572     /*
    00573      * If the date is less than 6 months in the past, it is shown without year
    00574      * other dates in the past or future are shown with year but without time
    00575      * This does not check for years before 1900 ... I don't know, how
    00576      * to represent them at all
    00577      */
    00578     if (!got_year &&
    00579         current_mon < 6 && current_mon < tim.tm_mon &&
    00580         tim.tm_mon - current_mon >= 6)
    00581
    00582         tim.tm_year--;
    00583
    00584     if ((*t = mktime(&tim)) < 0)
    00585         *t = 0;
    00586     return idx;
    00587 }
    00588
    00589 static int
    00590 vfs_parse_ls_lga (char * p, /*@out@*/ struct stat * st,
    00591                 /*@out@*/ const char ** filename,
    00592                 /*@out@*/ const char ** linkname)
    00593         /*@modifies *p, *st, *filename, *linkname @*/
    00594 {
    00595     int idx, idx2, num_cols;
    00596     int i;
    00597     char *p_copy;
    00598
    00599     if (strncmp (p, "total", 5) == 0)
    00600         return 0;
    00601
    00602     p_copy = g_strdup(p);
    00603 /* XXX FIXME: parse out inode number from "NLST -lai ." */
    00604 /* XXX FIXME: parse out sizein blocks from "NLST -lais ." */
    00605
    00606     if ((i = vfs_parse_filetype(*(p++))) == -1)
    00607         goto error;
    00608
    00609     st->st_mode = i;
    00610     if (*p == ' ')      /* Notwell 4 */
    00611         p++;
    00612     if (*p == '['){
    00613         if (strlen (p) <= 8 || p [8] != ']')
    00614             goto error;
    00615         /* Should parse here the Notwell permissions :) */
    00616         /*@-unrecog@*/
    00617         if (S_ISDIR (st->st_mode))
    00618             st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
    00619         else
    00620             st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
    00621         p += 9;
    00622         /*@=unrecog@*/
    00623     } else {
    00624         if ((i = vfs_parse_filemode(p)) == -1)
    00625             goto error;
    00626         st->st_mode |= i;
    00627         p += 9;
    00628
    00629         /* This is for an extra ACL attribute (HP-UX) */
    00630         if (*p == '+')
    00631             p++;
    00632     }
    00633
    00634     g_free(p_copy);
    00635     p_copy = g_strdup(p);
    00636     num_cols = vfs_split_text (p);
    00637
    00638     st->st_nlink = atol (columns [0]);
    00639     if (st->st_nlink < 0)
    00640         goto error;
    00641
    00642     if (!is_num (1))
    00643 #ifdef  HACK
    00644         st->st_uid = finduid (columns [1]);
    00645 #else
    00646         (void) unameToUid (columns [1], &st->st_uid);
    00647 #endif
    00648     else
    00649         st->st_uid = (uid_t) atol (columns [1]);
    00650
    00651     /* Mhm, the ls -lg did not produce a group field */
    00652     for (idx = 3; idx <= 5; idx++)
    00653         if (is_month(columns [idx], NULL) || is_week(columns [idx], NULL) || is_dos_date(columns[idx]))
    00654             break;
    00655
    00656     if (idx == 6 || (idx == 5 && !S_ISCHR (st->st_mode) && !S_ISBLK (st->st_mode)))
    00657         goto error;
    00658
    00659     /* We don't have gid */
    00660     if (idx == 3 || (idx == 4 && (S_ISCHR(st->st_mode) || S_ISBLK (st->st_mode))))
    00661         idx2 = 2;
    00662     else {
    00663         /* We have gid field */
    00664         if (is_num (2))
    00665             st->st_gid = (gid_t) atol (columns [2]);
    00666         else
    00667 #ifdef  HACK
    00668             st->st_gid = findgid (columns [2]);
    00669 #else
    00670             (void) gnameToGid (columns [1], &st->st_gid);
    00671 #endif
    00672         idx2 = 3;
    00673     }
    00674
    00675     /* This is device */
    00676     if (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode)){
    00677         int maj, min;
    00678
    00679         if (!is_num (idx2) || sscanf(columns [idx2], " %d,", &maj) != 1)
    00680             goto error;
    00681
    00682         if (!is_num (++idx2) || sscanf(columns [idx2], " %d", &min) != 1)
    00683             goto error;
    00684
    00685 #ifdef HAVE_ST_RDEV
    00686         st->st_rdev = ((maj & 0xff) << 8) | (min & 0xffff00ff);
    00687 #endif
    00688         st->st_size = 0;
    00689
    00690     } else {
    00691         /* Common file size */
    00692         if (!is_num (idx2))
    00693             goto error;
    00694
    00695         st->st_size = (size_t) atol (columns [idx2]);
    00696 #ifdef HAVE_ST_RDEV
    00697         st->st_rdev = 0;
    00698 #endif
    00699     }
    00700
    00701     idx = vfs_parse_filedate(idx, &st->st_mtime);
    00702     if (!idx)
    00703         goto error;
    00704     /* Use resulting time value */
    00705     st->st_atime = st->st_ctime = st->st_mtime;
    00706     st->st_dev = 0;
    00707     st->st_ino = 0;
    00708 #ifdef HAVE_ST_BLKSIZE
    00709     st->st_blksize = 512;
    00710 #endif
    00711 #ifdef HAVE_ST_BLOCKS
    00712     st->st_blocks = (st->st_size + 511) / 512;
    00713 #endif
    00714
    00715     for (i = idx + 1, idx2 = 0; i < num_cols; i++ )
    00716         if (strcmp (columns [i], "->") == 0){
    00717             idx2 = i;
    00718             break;
    00719         }
    00720
    00721     if (((S_ISLNK (st->st_mode) ||
    00722         (num_cols == idx + 3 && st->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
    00723         && idx2){
    00724         int tlen;
    00725         char *t;
    00726
    00727         if (filename){
    00728 #ifdef HACK
    00729             t = g_strndup (p_copy + column_ptr [idx], column_ptr [idx2] - column_ptr [idx] - 1);
    00730 #else
    00731             int nb = column_ptr [idx2] - column_ptr [idx] - 1;
    00732             t = xmalloc(nb+1);
    00733             strncpy(t, p_copy + column_ptr [idx], nb);
    00734 #endif
    00735             *filename = t;
    00736         }
    00737         if (linkname){
    00738             t = g_strdup (p_copy + column_ptr [idx2+1]);
    00739             tlen = strlen (t);
    00740             if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
    00741                 t [tlen-1] = 0;
    00742             if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
    00743                 t [tlen-2] = 0;
    00744
    00745             *linkname = t;
    00746         }
    00747     } else {
    00748         /* Extract the filename from the string copy, not from the columns
    00749          * this way we have a chance of entering hidden directories like ". ."
    00750          */
    00751         if (filename){
    00752             /*
    00753             *filename = g_strdup (columns [idx++]);
    00754             */
    00755             int tlen;
    00756             char *t;
    00757
    00758             t = g_strdup (p_copy + column_ptr [idx++]);
    00759             tlen = strlen (t);
    00760             /* g_strchomp(); */
    00761             if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
    00762                 t [tlen-1] = 0;
    00763             if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
    00764                 t [tlen-2] = 0;
    00765
    00766             *filename = t;
    00767         }
    00768         if (linkname)
    00769             *linkname = NULL;
    00770     }
    00771     g_free (p_copy);
    00772     return 1;
    00773
    00774 error:
    00775 #ifdef  HACK
    00776     {
    00777       static int errorcount = 0;
    00778
    00779       if (++errorcount < 5) {
    00780         message_1s (1, "Could not parse:", p_copy);
    00781       } else if (errorcount == 5)
    00782         message_1s (1, "More parsing errors will be ignored.", "(sorry)" );
    00783     }
    00784 #endif
    00785
    00786     /*@-usereleased@*/
    00787     if (p_copy != p)            /* Carefull! */
    00788     /*@=usereleased@*/
    00789         g_free (p_copy);
    00790     return 0;
    00791 }
    00792
    00793 typedef enum {
    00794         DO_FTP_STAT     = 1,
    00795         DO_FTP_LSTAT    = 2,
    00796         DO_FTP_READLINK = 3,
    00797         DO_FTP_ACCESS   = 4,
    00798         DO_FTP_GLOB     = 5
    00799 } ftpSysCall_t;
    00800
    00803 /*@unchecked@*/
    00804 static size_t ftpBufAlloced = 0;
    00805
    00808 /*@unchecked@*/
    00809 static /*@only@*/ char * ftpBuf = NULL;
    00810
    00811 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
    00812
    00813 /*@-mods@*/
    00814 static int ftpNLST(const char * url, ftpSysCall_t ftpSysCall,
    00815                 /*@out@*/ /*@null@*/ struct stat * st,
    00816                 /*@out@*/ /*@null@*/ char * rlbuf, size_t rlbufsiz)
    00817         /*@globals fileSystem @*/
    00818         /*@modifies *st, *rlbuf, fileSystem @*/
    00819 {
    00820     FD_t fd;
    00821     const char * path;
    00822     int bufLength, moretodo;
    00823     const char *n, *ne, *o, *oe;
    00824     char * s;
    00825     char * se;
    00826     const char * urldn;
    00827     char * bn = NULL;
    00828     int nbn = 0;
    00829     urlinfo u;
    00830     int rc;
    00831
    00832     n = ne = o = oe = NULL;
    00833     (void) urlPath(url, &path);
    00834     if (*path == '\0')
    00835         return -2;
    00836
    00837     switch (ftpSysCall) {
    00838     case DO_FTP_GLOB:
    00839         fd = ftpOpen(url, 0, 0, &u);
    00840         if (fd == NULL || u == NULL)
    00841             return -1;
    00842
    00843         u->openError = ftpReq(fd, "NLST", path);
    00844         break;
    00845     default:
    00846         urldn = alloca_strdup(url);
    00847         /*@-branchstate@*/
    00848         if ((bn = strrchr(urldn, '/')) == NULL)
    00849             return -2;
    00850         else if (bn == path)
    00851             bn = ".";
    00852         else
    00853             *bn++ = '\0';
    00854         /*@=branchstate@*/
    00855         nbn = strlen(bn);
    00856
    00857         rc = ftpChdir(urldn);           /* XXX don't care about CWD */
    00858         if (rc < 0)
    00859             return rc;
    00860
    00861         fd = ftpOpen(url, 0, 0, &u);
    00862         if (fd == NULL || u == NULL)
    00863             return -1;
    00864
    00865         /* XXX possibly should do "NLST -lais" to get st_ino/st_blocks also */
    00866         u->openError = ftpReq(fd, "NLST", "-la");
    00867
    00868         if (bn == NULL || nbn <= 0) {
    00869             rc = -2;
    00870             goto exit;
    00871         }
    00872         break;
    00873     }
    00874
    00875     if (u->openError < 0) {
    00876         fd = fdLink(fd, "error data (ftpStat)");
    00877         rc = -2;
    00878         goto exit;
    00879     }
    00880
    00881     if (ftpBufAlloced == 0 || ftpBuf == NULL) {
    00882         ftpBufAlloced = _url_iobuf_size;
    00883         ftpBuf = xcalloc(ftpBufAlloced, sizeof(ftpBuf[0]));
    00884     }
    00885     *ftpBuf = '\0';
    00886
    00887     bufLength = 0;
    00888     moretodo = 1;
    00889
    00890     do {
    00891
    00892         /* XXX FIXME: realloc ftpBuf if < ~128 chars remain */
    00893         if ((ftpBufAlloced - bufLength) < (1024+80)) {
    00894             ftpBufAlloced <<= 2;
    00895             ftpBuf = xrealloc(ftpBuf, ftpBufAlloced);
    00896         }
    00897         s = se = ftpBuf + bufLength;
    00898         *se = '\0';
    00899
    00900         rc = fdFgets(fd, se, (ftpBufAlloced - bufLength));
    00901         if (rc <= 0) {
    00902             moretodo = 0;
    00903             break;
    00904         }
    00905         if (ftpSysCall == DO_FTP_GLOB) {        /* XXX HACK */
    00906             bufLength += strlen(se);
    00907             continue;
    00908         }
    00909
    00910         for (s = se; *s != '\0'; s = se) {
    00911             int bingo;
    00912
    00913             while (*se && *se != '\n') se++;
    00914             if (se > s && se[-1] == '\r') se[-1] = '\0';
    00915             if (*se == '\0')
    00916                 /*@innerbreak@*/ break;
    00917             *se++ = '\0';
    00918
    00919             if (!strncmp(s, "total ", sizeof("total ")-1))
    00920                 /*@innercontinue@*/ continue;
    00921
    00922             o = NULL;
    00923             for (bingo = 0, n = se; n >= s; n--) {
    00924                 switch (*n) {
    00925                 case '\0':
    00926                     oe = ne = n;
    00927                     /*@switchbreak@*/ break;
    00928                 case ' ':
    00929                     if (o || !(n[-3] == ' ' && n[-2] == '-' && n[-1] == '>')) {
    00930                         while (*(++n) == ' ')
    00931                             {};
    00932                         bingo++;
    00933                         /*@switchbreak@*/ break;
    00934                     }
    00935                     for (o = n + 1; *o == ' '; o++)
    00936                         {};
    00937                     n -= 3;
    00938                     ne = n;
    00939                     /*@switchbreak@*/ break;
    00940                 default:
    00941                     /*@switchbreak@*/ break;
    00942                 }
    00943                 if (bingo)
    00944                     /*@innerbreak@*/ break;
    00945             }
    00946
    00947             if (nbn != (ne - n))        /* Same name length? */
    00948                 /*@innercontinue@*/ continue;
    00949             if (strncmp(n, bn, nbn))    /* Same name? */
    00950                 /*@innercontinue@*/ continue;
    00951
    00952             moretodo = 0;
    00953             /*@innerbreak@*/ break;
    00954         }
    00955
    00956         if (moretodo && se > s) {
    00957             bufLength = se - s - 1;
    00958             if (s != ftpBuf)
    00959                 memmove(ftpBuf, s, bufLength);
    00960         } else {
    00961             bufLength = 0;
    00962         }
    00963     } while (moretodo);
    00964
    00965     switch (ftpSysCall) {
    00966     case DO_FTP_STAT:
    00967         if (o && oe) {
    00968             /* XXX FIXME: symlink, replace urldn/bn from [o,oe) and restart */
    00969         }
    00970         /*@fallthrough@*/
    00971     case DO_FTP_LSTAT:
    00972         if (st == NULL || !(n && ne)) {
    00973             rc = -1;
    00974         } else {
    00975             rc = ((vfs_parse_ls_lga(s, st, NULL, NULL) > 0) ? 0 : -1);
    00976         }
    00977         break;
    00978     case DO_FTP_READLINK:
    00979         if (rlbuf == NULL || !(o && oe)) {
    00980             rc = -1;
    00981         } else {
    00982             rc = oe - o;
    00983             if (rc > rlbufsiz)
    00984                 rc = rlbufsiz;
    00985             memcpy(rlbuf, o, rc);
    00986             if (rc < rlbufsiz)
    00987                 rlbuf[rc] = '\0';
    00988         }
    00989         break;
    00990     case DO_FTP_ACCESS:
    00991         rc = 0;         /* XXX WRONG WRONG WRONG */
    00992         break;
    00993     case DO_FTP_GLOB:
    00994         rc = 0;         /* XXX WRONG WRONG WRONG */
    00995         break;
    00996     }
    00997
    00998 exit:
    00999     (void) ufdClose(fd);
    01000     return rc;
    01001 }
    01002 /*@=mods@*/
    01003
    01004 static int ftpStat(const char * path, /*@out@*/ struct stat *st)
    01005         /*@globals fileSystem @*/
    01006         /*@modifies *st, fileSystem @*/
    01007 {
    01008     return ftpNLST(path, DO_FTP_STAT, st, NULL, 0);
    01009 }
    01010
    01011 static int ftpLstat(const char * path, /*@out@*/ struct stat *st)
    01012         /*@globals fileSystem @*/
    01013         /*@modifies *st, fileSystem @*/
    01014 {
    01015     int rc;
    01016     rc = ftpNLST(path, DO_FTP_LSTAT, st, NULL, 0);
    01017 if (_rpmio_debug)
    01018 fprintf(stderr, "*** ftpLstat(%s) rc %d\n", path, rc);
    01019     return rc;
    01020 }
    01021
    01022 static int ftpReadlink(const char * path, /*@out@*/ char * buf, size_t bufsiz)
    01023         /*@globals fileSystem @*/
    01024         /*@modifies *buf, fileSystem @*/
    01025 {
    01026     return ftpNLST(path, DO_FTP_READLINK, NULL, buf, bufsiz);
    01027 }
    01028
    01029 static int ftpGlob(const char * path, int flags,
    01030                 int errfunc(const char * epath, int eerno),
    01031                 /*@out@*/ glob_t * pglob)
    01032         /*@globals fileSystem @*/
    01033         /*@modifies *pglob, fileSystem @*/
    01034 {
    01035     int rc;
    01036
    01037     if (pglob == NULL)
    01038         return -2;
    01039     rc = ftpNLST(path, DO_FTP_GLOB, NULL, NULL, 0);
    01040 /*@-castfcnptr@*/
    01041 if (_rpmio_debug)
    01042 fprintf(stderr, "*** ftpGlob(%s,0x%x,%p,%p) ftpNLST rc %d\n", path, (unsigned)flags, (void *)errfunc, pglob, rc);
    01043 /*@=castfcnptr@*/
    01044     if (rc)
    01045         return rc;
    01046     rc = poptParseArgvString(ftpBuf, &pglob->gl_pathc, (const char ***)&pglob->gl_pathv);
    01047     pglob->gl_offs = -1;        /* XXX HACK HACK HACK */
    01048     return rc;
    01049 }
    01050
    01051 static void ftpGlobfree(glob_t * pglob)
    01052         /*@modifies *pglob @*/
    01053 {
    01054 /*@-modfilesys@*/
    01055 if (_rpmio_debug)
    01056 fprintf(stderr, "*** ftpGlobfree(%p)\n", pglob);
    01057 /*@=modfilesys@*/
    01058     if (pglob->gl_offs == -1) { /* XXX HACK HACK HACK */
    01059         free((void *)pglob->gl_pathv);
    01060         pglob->gl_pathv = NULL;
    01061     }
    01062 }
    01063
    01064 int Stat(const char * path, struct stat * st)
    01065 {
    01066     const char * lpath;
    01067     int ut = urlPath(path, &lpath);
    01068
    01069 if (_rpmio_debug)
    01070 fprintf(stderr, "*** Stat(%s,%p)\n", path, st);
    01071     switch (ut) {
    01072     case URL_IS_FTP:
    01073         return ftpStat(path, st);
    01074         /*@notreached@*/ break;
    01075     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    01076     case URL_IS_PATH:
    01077         path = lpath;
    01078         /*@fallthrough@*/
    01079     case URL_IS_UNKNOWN:
    01080         break;
    01081     case URL_IS_DASH:
    01082     default:
    01083         return -2;
    01084         /*@notreached@*/ break;
    01085     }
    01086     return stat(path, st);
    01087 }
    01088
    01089 int Lstat(const char * path, struct stat * st)
    01090 {
    01091     const char * lpath;
    01092     int ut = urlPath(path, &lpath);
    01093
    01094 if (_rpmio_debug)
    01095 fprintf(stderr, "*** Lstat(%s,%p)\n", path, st);
    01096     switch (ut) {
    01097     case URL_IS_FTP:
    01098         return ftpLstat(path, st);
    01099         /*@notreached@*/ break;
    01100     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    01101     case URL_IS_PATH:
    01102         path = lpath;
    01103         /*@fallthrough@*/
    01104     case URL_IS_UNKNOWN:
    01105         break;
    01106     case URL_IS_DASH:
    01107     default:
    01108         return -2;
    01109         /*@notreached@*/ break;
    01110     }
    01111     return lstat(path, st);
    01112 }
    01113
    01114 int Readlink(const char * path, char * buf, size_t bufsiz)
    01115 {
    01116     const char * lpath;
    01117     int ut = urlPath(path, &lpath);
    01118
    01119     switch (ut) {
    01120     case URL_IS_FTP:
    01121         return ftpReadlink(path, buf, bufsiz);
    01122         /*@notreached@*/ break;
    01123     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    01124     case URL_IS_PATH:
    01125         path = lpath;
    01126         /*@fallthrough@*/
    01127     case URL_IS_UNKNOWN:
    01128         break;
    01129     case URL_IS_DASH:
    01130     default:
    01131         return -2;
    01132         /*@notreached@*/ break;
    01133     }
    01134     return readlink(path, buf, bufsiz);
    01135 }
    01136
    01137 int Access(const char * path, int amode)
    01138 {
    01139     const char * lpath;
    01140     int ut = urlPath(path, &lpath);
    01141
    01142 if (_rpmio_debug)
    01143 fprintf(stderr, "*** Access(%s,%d)\n", path, amode);
    01144     switch (ut) {
    01145     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
    01146     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    01147     case URL_IS_PATH:
    01148         path = lpath;
    01149         /*@fallthrough@*/
    01150     case URL_IS_UNKNOWN:
    01151         break;
    01152     case URL_IS_DASH:
    01153     default:
    01154         return -2;
    01155         /*@notreached@*/ break;
    01156     }
    01157     return access(path, amode);
    01158 }
    01159
    01160 int Glob(const char *pattern, int flags,
    01161         int errfunc(const char * epath, int eerrno), glob_t *pglob)
    01162 {
    01163     const char * lpath;
    01164     int ut = urlPath(pattern, &lpath);
    01165
    01166 /*@-castfcnptr@*/
    01167 if (_rpmio_debug)
    01168 fprintf(stderr, "*** Glob(%s,0x%x,%p,%p)\n", pattern, (unsigned)flags, (void *)errfunc, pglob);
    01169 /*@=castfcnptr@*/
    01170     switch (ut) {
    01171     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
    01172         return ftpGlob(pattern, flags, errfunc, pglob);
    01173         /*@notreached@*/ break;
    01174     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    01175     case URL_IS_PATH:
    01176         pattern = lpath;
    01177         /*@fallthrough@*/
    01178     case URL_IS_UNKNOWN:
    01179         break;
    01180     case URL_IS_DASH:
    01181     default:
    01182         return -2;
    01183         /*@notreached@*/ break;
    01184     }
    01185     return glob(pattern, flags, errfunc, pglob);
    01186 }
    01187
    01188 void Globfree(glob_t *pglob)
    01189 {
    01190 if (_rpmio_debug)
    01191 fprintf(stderr, "*** Globfree(%p)\n", pglob);
    01192     /*@-branchstate@*/
    01193     if (pglob->gl_offs == -1) /* XXX HACK HACK HACK */
    01194         ftpGlobfree(pglob);
    01195     else
    01196         globfree(pglob);
    01197     /*@=branchstate@*/
    01198 }
    01199
    01200 DIR * Opendir(const char * path)
    01201 {
    01202     const char * lpath;
    01203     int ut = urlPath(path, &lpath);
    01204
    01205 if (_rpmio_debug)
    01206 fprintf(stderr, "*** Opendir(%s)\n", path);
    01207     switch (ut) {
    01208     case URL_IS_FTP:            /* XXX WRONG WRONG WRONG */
    01209     case URL_IS_HTTP:           /* XXX WRONG WRONG WRONG */
    01210     case URL_IS_PATH:
    01211         path = lpath;
    01212         /*@fallthrough@*/
    01213     case URL_IS_UNKNOWN:
    01214         break;
    01215     case URL_IS_DASH:
    01216     default:
    01217         return NULL;
    01218         /*@notreached@*/ break;
    01219     }
    01220     /*@-dependenttrans@*/
    01221     return opendir(path);
    01222     /*@=dependenttrans@*/
    01223 }
    01224
    01225 /*@+voidabstract@*/
    01226 struct dirent * Readdir(DIR * dir)
    01227 {
    01228 if (_rpmio_debug)
    01229 fprintf(stderr, "*** Readdir(%p)\n", (void *)dir);
    01230     return readdir(dir);
    01231 }
    01232
    01233 int Closedir(DIR * dir)
    01234 {
    01235 if (_rpmio_debug)
    01236 fprintf(stderr, "*** Closedir(%p)\n", (void *)dir);
    01237     return closedir(dir);
    01238 }
    01239 /*@=voidabstract@*/
    01240 /*@=type@*/