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