00001
00005 #include "system.h"
00006
00007 #if defined(HAVE_PTHREAD_H) && !defined(__LCLINT__)
00008 #include <pthread.h>
00009 #endif
00010
00011 #include "rpmio_internal.h"
00012 #include <popt.h>
00013 #include "ugid.h"
00014 #include "debug.h"
00015
00016
00017
00018
00019
00020 static int ftpMkdir(const char * path, mode_t mode)
00021
00022
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
00038
00039 {
00040 return ftpCmd("CWD", path, NULL);
00041 }
00042
00043 static int ftpRmdir(const char * path)
00044
00045
00046 {
00047 return ftpCmd("RMD", path, NULL);
00048 }
00049
00050 static int ftpRename(const char * oldpath, const char * newpath)
00051
00052
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
00062
00063 {
00064 return ftpCmd("DELE", path, NULL);
00065 }
00066
00067
00068 static int
00069 make_path (const char *apath, mode_t mode)
00070 {
00071 struct stat st;
00072
00073 if (stat (apath, &st))
00074 {
00075 char *path = (char *) alloca (strlen (apath) + 1);
00076 char *slash;
00077
00078 strcpy (path, apath);
00079 slash = path = rpmCleanPath (path);
00080
00081 while (*slash == '/')
00082 slash++;
00083
00084 while ((slash = strchr (slash, '/')))
00085 {
00086 char c = *slash;
00087
00088 *slash = '\0';
00089 if (mkdir (path, mode) < 0)
00090 {
00091 int saved_errno = errno;
00092
00093 if (stat (path, &st))
00094 {
00095 errno = saved_errno;
00096 return -1;
00097 }
00098
00099 if (!S_ISDIR (st.st_mode))
00100 {
00101 errno = ENOTDIR;
00102 return -1;
00103 }
00104 }
00105 *(slash++) = c;
00106 }
00107
00108 if (mkdir (path, mode) < 0)
00109 {
00110 int saved_errno = errno;
00111
00112 if (stat (path, &st))
00113 {
00114 errno = saved_errno;
00115 return -1;
00116 }
00117
00118 if (!S_ISDIR (st.st_mode))
00119 {
00120 errno = ENOTDIR;
00121 return -1;
00122 }
00123 }
00124
00125 return 0;
00126 } else
00127 {
00128 if (!S_ISDIR (st.st_mode))
00129 {
00130 errno = ENOTDIR;
00131 return -1;
00132 }
00133
00134 return 0;
00135 }
00136 }
00137
00138 int MkdirP (const char * path, mode_t mode)
00139 {
00140 const char * lpath;
00141 int ut = urlPath(path, &lpath);
00142
00143 switch (ut) {
00144 case URL_IS_FTP:
00145 case URL_IS_HTTP:
00146 return Mkdir(path, mode);
00147 case URL_IS_PATH:
00148 path = lpath;
00149
00150 case URL_IS_UNKNOWN:
00151 break;
00152 case URL_IS_DASH:
00153 default:
00154 return Mkdir (path, mode);
00155 }
00156 return make_path(path, mode);
00157 }
00158
00159
00160 int Mkdir (const char * path, mode_t mode)
00161 {
00162 const char * lpath;
00163 int ut = urlPath(path, &lpath);
00164
00165 switch (ut) {
00166 case URL_IS_FTP:
00167 return ftpMkdir(path, mode);
00168 break;
00169 case URL_IS_HTTP:
00170 case URL_IS_PATH:
00171 path = lpath;
00172
00173 case URL_IS_UNKNOWN:
00174 break;
00175 case URL_IS_DASH:
00176 default:
00177 return -2;
00178 break;
00179 }
00180 return mkdir(path, mode);
00181 }
00182
00183 int Chdir (const char * path)
00184 {
00185 const char * lpath;
00186 int ut = urlPath(path, &lpath);
00187
00188 switch (ut) {
00189 case URL_IS_FTP:
00190 return ftpChdir(path);
00191 break;
00192 case URL_IS_HTTP:
00193 case URL_IS_PATH:
00194 path = lpath;
00195
00196 case URL_IS_UNKNOWN:
00197 break;
00198 case URL_IS_DASH:
00199 default:
00200 return -2;
00201 break;
00202 }
00203 return chdir(path);
00204 }
00205
00206 int Rmdir (const char * path)
00207 {
00208 const char * lpath;
00209 int ut = urlPath(path, &lpath);
00210
00211 switch (ut) {
00212 case URL_IS_FTP:
00213 return ftpRmdir(path);
00214 break;
00215 case URL_IS_HTTP:
00216 case URL_IS_PATH:
00217 path = lpath;
00218
00219 case URL_IS_UNKNOWN:
00220 break;
00221 case URL_IS_DASH:
00222 default:
00223 return -2;
00224 break;
00225 }
00226 return rmdir(path);
00227 }
00228
00229
00230
00231 int Rename (const char * oldpath, const char * newpath)
00232 {
00233 const char *oe = NULL;
00234 const char *ne = NULL;
00235 int oldut, newut;
00236
00237
00238 if (!strcmp(oldpath, newpath)) return 0;
00239
00240 oldut = urlPath(oldpath, &oe);
00241 switch (oldut) {
00242 case URL_IS_FTP:
00243 case URL_IS_HTTP:
00244 case URL_IS_PATH:
00245 case URL_IS_UNKNOWN:
00246 break;
00247 case URL_IS_DASH:
00248 default:
00249 return -2;
00250 break;
00251 }
00252
00253 newut = urlPath(newpath, &ne);
00254 switch (newut) {
00255 case URL_IS_FTP:
00256 if (_rpmio_debug)
00257 fprintf(stderr, "*** rename old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
00258 if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
00259 !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
00260 return -2;
00261 return ftpRename(oldpath, newpath);
00262 break;
00263 case URL_IS_HTTP:
00264 case URL_IS_PATH:
00265 oldpath = oe;
00266 newpath = ne;
00267 break;
00268 case URL_IS_UNKNOWN:
00269 break;
00270 case URL_IS_DASH:
00271 default:
00272 return -2;
00273 break;
00274 }
00275 return rename(oldpath, newpath);
00276 }
00277
00278 int Link (const char * oldpath, const char * newpath)
00279 {
00280 const char *oe = NULL;
00281 const char *ne = NULL;
00282 int oldut, newut;
00283
00284 oldut = urlPath(oldpath, &oe);
00285 switch (oldut) {
00286 case URL_IS_FTP:
00287 case URL_IS_HTTP:
00288 case URL_IS_PATH:
00289 case URL_IS_UNKNOWN:
00290 break;
00291 case URL_IS_DASH:
00292 default:
00293 return -2;
00294 break;
00295 }
00296
00297 newut = urlPath(newpath, &ne);
00298 switch (newut) {
00299 case URL_IS_HTTP:
00300 case URL_IS_FTP:
00301 case URL_IS_PATH:
00302 if (_rpmio_debug)
00303 fprintf(stderr, "*** link old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
00304 if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
00305 !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
00306 return -2;
00307 oldpath = oe;
00308 newpath = ne;
00309 break;
00310 case URL_IS_UNKNOWN:
00311 break;
00312 case URL_IS_DASH:
00313 default:
00314 return -2;
00315 break;
00316 }
00317 return link(oldpath, newpath);
00318 }
00319
00320
00321
00322 int Unlink(const char * path) {
00323 const char * lpath;
00324 int ut = urlPath(path, &lpath);
00325
00326 switch (ut) {
00327 case URL_IS_FTP:
00328 return ftpUnlink(path);
00329 break;
00330 case URL_IS_HTTP:
00331 case URL_IS_PATH:
00332 path = lpath;
00333
00334 case URL_IS_UNKNOWN:
00335 break;
00336 case URL_IS_DASH:
00337 default:
00338 return -2;
00339 break;
00340 }
00341 return unlink(path);
00342 }
00343
00344
00345
00346 #define g_strdup xstrdup
00347 #define g_free free
00348
00349
00350
00351
00352
00353 static int current_mday;
00354
00355 static int current_mon;
00356
00357 static int current_year;
00358
00359
00360 #define MAXCOLS 30
00361
00362
00363 static char *columns [MAXCOLS];
00364
00365 static int column_ptr [MAXCOLS];
00366
00367 static int
00368 vfs_split_text (char *p)
00369
00370
00371 {
00372 char *original = p;
00373 int numcols;
00374
00375
00376 for (numcols = 0; *p && numcols < MAXCOLS; numcols++){
00377 while (*p == ' ' || *p == '\r' || *p == '\n'){
00378 *p = 0;
00379 p++;
00380 }
00381 columns [numcols] = p;
00382 column_ptr [numcols] = p - original;
00383 while (*p && *p != ' ' && *p != '\r' && *p != '\n')
00384 p++;
00385 }
00386 return numcols;
00387 }
00388
00389 static int
00390 is_num (int idx)
00391
00392 {
00393 if (!columns [idx] || columns [idx][0] < '0' || columns [idx][0] > '9')
00394 return 0;
00395 return 1;
00396 }
00397
00398 static int
00399 is_dos_date( const char *str)
00400
00401 {
00402 if (str != NULL && strlen(str) == 8 &&
00403 str[2] == str[5] && strchr("\\-/", (int)str[2]) != NULL)
00404 return 1;
00405 return 0;
00406 }
00407
00408 static int
00409 is_week ( const char * str, struct tm * tim)
00410
00411 {
00412 static const char * week = "SunMonTueWedThuFriSat";
00413 const char * pos;
00414
00415
00416 if (str != NULL && (pos=strstr(week, str)) != NULL) {
00417
00418 if (tim != NULL)
00419 tim->tm_wday = (pos - week)/3;
00420 return 1;
00421 }
00422 return 0;
00423 }
00424
00425 static int
00426 is_month ( const char * str, struct tm * tim)
00427
00428 {
00429 static const char * month = "JanFebMarAprMayJunJulAugSepOctNovDec";
00430 const char * pos;
00431
00432
00433 if (str != NULL && (pos = strstr(month, str)) != NULL) {
00434
00435 if (tim != NULL)
00436 tim->tm_mon = (pos - month)/3;
00437 return 1;
00438 }
00439 return 0;
00440 }
00441
00442 static int
00443 is_time ( const char * str, struct tm * tim)
00444
00445 {
00446 const char * p, * p2;
00447
00448 if (str != NULL && (p = strchr(str, ':')) && (p2 = strrchr(str, ':'))) {
00449 if (p != p2) {
00450 if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
00451 return 0;
00452 } else {
00453 if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
00454 return 0;
00455 }
00456 } else
00457 return 0;
00458
00459 return 1;
00460 }
00461
00462 static int is_year( const char * str, struct tm * tim)
00463
00464 {
00465 long year;
00466
00467 if (str == NULL)
00468 return 0;
00469
00470 if (strchr(str,':'))
00471 return 0;
00472
00473 if (strlen(str) != 4)
00474 return 0;
00475
00476 if (sscanf(str, "%ld", &year) != 1)
00477 return 0;
00478
00479 if (year < 1900 || year > 3000)
00480 return 0;
00481
00482 tim->tm_year = (int) (year - 1900);
00483
00484 return 1;
00485 }
00486
00487
00488
00489
00490
00491
00492
00493 static int
00494 vfs_parse_filetype (char c)
00495
00496 {
00497 switch (c) {
00498 case 'd': return S_IFDIR;
00499 case 'b': return S_IFBLK;
00500 case 'c': return S_IFCHR;
00501 case 'l': return S_IFLNK;
00502 case 's':
00503 #ifdef IS_IFSOCK
00504 return S_IFSOCK;
00505 #endif
00506 case 'p': return S_IFIFO;
00507 case 'm': case 'n':
00508 case '-': case '?': return S_IFREG;
00509 default: return -1;
00510 }
00511 }
00512
00513 static int vfs_parse_filemode (const char *p)
00514
00515 {
00516 int res = 0;
00517 switch (*(p++)) {
00518 case 'r': res |= 0400; break;
00519 case '-': break;
00520 default: return -1;
00521 }
00522 switch (*(p++)) {
00523 case 'w': res |= 0200; break;
00524 case '-': break;
00525 default: return -1;
00526 }
00527 switch (*(p++)) {
00528 case 'x': res |= 0100; break;
00529 case 's': res |= 0100 | S_ISUID; break;
00530 case 'S': res |= S_ISUID; break;
00531 case '-': break;
00532 default: return -1;
00533 }
00534 switch (*(p++)) {
00535 case 'r': res |= 0040; break;
00536 case '-': break;
00537 default: return -1;
00538 }
00539 switch (*(p++)) {
00540 case 'w': res |= 0020; break;
00541 case '-': break;
00542 default: return -1;
00543 }
00544 switch (*(p++)) {
00545 case 'x': res |= 0010; break;
00546 case 's': res |= 0010 | S_ISGID; break;
00547 case 'l':
00548 case 'S': res |= S_ISGID; break;
00549 case '-': break;
00550 default: return -1;
00551 }
00552 switch (*(p++)) {
00553 case 'r': res |= 0004; break;
00554 case '-': break;
00555 default: return -1;
00556 }
00557 switch (*(p++)) {
00558 case 'w': res |= 0002; break;
00559 case '-': break;
00560 default: return -1;
00561 }
00562 switch (*(p++)) {
00563 case 'x': res |= 0001; break;
00564 case 't': res |= 0001 | S_ISVTX; break;
00565 case 'T': res |= S_ISVTX; break;
00566 case '-': break;
00567 default: return -1;
00568 }
00569 return res;
00570 }
00571
00572 static int vfs_parse_filedate(int idx, time_t *t)
00573
00574 {
00575
00576 char *p;
00577 struct tm tim;
00578 int d[3];
00579 int got_year = 0;
00580
00581
00582 tim.tm_year = current_year;
00583 tim.tm_mon = current_mon;
00584 tim.tm_mday = current_mday;
00585 tim.tm_hour = 0;
00586 tim.tm_min = 0;
00587 tim.tm_sec = 0;
00588 tim.tm_isdst = -1;
00589
00590 p = columns [idx++];
00591
00592
00593 if(is_week(p, &tim))
00594 p = columns [idx++];
00595
00596
00597 if(is_month(p, &tim)){
00598
00599 if (is_num (idx))
00600 tim.tm_mday = (int)atol (columns [idx++]);
00601 else
00602 return 0;
00603
00604 } else {
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 if (is_dos_date(p)){
00618
00619 p[2] = p[5] = '-';
00620
00621
00622 memset(d, 0, sizeof(d));
00623 if (sscanf(p, "%2d-%2d-%2d", &d[0], &d[1], &d[2]) == 3){
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 d[0]--;
00634
00635 if(d[2] < 70)
00636 d[2] += 100;
00637
00638 tim.tm_mon = d[0];
00639 tim.tm_mday = d[1];
00640 tim.tm_year = d[2];
00641 got_year = 1;
00642 } else
00643 return 0;
00644 } else
00645 return 0;
00646 }
00647
00648
00649
00650 if (is_num (idx)) {
00651 if(is_time(columns[idx], &tim) || (got_year = is_year(columns[idx], &tim))) {
00652 idx++;
00653
00654
00655 if(is_num (idx) &&
00656 ((got_year = is_year(columns[idx], &tim)) || is_time(columns[idx], &tim)))
00657 idx++;
00658 }
00659 }
00660 else
00661 return 0;
00662
00663
00664
00665
00666
00667
00668
00669 if (!got_year &&
00670 current_mon < 6 && current_mon < tim.tm_mon &&
00671 tim.tm_mon - current_mon >= 6)
00672
00673 tim.tm_year--;
00674
00675 if ((*t = mktime(&tim)) < 0)
00676 *t = 0;
00677 return idx;
00678 }
00679
00680 static int
00681 vfs_parse_ls_lga (char * p, struct stat * st,
00682 const char ** filename,
00683 const char ** linkname)
00684
00685 {
00686 int idx, idx2, num_cols;
00687 int i;
00688 char *p_copy;
00689
00690 if (strncmp (p, "total", 5) == 0)
00691 return 0;
00692
00693 p_copy = g_strdup(p);
00694
00695
00696
00697 if ((i = vfs_parse_filetype(*(p++))) == -1)
00698 goto error;
00699
00700 st->st_mode = i;
00701 if (*p == ' ')
00702 p++;
00703 if (*p == '['){
00704 if (strlen (p) <= 8 || p [8] != ']')
00705 goto error;
00706
00707
00708 if (S_ISDIR (st->st_mode))
00709 st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
00710 else
00711 st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
00712 p += 9;
00713
00714 } else {
00715 if ((i = vfs_parse_filemode(p)) == -1)
00716 goto error;
00717 st->st_mode |= i;
00718 p += 9;
00719
00720
00721 if (*p == '+')
00722 p++;
00723 }
00724
00725 g_free(p_copy);
00726 p_copy = g_strdup(p);
00727 num_cols = vfs_split_text (p);
00728
00729 st->st_nlink = atol (columns [0]);
00730 if (st->st_nlink < 0)
00731 goto error;
00732
00733 if (!is_num (1))
00734 #ifdef HACK
00735 st->st_uid = finduid (columns [1]);
00736 #else
00737 (void) unameToUid (columns [1], &st->st_uid);
00738 #endif
00739 else
00740 st->st_uid = (uid_t) atol (columns [1]);
00741
00742
00743 for (idx = 3; idx <= 5; idx++)
00744 if (is_month(columns [idx], NULL) || is_week(columns [idx], NULL) || is_dos_date(columns[idx]))
00745 break;
00746
00747 if (idx == 6 || (idx == 5 && !S_ISCHR (st->st_mode) && !S_ISBLK (st->st_mode)))
00748 goto error;
00749
00750
00751 if (idx == 3 || (idx == 4 && (S_ISCHR(st->st_mode) || S_ISBLK (st->st_mode))))
00752 idx2 = 2;
00753 else {
00754
00755 if (is_num (2))
00756 st->st_gid = (gid_t) atol (columns [2]);
00757 else
00758 #ifdef HACK
00759 st->st_gid = findgid (columns [2]);
00760 #else
00761 (void) gnameToGid (columns [1], &st->st_gid);
00762 #endif
00763 idx2 = 3;
00764 }
00765
00766
00767 if (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode)){
00768 int maj, min;
00769
00770 if (!is_num (idx2) || sscanf(columns [idx2], " %d,", &maj) != 1)
00771 goto error;
00772
00773 if (!is_num (++idx2) || sscanf(columns [idx2], " %d", &min) != 1)
00774 goto error;
00775
00776 #ifdef HAVE_ST_RDEV
00777 st->st_rdev = ((maj & 0xff) << 8) | (min & 0xffff00ff);
00778 #endif
00779 st->st_size = 0;
00780
00781 } else {
00782
00783 if (!is_num (idx2))
00784 goto error;
00785
00786 st->st_size = (size_t) atol (columns [idx2]);
00787 #ifdef HAVE_ST_RDEV
00788 st->st_rdev = 0;
00789 #endif
00790 }
00791
00792 idx = vfs_parse_filedate(idx, &st->st_mtime);
00793 if (!idx)
00794 goto error;
00795
00796 st->st_atime = st->st_ctime = st->st_mtime;
00797 st->st_dev = 0;
00798 st->st_ino = 0;
00799 #ifdef HAVE_ST_BLKSIZE
00800 st->st_blksize = 512;
00801 #endif
00802 #ifdef HAVE_ST_BLOCKS
00803 st->st_blocks = (st->st_size + 511) / 512;
00804 #endif
00805
00806 for (i = idx + 1, idx2 = 0; i < num_cols; i++ )
00807 if (strcmp (columns [i], "->") == 0){
00808 idx2 = i;
00809 break;
00810 }
00811
00812 if (((S_ISLNK (st->st_mode) ||
00813 (num_cols == idx + 3 && st->st_nlink > 1)))
00814 && idx2){
00815 int tlen;
00816 char *t;
00817
00818 if (filename){
00819 #ifdef HACK
00820 t = g_strndup (p_copy + column_ptr [idx], column_ptr [idx2] - column_ptr [idx] - 1);
00821 #else
00822 int nb = column_ptr [idx2] - column_ptr [idx] - 1;
00823 t = xmalloc(nb+1);
00824 strncpy(t, p_copy + column_ptr [idx], nb);
00825 #endif
00826 *filename = t;
00827 }
00828 if (linkname){
00829 t = g_strdup (p_copy + column_ptr [idx2+1]);
00830 tlen = strlen (t);
00831 if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
00832 t [tlen-1] = 0;
00833 if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
00834 t [tlen-2] = 0;
00835
00836 *linkname = t;
00837 }
00838 } else {
00839
00840
00841
00842 if (filename){
00843
00844
00845
00846 int tlen;
00847 char *t;
00848
00849 t = g_strdup (p_copy + column_ptr [idx]); idx++;
00850 tlen = strlen (t);
00851
00852 if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
00853 t [tlen-1] = 0;
00854 if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
00855 t [tlen-2] = 0;
00856
00857 *filename = t;
00858 }
00859 if (linkname)
00860 *linkname = NULL;
00861 }
00862 g_free (p_copy);
00863 return 1;
00864
00865 error:
00866 #ifdef HACK
00867 {
00868 static int errorcount = 0;
00869
00870 if (++errorcount < 5) {
00871 message_1s (1, "Could not parse:", p_copy);
00872 } else if (errorcount == 5)
00873 message_1s (1, "More parsing errors will be ignored.", "(sorry)" );
00874 }
00875 #endif
00876
00877
00878 if (p_copy != p)
00879
00880 g_free (p_copy);
00881 return 0;
00882 }
00883
00884 typedef enum {
00885 DO_FTP_STAT = 1,
00886 DO_FTP_LSTAT = 2,
00887 DO_FTP_READLINK = 3,
00888 DO_FTP_ACCESS = 4,
00889 DO_FTP_GLOB = 5
00890 } ftpSysCall_t;
00891
00894
00895 static size_t ftpBufAlloced = 0;
00896
00899
00900 static char * ftpBuf = NULL;
00901
00902 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
00903
00904
00905 static int ftpNLST(const char * url, ftpSysCall_t ftpSysCall,
00906 struct stat * st,
00907 char * rlbuf, size_t rlbufsiz)
00908
00909
00910 {
00911 FD_t fd;
00912 const char * path;
00913 int bufLength, moretodo;
00914 const char *n, *ne, *o, *oe;
00915 char * s;
00916 char * se;
00917 const char * urldn;
00918 char * bn = NULL;
00919 int nbn = 0;
00920 urlinfo u;
00921 int rc;
00922
00923 n = ne = o = oe = NULL;
00924 (void) urlPath(url, &path);
00925 if (*path == '\0')
00926 return -2;
00927
00928 switch (ftpSysCall) {
00929 case DO_FTP_GLOB:
00930 fd = ftpOpen(url, 0, 0, &u);
00931 if (fd == NULL || u == NULL)
00932 return -1;
00933
00934 u->openError = ftpReq(fd, "LIST", path);
00935 break;
00936 default:
00937 urldn = alloca_strdup(url);
00938
00939 if ((bn = strrchr(urldn, '/')) == NULL)
00940 return -2;
00941 else if (bn == path)
00942 bn = ".";
00943 else
00944 *bn++ = '\0';
00945
00946 nbn = strlen(bn);
00947
00948 rc = ftpChdir(urldn);
00949 if (rc < 0)
00950 return rc;
00951
00952 fd = ftpOpen(url, 0, 0, &u);
00953 if (fd == NULL || u == NULL)
00954 return -1;
00955
00956
00957 u->openError = ftpReq(fd, "NLST", "-la");
00958
00959 if (bn == NULL || nbn <= 0) {
00960 rc = -2;
00961 goto exit;
00962 }
00963 break;
00964 }
00965
00966 if (u->openError < 0) {
00967 fd = fdLink(fd, "error data (ftpStat)");
00968 rc = -2;
00969 goto exit;
00970 }
00971
00972 if (ftpBufAlloced == 0 || ftpBuf == NULL) {
00973 ftpBufAlloced = _url_iobuf_size;
00974 ftpBuf = xcalloc(ftpBufAlloced, sizeof(ftpBuf[0]));
00975 }
00976 *ftpBuf = '\0';
00977
00978 bufLength = 0;
00979 moretodo = 1;
00980
00981 do {
00982
00983
00984 if ((ftpBufAlloced - bufLength) < (1024+80)) {
00985 ftpBufAlloced <<= 2;
00986 ftpBuf = xrealloc(ftpBuf, ftpBufAlloced);
00987 }
00988 s = se = ftpBuf + bufLength;
00989 *se = '\0';
00990
00991 rc = fdFgets(fd, se, (ftpBufAlloced - bufLength));
00992 if (rc <= 0) {
00993 moretodo = 0;
00994 break;
00995 }
00996 if (ftpSysCall == DO_FTP_GLOB) {
00997 bufLength += strlen(se);
00998 continue;
00999 }
01000
01001 for (s = se; *s != '\0'; s = se) {
01002 int bingo;
01003
01004 while (*se && *se != '\n') se++;
01005 if (se > s && se[-1] == '\r') se[-1] = '\0';
01006 if (*se == '\0')
01007 break;
01008 *se++ = '\0';
01009
01010 if (!strncmp(s, "total ", sizeof("total ")-1))
01011 continue;
01012
01013 o = NULL;
01014 for (bingo = 0, n = se; n >= s; n--) {
01015 switch (*n) {
01016 case '\0':
01017 oe = ne = n;
01018 break;
01019 case ' ':
01020 if (o || !(n[-3] == ' ' && n[-2] == '-' && n[-1] == '>')) {
01021 while (*(++n) == ' ')
01022 {};
01023 bingo++;
01024 break;
01025 }
01026 for (o = n + 1; *o == ' '; o++)
01027 {};
01028 n -= 3;
01029 ne = n;
01030 break;
01031 default:
01032 break;
01033 }
01034 if (bingo)
01035 break;
01036 }
01037
01038 if (nbn != (ne - n))
01039 continue;
01040 if (strncmp(n, bn, nbn))
01041 continue;
01042
01043 moretodo = 0;
01044 break;
01045 }
01046
01047 if (moretodo && se > s) {
01048 bufLength = se - s - 1;
01049 if (s != ftpBuf)
01050 memmove(ftpBuf, s, bufLength);
01051 } else {
01052 bufLength = 0;
01053 }
01054 } while (moretodo);
01055
01056 switch (ftpSysCall) {
01057 case DO_FTP_STAT:
01058 if (o && oe) {
01059
01060 }
01061
01062 case DO_FTP_LSTAT:
01063 if (st == NULL || !(n && ne)) {
01064 rc = -1;
01065 } else {
01066 rc = ((vfs_parse_ls_lga(s, st, NULL, NULL) > 0) ? 0 : -1);
01067 }
01068 break;
01069 case DO_FTP_READLINK:
01070 if (rlbuf == NULL || !(o && oe)) {
01071 rc = -1;
01072 } else {
01073 rc = oe - o;
01074 if (rc > rlbufsiz)
01075 rc = rlbufsiz;
01076 memcpy(rlbuf, o, rc);
01077 if (rc < rlbufsiz)
01078 rlbuf[rc] = '\0';
01079 }
01080 break;
01081 case DO_FTP_ACCESS:
01082 rc = 0;
01083 break;
01084 case DO_FTP_GLOB:
01085 rc = 0;
01086 break;
01087 }
01088
01089 exit:
01090 (void) ufdClose(fd);
01091 return rc;
01092 }
01093
01094
01095 static const char * statstr(const struct stat * st,
01096 char * buf, size_t size)
01097
01098 {
01099 snprintf(buf, size,
01100 "*** dev %x ino %x mode %0o nlink %d uid %d gid %d rdev %x size %x\n",
01101 (unsigned)st->st_dev,
01102 (unsigned)st->st_ino,
01103 st->st_mode,
01104 st->st_nlink,
01105 st->st_uid,
01106 st->st_gid,
01107 (unsigned)st->st_rdev,
01108 (unsigned)st->st_size);
01109 return buf;
01110 }
01111
01112
01113 static int ftp_st_ino = 0xdead0000;
01114
01115 static int ftpStat(const char * path, struct stat *st)
01116
01117
01118 {
01119 char buf[1024];
01120 int rc;
01121 rc = ftpNLST(path, DO_FTP_STAT, st, NULL, 0);
01122
01123
01124 if (st->st_ino == 0)
01125 st->st_ino = ftp_st_ino++;
01126
01127 if (_ftp_debug)
01128 fprintf(stderr, "*** ftpStat(%s) rc %d\n%s", path, rc, statstr(st, buf, sizeof buf));
01129 return rc;
01130 }
01131
01132 static int ftpLstat(const char * path, struct stat *st)
01133
01134
01135 {
01136 char buf[1024];
01137 int rc;
01138 rc = ftpNLST(path, DO_FTP_LSTAT, st, NULL, 0);
01139
01140
01141 if (st->st_ino == 0)
01142 st->st_ino = ftp_st_ino++;
01143
01144 if (_ftp_debug)
01145 fprintf(stderr, "*** ftpLstat(%s) rc %d\n%s\n", path, rc, statstr(st, buf, sizeof buf));
01146 return rc;
01147 }
01148
01149 static int ftpReadlink(const char * path, char * buf, size_t bufsiz)
01150
01151
01152 {
01153 int rc;
01154 rc = ftpNLST(path, DO_FTP_READLINK, NULL, buf, bufsiz);
01155 if (_ftp_debug)
01156 fprintf(stderr, "*** ftpReadlink(%s) rc %d\n", path, rc);
01157 return rc;
01158 }
01159
01160 struct __dirstream {
01161 int fd;
01162 char * data;
01163 size_t allocation;
01164 size_t size;
01165 size_t offset;
01166 off_t filepos;
01167 #if defined(HAVE_PTHREAD_H) && !defined(__LCLINT__)
01168 pthread_mutex_t lock;
01169 #endif
01170 };
01171
01172
01173 static int ftpmagicdir = 0x8440291;
01174 #define ISFTPMAGIC(_dir) (!memcmp((_dir), &ftpmagicdir, sizeof(ftpmagicdir)))
01175
01176
01177
01178 static DIR * ftpOpendir(const char * path)
01179
01180
01181 {
01182 DIR * dir;
01183 struct dirent * dp;
01184 size_t nb;
01185 const char * s, * sb, * se;
01186 const char ** av;
01187 unsigned char * dt;
01188 char * t;
01189 int ac;
01190 int c;
01191 int rc;
01192
01193 if (_ftp_debug)
01194 fprintf(stderr, "*** ftpOpendir(%s)\n", path);
01195 rc = ftpNLST(path, DO_FTP_GLOB, NULL, NULL, 0);
01196 if (rc)
01197 return NULL;
01198
01199
01200
01201
01202
01203 nb = sizeof(".") + sizeof("..");
01204 ac = 2;
01205 sb = NULL;
01206 s = se = ftpBuf;
01207 while ((c = *se) != '\0') {
01208 se++;
01209 switch (c) {
01210 case '/':
01211 sb = se;
01212 break;
01213 case '\r':
01214 if (sb == NULL) {
01215 for (sb = se; sb > s && sb[-1] != ' '; sb--)
01216 {};
01217 }
01218 ac++;
01219 nb += (se - sb);
01220
01221 if (*se == '\n') se++;
01222 sb = NULL;
01223 s = se;
01224 break;
01225 default:
01226 break;
01227 }
01228 }
01229
01230 nb += sizeof(*dir) + sizeof(*dp) + ((ac + 1) * sizeof(*av)) + (ac + 1);
01231 dir = xcalloc(1, nb);
01232
01233 dp = (struct dirent *) (dir + 1);
01234 av = (const char **) (dp + 1);
01235 dt = (char *) (av + (ac + 1));
01236 t = (char *) (dt + ac + 1);
01237
01238
01239 dir->fd = ftpmagicdir;
01240 dir->data = (char *) dp;
01241 dir->allocation = nb;
01242 dir->size = ac;
01243 dir->offset = -1;
01244 dir->filepos = 0;
01245
01246 ac = 0;
01247
01248 dt[ac] = DT_DIR; av[ac++] = t; t = stpcpy(t, "."); t++;
01249 dt[ac] = DT_DIR; av[ac++] = t; t = stpcpy(t, ".."); t++;
01250
01251 sb = NULL;
01252 s = se = ftpBuf;
01253 while ((c = *se) != '\0') {
01254 se++;
01255 switch (c) {
01256 case '/':
01257 sb = se;
01258 break;
01259 case '\r':
01260
01261 av[ac] = t;
01262
01263 if (sb == NULL) {
01264
01265 switch(*s) {
01266 case 'p':
01267 dt[ac] = DT_FIFO;
01268 break;
01269 case 'c':
01270 dt[ac] = DT_CHR;
01271 break;
01272 case 'd':
01273 dt[ac] = DT_DIR;
01274 break;
01275 case 'b':
01276 dt[ac] = DT_BLK;
01277 break;
01278 case '-':
01279 dt[ac] = DT_REG;
01280 break;
01281 case 'l':
01282 dt[ac] = DT_LNK;
01283 break;
01284 case 's':
01285 dt[ac] = DT_SOCK;
01286 break;
01287 default:
01288 dt[ac] = DT_UNKNOWN;
01289 break;
01290 }
01291
01292 for (sb = se; sb > s && sb[-1] != ' '; sb--)
01293 {};
01294 }
01295 ac++;
01296 t = stpncpy(t, sb, (se - sb));
01297 t[-1] = '\0';
01298 if (*se == '\n') se++;
01299 sb = NULL;
01300 s = se;
01301 break;
01302 default:
01303 break;
01304 }
01305 }
01306 av[ac] = NULL;
01307
01308 return dir;
01309 }
01310
01311
01312 static struct dirent * ftpReaddir(DIR * dir)
01313
01314
01315 {
01316 struct dirent * dp;
01317 const char ** av;
01318 unsigned char * dt;
01319 int ac;
01320 int i;
01321
01322
01323 if (dir == NULL || !ISFTPMAGIC(dir) || dir->data == NULL) {
01324
01325 return NULL;
01326 }
01327
01328
01329 dp = (struct dirent *) dir->data;
01330 av = (const char **) (dp + 1);
01331 ac = dir->size;
01332 dt = (char *) (av + (ac + 1));
01333 i = dir->offset + 1;
01334
01335 if (i < 0 || i >= ac || av[i] == NULL)
01336 return NULL;
01337
01338 dir->offset = i;
01339
01340
01341 dp->d_ino = i + 1;
01342 dp->d_off = 0;
01343 dp->d_reclen = 0;
01344 dp->d_type = dt[i];
01345
01346 strncpy(dp->d_name, av[i], sizeof(dp->d_name));
01347
01348 if (_ftp_debug)
01349 fprintf(stderr, "*** ftpReaddir(%p) %p \"%s\"\n", (void *)dir, dp, dp->d_name);
01350
01351
01352 return dp;
01353 }
01354
01355
01356 static int ftpClosedir( DIR * dir)
01357
01358
01359 {
01360
01361 if (_ftp_debug)
01362 fprintf(stderr, "*** ftpClosedir(%p)\n", (void *)dir);
01363 if (dir == NULL || !ISFTPMAGIC(dir)) {
01364
01365 return -1;
01366 }
01367 free((void *)dir);
01368
01369 dir = NULL;
01370 return 0;
01371 }
01372
01373 int Stat(const char * path, struct stat * st)
01374 {
01375 const char * lpath;
01376 int ut = urlPath(path, &lpath);
01377
01378 if (_rpmio_debug)
01379 fprintf(stderr, "*** Stat(%s,%p)\n", path, st);
01380 switch (ut) {
01381 case URL_IS_FTP:
01382 return ftpStat(path, st);
01383 break;
01384 case URL_IS_HTTP:
01385 case URL_IS_PATH:
01386 path = lpath;
01387
01388 case URL_IS_UNKNOWN:
01389 break;
01390 case URL_IS_DASH:
01391 default:
01392 return -2;
01393 break;
01394 }
01395 return stat(path, st);
01396 }
01397
01398 int Lstat(const char * path, struct stat * st)
01399 {
01400 const char * lpath;
01401 int ut = urlPath(path, &lpath);
01402
01403 if (_rpmio_debug)
01404 fprintf(stderr, "*** Lstat(%s,%p)\n", path, st);
01405 switch (ut) {
01406 case URL_IS_FTP:
01407 return ftpLstat(path, st);
01408 break;
01409 case URL_IS_HTTP:
01410 case URL_IS_PATH:
01411 path = lpath;
01412
01413 case URL_IS_UNKNOWN:
01414 break;
01415 case URL_IS_DASH:
01416 default:
01417 return -2;
01418 break;
01419 }
01420 return lstat(path, st);
01421 }
01422
01423 int Readlink(const char * path, char * buf, size_t bufsiz)
01424 {
01425 const char * lpath;
01426 int ut = urlPath(path, &lpath);
01427
01428 switch (ut) {
01429 case URL_IS_FTP:
01430 return ftpReadlink(path, buf, bufsiz);
01431 break;
01432 case URL_IS_HTTP:
01433 case URL_IS_PATH:
01434 path = lpath;
01435
01436 case URL_IS_UNKNOWN:
01437 break;
01438 case URL_IS_DASH:
01439 default:
01440 return -2;
01441 break;
01442 }
01443 return readlink(path, buf, bufsiz);
01444 }
01445
01446 int Access(const char * path, int amode)
01447 {
01448 const char * lpath;
01449 int ut = urlPath(path, &lpath);
01450
01451 if (_rpmio_debug)
01452 fprintf(stderr, "*** Access(%s,%d)\n", path, amode);
01453 switch (ut) {
01454 case URL_IS_FTP:
01455 case URL_IS_HTTP:
01456 case URL_IS_PATH:
01457 path = lpath;
01458
01459 case URL_IS_UNKNOWN:
01460 break;
01461 case URL_IS_DASH:
01462 default:
01463 return -2;
01464 break;
01465 }
01466 return access(path, amode);
01467 }
01468
01469 int Glob(const char *pattern, int flags,
01470 int errfunc(const char * epath, int eerrno), glob_t *pglob)
01471 {
01472 const char * lpath;
01473 int ut = urlPath(pattern, &lpath);
01474
01475
01476 if (_rpmio_debug)
01477 fprintf(stderr, "*** Glob(%s,0x%x,%p,%p)\n", pattern, (unsigned)flags, (void *)errfunc, pglob);
01478
01479 switch (ut) {
01480 case URL_IS_FTP:
01481
01482 pglob->gl_closedir = Closedir;
01483 pglob->gl_readdir = Readdir;
01484 pglob->gl_opendir = Opendir;
01485 pglob->gl_lstat = Lstat;
01486 pglob->gl_stat = Stat;
01487
01488 flags |= GLOB_ALTDIRFUNC;
01489 break;
01490 case URL_IS_HTTP:
01491 case URL_IS_PATH:
01492 pattern = lpath;
01493
01494 case URL_IS_UNKNOWN:
01495 break;
01496 case URL_IS_DASH:
01497 default:
01498 return -2;
01499 break;
01500 }
01501 return glob(pattern, flags, errfunc, pglob);
01502 }
01503
01504 void Globfree(glob_t *pglob)
01505 {
01506 if (_rpmio_debug)
01507 fprintf(stderr, "*** Globfree(%p)\n", pglob);
01508 globfree(pglob);
01509 }
01510
01511 DIR * Opendir(const char * path)
01512 {
01513 const char * lpath;
01514 int ut = urlPath(path, &lpath);
01515
01516 if (_rpmio_debug)
01517 fprintf(stderr, "*** Opendir(%s)\n", path);
01518 switch (ut) {
01519 case URL_IS_FTP:
01520 return ftpOpendir(path);
01521 break;
01522 case URL_IS_HTTP:
01523 case URL_IS_PATH:
01524 path = lpath;
01525
01526 case URL_IS_UNKNOWN:
01527 break;
01528 case URL_IS_DASH:
01529 default:
01530 return NULL;
01531 break;
01532 }
01533
01534 return opendir(path);
01535
01536 }
01537
01538
01539 struct dirent * Readdir(DIR * dir)
01540 {
01541 if (_rpmio_debug)
01542 fprintf(stderr, "*** Readdir(%p)\n", (void *)dir);
01543 if (dir == NULL || ISFTPMAGIC(dir))
01544 return ftpReaddir(dir);
01545 return readdir(dir);
01546 }
01547
01548 int Closedir(DIR * dir)
01549 {
01550 if (_rpmio_debug)
01551 fprintf(stderr, "*** Closedir(%p)\n", (void *)dir);
01552 if (dir == NULL || ISFTPMAGIC(dir))
01553 return ftpClosedir(dir);
01554 return closedir(dir);
01555 }
01556