rpm  5.2.1
rpmrpc.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <rpmio_internal.h>
8 #include <rpmmacro.h>
9 
10 #define _RPMAV_INTERNAL
11 #define _RPMDAV_INTERNAL
12 #include <rpmdav.h>
13 
14 #include <rpmhash.h>
15 #include <ugid.h>
16 
17 #include "debug.h"
18 
19 /*@access DIR @*/
20 /*@access FD_t @*/
21 /*@access urlinfo @*/
22 
23 /* =============================================================== */
24 static int ftpMkdir(const char * path, /*@unused@*/ mode_t mode)
25  /*@globals h_errno, fileSystem, internalState @*/
26  /*@modifies fileSystem, internalState @*/
27 {
28  int rc;
29  if ((rc = ftpCmd("MKD", path, NULL)) != 0)
30  return rc;
31 #if NOTYET
32  { char buf[20];
33  sprintf(buf, " 0%o", mode);
34  (void) ftpCmd("SITE CHMOD", path, buf);
35  }
36 #endif
37  return rc;
38 }
39 
40 static int ftpChdir(const char * path)
41  /*@globals h_errno, fileSystem, internalState @*/
42  /*@modifies fileSystem, internalState @*/
43 {
44  return ftpCmd("CWD", path, NULL);
45 }
46 
47 static int ftpRmdir(const char * path)
48  /*@globals h_errno, fileSystem, internalState @*/
49  /*@modifies fileSystem, internalState @*/
50 {
51  return ftpCmd("RMD", path, NULL);
52 }
53 
54 static int ftpRename(const char * oldpath, const char * newpath)
55  /*@globals h_errno, fileSystem, internalState @*/
56  /*@modifies fileSystem, internalState @*/
57 {
58  int rc;
59  if ((rc = ftpCmd("RNFR", oldpath, NULL)) != 0)
60  return rc;
61  return ftpCmd("RNTO", newpath, NULL);
62 }
63 
64 static int ftpUnlink(const char * path)
65  /*@globals h_errno, fileSystem, internalState @*/
66  /*@modifies fileSystem, internalState @*/
67 {
68  return ftpCmd("DELE", path, NULL);
69 }
70 
71 /* =============================================================== */
72 int Mkdir (const char * path, mode_t mode)
73 {
74  const char * lpath;
75  int ut = urlPath(path, &lpath);
76 
77 if (_rpmio_debug)
78 fprintf(stderr, "*** Mkdir(%s, 0%o)\n", path, (unsigned)mode);
79  switch (ut) {
80  case URL_IS_FTP:
81  return ftpMkdir(path, mode);
82  /*@notreached@*/ break;
83  case URL_IS_HTTPS:
84  case URL_IS_HTTP:
85 #ifdef WITH_NEON
86  return davMkdir(path, mode);
87 #endif
88  /*@notreached@*/ break;
89  case URL_IS_PATH:
90  path = lpath;
91  /*@fallthrough@*/
92  case URL_IS_UNKNOWN:
93  break;
94  case URL_IS_DASH:
95  case URL_IS_HKP:
96  default:
97  return -2;
98  /*@notreached@*/ break;
99  }
100  return mkdir(path, mode);
101 }
102 
103 int Chdir (const char * path)
104 {
105  const char * lpath;
106  int ut = urlPath(path, &lpath);
107 
108 if (_rpmio_debug)
109 fprintf(stderr, "*** Chdir(%s)\n", path);
110  switch (ut) {
111  case URL_IS_FTP:
112  return ftpChdir(path);
113  /*@notreached@*/ break;
114  case URL_IS_HTTPS:
115  case URL_IS_HTTP:
116 #ifdef NOTYET
117  return davChdir(path);
118 #else
119  errno = EINVAL; /* XXX W2DO? */
120  return -2;
121 #endif
122  /*@notreached@*/ break;
123  case URL_IS_PATH:
124  path = lpath;
125  /*@fallthrough@*/
126  case URL_IS_UNKNOWN:
127  break;
128  case URL_IS_DASH:
129  case URL_IS_HKP:
130  default:
131  errno = EINVAL; /* XXX W2DO? */
132  return -2;
133  /*@notreached@*/ break;
134  }
135  return chdir(path);
136 }
137 
138 int Rmdir (const char * path)
139 {
140  const char * lpath;
141  int ut = urlPath(path, &lpath);
142 
143 if (_rpmio_debug)
144 fprintf(stderr, "*** Rmdir(%s)\n", path);
145  switch (ut) {
146  case URL_IS_FTP:
147  return ftpRmdir(path);
148  /*@notreached@*/ break;
149  case URL_IS_HTTPS:
150  case URL_IS_HTTP:
151 #ifdef WITH_NEON
152  return davRmdir(path);
153 #endif
154  /*@notreached@*/ break;
155  case URL_IS_PATH:
156  path = lpath;
157  /*@fallthrough@*/
158  case URL_IS_UNKNOWN:
159  break;
160  case URL_IS_DASH:
161  case URL_IS_HKP:
162  default:
163  return -2;
164  /*@notreached@*/ break;
165  }
166  return rmdir(path);
167 }
168 
169 /*@unchecked@*/
170 const char * _chroot_prefix = NULL;
171 
172 int Chroot(const char * path)
173 {
174  const char * lpath;
175  int ut = urlPath(path, &lpath);
176 
177 if (_rpmio_debug)
178 fprintf(stderr, "*** Chroot(%s)\n", path);
179  switch (ut) {
180  case URL_IS_PATH:
181  path = lpath;
182  /*@fallthrough@*/
183  case URL_IS_UNKNOWN:
184  break;
185  case URL_IS_DASH:
186  case URL_IS_HKP:
187  case URL_IS_FTP: /* XXX TODO: implement. */
188  case URL_IS_HTTPS: /* XXX TODO: implement. */
189  case URL_IS_HTTP: /* XXX TODO: implement. */
190  default:
191  errno = EINVAL; /* XXX W2DO? */
192  return -2;
193  /*@notreached@*/ break;
194  }
195 
196 /*@-dependenttrans -modobserver -observertrans @*/
198 /*@=dependenttrans =modobserver =observertrans @*/
199 /*@-globs -mods@*/ /* XXX hide rpmGlobalMacroContext mods for now. */
200  if (strcmp(path, "."))
201  _chroot_prefix = rpmGetPath(path, NULL);
202 /*@=globs =mods@*/
203 
204 /*@-superuser@*/
205  return chroot(path);
206 /*@=superuser@*/
207 }
208 /*@=mods@*/
209 
210 int Open(const char * path, int flags, mode_t mode)
211 {
212  const char * lpath;
213  int ut = urlPath(path, &lpath);
214  int fdno;
215 
216 if (_rpmio_debug)
217 fprintf(stderr, "*** Open(%s, 0x%x, 0%o)\n", path, flags, (unsigned)mode);
218  switch (ut) {
219  case URL_IS_PATH:
220  path = lpath;
221  /*@fallthrough@*/
222  case URL_IS_UNKNOWN:
223  break;
224  case URL_IS_DASH:
225  case URL_IS_HKP:
226  case URL_IS_FTP: /* XXX TODO: implement. */
227  case URL_IS_HTTPS: /* XXX TODO: implement. */
228  case URL_IS_HTTP: /* XXX TODO: implement. */
229  default:
230  errno = EINVAL; /* XXX W2DO? */
231  return -2;
232  /*@notreached@*/ break;
233  }
234 
235  if (_chroot_prefix && _chroot_prefix[0] == '/' && _chroot_prefix[1] != '\0')
236  {
237  size_t nb = strlen(_chroot_prefix);
238  size_t ob = strlen(path);
239  while (nb > 0 && _chroot_prefix[nb-1] == '/')
240  nb--;
241  if (ob > nb && !strncmp(path, _chroot_prefix, nb) && path[nb] == '/')
242  path += nb;
243  }
244 #ifdef NOTYET /* XXX likely sane default. */
245  if (mode == 0)
246  mode = 0644;
247 #endif
248  fdno = open(path, flags, mode);
249  if (fdno >= 0) {
250  if (fcntl(fdno, F_SETFD, FD_CLOEXEC) < 0) {
251  (void) close(fdno);
252  fdno = -1;
253  }
254  }
255  return fdno;
256 }
257 
258 /* XXX rpmdb.c: analogue to rename(2). */
259 
260 int Rename (const char * oldpath, const char * newpath)
261 {
262  const char *oe = NULL;
263  const char *ne = NULL;
264  int oldut, newut;
265 
266 if (_rpmio_debug)
267 fprintf(stderr, "*** Rename(%s, %s)\n", oldpath, newpath);
268  /* XXX lib/install.c used to rely on this behavior. */
269  if (!strcmp(oldpath, newpath)) return 0;
270 
271  oldut = urlPath(oldpath, &oe);
272  switch (oldut) {
273  case URL_IS_HTTPS:
274  case URL_IS_HTTP:
275 #ifdef WITH_NEON
276  return davRename(oldpath, newpath);
277 #endif
278  /*@notreached@*/ break;
279  case URL_IS_FTP: /* XXX WRONG WRONG WRONG */
280  case URL_IS_PATH:
281  case URL_IS_UNKNOWN:
282  break;
283  case URL_IS_DASH:
284  case URL_IS_HKP:
285  default:
286  return -2;
287  /*@notreached@*/ break;
288  }
289 
290  newut = urlPath(newpath, &ne);
291  switch (newut) {
292  case URL_IS_FTP:
293 if (_rpmio_debug)
294 fprintf(stderr, "*** rename old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
295  if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
296  !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
297  return -2;
298  return ftpRename(oldpath, newpath);
299  /*@notreached@*/ break;
300  case URL_IS_HTTPS: /* XXX WRONG WRONG WRONG */
301  case URL_IS_HTTP: /* XXX WRONG WRONG WRONG */
302  case URL_IS_PATH:
303  oldpath = oe;
304  newpath = ne;
305  break;
306  case URL_IS_UNKNOWN:
307  break;
308  case URL_IS_DASH:
309  case URL_IS_HKP:
310  default:
311  return -2;
312  /*@notreached@*/ break;
313  }
314  return rename(oldpath, newpath);
315 }
316 
317 int Link (const char * oldpath, const char * newpath)
318 {
319  const char *oe = NULL;
320  const char *ne = NULL;
321  int oldut, newut;
322 
323 if (_rpmio_debug)
324 fprintf(stderr, "*** Link(%s, %s)\n", oldpath, newpath);
325  oldut = urlPath(oldpath, &oe);
326  switch (oldut) {
327  case URL_IS_HTTPS: /* XXX WRONG WRONG WRONG */
328  case URL_IS_HTTP: /* XXX WRONG WRONG WRONG */
329  case URL_IS_FTP: /* XXX WRONG WRONG WRONG */
330  case URL_IS_PATH:
331  case URL_IS_UNKNOWN:
332  break;
333  case URL_IS_DASH:
334  case URL_IS_HKP:
335  default:
336  return -2;
337  /*@notreached@*/ break;
338  }
339 
340  newut = urlPath(newpath, &ne);
341  switch (newut) {
342  case URL_IS_HTTPS: /* XXX WRONG WRONG WRONG */
343  case URL_IS_HTTP: /* XXX WRONG WRONG WRONG */
344  case URL_IS_FTP: /* XXX WRONG WRONG WRONG */
345  case URL_IS_PATH:
346 if (_rpmio_debug)
347 fprintf(stderr, "*** link old %*s new %*s\n", (int)(oe - oldpath), oldpath, (int)(ne - newpath), newpath);
348  if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
349  !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
350  return -2;
351  oldpath = oe;
352  newpath = ne;
353  break;
354  case URL_IS_UNKNOWN:
355  break;
356  case URL_IS_DASH:
357  case URL_IS_HKP:
358  default:
359  return -2;
360  /*@notreached@*/ break;
361  }
362  return link(oldpath, newpath);
363 }
364 
365 /* XXX build/build.c: analogue to unlink(2). */
366 
367 int Unlink(const char * path) {
368  const char * lpath;
369  int ut = urlPath(path, &lpath);
370 
371 if (_rpmio_debug)
372 fprintf(stderr, "*** Unlink(%s)\n", path);
373  switch (ut) {
374  case URL_IS_FTP:
375  return ftpUnlink(path);
376  /*@notreached@*/ break;
377  case URL_IS_HTTPS:
378  case URL_IS_HTTP:
379 #ifdef WITH_NEON
380  return davUnlink(path);
381 #endif
382  /*@notreached@*/ break;
383  case URL_IS_PATH:
384  path = lpath;
385  /*@fallthrough@*/
386  case URL_IS_UNKNOWN:
387  break;
388  case URL_IS_DASH:
389  case URL_IS_HKP:
390  default:
391  return -2;
392  /*@notreached@*/ break;
393  }
394  return unlink(path);
395 }
396 
397 /* XXX swiped from mc-4.5.39-pre9 vfs/ftpfs.c */
398 
399 #define g_strdup xstrdup
400 #define g_free free
401 
402 /*
403  * FIXME: this is broken. It depends on mc not crossing border on month!
404  */
405 /*@unchecked@*/
406 static int current_mday;
407 /*@unchecked@*/
408 static int current_mon;
409 /*@unchecked@*/
410 static int current_year;
411 
412 /* Following stuff (parse_ls_lga) is used by ftpfs and extfs */
413 #define MAXCOLS 30
414 
415 /*@unchecked@*/
416 static char *columns [MAXCOLS]; /* Points to the string in column n */
417 /*@unchecked@*/
418 static int column_ptr [MAXCOLS]; /* Index from 0 to the starting positions of the columns */
419 
420 static int
421 vfs_split_text (char *p)
422  /*@globals columns, column_ptr @*/
423  /*@modifies *p, columns, column_ptr @*/
424 {
425  char *original = p;
426  int numcols;
427 
428 
429  for (numcols = 0; *p && numcols < MAXCOLS; numcols++){
430  while (*p == ' ' || *p == '\r' || *p == '\n'){
431  *p = '\0';
432  p++;
433  }
434  columns [numcols] = p;
435  column_ptr [numcols] = p - original;
436  while (*p && *p != ' ' && *p != '\r' && *p != '\n')
437  p++;
438  }
439  return numcols;
440 }
441 
442 static int
443 is_num (int idx)
444  /*@*/
445 {
446  if (!columns [idx] || columns [idx][0] < '0' || columns [idx][0] > '9')
447  return 0;
448  return 1;
449 }
450 
451 static int
452 is_dos_date(/*@null@*/ const char *str)
453  /*@*/
454 {
455  if (str != NULL && strlen(str) == 8 &&
456  str[2] == str[5] && strchr("\\-/", (int)str[2]) != NULL)
457  return 1;
458  return 0;
459 }
460 
461 static int
462 is_week (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
463  /*@modifies *tim @*/
464 {
465 /*@observer@*/ static const char * week = "SunMonTueWedThuFriSat";
466  const char * pos;
467 
468  /*@-observertrans -mayaliasunique@*/
469  if (str != NULL && (pos=strstr(week, str)) != NULL) {
470  /*@=observertrans =mayaliasunique@*/
471  if (tim != NULL)
472  tim->tm_wday = (pos - week)/3;
473  return 1;
474  }
475  return 0;
476 }
477 
478 static int
479 is_month (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
480  /*@modifies *tim @*/
481 {
482 /*@observer@*/ static const char * month = "JanFebMarAprMayJunJulAugSepOctNovDec";
483  const char * pos;
484 
485  /*@-observertrans -mayaliasunique@*/
486  if (str != NULL && (pos = strstr(month, str)) != NULL) {
487  /*@=observertrans -mayaliasunique@*/
488  if (tim != NULL)
489  tim->tm_mon = (pos - month)/3;
490  return 1;
491  }
492  return 0;
493 }
494 
495 static int
496 is_time (/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
497  /*@modifies *tim @*/
498 {
499  const char * p, * p2;
500 
501  if (str != NULL && (p = strchr(str, ':')) && (p2 = strrchr(str, ':'))) {
502  if (p != p2) {
503  if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
504  return 0;
505  } else {
506  if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
507  return 0;
508  }
509  } else
510  return 0;
511 
512  return 1;
513 }
514 
515 static int is_year(/*@null@*/ const char * str, /*@out@*/ struct tm * tim)
516  /*@modifies *tim @*/
517 {
518  long year;
519 
520  if (str == NULL)
521  return 0;
522 
523  if (strchr(str,':'))
524  return 0;
525 
526  if (strlen(str) != 4)
527  return 0;
528 
529  if (sscanf(str, "%ld", &year) != 1)
530  return 0;
531 
532  if (year < 1900 || year > 3000)
533  return 0;
534 
535  tim->tm_year = (int) (year - 1900);
536 
537  return 1;
538 }
539 
540 /*
541  * FIXME: this is broken. Consider following entry:
542  * -rwx------ 1 root root 1 Aug 31 10:04 2904 1234
543  * where "2904 1234" is filename. Well, this code decodes it as year :-(.
544  */
545 
546 static int
548  /*@*/
549 {
550  switch (c) {
551  case 'd': return (int)S_IFDIR;
552  case 'b': return (int)S_IFBLK;
553  case 'c': return (int)S_IFCHR;
554  case 'l': return (int)S_IFLNK;
555  case 's':
556 #ifdef IS_IFSOCK /* And if not, we fall through to IFIFO, which is pretty close */
557  return (int)S_IFSOCK;
558 #endif
559  case 'p': return (int)S_IFIFO;
560  case 'm': case 'n': /* Don't know what these are :-) */
561  case '-': case '?': return (int)S_IFREG;
562  default: return -1;
563  }
564 }
565 
566 static int vfs_parse_filemode (const char *p)
567  /*@*/
568 { /* converts rw-rw-rw- into 0666 */
569  int res = 0;
570  switch (*(p++)) {
571  case 'r': res |= 0400; break;
572  case '-': break;
573  default: return -1;
574  }
575  switch (*(p++)) {
576  case 'w': res |= 0200; break;
577  case '-': break;
578  default: return -1;
579  }
580  switch (*(p++)) {
581  case 'x': res |= 0100; break;
582  case 's': res |= 0100 | S_ISUID; break;
583  case 'S': res |= S_ISUID; break;
584  case '-': break;
585  default: return -1;
586  }
587  switch (*(p++)) {
588  case 'r': res |= 0040; break;
589  case '-': break;
590  default: return -1;
591  }
592  switch (*(p++)) {
593  case 'w': res |= 0020; break;
594  case '-': break;
595  default: return -1;
596  }
597  switch (*(p++)) {
598  case 'x': res |= 0010; break;
599  case 's': res |= 0010 | S_ISGID; break;
600  case 'l': /* Solaris produces these */
601  case 'S': res |= S_ISGID; break;
602  case '-': break;
603  default: return -1;
604  }
605  switch (*(p++)) {
606  case 'r': res |= 0004; break;
607  case '-': break;
608  default: return -1;
609  }
610  switch (*(p++)) {
611  case 'w': res |= 0002; break;
612  case '-': break;
613  default: return -1;
614  }
615  switch (*(p++)) {
616  case 'x': res |= 0001; break;
617  case 't': res |= 0001 | S_ISVTX; break;
618  case 'T': res |= S_ISVTX; break;
619  case '-': break;
620  default: return -1;
621  }
622  return res;
623 }
624 
625 static int vfs_parse_filedate(int idx, /*@out@*/ time_t *t)
626  /*@modifies *t @*/
627 { /* This thing parses from idx in columns[] array */
628 
629  char *p;
630  struct tm tim;
631  int d[3];
632  int got_year = 0;
633 
634  /* Let's setup default time values */
635  tim.tm_year = current_year;
636  tim.tm_mon = current_mon;
637  tim.tm_mday = current_mday;
638  tim.tm_hour = 0;
639  tim.tm_min = 0;
640  tim.tm_sec = 0;
641  tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
642 
643  p = columns [idx++];
644 
645  /* We eat weekday name in case of extfs */
646  if(is_week(p, &tim))
647  p = columns [idx++];
648 
649  /* Month name */
650  if(is_month(p, &tim)){
651  /* And we expect, it followed by day number */
652  if (is_num (idx))
653  tim.tm_mday = (int)atol (columns [idx++]);
654  else
655  return 0; /* No day */
656 
657  } else {
658  /* We usually expect:
659  Mon DD hh:mm
660  Mon DD YYYY
661  But in case of extfs we allow these date formats:
662  Mon DD YYYY hh:mm
663  Mon DD hh:mm YYYY
664  Wek Mon DD hh:mm:ss YYYY
665  MM-DD-YY hh:mm
666  where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
667  YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
668 
669  /* Here just this special case with MM-DD-YY */
670  if (is_dos_date(p)){
671 /*@-mods@*/
672  p[2] = p[5] = '-';
673 /*@=mods@*/
674 
675  memset(d, 0, sizeof(d));
676  if (sscanf(p, "%2d-%2d-%2d", &d[0], &d[1], &d[2]) == 3){
677  /* We expect to get:
678  1. MM-DD-YY
679  2. DD-MM-YY
680  3. YY-MM-DD
681  4. YY-DD-MM */
682 
683  /* Hmm... maybe, next time :)*/
684 
685  /* At last, MM-DD-YY */
686  d[0]--; /* Months are zerobased */
687  /* Y2K madness */
688  if(d[2] < 70)
689  d[2] += 100;
690 
691  tim.tm_mon = d[0];
692  tim.tm_mday = d[1];
693  tim.tm_year = d[2];
694  got_year = 1;
695  } else
696  return 0; /* sscanf failed */
697  } else
698  return 0; /* unsupported format */
699  }
700 
701  /* Here we expect to find time and/or year */
702 
703  if (is_num (idx)) {
704  if(is_time(columns[idx], &tim) || (got_year = is_year(columns[idx], &tim))) {
705  idx++;
706 
707  /* This is a special case for ctime() or Mon DD YYYY hh:mm */
708  if(is_num (idx) &&
709  ((got_year = is_year(columns[idx], &tim)) || is_time(columns[idx], &tim)))
710  idx++; /* time & year or reverse */
711  } /* only time or date */
712  }
713  else
714  return 0; /* Nor time or date */
715 
716  /*
717  * If the date is less than 6 months in the past, it is shown without year
718  * other dates in the past or future are shown with year but without time
719  * This does not check for years before 1900 ... I don't know, how
720  * to represent them at all
721  */
722  if (!got_year &&
723  current_mon < 6 && current_mon < tim.tm_mon &&
724  tim.tm_mon - current_mon >= 6)
725 
726  tim.tm_year--;
727 
728  if ((*t = mktime(&tim)) < 0)
729  *t = 0;
730  return idx;
731 }
732 
733 static int
734 vfs_parse_ls_lga (char * p, /*@out@*/ struct stat * st,
735  /*@out@*/ const char ** filename,
736  /*@out@*/ const char ** linkname)
737  /*@modifies *p, *st, *filename, *linkname @*/
738 {
739  int idx, idx2, num_cols;
740  int i;
741  char *p_copy;
742  long n;
743 
744  if (strncmp (p, "total", 5) == 0)
745  return 0;
746 
747  p_copy = g_strdup(p);
748 /* XXX FIXME: parse out inode number from "NLST -lai ." */
749 /* XXX FIXME: parse out sizein blocks from "NLST -lais ." */
750 
751  if ((i = vfs_parse_filetype(*(p++))) == -1)
752  goto error;
753 
754  st->st_mode = i;
755  if (*p == ' ') /* Notwell 4 */
756  p++;
757  if (*p == '['){
758  if (strlen (p) <= 8 || p [8] != ']')
759  goto error;
760  /* Should parse here the Notwell permissions :) */
761  /*@-unrecog@*/
762  if (S_ISDIR (st->st_mode))
763  st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
764  else
765  st->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
766  p += 9;
767  /*@=unrecog@*/
768  } else {
769  if ((i = vfs_parse_filemode(p)) == -1)
770  goto error;
771  st->st_mode |= i;
772  p += 9;
773 
774  /* This is for an extra ACL attribute (HP-UX) */
775  if (*p == '+')
776  p++;
777  }
778 
779  g_free(p_copy);
780  p_copy = g_strdup(p);
781  num_cols = vfs_split_text (p);
782 
783  n = atol(columns[0]);
784  st->st_nlink = n;
785  if (n < 0)
786  goto error;
787 
788  if (!is_num (1))
789 #ifdef HACK
790  st->st_uid = finduid (columns [1]);
791 #else
792  (void) unameToUid (columns [1], &st->st_uid);
793 #endif
794  else
795  st->st_uid = (uid_t) atol (columns [1]);
796 
797  /* Mhm, the ls -lg did not produce a group field */
798  for (idx = 3; idx <= 5; idx++)
799  if (is_month(columns [idx], NULL) || is_week(columns [idx], NULL) || is_dos_date(columns[idx]))
800  break;
801 
802  if (idx == 6 || (idx == 5 && !S_ISCHR (st->st_mode) && !S_ISBLK (st->st_mode)))
803  goto error;
804 
805  /* We don't have gid */
806  if (idx == 3 || (idx == 4 && (S_ISCHR(st->st_mode) || S_ISBLK (st->st_mode))))
807  idx2 = 2;
808  else {
809  /* We have gid field */
810  if (is_num (2))
811  st->st_gid = (gid_t) atol (columns [2]);
812  else
813 #ifdef HACK
814  st->st_gid = findgid (columns [2]);
815 #else
816  (void) gnameToGid (columns [1], &st->st_gid);
817 #endif
818  idx2 = 3;
819  }
820 
821  /* This is device */
822  if (S_ISCHR (st->st_mode) || S_ISBLK (st->st_mode)){
823  unsigned maj, min;
824 
825  if (!is_num (idx2) || sscanf(columns [idx2], " %d,", &maj) != 1)
826  goto error;
827 
828  if (!is_num (++idx2) || sscanf(columns [idx2], " %d", &min) != 1)
829  goto error;
830 
831 #ifdef HAVE_ST_RDEV
832  st->st_rdev = ((maj & 0x000000ffU) << 8) | (min & 0x000000ffU);
833 #endif
834  st->st_size = 0;
835 
836  } else {
837  /* Common file size */
838  if (!is_num (idx2))
839  goto error;
840 
841  st->st_size = (size_t) atol (columns [idx2]);
842 #ifdef HAVE_ST_RDEV
843  st->st_rdev = 0;
844 #endif
845  }
846 
847  idx = vfs_parse_filedate(idx, &st->st_mtime);
848  if (!idx)
849  goto error;
850  /* Use resulting time value */
851  st->st_atime = st->st_ctime = st->st_mtime;
852  st->st_dev = 0;
853  st->st_ino = 0;
854 #ifdef HAVE_ST_BLKSIZE
855  st->st_blksize = 512;
856 #endif
857 #ifdef HAVE_ST_BLOCKS
858  st->st_blocks = (st->st_size + 511) / 512;
859 #endif
860 
861  for (i = idx + 1, idx2 = 0; i < num_cols; i++ )
862  if (strcmp (columns [i], "->") == 0){
863  idx2 = i;
864  break;
865  }
866 
867  if (((S_ISLNK (st->st_mode) ||
868  (num_cols == idx + 3 && st->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
869  && idx2)
870  {
871  size_t tlen;
872  char *t;
873 
874  if (filename){
875  size_t nb = column_ptr [idx2] - column_ptr [idx] - 1;
876  t = strncpy(xcalloc(1, nb+1), p_copy + column_ptr [idx], nb);
877  *filename = t;
878  }
879  if (linkname){
880  t = g_strdup (p_copy + column_ptr [idx2+1]);
881  tlen = strlen (t);
882  if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
883  t [tlen-1] = '\0';
884  if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
885  t [tlen-2] = '\0';
886 
887  *linkname = t;
888  }
889  } else {
890  /* Extract the filename from the string copy, not from the columns
891  * this way we have a chance of entering hidden directories like ". ."
892  */
893  if (filename){
894  /*
895  *filename = g_strdup (columns [idx++]);
896  */
897  size_t tlen;
898  char *t;
899 
900  t = g_strdup (p_copy + column_ptr [idx]); idx++;
901  tlen = strlen (t);
902  /* g_strchomp(); */
903  if (t [tlen-1] == '\r' || t [tlen-1] == '\n')
904  t [tlen-1] = '\0';
905  if (t [tlen-2] == '\r' || t [tlen-2] == '\n')
906  t [tlen-2] = '\0';
907 
908  *filename = t;
909  }
910  if (linkname)
911  *linkname = NULL;
912  }
913  g_free (p_copy);
914  return 1;
915 
916 error:
917 #ifdef HACK
918  {
919  static int errorcount = 0;
920 
921  if (++errorcount < 5) {
922  message_1s (1, "Could not parse:", p_copy);
923  } else if (errorcount == 5)
924  message_1s (1, "More parsing errors will be ignored.", "(sorry)" );
925  }
926 #endif
927 
928  /*@-usereleased@*/
929  if (p_copy != p) /* Carefull! */
930  /*@=usereleased@*/
931  g_free (p_copy);
932  return 0;
933 }
934 
935 typedef enum {
941 } ftpSysCall_t;
942 
945 static size_t ftpBufAlloced;
946 
949 /*@only@*/ /*@relnull@*/
950 static char * ftpBuf;
951 
952 #define alloca_strdup(_s) strcpy(alloca(strlen(_s)+1), (_s))
953 
954 static int ftpNLST(const char * url, ftpSysCall_t ftpSysCall,
955  /*@out@*/ /*@null@*/ struct stat * st,
956  /*@out@*/ /*@null@*/ char * rlbuf, size_t rlbufsiz)
957  /*@globals ftpBufAlloced, ftpBuf,
958  h_errno, fileSystem, internalState @*/
959  /*@modifies *st, *rlbuf, ftpBufAlloced, ftpBuf,
960  fileSystem, internalState @*/
961 {
962  FD_t fd;
963  const char * path;
964  int bufLength, moretodo;
965  const char *n, *ne, *o, *oe;
966  char * s;
967  char * se;
968  const char * urldn;
969  char * bn = NULL;
970  size_t nbn = 0;
971  urlinfo u;
972  int rc;
973 
974  n = ne = o = oe = NULL;
975  (void) urlPath(url, &path);
976  if (*path == '\0')
977  return -2;
978 
979  switch (ftpSysCall) {
980  case DO_FTP_GLOB:
981  fd = ftpOpen(url, 0, 0, &u);
982  if (fd == NULL || u == NULL)
983  return -1;
984 
985  u->openError = ftpReq(fd, "LIST", path);
986  break;
987  default:
988  urldn = alloca_strdup(url);
989  if ((bn = strrchr(urldn, '/')) == NULL)
990  return -2;
991  else if (bn == path)
992  bn = ".";
993  else
994  *bn++ = '\0';
995  nbn = strlen(bn);
996 
997  rc = ftpChdir(urldn); /* XXX don't care about CWD */
998  if (rc < 0)
999  return rc;
1000 
1001  fd = ftpOpen(url, 0, 0, &u);
1002  if (fd == NULL || u == NULL)
1003  return -1;
1004 
1005  /* XXX possibly should do "NLST -lais" to get st_ino/st_blocks also */
1006  u->openError = ftpReq(fd, "NLST", "-la");
1007 
1008  if (bn == NULL || nbn == 0) {
1009  rc = -2;
1010  goto exit;
1011  }
1012  break;
1013  }
1014 
1015  if (u->openError < 0) {
1016  fd = fdLink(fd, "error data (ftpStat)");
1017  rc = -2;
1018  goto exit;
1019  }
1020 
1021  if (ftpBufAlloced == 0 || ftpBuf == NULL) {
1023  ftpBuf = xcalloc(ftpBufAlloced, sizeof(ftpBuf[0]));
1024  }
1025  *ftpBuf = '\0';
1026 
1027  bufLength = 0;
1028  moretodo = 1;
1029 
1030  do {
1031 
1032  /* XXX FIXME: realloc ftpBuf if < ~128 chars remain */
1033  if ((ftpBufAlloced - bufLength) < (1024+80)) {
1034  ftpBufAlloced <<= 2;
1035  assert(ftpBufAlloced < (8*1024*1024));
1037  }
1038  s = se = ftpBuf + bufLength;
1039  *se = '\0';
1040 
1041  rc = fdFgets(fd, se, (ftpBufAlloced - bufLength));
1042  if (rc <= 0) {
1043  moretodo = 0;
1044  break;
1045  }
1046  if (ftpSysCall == DO_FTP_GLOB) { /* XXX HACK */
1047  bufLength += strlen(se);
1048  continue;
1049  }
1050 
1051  for (s = se; *s != '\0'; s = se) {
1052  int bingo;
1053 
1054  while (*se && *se != '\n') se++;
1055  if (se > s && se[-1] == '\r') se[-1] = '\0';
1056  if (*se == '\0')
1057  /*@innerbreak@*/ break;
1058  *se++ = '\0';
1059 
1060  if (!strncmp(s, "total ", sizeof("total ")-1))
1061  /*@innercontinue@*/ continue;
1062 
1063  o = NULL;
1064  for (bingo = 0, n = se; n >= s; n--) {
1065  switch (*n) {
1066  case '\0':
1067  oe = ne = n;
1068  /*@switchbreak@*/ break;
1069  case ' ':
1070  if (o || !(n[-3] == ' ' && n[-2] == '-' && n[-1] == '>')) {
1071  while (*(++n) == ' ')
1072  {};
1073  bingo++;
1074  /*@switchbreak@*/ break;
1075  }
1076  for (o = n + 1; *o == ' '; o++)
1077  {};
1078  n -= 3;
1079  ne = n;
1080  /*@switchbreak@*/ break;
1081  default:
1082  /*@switchbreak@*/ break;
1083  }
1084  if (bingo)
1085  /*@innerbreak@*/ break;
1086  }
1087 
1088  if (nbn != (size_t)(ne - n)) /* Same name length? */
1089  /*@innercontinue@*/ continue;
1090  if (strncmp(n, bn, nbn)) /* Same name? */
1091  /*@innercontinue@*/ continue;
1092 
1093  moretodo = 0;
1094  /*@innerbreak@*/ break;
1095  }
1096 
1097  if (moretodo && se > s) {
1098  bufLength = se - s - 1;
1099  if (s != ftpBuf)
1100  memmove(ftpBuf, s, bufLength);
1101  } else {
1102  bufLength = 0;
1103  }
1104  } while (moretodo);
1105 
1106  switch (ftpSysCall) {
1107  case DO_FTP_STAT:
1108  if (o && oe) {
1109  /* XXX FIXME: symlink, replace urldn/bn from [o,oe) and restart */
1110  }
1111  /*@fallthrough@*/
1112  case DO_FTP_LSTAT:
1113  if (st == NULL || !(n && ne)) {
1114  rc = -1;
1115  } else {
1116  rc = ((vfs_parse_ls_lga(s, st, NULL, NULL) > 0) ? 0 : -1);
1117  }
1118  break;
1119  case DO_FTP_READLINK:
1120  if (rlbuf == NULL || !(o && oe)) {
1121  rc = -1;
1122  } else {
1123  rc = oe - o;
1124 assert(rc >= 0);
1125  if (rc > (int)rlbufsiz)
1126  rc = (int)rlbufsiz;
1127  memcpy(rlbuf, o, (size_t)rc);
1128  if (rc < (int)rlbufsiz)
1129  rlbuf[rc] = '\0';
1130  }
1131  break;
1132  case DO_FTP_ACCESS:
1133  rc = 0; /* XXX WRONG WRONG WRONG */
1134  break;
1135  case DO_FTP_GLOB:
1136  rc = 0; /* XXX WRONG WRONG WRONG */
1137  break;
1138  }
1139 
1140 exit:
1141  (void) ufdClose(fd);
1142  return rc;
1143 }
1144 
1145 static const char * statstr(const struct stat * st,
1146  /*@returned@*/ /*@out@*/ char * buf)
1147  /*@modifies *buf @*/
1148 {
1149  char * t = buf;
1150  sprintf(t, "*** dev %x", (unsigned int)st->st_dev);
1151  t += strlen(t);
1152  sprintf(t, " ino %x", (unsigned int)st->st_ino);
1153  t += strlen(t);
1154  sprintf(t, " mode %0o", (unsigned int)st->st_mode);
1155  t += strlen(t);
1156  sprintf(t, " nlink %d", (unsigned int)st->st_nlink);
1157  t += strlen(t);
1158  sprintf(t, " uid %d", (unsigned int)st->st_uid);
1159  t += strlen(t);
1160  sprintf(t, " gid %d", (unsigned int)st->st_gid);
1161  t += strlen(t);
1162  sprintf(t, " rdev %x", (unsigned int)st->st_rdev);
1163  t += strlen(t);
1164  sprintf(t, " size %x", (unsigned int)st->st_size);
1165  t += strlen(t);
1166  sprintf(t, "\n");
1167  return buf;
1168 }
1169 
1170 /* FIXME: borked for path with trailing '/' */
1171 static int ftpStat(const char * path, /*@out@*/ struct stat *st)
1172  /*@globals ftpBufAlloced, ftpBuf, h_errno, fileSystem, internalState @*/
1173  /*@modifies ftpBufAlloced, ftpBuf, *st, fileSystem, internalState @*/
1174 {
1175  char buf[1024];
1176  int rc;
1177  rc = ftpNLST(path, DO_FTP_STAT, st, NULL, 0);
1178 
1179  /* XXX fts(3) needs/uses st_ino. */
1180  /* Hash the path to generate a st_ino analogue. */
1181  if (st->st_ino == 0)
1182  st->st_ino = hashFunctionString(0, path, 0);
1183 
1184 if (_ftp_debug)
1185 fprintf(stderr, "*** ftpStat(%s) rc %d\n%s", path, rc, statstr(st, buf));
1186  return rc;
1187 }
1188 
1189 /* FIXME: borked for path with trailing '/' */
1190 static int ftpLstat(const char * path, /*@out@*/ struct stat *st)
1191  /*@globals ftpBufAlloced, ftpBuf, h_errno, fileSystem, internalState @*/
1192  /*@modifies ftpBufAlloced, ftpBuf, *st, fileSystem, internalState @*/
1193 {
1194  char buf[1024];
1195  int rc;
1196  rc = ftpNLST(path, DO_FTP_LSTAT, st, NULL, 0);
1197 
1198  /* XXX fts(3) needs/uses st_ino. */
1199  /* Hash the path to generate a st_ino analogue. */
1200  if (st->st_ino == 0)
1201  st->st_ino = hashFunctionString(0, path, 0);
1202 
1203 if (_ftp_debug)
1204 fprintf(stderr, "*** ftpLstat(%s) rc %d\n%s\n", path, rc, statstr(st, buf));
1205  return rc;
1206 }
1207 
1208 static int ftpReadlink(const char * path, /*@out@*/ char * buf, size_t bufsiz)
1209  /*@globals ftpBufAlloced, ftpBuf, h_errno, fileSystem, internalState @*/
1210  /*@modifies ftpBufAlloced, ftpBuf, *buf, fileSystem, internalState @*/
1211 {
1212  int rc;
1213  rc = ftpNLST(path, DO_FTP_READLINK, NULL, buf, bufsiz);
1214 if (_ftp_debug)
1215 fprintf(stderr, "*** ftpReadlink(%s) rc %d\n", path, rc);
1216  return rc;
1217 }
1218 
1219 /*@null@*/
1220 static DIR * ftpOpendir(const char * path)
1221  /*@globals ftpBufAlloced, ftpBuf, h_errno, errno,
1222  fileSystem, internalState @*/
1223  /*@modifies ftpBufAlloced, ftpBuf, errno,
1224  fileSystem, internalState @*/
1225 {
1226  AVDIR avdir;
1227  avContext ctx;
1228  struct stat * st = NULL;
1229  const char * s, * sb, * se;
1230  int nac;
1231  int c;
1232  int rc;
1233 
1234 if (_ftp_debug)
1235 fprintf(stderr, "*** ftpOpendir(%s)\n", path);
1236 
1237  /* Load FTP collection into argv. */
1238  ctx = avContextCreate(path, st);
1239  if (ctx == NULL) {
1240  errno = ENOENT; /* Note: ctx is NULL iff urlSplit() fails. */
1241  return NULL;
1242  }
1243 
1244  rc = ftpNLST(path, DO_FTP_GLOB, NULL, NULL, 0);
1245  if (rc)
1246  return NULL;
1247 
1248  nac = 0;
1249  sb = NULL;
1250  s = se = ftpBuf;
1251  while ((c = (int) *se++) != (int) '\0') {
1252  switch (c) {
1253  case '/':
1254  sb = se;
1255  /*@switchbreak@*/ break;
1256  case '\r':
1257  if (sb == NULL) {
1258  for (sb = se; sb > s && sb[-1] != ' '; sb--)
1259  {};
1260  }
1261  nac++;
1262 
1263  if (*se == '\n') se++;
1264  sb = NULL;
1265  s = se;
1266  /*@switchbreak@*/ break;
1267  default:
1268  /*@switchbreak@*/ break;
1269  }
1270  }
1271 
1272  ctx->av = xcalloc(nac+1, sizeof(*ctx->av));
1273  ctx->modes = xcalloc(nac, sizeof(*ctx->modes));
1274 
1275  nac = 0;
1276  sb = NULL;
1277  s = se = ftpBuf;
1278  while ((c = (int) *se) != (int) '\0') {
1279  se++;
1280  switch (c) {
1281  case '/':
1282  sb = se;
1283  /*@switchbreak@*/ break;
1284  case '\r':
1285  if (sb == NULL) {
1286  ctx->modes[nac] = (*s == 'd' ? 0755 : 0644);
1287  /*@-unrecog@*/
1288  switch(*s) {
1289  case 'p': ctx->modes[nac] |= S_IFIFO; /*@innerbreak@*/ break;
1290  case 'c': ctx->modes[nac] |= S_IFCHR; /*@innerbreak@*/ break;
1291  case 'd': ctx->modes[nac] |= S_IFDIR; /*@innerbreak@*/ break;
1292  case 'b': ctx->modes[nac] |= S_IFBLK; /*@innerbreak@*/ break;
1293  case '-': ctx->modes[nac] |= S_IFREG; /*@innerbreak@*/ break;
1294  case 'l': ctx->modes[nac] |= S_IFLNK; /*@innerbreak@*/ break;
1295  case 's': ctx->modes[nac] |= S_IFSOCK; /*@innerbreak@*/ break;
1296  default: ctx->modes[nac] |= S_IFREG; /*@innerbreak@*/ break;
1297  }
1298  /*@=unrecog@*/
1299  for (sb = se; sb > s && sb[-1] != ' '; sb--)
1300  {};
1301  }
1302  ctx->av[nac++] = strncpy(xcalloc(1, (se-sb-1)+1), sb, (se-sb-1));
1303  if (*se == '\n') se++;
1304  sb = NULL;
1305  s = se;
1306  /*@switchbreak@*/ break;
1307  default:
1308  /*@switchbreak@*/ break;
1309  }
1310  }
1311 
1312  avdir = (AVDIR) avOpendir(path, ctx->av, ctx->modes);
1313 
1314  ctx = avContextDestroy(ctx);
1315 
1316 /*@-kepttrans@*/
1317  return (DIR *) avdir;
1318 /*@=kepttrans@*/
1319 }
1320 
1321 static char * ftpRealpath(const char * path, /*@null@*/ char * resolved_path)
1322  /*@*/
1323 {
1324 assert(resolved_path == NULL); /* XXX no POSIXly broken realpath(3) here. */
1325  /* XXX TODO: handle redirects. For now, just dupe the path. */
1326  return xstrdup(path);
1327 }
1328 
1329 int Stat(const char * path, struct stat * st)
1330  /*@globals ftpBufAlloced, ftpBuf @*/
1331  /*@modifies ftpBufAlloced, ftpBuf @*/
1332 {
1333  const char * lpath;
1334  int ut = urlPath(path, &lpath);
1335 
1336 if (_rpmio_debug)
1337 fprintf(stderr, "*** Stat(%s,%p)\n", path, st);
1338  switch (ut) {
1339  case URL_IS_FTP:
1340  return ftpStat(path, st);
1341  /*@notreached@*/ break;
1342  case URL_IS_HTTPS:
1343  case URL_IS_HTTP:
1344 #ifdef WITH_NEON
1345  return davStat(path, st);
1346 #endif
1347  /*@notreached@*/ break;
1348  case URL_IS_PATH:
1349  path = lpath;
1350  /*@fallthrough@*/
1351  case URL_IS_UNKNOWN:
1352  break;
1353  case URL_IS_DASH:
1354  case URL_IS_HKP:
1355  default:
1356  errno = ENOENT;
1357  return -2;
1358  /*@notreached@*/ break;
1359  }
1360  return stat(path, st);
1361 }
1362 
1363 int Lstat(const char * path, struct stat * st)
1364  /*@globals ftpBufAlloced, ftpBuf @*/
1365  /*@modifies ftpBufAlloced, ftpBuf @*/
1366 {
1367  const char * lpath;
1368  int ut = urlPath(path, &lpath);
1369 
1370 if (_rpmio_debug)
1371 fprintf(stderr, "*** Lstat(%s,%p)\n", path, st);
1372  switch (ut) {
1373  case URL_IS_FTP:
1374  return ftpLstat(path, st);
1375  /*@notreached@*/ break;
1376  case URL_IS_HTTPS:
1377  case URL_IS_HTTP:
1378 #ifdef WITH_NEON
1379  return davLstat(path, st);
1380 #endif
1381  /*@notreached@*/ break;
1382  case URL_IS_PATH:
1383  path = lpath;
1384  /*@fallthrough@*/
1385  case URL_IS_UNKNOWN:
1386  break;
1387  case URL_IS_DASH:
1388  case URL_IS_HKP:
1389  default:
1390  errno = ENOENT;
1391  return -2;
1392  /*@notreached@*/ break;
1393  }
1394  return lstat(path, st);
1395 }
1396 
1397 int Fstat(FD_t fd, struct stat * st)
1398 {
1399  const char * path = fdGetOPath(fd);
1400  const char * lpath;
1401  int ut = urlPath(path, &lpath);
1402 
1403 if (_rpmio_debug)
1404 fprintf(stderr, "*** Fstat(%p,%p) path %s\n", fd, st, path);
1405  if (fd == NULL || path == NULL || *path == '\0' || st == NULL) {
1406  errno = ENOENT;
1407  return -2;
1408  }
1409 
1410  switch (ut) {
1411  case URL_IS_DASH:
1412  case URL_IS_PATH:
1413  case URL_IS_UNKNOWN:
1414  break;
1415  case URL_IS_FTP:
1416  case URL_IS_HTTPS:
1417  case URL_IS_HTTP:
1418  case URL_IS_HKP:
1419  if (fd->contentLength < 0) {
1420  errno = ENOENT;
1421  return -2;
1422  }
1423  memset(st, 0, sizeof(*st));
1424  if (path[strlen(path)-1] == '/') {
1425  st->st_nlink = 2;
1426  st->st_mode = (S_IFDIR | 0755);
1427  } else {
1428  st->st_nlink = 1;
1429  st->st_mode = (S_IFREG | 0644);
1430  }
1431  st->st_ino = hashFunctionString(0, path, 0);;
1432  st->st_size = fd->contentLength;
1433  st->st_mtime = fd->lastModified;
1434 
1435  st->st_atime = st->st_ctime = st->st_mtime;
1436  st->st_blksize = 4 * 1024; /* HACK correct for linux ext */
1437  st->st_blocks = (st->st_size + 511)/512;
1438  break;
1439  default:
1440  errno = ENOENT;
1441  return -2;
1442  /*@notreached@*/ break;
1443  }
1444  return fstat(Fileno(fd), st);
1445 }
1446 
1447 int Chown(const char * path, uid_t owner, gid_t group)
1448 {
1449  const char * lpath;
1450  int ut = urlPath(path, &lpath);
1451 
1452 if (_rpmio_debug)
1453 fprintf(stderr, "*** Chown(%s,%u,%u)\n", path, (unsigned)owner, (unsigned)group);
1454  switch (ut) {
1455  case URL_IS_PATH:
1456  path = lpath;
1457  /*@fallthrough@*/
1458  case URL_IS_UNKNOWN:
1459  break;
1460  case URL_IS_DASH:
1461  case URL_IS_HKP:
1462  case URL_IS_FTP: /* XXX TODO: implement. */
1463  case URL_IS_HTTPS: /* XXX TODO: implement. */
1464  case URL_IS_HTTP: /* XXX TODO: implement. */
1465  default:
1466  errno = EINVAL; /* XXX W2DO? */
1467  return -2;
1468  /*@notreached@*/ break;
1469  }
1470  return chown(path, owner, group);
1471 }
1472 
1473 int Fchown(FD_t fd, uid_t owner, gid_t group)
1474 {
1475  const char * path = fdGetOPath(fd);
1476  const char * lpath;
1477  int ut = urlPath(path, &lpath);
1478 
1479 if (_rpmio_debug)
1480 fprintf(stderr, "*** Fchown(%p,%u,%u) path %s\n", fd, (unsigned)owner, (unsigned)group, path);
1481  switch (ut) {
1482  case URL_IS_PATH:
1483  path = lpath;
1484  /*@fallthrough@*/
1485  case URL_IS_UNKNOWN:
1486  break;
1487  case URL_IS_DASH:
1488  case URL_IS_HKP:
1489  case URL_IS_FTP: /* XXX TODO: implement. */
1490  case URL_IS_HTTPS: /* XXX TODO: implement. */
1491  case URL_IS_HTTP: /* XXX TODO: implement. */
1492  default:
1493  errno = EINVAL; /* XXX W2DO? */
1494  return -2;
1495  /*@notreached@*/ break;
1496  }
1497  return fchown(Fileno(fd), owner, group);
1498 }
1499 
1500 int Lchown(const char * path, uid_t owner, gid_t group)
1501 {
1502  const char * lpath;
1503  int ut = urlPath(path, &lpath);
1504 
1505 if (_rpmio_debug)
1506 fprintf(stderr, "*** Lchown(%s,%u,%u)\n", path, (unsigned)owner, (unsigned)group);
1507  switch (ut) {
1508  case URL_IS_PATH:
1509  path = lpath;
1510  /*@fallthrough@*/
1511  case URL_IS_UNKNOWN:
1512  break;
1513  case URL_IS_DASH:
1514  case URL_IS_HKP:
1515  case URL_IS_FTP: /* XXX TODO: implement. */
1516  case URL_IS_HTTPS: /* XXX TODO: implement. */
1517  case URL_IS_HTTP: /* XXX TODO: implement. */
1518  default:
1519  errno = EINVAL; /* XXX W2DO? */
1520  return -2;
1521  /*@notreached@*/ break;
1522  }
1523  return lchown(path, owner, group);
1524 }
1525 
1526 int Chmod(const char * path, mode_t mode)
1527 {
1528  const char * lpath;
1529  int ut = urlPath(path, &lpath);
1530 
1531 if (_rpmio_debug)
1532 fprintf(stderr, "*** Chmod(%s,%0o)\n", path, (int)mode);
1533  switch (ut) {
1534  case URL_IS_PATH:
1535  path = lpath;
1536  /*@fallthrough@*/
1537  case URL_IS_UNKNOWN:
1538  break;
1539  case URL_IS_DASH:
1540  case URL_IS_HKP:
1541  case URL_IS_FTP: /* XXX TODO: implement. */
1542  case URL_IS_HTTPS: /* XXX TODO: implement. */
1543  case URL_IS_HTTP: /* XXX TODO: implement. */
1544  default:
1545  errno = EINVAL; /* XXX W2DO? */
1546  return -2;
1547  /*@notreached@*/ break;
1548  }
1549  return chmod(path, mode);
1550 }
1551 
1552 int Fchmod(FD_t fd, mode_t mode)
1553 {
1554  const char * path = fdGetOPath(fd);
1555  const char * lpath;
1556  int ut = urlPath(path, &lpath);
1557 
1558 if (_rpmio_debug)
1559 fprintf(stderr, "*** Fchmod(%p,%0o) path %s\n", fd, (int)mode, path);
1560  switch (ut) {
1561  case URL_IS_PATH:
1562  path = lpath;
1563  /*@fallthrough@*/
1564  case URL_IS_UNKNOWN:
1565  break;
1566  case URL_IS_DASH:
1567  case URL_IS_HKP:
1568  case URL_IS_FTP: /* XXX TODO: implement. */
1569  case URL_IS_HTTPS: /* XXX TODO: implement. */
1570  case URL_IS_HTTP: /* XXX TODO: implement. */
1571  default:
1572  errno = EINVAL; /* XXX W2DO? */
1573  return -2;
1574  /*@notreached@*/ break;
1575  }
1576  return fchmod(Fileno(fd), mode);
1577 }
1578 
1579 int Mkfifo(const char * path, mode_t mode)
1580 {
1581  const char * lpath;
1582  int ut = urlPath(path, &lpath);
1583 
1584 if (_rpmio_debug)
1585 fprintf(stderr, "*** Mkfifo(%s,%0o)\n", path, (int)mode);
1586  switch (ut) {
1587  case URL_IS_PATH:
1588  path = lpath;
1589  /*@fallthrough@*/
1590  case URL_IS_UNKNOWN:
1591  break;
1592  case URL_IS_DASH:
1593  case URL_IS_HKP:
1594  case URL_IS_FTP: /* XXX TODO: implement. */
1595  case URL_IS_HTTPS: /* XXX TODO: implement. */
1596  case URL_IS_HTTP: /* XXX TODO: implement. */
1597  default:
1598  errno = EINVAL; /* XXX W2DO? */
1599  return -2;
1600  /*@notreached@*/ break;
1601  }
1602  return mkfifo(path, mode);
1603 }
1604 
1605 int Mknod(const char * path, mode_t mode, dev_t dev)
1606 {
1607  const char * lpath;
1608  int ut = urlPath(path, &lpath);
1609 
1610 if (_rpmio_debug)
1611 fprintf(stderr, "*** Mknod(%s,%0o, 0x%x)\n", path, (int)mode, (int)dev);
1612  switch (ut) {
1613  case URL_IS_PATH:
1614  path = lpath;
1615  /*@fallthrough@*/
1616  case URL_IS_UNKNOWN:
1617  break;
1618  case URL_IS_DASH:
1619  case URL_IS_HKP:
1620  case URL_IS_FTP: /* XXX TODO: implement. */
1621  case URL_IS_HTTPS: /* XXX TODO: implement. */
1622  case URL_IS_HTTP: /* XXX TODO: implement. */
1623  default:
1624  errno = EINVAL; /* XXX W2DO? */
1625  return -2;
1626  /*@notreached@*/ break;
1627  }
1628 /*@-portability@*/
1629  return mknod(path, mode, dev);
1630 /*@=portability@*/
1631 }
1632 
1633 int Utime(const char * path, const struct utimbuf *buf)
1634 {
1635  const char * lpath;
1636  int ut = urlPath(path, &lpath);
1637 
1638 if (_rpmio_debug)
1639 fprintf(stderr, "*** Utime(%s,%p)\n", path, buf);
1640  switch (ut) {
1641  case URL_IS_PATH:
1642  path = lpath;
1643  /*@fallthrough@*/
1644  case URL_IS_UNKNOWN:
1645  break;
1646  case URL_IS_DASH:
1647  case URL_IS_HKP:
1648  case URL_IS_FTP: /* XXX TODO: implement. */
1649  case URL_IS_HTTPS: /* XXX TODO: implement. */
1650  case URL_IS_HTTP: /* XXX TODO: implement. */
1651  default:
1652  errno = EINVAL; /* XXX W2DO? */
1653  return -2;
1654  /*@notreached@*/ break;
1655  }
1656  return utime(path, buf);
1657 }
1658 
1659 /*@-fixedformalarray@*/
1660 int Utimes(const char * path, const struct timeval times[2])
1661 {
1662  const char * lpath;
1663  int ut = urlPath(path, &lpath);
1664 
1665 if (_rpmio_debug)
1666 fprintf(stderr, "*** Utimes(%s,%p)\n", path, times);
1667  switch (ut) {
1668  case URL_IS_PATH:
1669  path = lpath;
1670  /*@fallthrough@*/
1671  case URL_IS_UNKNOWN:
1672  break;
1673  case URL_IS_DASH:
1674  case URL_IS_HKP:
1675  case URL_IS_FTP: /* XXX TODO: implement. */
1676  case URL_IS_HTTPS: /* XXX TODO: implement. */
1677  case URL_IS_HTTP: /* XXX TODO: implement. */
1678  default:
1679  errno = EINVAL; /* XXX W2DO? */
1680  return -2;
1681  /*@notreached@*/ break;
1682  }
1683  return utimes(path, times);
1684 }
1685 /*@=fixedformalarray@*/
1686 
1687 int Symlink(const char * oldpath, const char * newpath)
1688 {
1689  const char * opath;
1690  int out = urlPath(oldpath, &opath);
1691  const char * npath;
1692  int nut = urlPath(newpath, &npath);
1693 
1694  nut = 0; /* XXX keep gcc quiet. */
1695 if (_rpmio_debug)
1696 fprintf(stderr, "*** Symlink(%s,%s)\n", oldpath, newpath);
1697  switch (out) {
1698  case URL_IS_PATH:
1699  oldpath = opath;
1700  newpath = npath;
1701  /*@fallthrough@*/
1702  case URL_IS_UNKNOWN:
1703  break;
1704  case URL_IS_DASH:
1705  case URL_IS_HKP:
1706  case URL_IS_FTP: /* XXX TODO: implement. */
1707  case URL_IS_HTTPS: /* XXX TODO: implement. */
1708  case URL_IS_HTTP: /* XXX TODO: implement. */
1709  default:
1710  errno = EINVAL; /* XXX W2DO? */
1711  return -2;
1712  /*@notreached@*/ break;
1713  }
1714  return symlink(oldpath, newpath);
1715 }
1716 
1717 int Readlink(const char * path, char * buf, size_t bufsiz)
1718  /*@globals ftpBufAlloced, ftpBuf @*/
1719  /*@modifies ftpBufAlloced, ftpBuf @*/
1720 {
1721  const char * lpath;
1722  int ut = urlPath(path, &lpath);
1723 
1724 if (_rpmio_debug)
1725 fprintf(stderr, "*** Readlink(%s,%p[%u])\n", path, buf, (unsigned)bufsiz);
1726  switch (ut) {
1727  case URL_IS_FTP:
1728  return ftpReadlink(path, buf, bufsiz);
1729  /*@notreached@*/ break;
1730  case URL_IS_HTTPS:
1731  case URL_IS_HTTP:
1732 #ifdef NOTYET
1733  return davReadlink(path, buf, bufsiz);
1734 #else
1735  return -2;
1736 #endif
1737  /*@notreached@*/ break;
1738  case URL_IS_PATH:
1739  path = lpath;
1740  /*@fallthrough@*/
1741  case URL_IS_UNKNOWN:
1742  break;
1743  case URL_IS_DASH:
1744  case URL_IS_HKP:
1745  default:
1746  errno = EINVAL; /* XXX W2DO? */
1747  return -2;
1748  /*@notreached@*/ break;
1749  }
1750 /*@-compdef@*/ /* FIX: *buf is undefined */
1751  return readlink(path, buf, bufsiz);
1752 /*@=compdef@*/
1753 }
1754 
1755 int Access(const char * path, int amode)
1756 {
1757  const char * lpath;
1758  int ut = urlPath(path, &lpath);
1759 
1760 if (_rpmio_debug)
1761 fprintf(stderr, "*** Access(%s,%d)\n", path, amode);
1762  switch (ut) {
1763  case URL_IS_PATH:
1764  path = lpath;
1765  /*@fallthrough@*/
1766  case URL_IS_UNKNOWN:
1767  break;
1768  case URL_IS_DASH:
1769  case URL_IS_HKP:
1770  case URL_IS_HTTPS: /* XXX TODO: implement. */
1771  case URL_IS_HTTP: /* XXX TODO: implement. */
1772  case URL_IS_FTP: /* XXX TODO: implement. */
1773  default:
1774  errno = EINVAL; /* XXX W2DO? */
1775  return -2;
1776  /*@notreached@*/ break;
1777  }
1778  return access(path, amode);
1779 }
1780 
1781 /* glob_pattern_p() taken from bash
1782  * Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
1783  *
1784  * Return nonzero if PATTERN has any special globbing chars in it.
1785  */
1786 int Glob_pattern_p (const char * pattern, int quote)
1787 {
1788  const char *p;
1789  int ut = urlPath(pattern, &p);
1790  int open = 0;
1791  char c;
1792 
1793  while ((c = *p++) != '\0')
1794  switch (c) {
1795  case '?':
1796  /* Don't treat '?' as a glob char in HTTP URL's */
1797  if (ut == URL_IS_HTTPS || ut == URL_IS_HTTP || ut == URL_IS_HKP)
1798  continue;
1799  /*@fallthrough@*/
1800  case '*':
1801  return (1);
1802  case '\\':
1803  if (quote && *p != '\0')
1804  p++;
1805  continue;
1806 
1807  case '[':
1808  open = 1;
1809  continue;
1810  case ']':
1811  if (open)
1812  return (1);
1813  continue;
1814 
1815  case '+':
1816  case '@':
1817  case '!':
1818  if (*p == '(')
1819  return (1);
1820  continue;
1821  }
1822 
1823  return (0);
1824 }
1825 
1826 int Glob_error(/*@unused@*/ const char * epath,
1827  /*@unused@*/ int eerrno)
1828 {
1829  return 1;
1830 }
1831 
1832 int Glob(const char *pattern, int flags,
1833  int errfunc(const char * epath, int eerrno), void *_pglob)
1834 {
1835  glob_t *pglob = _pglob;
1836  const char * lpath;
1837  int ut = urlPath(pattern, &lpath);
1838  const char *home = getenv("HOME");
1839 
1840 /*@-castfcnptr@*/
1841 if (_rpmio_debug)
1842 fprintf(stderr, "*** Glob(%s,0x%x,%p,%p)\n", pattern, (unsigned)flags, (void *)errfunc, pglob);
1843 /*@=castfcnptr@*/
1844  switch (ut) {
1845  case URL_IS_HTTPS:
1846  case URL_IS_HTTP:
1847  case URL_IS_FTP:
1848 /*@-type@*/
1849  pglob->gl_closedir = (void *) Closedir;
1850  pglob->gl_readdir = (void *) Readdir;
1851  pglob->gl_opendir = (void *) Opendir;
1852  pglob->gl_lstat = Lstat;
1853  pglob->gl_stat = Stat;
1854 /*@=type@*/
1855  flags |= GLOB_ALTDIRFUNC;
1856  flags &= ~GLOB_TILDE;
1857  break;
1858  case URL_IS_PATH:
1859  pattern = lpath;
1860  /*@fallthrough@*/
1861  case URL_IS_UNKNOWN:
1862  if (home && home[0])
1863  flags |= GLOB_TILDE;
1864  else
1865  flags &= ~GLOB_TILDE;
1866  break;
1867  case URL_IS_DASH:
1868  case URL_IS_HKP:
1869  default:
1870  return -2;
1871  /*@notreached@*/ break;
1872  }
1873  return glob(pattern, flags, errfunc, pglob);
1874 }
1875 
1876 void Globfree(void *_pglob)
1877 {
1878  glob_t *pglob = _pglob;
1879 if (_rpmio_debug)
1880 fprintf(stderr, "*** Globfree(%p)\n", pglob);
1881  globfree(pglob);
1882 }
1883 
1884 DIR * Opendir(const char * path)
1885  /*@globals ftpBufAlloced, ftpBuf @*/
1886  /*@modifies ftpBufAlloced, ftpBuf @*/
1887 {
1888  const char * lpath;
1889  int ut = urlPath(path, &lpath);
1890 
1891 if (_rpmio_debug)
1892 fprintf(stderr, "*** Opendir(%s)\n", path);
1893  switch (ut) {
1894  case URL_IS_FTP:
1895  return ftpOpendir(path);
1896  /*@notreached@*/ break;
1897  case URL_IS_HTTPS:
1898  case URL_IS_HTTP:
1899 #ifdef WITH_NEON
1900  return davOpendir(path);
1901 #endif
1902  /*@notreached@*/ break;
1903  case URL_IS_PATH:
1904  path = lpath;
1905  /*@fallthrough@*/
1906  case URL_IS_UNKNOWN:
1907  break;
1908  case URL_IS_DASH:
1909  case URL_IS_HKP:
1910  default:
1911  return NULL;
1912  /*@notreached@*/ break;
1913  }
1914  /*@-dependenttrans@*/
1915  return opendir(path);
1916  /*@=dependenttrans@*/
1917 }
1918 
1919 struct dirent * Readdir(DIR * dir)
1920 {
1921 if (_rpmio_debug)
1922 fprintf(stderr, "*** Readdir(%p)\n", (void *)dir);
1923  if (dir == NULL)
1924  return NULL;
1925  if (ISAVMAGIC(dir))
1926  return avReaddir(dir);
1927  return readdir(dir);
1928 }
1929 
1930 int Closedir(DIR * dir)
1931 {
1932 if (_rpmio_debug)
1933 fprintf(stderr, "*** Closedir(%p)\n", (void *)dir);
1934  if (dir == NULL)
1935  return 0;
1936  if (ISAVMAGIC(dir))
1937  return avClosedir(dir);
1938  return closedir(dir);
1939 }
1940 
1941 char * Realpath(const char * path, /*@null@*/ char * resolved_path)
1942 {
1943  const char * lpath;
1944  int ut = urlPath(path, &lpath);
1945  char * rpath = NULL;
1946 
1947 if (_rpmio_debug)
1948 fprintf(stderr, "*** Realpath(%s, %s)\n", path, (resolved_path ? resolved_path : "NULL"));
1949 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */
1950 /*@-nullpass@*/
1951  /* XXX if POSIXly broken realpath(3) is desired, do that. */
1952  /* XXX note: preserves current rpmlib realpath(3) usage cases. */
1953  if (path == NULL || resolved_path != NULL)
1954  return realpath(path, resolved_path);
1955 /*@=nullpass@*/
1956 #endif /* !__LCLINT__ */
1957 
1958  switch (ut) {
1959  case URL_IS_FTP:
1960  return ftpRealpath(path, resolved_path);
1961  /*@notreached@*/ break;
1962  case URL_IS_HTTPS:
1963  case URL_IS_HTTP:
1964  case URL_IS_HKP:
1965 #ifdef WITH_NEON
1966  return davRealpath(path, resolved_path);
1967  /*@notreached@*/ break;
1968 #endif
1969  /*@fallthrough@*/
1970  default:
1971  return xstrdup(path);
1972  /*@notreached@*/ break;
1973  case URL_IS_DASH:
1974  /* non-GLIBC systems => EINVAL. non-linux systems => EINVAL */
1975 #if defined(__linux__)
1976  lpath = "/dev/stdin";
1977 #else
1978  lpath = NULL;
1979 #endif
1980  break;
1981  case URL_IS_PATH: /* XXX note: file:/// prefix is dropped. */
1982  case URL_IS_UNKNOWN:
1983  path = lpath;
1984  break;
1985  }
1986 
1987 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */
1988  if (lpath == NULL || *lpath == '/')
1989 /*@-nullpass@*/ /* XXX glibc extension */
1990  rpath = realpath(lpath, resolved_path);
1991 /*@=nullpass@*/
1992  else {
1993  char * t;
1994 #if defined(__GLIBC__)
1995  char * dn = NULL;
1996 #else
1997  char dn[PATH_MAX];
1998  dn[0] = '\0';
1999 #endif
2000  /*
2001  * Using realpath on lpath isn't correct if the lpath is a symlink,
2002  * especially if the symlink is a dangling link. What we
2003  * do instead is use realpath() on `.' and then append lpath to
2004  * the result.
2005  */
2006  if ((t = realpath(".", dn)) != NULL) {
2007 /*@-globs -mods@*/ /* XXX no rpmGlobalMacroContext mods please. */
2008  rpath = (char *) rpmGetPath(t, "/", lpath, NULL);
2009  /* XXX preserve the pesky trailing '/' */
2010  if (lpath[strlen(lpath)-1] == '/') {
2011  char * s = rpath;
2012  rpath = rpmExpand(s, "/", NULL);
2013  s = _free(s);
2014  }
2015 /*@=globs =mods@*/
2016  } else
2017  rpath = NULL;
2018 #if defined(__GLIBC__)
2019  t = _free(t);
2020 #endif
2021  }
2022 #endif /* !__LCLINT__ */
2023 
2024  return rpath;
2025 }
2026 
2027 off_t Lseek(int fdno, off_t offset, int whence)
2028 {
2029 if (_rpmio_debug)
2030 fprintf(stderr, "*** Lseek(%d,0x%lx,%d)\n", fdno, (long)offset, whence);
2031  return lseek(fdno, offset, whence);
2032 }