| File: | src/usr.bin/du/du.c |
| Warning: | line 299, column 2 Potential leak of memory pointed to by 'le' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: du.c,v 1.33 2022/12/04 23:50:48 cheloha Exp $ */ | |||
| 2 | /* $NetBSD: du.c,v 1.11 1996/10/18 07:20:35 thorpej Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1989, 1993, 1994 | |||
| 6 | * The Regents of the University of California. All rights reserved. | |||
| 7 | * | |||
| 8 | * This code is derived from software contributed to Berkeley by | |||
| 9 | * Chris Newcomb. | |||
| 10 | * | |||
| 11 | * Redistribution and use in source and binary forms, with or without | |||
| 12 | * modification, are permitted provided that the following conditions | |||
| 13 | * are met: | |||
| 14 | * 1. Redistributions of source code must retain the above copyright | |||
| 15 | * notice, this list of conditions and the following disclaimer. | |||
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 17 | * notice, this list of conditions and the following disclaimer in the | |||
| 18 | * documentation and/or other materials provided with the distribution. | |||
| 19 | * 3. Neither the name of the University nor the names of its contributors | |||
| 20 | * may be used to endorse or promote products derived from this software | |||
| 21 | * without specific prior written permission. | |||
| 22 | * | |||
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 33 | * SUCH DAMAGE. | |||
| 34 | */ | |||
| 35 | ||||
| 36 | #include <sys/types.h> | |||
| 37 | #include <sys/stat.h> | |||
| 38 | ||||
| 39 | #include <dirent.h> | |||
| 40 | #include <err.h> | |||
| 41 | #include <errno(*__errno()).h> | |||
| 42 | #include <fts.h> | |||
| 43 | #include <limits.h> | |||
| 44 | #include <stdio.h> | |||
| 45 | #include <stdlib.h> | |||
| 46 | #include <string.h> | |||
| 47 | #include <sys/tree.h> | |||
| 48 | #include <unistd.h> | |||
| 49 | #include <util.h> | |||
| 50 | ||||
| 51 | ||||
| 52 | int linkchk(FTSENT *); | |||
| 53 | void prtout(int64_t, char *, int); | |||
| 54 | void usage(void); | |||
| 55 | ||||
| 56 | int | |||
| 57 | main(int argc, char *argv[]) | |||
| 58 | { | |||
| 59 | FTS *fts; | |||
| 60 | FTSENT *p; | |||
| 61 | long blocksize; | |||
| 62 | int64_t totalblocks; | |||
| 63 | int ftsoptions, listfiles, maxdepth; | |||
| 64 | int Hflag, Lflag, cflag, hflag, kflag; | |||
| 65 | int ch, notused, rval; | |||
| 66 | char **save; | |||
| 67 | const char *errstr; | |||
| 68 | ||||
| 69 | if (pledge("stdio rpath", NULL((void *)0)) == -1) | |||
| ||||
| 70 | err(1, "pledge"); | |||
| 71 | ||||
| 72 | save = argv; | |||
| 73 | Hflag = Lflag = cflag = hflag = kflag = listfiles = 0; | |||
| 74 | totalblocks = 0; | |||
| 75 | ftsoptions = FTS_PHYSICAL0x0010; | |||
| 76 | maxdepth = -1; | |||
| 77 | while ((ch = getopt(argc, argv, "HLPacd:hkrsx")) != -1) | |||
| 78 | switch (ch) { | |||
| 79 | case 'H': | |||
| 80 | Hflag = 1; | |||
| 81 | Lflag = 0; | |||
| 82 | break; | |||
| 83 | case 'L': | |||
| 84 | Lflag = 1; | |||
| 85 | Hflag = 0; | |||
| 86 | break; | |||
| 87 | case 'P': | |||
| 88 | Hflag = Lflag = 0; | |||
| 89 | break; | |||
| 90 | case 'a': | |||
| 91 | listfiles = 1; | |||
| 92 | break; | |||
| 93 | case 'c': | |||
| 94 | cflag = 1; | |||
| 95 | break; | |||
| 96 | case 'd': | |||
| 97 | maxdepth = strtonum(optarg, 0, INT_MAX0x7fffffff, &errstr); | |||
| 98 | if (errstr) { | |||
| 99 | warnx("max depth %s: %s", optarg, errstr); | |||
| 100 | usage(); | |||
| 101 | } | |||
| 102 | break; | |||
| 103 | case 'h': | |||
| 104 | hflag = 1; | |||
| 105 | kflag = 0; | |||
| 106 | break; | |||
| 107 | case 'k': | |||
| 108 | kflag = 1; | |||
| 109 | hflag = 0; | |||
| 110 | break; | |||
| 111 | case 's': | |||
| 112 | maxdepth = 0; | |||
| 113 | break; | |||
| 114 | case 'r': | |||
| 115 | break; | |||
| 116 | case 'x': | |||
| 117 | ftsoptions |= FTS_XDEV0x0040; | |||
| 118 | break; | |||
| 119 | default: | |||
| 120 | usage(); | |||
| 121 | } | |||
| 122 | argc -= optind; | |||
| 123 | argv += optind; | |||
| 124 | ||||
| 125 | /* | |||
| 126 | * XXX | |||
| 127 | * Because of the way that fts(3) works, logical walks will not count | |||
| 128 | * the blocks actually used by symbolic links. We rationalize this by | |||
| 129 | * noting that users computing logical sizes are likely to do logical | |||
| 130 | * copies, so not counting the links is correct. The real reason is | |||
| 131 | * that we'd have to re-implement the kernel's symbolic link traversing | |||
| 132 | * algorithm to get this right. If, for example, you have relative | |||
| 133 | * symbolic links referencing other relative symbolic links, it gets | |||
| 134 | * very nasty, very fast. The bottom line is that it's documented in | |||
| 135 | * the man page, so it's a feature. | |||
| 136 | */ | |||
| 137 | if (Hflag
| |||
| 138 | ftsoptions |= FTS_COMFOLLOW0x0001; | |||
| 139 | if (Lflag
| |||
| 140 | ftsoptions &= ~FTS_PHYSICAL0x0010; | |||
| 141 | ftsoptions |= FTS_LOGICAL0x0002; | |||
| 142 | } | |||
| 143 | ||||
| 144 | if (maxdepth == -1) | |||
| 145 | maxdepth = INT_MAX0x7fffffff; | |||
| 146 | ||||
| 147 | if (!*argv) { | |||
| 148 | argv = save; | |||
| 149 | argv[0] = "."; | |||
| 150 | argv[1] = NULL((void *)0); | |||
| 151 | } | |||
| 152 | ||||
| 153 | if (hflag
| |||
| 154 | blocksize = 512; | |||
| 155 | else if (kflag
| |||
| 156 | blocksize = 1024; | |||
| 157 | else | |||
| 158 | (void)getbsize(¬used, &blocksize); | |||
| 159 | blocksize /= 512; | |||
| 160 | ||||
| 161 | if ((fts = fts_open(argv, ftsoptions, NULL((void *)0))) == NULL((void *)0)) | |||
| 162 | err(1, "fts_open"); | |||
| 163 | ||||
| 164 | for (rval = 0; (p = fts_read(fts)) != NULL((void *)0);) | |||
| 165 | switch (p->fts_info) { | |||
| 166 | case FTS_D1: /* Ignore. */ | |||
| 167 | break; | |||
| 168 | case FTS_DP6: | |||
| 169 | p->fts_parent->fts_number += | |||
| 170 | p->fts_number += p->fts_statp->st_blocks; | |||
| 171 | if (cflag) | |||
| 172 | totalblocks += p->fts_statp->st_blocks; | |||
| 173 | /* | |||
| 174 | * If listing each directory, or not listing files | |||
| 175 | * or directories and this is post-order of the | |||
| 176 | * root of a traversal, display the total. | |||
| 177 | */ | |||
| 178 | if (p->fts_level <= maxdepth) | |||
| 179 | prtout(howmany(p->fts_number,(((p->fts_number) + (((unsigned long)blocksize) - 1)) / (( unsigned long)blocksize)) | |||
| 180 | (unsigned long)blocksize)(((p->fts_number) + (((unsigned long)blocksize) - 1)) / (( unsigned long)blocksize)), p->fts_path, | |||
| 181 | hflag); | |||
| 182 | break; | |||
| 183 | case FTS_DC2: /* Ignore. */ | |||
| 184 | break; | |||
| 185 | case FTS_DNR4: /* Warn, continue. */ | |||
| 186 | case FTS_ERR7: | |||
| 187 | case FTS_NS10: | |||
| 188 | warnc(p->fts_errno, "%s", p->fts_path); | |||
| 189 | rval = 1; | |||
| 190 | break; | |||
| 191 | default: | |||
| 192 | if (p->fts_statp->st_nlink > 1 && linkchk(p)) | |||
| 193 | break; | |||
| 194 | /* | |||
| 195 | * If listing each file, or a non-directory file was | |||
| 196 | * the root of a traversal, display the total. | |||
| 197 | */ | |||
| 198 | if ((listfiles && p->fts_level <= maxdepth) || | |||
| 199 | p->fts_level == FTS_ROOTLEVEL0) | |||
| 200 | prtout(howmany(p->fts_statp->st_blocks,(((p->fts_statp->st_blocks) + ((blocksize) - 1)) / (blocksize )) | |||
| 201 | blocksize)(((p->fts_statp->st_blocks) + ((blocksize) - 1)) / (blocksize )), p->fts_path, hflag); | |||
| 202 | p->fts_parent->fts_number += p->fts_statp->st_blocks; | |||
| 203 | if (cflag) | |||
| 204 | totalblocks += p->fts_statp->st_blocks; | |||
| 205 | } | |||
| 206 | if (errno(*__errno())) | |||
| 207 | err(1, "fts_read"); | |||
| 208 | if (cflag) { | |||
| 209 | prtout(howmany(totalblocks, blocksize)(((totalblocks) + ((blocksize) - 1)) / (blocksize)), "total", hflag); | |||
| 210 | } | |||
| 211 | fts_close(fts); | |||
| 212 | exit(rval); | |||
| 213 | } | |||
| 214 | ||||
| 215 | ||||
| 216 | struct links_entry { | |||
| 217 | RB_ENTRY(links_entry)struct { struct links_entry *rbe_left; struct links_entry *rbe_right ; struct links_entry *rbe_parent; int rbe_color; } entry; | |||
| 218 | struct links_entry *fnext; | |||
| 219 | int links; | |||
| 220 | dev_t dev; | |||
| 221 | ino_t ino; | |||
| 222 | }; | |||
| 223 | ||||
| 224 | static int | |||
| 225 | links_cmp(struct links_entry *e1, struct links_entry *e2) | |||
| 226 | { | |||
| 227 | if (e1->dev == e2->dev) { | |||
| 228 | if (e1->ino == e2->ino) | |||
| 229 | return (0); | |||
| 230 | else | |||
| 231 | return (e1->ino < e2->ino ? -1 : 1); | |||
| 232 | } | |||
| 233 | else | |||
| 234 | return (e1->dev < e2->dev ? -1 : 1); | |||
| 235 | } | |||
| 236 | ||||
| 237 | RB_HEAD(ltree, links_entry)struct ltree { struct links_entry *rbh_root; } links = RB_INITIALIZER(&links){ ((void *)0) }; | |||
| 238 | ||||
| 239 | RB_GENERATE_STATIC(ltree, links_entry, entry, links_cmp)__attribute__((__unused__)) static void ltree_RB_INSERT_COLOR (struct ltree *head, struct links_entry *elm) { struct links_entry *parent, *gparent, *tmp; while ((parent = (elm)->entry.rbe_parent ) && (parent)->entry.rbe_color == 1) { gparent = ( parent)->entry.rbe_parent; if (parent == (gparent)->entry .rbe_left) { tmp = (gparent)->entry.rbe_right; if (tmp && (tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (parent)->entry.rbe_color = 0; (gparent)->entry .rbe_color = 1; } while (0); elm = gparent; continue; } if (( parent)->entry.rbe_right == elm) { do { (tmp) = (parent)-> entry.rbe_right; if (((parent)->entry.rbe_right = (tmp)-> entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent )->entry.rbe_parent)->entry.rbe_left) ((parent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry .rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)-> entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)-> entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent )->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((gparent)-> entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.rbe_right = (gparent); (gparent )->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> entry.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->entry.rbe_left; if (tmp && (tmp)-> entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { ( parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)-> entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left ; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right )) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->entry.rbe_color = 0; (gparent)-> entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> entry.rbe_right; if (((gparent)->entry.rbe_right = (tmp)-> entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent = (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent )->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry .rbe_parent)->entry.rbe_left = (tmp); else ((gparent)-> entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->entry.rbe_left = (gparent); (gparent )->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> entry.rbe_parent)) do {} while (0); } while (0); } } (head-> rbh_root)->entry.rbe_color = 0; } __attribute__((__unused__ )) static void ltree_RB_REMOVE_COLOR(struct ltree *head, struct links_entry *parent, struct links_entry *elm) { struct links_entry *tmp; while ((elm == ((void *)0) || (elm)->entry.rbe_color == 0) && elm != (head)->rbh_root) { if ((parent)-> entry.rbe_left == elm) { tmp = (parent)->entry.rbe_right; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while (0); do { (tmp ) = (parent)->entry.rbe_right; if (((parent)->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left)-> entry.rbe_parent = (parent); } do {} while (0); if (((tmp)-> entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent ) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent )->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent )->entry.rbe_parent)->entry.rbe_right = (tmp); } else ( head)->rbh_root = (tmp); (tmp)->entry.rbe_left = (parent ); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) && ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp )->entry.rbe_color = 1; elm = parent; parent = (elm)->entry .rbe_parent; } else { if ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0 ) { struct links_entry *oleft; if ((oleft = (tmp)->entry.rbe_left )) (oleft)->entry.rbe_color = 0; (tmp)->entry.rbe_color = 1; do { (oleft) = (tmp)->entry.rbe_left; if (((tmp)-> entry.rbe_left = (oleft)->entry.rbe_right)) { ((oleft)-> entry.rbe_right)->entry.rbe_parent = (tmp); } do {} while ( 0); if (((oleft)->entry.rbe_parent = (tmp)->entry.rbe_parent )) { if ((tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left ) ((tmp)->entry.rbe_parent)->entry.rbe_left = (oleft); else ((tmp)->entry.rbe_parent)->entry.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (oleft)->entry.rbe_right = (tmp); (tmp)->entry.rbe_parent = (oleft); do {} while ( 0); if (((oleft)->entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right; } (tmp)->entry.rbe_color = (parent)->entry.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry.rbe_right) ((tmp)->entry.rbe_right )->entry.rbe_color = 0; do { (tmp) = (parent)->entry.rbe_right ; if (((parent)->entry.rbe_right = (tmp)->entry.rbe_left )) { ((tmp)->entry.rbe_left)->entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent )->entry.rbe_parent)) { if ((parent) == ((parent)->entry .rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent )->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent )->entry.rbe_right = (tmp); } else (head)->rbh_root = ( tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry .rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent )) do {} while (0); } while (0); elm = (head)->rbh_root; break ; } } else { tmp = (parent)->entry.rbe_left; if ((tmp)-> entry.rbe_color == 1) { do { (tmp)->entry.rbe_color = 0; ( parent)->entry.rbe_color = 1; } while (0); do { (tmp) = (parent )->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp )->entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->entry .rbe_parent = (parent)->entry.rbe_parent)) { if ((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent )->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent )->entry.rbe_parent)->entry.rbe_right = (tmp); } else ( head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent ); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) && ((tmp)->entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color == 0)) { (tmp )->entry.rbe_color = 1; elm = parent; parent = (elm)->entry .rbe_parent; } else { if ((tmp)->entry.rbe_left == ((void * )0) || ((tmp)->entry.rbe_left)->entry.rbe_color == 0) { struct links_entry *oright; if ((oright = (tmp)->entry.rbe_right )) (oright)->entry.rbe_color = 0; (tmp)->entry.rbe_color = 1; do { (oright) = (tmp)->entry.rbe_right; if (((tmp)-> entry.rbe_right = (oright)->entry.rbe_left)) { ((oright)-> entry.rbe_left)->entry.rbe_parent = (tmp); } do {} while ( 0); if (((oright)->entry.rbe_parent = (tmp)->entry.rbe_parent )) { if ((tmp) == ((tmp)->entry.rbe_parent)->entry.rbe_left ) ((tmp)->entry.rbe_parent)->entry.rbe_left = (oright); else ((tmp)->entry.rbe_parent)->entry.rbe_right = (oright ); } else (head)->rbh_root = (oright); (oright)->entry. rbe_left = (tmp); (tmp)->entry.rbe_parent = (oright); do { } while (0); if (((oright)->entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left; } (tmp) ->entry.rbe_color = (parent)->entry.rbe_color; (parent) ->entry.rbe_color = 0; if ((tmp)->entry.rbe_left) ((tmp )->entry.rbe_left)->entry.rbe_color = 0; do { (tmp) = ( parent)->entry.rbe_left; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry.rbe_right)-> entry.rbe_parent = (parent); } do {} while (0); if (((tmp)-> entry.rbe_parent = (parent)->entry.rbe_parent)) { if ((parent ) == ((parent)->entry.rbe_parent)->entry.rbe_left) ((parent )->entry.rbe_parent)->entry.rbe_left = (tmp); else ((parent )->entry.rbe_parent)->entry.rbe_right = (tmp); } else ( head)->rbh_root = (tmp); (tmp)->entry.rbe_right = (parent ); (parent)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->entry .rbe_color = 0; } __attribute__((__unused__)) static struct links_entry * ltree_RB_REMOVE(struct ltree *head, struct links_entry *elm ) { struct links_entry *child, *parent, *old = elm; int color ; if ((elm)->entry.rbe_left == ((void *)0)) child = (elm)-> entry.rbe_right; else if ((elm)->entry.rbe_right == ((void *)0)) child = (elm)->entry.rbe_left; else { struct links_entry *left; elm = (elm)->entry.rbe_right; while ((left = (elm) ->entry.rbe_left)) elm = left; child = (elm)->entry.rbe_right ; parent = (elm)->entry.rbe_parent; color = (elm)->entry .rbe_color; if (child) (child)->entry.rbe_parent = parent; if (parent) { if ((parent)->entry.rbe_left == elm) (parent )->entry.rbe_left = child; else (parent)->entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child ; if ((elm)->entry.rbe_parent == old) parent = elm; (elm)-> entry = (old)->entry; if ((old)->entry.rbe_parent) { if (((old)->entry.rbe_parent)->entry.rbe_left == old) ((old )->entry.rbe_parent)->entry.rbe_left = elm; else ((old) ->entry.rbe_parent)->entry.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->entry.rbe_left )->entry.rbe_parent = elm; if ((old)->entry.rbe_right) ( (old)->entry.rbe_right)->entry.rbe_parent = elm; if (parent ) { left = parent; do { do {} while (0); } while ((left = (left )->entry.rbe_parent)); } goto color; } parent = (elm)-> entry.rbe_parent; color = (elm)->entry.rbe_color; if (child ) (child)->entry.rbe_parent = parent; if (parent) { if ((parent )->entry.rbe_left == elm) (parent)->entry.rbe_left = child ; else (parent)->entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child; color: if (color == 0) ltree_RB_REMOVE_COLOR (head, parent, child); return (old); } __attribute__((__unused__ )) static struct links_entry * ltree_RB_INSERT(struct ltree * head, struct links_entry *elm) { struct links_entry *tmp; struct links_entry *parent = ((void *)0); int comp = 0; tmp = (head )->rbh_root; while (tmp) { parent = tmp; comp = (links_cmp )(elm, parent); if (comp < 0) tmp = (tmp)->entry.rbe_left ; else if (comp > 0) tmp = (tmp)->entry.rbe_right; else return (tmp); } do { (elm)->entry.rbe_parent = parent; (elm )->entry.rbe_left = (elm)->entry.rbe_right = ((void *)0 ); (elm)->entry.rbe_color = 1; } while (0); if (parent != ( (void *)0)) { if (comp < 0) (parent)->entry.rbe_left = elm ; else (parent)->entry.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ltree_RB_INSERT_COLOR(head, elm ); return (((void *)0)); } __attribute__((__unused__)) static struct links_entry * ltree_RB_FIND(struct ltree *head, struct links_entry *elm) { struct links_entry *tmp = (head)->rbh_root ; int comp; while (tmp) { comp = links_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->entry.rbe_left; else if (comp > 0 ) tmp = (tmp)->entry.rbe_right; else return (tmp); } return (((void *)0)); } __attribute__((__unused__)) static struct links_entry * ltree_RB_NFIND(struct ltree *head, struct links_entry *elm ) { struct links_entry *tmp = (head)->rbh_root; struct links_entry *res = ((void *)0); int comp; while (tmp) { comp = links_cmp (elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->entry .rbe_left; } else if (comp > 0) tmp = (tmp)->entry.rbe_right ; else return (tmp); } return (res); } __attribute__((__unused__ )) static struct links_entry * ltree_RB_NEXT(struct links_entry *elm) { if ((elm)->entry.rbe_right) { elm = (elm)->entry .rbe_right; while ((elm)->entry.rbe_left) elm = (elm)-> entry.rbe_left; } else { if ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_left)) elm = (elm)->entry.rbe_parent; else { while ((elm)->entry. rbe_parent && (elm == ((elm)->entry.rbe_parent)-> entry.rbe_right)) elm = (elm)->entry.rbe_parent; elm = (elm )->entry.rbe_parent; } } return (elm); } __attribute__((__unused__ )) static struct links_entry * ltree_RB_PREV(struct links_entry *elm) { if ((elm)->entry.rbe_left) { elm = (elm)->entry .rbe_left; while ((elm)->entry.rbe_right) elm = (elm)-> entry.rbe_right; } else { if ((elm)->entry.rbe_parent && (elm == ((elm)->entry.rbe_parent)->entry.rbe_right)) elm = (elm)->entry.rbe_parent; else { while ((elm)->entry. rbe_parent && (elm == ((elm)->entry.rbe_parent)-> entry.rbe_left)) elm = (elm)->entry.rbe_parent; elm = (elm )->entry.rbe_parent; } } return (elm); } __attribute__((__unused__ )) static struct links_entry * ltree_RB_MINMAX(struct ltree * head, int val) { struct links_entry *tmp = (head)->rbh_root ; struct links_entry *parent = ((void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry.rbe_left; else tmp = (tmp)->entry.rbe_right; } return (parent); }; | |||
| 240 | ||||
| 241 | ||||
| 242 | int | |||
| 243 | linkchk(FTSENT *p) | |||
| 244 | { | |||
| 245 | static struct links_entry *free_list = NULL((void *)0); | |||
| 246 | static int stop_allocating = 0; | |||
| 247 | struct links_entry ltmp, *le; | |||
| 248 | struct stat *st; | |||
| 249 | ||||
| 250 | st = p->fts_statp; | |||
| 251 | ||||
| 252 | ltmp.ino = st->st_ino; | |||
| 253 | ltmp.dev = st->st_dev; | |||
| 254 | ||||
| 255 | le = RB_FIND(ltree, &links, <mp)ltree_RB_FIND(&links, <mp); | |||
| 256 | if (le
| |||
| 257 | /* | |||
| 258 | * Save memory by releasing an entry when we've seen | |||
| 259 | * all of it's links. | |||
| 260 | */ | |||
| 261 | if (--le->links <= 0) { | |||
| 262 | RB_REMOVE(ltree, &links, le)ltree_RB_REMOVE(&links, le); | |||
| 263 | /* Recycle this node through the free list */ | |||
| 264 | if (stop_allocating) { | |||
| 265 | free(le); | |||
| 266 | } else { | |||
| 267 | le->fnext = free_list; | |||
| 268 | free_list = le; | |||
| 269 | } | |||
| 270 | } | |||
| 271 | return (1); | |||
| 272 | } | |||
| 273 | ||||
| 274 | if (stop_allocating
| |||
| 275 | return (0); | |||
| 276 | ||||
| 277 | /* Add this entry to the links cache. */ | |||
| 278 | if (free_list
| |||
| 279 | /* Pull a node from the free list if we can. */ | |||
| 280 | le = free_list; | |||
| 281 | free_list = le->fnext; | |||
| 282 | } else | |||
| 283 | /* Malloc one if we have to. */ | |||
| 284 | le = malloc(sizeof(struct links_entry)); | |||
| 285 | ||||
| 286 | if (le == NULL((void *)0)) { | |||
| 287 | stop_allocating = 1; | |||
| 288 | warnx("No more memory for tracking hard links"); | |||
| 289 | return (0); | |||
| 290 | } | |||
| 291 | ||||
| 292 | le->dev = st->st_dev; | |||
| 293 | le->ino = st->st_ino; | |||
| 294 | le->links = st->st_nlink - 1; | |||
| 295 | le->fnext = NULL((void *)0); | |||
| 296 | ||||
| 297 | RB_INSERT(ltree, &links, le)ltree_RB_INSERT(&links, le); | |||
| 298 | ||||
| 299 | return (0); | |||
| ||||
| 300 | } | |||
| 301 | ||||
| 302 | void | |||
| 303 | prtout(int64_t size, char *path, int hflag) | |||
| 304 | { | |||
| 305 | if (!hflag) | |||
| 306 | (void)printf("%lld\t%s\n", size, path); | |||
| 307 | else { | |||
| 308 | char buf[FMT_SCALED_STRSIZE7]; | |||
| 309 | ||||
| 310 | if (fmt_scaled(size * 512, buf) == 0) | |||
| 311 | (void)printf("%s\t%s\n", buf, path); | |||
| 312 | else | |||
| 313 | (void)printf("%lld\t%s\n", size, path); | |||
| 314 | } | |||
| 315 | } | |||
| 316 | ||||
| 317 | void | |||
| 318 | usage(void) | |||
| 319 | { | |||
| 320 | ||||
| 321 | (void)fprintf(stderr(&__sF[2]), | |||
| 322 | "usage: du [-achkrsx] [-H | -L | -P] [-d depth] [file ...]\n"); | |||
| 323 | exit(1); | |||
| 324 | } |