1/*- 2 * Copyright (c) 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 23 unchanged lines hidden (view full) --- 32 * 33 * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ 34 */ 35 36#if defined(LIBC_SCCS) && !defined(lint) 37static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; 38#endif /* LIBC_SCCS and not lint */ 39#include <sys/cdefs.h> |
40__FBSDID("$FreeBSD: head/lib/libc/gen/fts-compat.c 129052 2004-05-08 15:09:02Z peadar $"); |
41 42#include "namespace.h" 43#include <sys/types.h> 44#include <sys/param.h> 45#include <sys/stat.h> |
46#include <sys/mount.h> |
47 48#include <dirent.h> 49#include <errno.h> 50#include <fcntl.h> 51#include <fts.h> 52#include <stdlib.h> 53#include <string.h> 54#include <unistd.h> --- 4 unchanged lines hidden (view full) --- 59static void fts_lfree(FTSENT *); 60static void fts_load(FTS *, FTSENT *); 61static size_t fts_maxarglen(char * const *); 62static void fts_padjust(FTS *, FTSENT *); 63static int fts_palloc(FTS *, size_t); 64static FTSENT *fts_sort(FTS *, FTSENT *, int); 65static u_short fts_stat(FTS *, FTSENT *, int); 66static int fts_safe_changedir(FTS *, FTSENT *, int, char *); |
67static int fts_ufslinks(FTS *sp, const FTSENT *ent); |
68 69#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) 70 71#define CLR(opt) (sp->fts_options &= ~(opt)) 72#define ISSET(opt) (sp->fts_options & (opt)) 73#define SET(opt) (sp->fts_options |= (opt)) 74 75#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) 76 77/* fts_build flags */ 78#define BCHILD 1 /* fts_children */ 79#define BNAMES 2 /* fts_children, names only */ 80#define BREAD 3 /* fts_read */ 81 |
82/* 83 * Internal representation of FTS, including extra implementation details. 84 * The FTS returned from fts_open is ftsp_fts from this structure, and it's 85 * fts_priv in turn points back to this internal version. i.e. for a given 86 * fts_private *priv: &priv->fts_fts == (FTS *)f == priv->fts_fts.fts_priv 87 */ 88struct _fts_private { 89 FTS ftsp_fts; 90 struct statfs ftsp_statfs; 91 dev_t ftsp_dev; 92 int ftsp_linksreliable; 93}; 94 95/* 96 * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it knows 97 * that a directory could not possibly have subdirectories. This is decided 98 * by looking at the link count: A subdirectory would increment its parent's 99 * link count by virtue of its own ".." entry. 100 * This assumption only holds for UFS-like filesystems that implement links 101 * and directories this way, so we must punt for others. 102 */ 103 104static const char *ufslike_filesystems[] = { 105 "ufs", 106 "nfs", 107 "nfs4", 108 "ext2fs", 109 0 110}; 111 |
112FTS * 113fts_open(argv, options, compar) 114 char * const *argv; 115 int options; 116 int (*compar)(const FTSENT * const *, const FTSENT * const *); 117{ |
118 struct _fts_private *priv; |
119 FTS *sp; 120 FTSENT *p, *root; 121 int nitems; 122 FTSENT *parent, *tmp; 123 int len; 124 125 /* Options check. */ 126 if (options & ~FTS_OPTIONMASK) { 127 errno = EINVAL; 128 return (NULL); 129 } 130 131 /* Allocate/initialize the stream */ |
132 if ((priv = malloc(sizeof(struct _fts_private))) == NULL) |
133 return (NULL); |
134 memset(priv, 0, sizeof(struct _fts_private)); 135 sp = &priv->ftsp_fts; |
136 sp->fts_compar = compar; 137 sp->fts_options = options; |
138 sp->fts_priv = priv; |
139 140 /* Shush, GCC. */ 141 tmp = NULL; 142 143 /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ 144 if (ISSET(FTS_LOGICAL)) 145 SET(FTS_NOCHDIR); 146 --- 520 unchanged lines hidden (view full) --- 667 * directory if we're cheating on stat calls, 0 if we're not doing 668 * any stat calls at all, -1 if we're doing stats on everything. 669 */ 670 if (type == BNAMES) { 671 nlinks = 0; 672 /* Be quiet about nostat, GCC. */ 673 nostat = 0; 674 } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { |
675 if (fts_ufslinks(sp, cur)) 676 nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); 677 else 678 nlinks = -1; |
679 nostat = 1; 680 } else { 681 nlinks = -1; 682 nostat = 0; 683 } 684 685#ifdef notdef 686 (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); --- 500 unchanged lines hidden (view full) --- 1187 ret = fchdir(newfd); 1188bail: 1189 oerrno = errno; 1190 if (fd < 0) 1191 (void)_close(newfd); 1192 errno = oerrno; 1193 return (ret); 1194} |
1195 1196/* 1197 * Check if the filesystem for "ent" has UFS-style links. 1198 */ 1199static int 1200fts_ufslinks(FTS *sp, const FTSENT *ent) 1201{ 1202 struct _fts_private *priv; 1203 const char **cpp; 1204 1205 priv = sp->fts_priv; 1206 /* 1207 * If this node's device is different from the previous, grab 1208 * the filesystem information, and decide on the reliability 1209 * of the link information from this filesystem for stat(2) 1210 * avoidance. 1211 */ 1212 if (priv->ftsp_dev != ent->fts_dev) { 1213 if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { 1214 priv->ftsp_dev = ent->fts_dev; 1215 priv->ftsp_linksreliable = 0; 1216 for (cpp = ufslike_filesystems; *cpp; cpp++) { 1217 if (strcmp(priv->ftsp_statfs.f_fstypename, 1218 *cpp) == 0) { 1219 priv->ftsp_linksreliable = 1; 1220 break; 1221 } 1222 } 1223 } else { 1224 priv->ftsp_linksreliable = 0; 1225 } 1226 } 1227 return priv->ftsp_linksreliable; 1228} |