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