1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc. 24*0Sstevel@tonic-gate * All rights reserved. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * logadm/fn.c -- "filename" string module 27*0Sstevel@tonic-gate * 28*0Sstevel@tonic-gate * this file contains routines for the manipulation of filenames. 29*0Sstevel@tonic-gate * they aren't particularly fast (at least they weren't designed 30*0Sstevel@tonic-gate * for performance), but they are simple and put all the malloc/free 31*0Sstevel@tonic-gate * stuff for these strings in a central place. most routines in 32*0Sstevel@tonic-gate * logadm that return filenames return a struct fn, and most routines 33*0Sstevel@tonic-gate * that return lists of strings return a struct fn_list. 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #include <stdio.h> 39*0Sstevel@tonic-gate #include <libintl.h> 40*0Sstevel@tonic-gate #include <strings.h> 41*0Sstevel@tonic-gate #include <sys/types.h> 42*0Sstevel@tonic-gate #include <sys/stat.h> 43*0Sstevel@tonic-gate #include "err.h" 44*0Sstevel@tonic-gate #include "fn.h" 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate /* 49*0Sstevel@tonic-gate * constants controlling how we malloc space. bigger means fewer 50*0Sstevel@tonic-gate * calls to malloc. smaller means less wasted space. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate #define FN_MIN 1024 /* initial size of string buffers */ 53*0Sstevel@tonic-gate #define FN_MAX 10240 /* maximum size allowed before fatal "overflow" error */ 54*0Sstevel@tonic-gate #define FN_INC 1024 /* increments in buffer size as strings grow */ 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* info created by fn_new(), private to this module */ 57*0Sstevel@tonic-gate struct fn { 58*0Sstevel@tonic-gate char *fn_buf; /* first location in buf */ 59*0Sstevel@tonic-gate char *fn_buflast; /* last location in buf */ 60*0Sstevel@tonic-gate char *fn_rptr; /* read pointer (next unread character) */ 61*0Sstevel@tonic-gate char *fn_wptr; /* write pointer (points at null terminator) */ 62*0Sstevel@tonic-gate struct fn *fn_next; /* next in list */ 63*0Sstevel@tonic-gate struct stat fn_stbuf; 64*0Sstevel@tonic-gate int fn_n; 65*0Sstevel@tonic-gate }; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /* info created by fn_list_new(), private to this module */ 68*0Sstevel@tonic-gate struct fn_list { 69*0Sstevel@tonic-gate struct fn *fnl_first; /* first element of list */ 70*0Sstevel@tonic-gate struct fn *fnl_last; /* last element of list */ 71*0Sstevel@tonic-gate struct fn *fnl_rptr; /* read pointer for iterating through list */ 72*0Sstevel@tonic-gate }; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /* 75*0Sstevel@tonic-gate * fn_new -- create a new filename buffer, possibly with initial contents 76*0Sstevel@tonic-gate * 77*0Sstevel@tonic-gate * use like this: 78*0Sstevel@tonic-gate * struct fn *fnp = fn_new("this is a string"); 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate struct fn * 81*0Sstevel@tonic-gate fn_new(const char *s) 82*0Sstevel@tonic-gate { 83*0Sstevel@tonic-gate struct fn *fnp = MALLOC(sizeof (struct fn)); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate fnp->fn_n = -1; 86*0Sstevel@tonic-gate bzero(&fnp->fn_stbuf, sizeof (fnp->fn_stbuf)); 87*0Sstevel@tonic-gate fnp->fn_next = NULL; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate /* if passed-in string contains at least 1 non-null character... */ 90*0Sstevel@tonic-gate if (s && *s) { 91*0Sstevel@tonic-gate int len = strlen(s); 92*0Sstevel@tonic-gate int buflen = roundup(len + 1, FN_INC); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* start with buffer filled with passed-in string */ 95*0Sstevel@tonic-gate fnp->fn_buf = MALLOC(buflen); 96*0Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[buflen - 1]; 97*0Sstevel@tonic-gate (void) strlcpy(fnp->fn_buf, s, buflen); 98*0Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 99*0Sstevel@tonic-gate fnp->fn_wptr = &fnp->fn_buf[len]; 100*0Sstevel@tonic-gate } else { 101*0Sstevel@tonic-gate /* start with empty buffer */ 102*0Sstevel@tonic-gate fnp->fn_buf = MALLOC(FN_MIN); 103*0Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[FN_MIN - 1]; 104*0Sstevel@tonic-gate *fnp->fn_buf = '\0'; 105*0Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 106*0Sstevel@tonic-gate fnp->fn_wptr = fnp->fn_buf; 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate return (fnp); 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate /* 113*0Sstevel@tonic-gate * fn_dup -- duplicate a filename buffer 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate struct fn * 116*0Sstevel@tonic-gate fn_dup(struct fn *fnp) 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate struct fn *ret = fn_new(fn_s(fnp)); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate ret->fn_n = fnp->fn_n; 121*0Sstevel@tonic-gate ret->fn_stbuf = fnp->fn_stbuf; 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate return (ret); 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate /* 127*0Sstevel@tonic-gate * fn_dirname -- return the dirname part of a filename 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate struct fn * 130*0Sstevel@tonic-gate fn_dirname(struct fn *fnp) 131*0Sstevel@tonic-gate { 132*0Sstevel@tonic-gate char *ptr; 133*0Sstevel@tonic-gate struct fn *ret; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate if ((ptr = strrchr(fn_s(fnp), '/')) == NULL) 136*0Sstevel@tonic-gate return (fn_new(".")); 137*0Sstevel@tonic-gate else { 138*0Sstevel@tonic-gate *ptr = '\0'; 139*0Sstevel@tonic-gate ret = fn_new(fn_s(fnp)); 140*0Sstevel@tonic-gate *ptr = '/'; 141*0Sstevel@tonic-gate return (ret); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * fn_setn -- set the "n" value for a filename 147*0Sstevel@tonic-gate * 148*0Sstevel@tonic-gate * the "n" value is initially -1, and is used by logadm to store 149*0Sstevel@tonic-gate * the suffix for rotated log files. the function fn_list_popoldest() 150*0Sstevel@tonic-gate * looks at these "n" values when sorting filenames to determine which 151*0Sstevel@tonic-gate * old log file is the oldest and should be expired first. 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate void 154*0Sstevel@tonic-gate fn_setn(struct fn *fnp, int n) 155*0Sstevel@tonic-gate { 156*0Sstevel@tonic-gate fnp->fn_n = n; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * fn_setstat -- store a struct stat with a filename 161*0Sstevel@tonic-gate * 162*0Sstevel@tonic-gate * the glob functions typically fill in these struct stats since they 163*0Sstevel@tonic-gate * have to stat while globbing anyway. just turned out to be a common 164*0Sstevel@tonic-gate * piece of information that was conveniently stored with the associated 165*0Sstevel@tonic-gate * filename. 166*0Sstevel@tonic-gate */ 167*0Sstevel@tonic-gate void 168*0Sstevel@tonic-gate fn_setstat(struct fn *fnp, struct stat *stp) 169*0Sstevel@tonic-gate { 170*0Sstevel@tonic-gate fnp->fn_stbuf = *stp; 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * fn_getstat -- return a pointer to the stat info stored by fn_setstat() 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate struct stat * 177*0Sstevel@tonic-gate fn_getstat(struct fn *fnp) 178*0Sstevel@tonic-gate { 179*0Sstevel@tonic-gate return (&fnp->fn_stbuf); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /* 183*0Sstevel@tonic-gate * fn_free -- free a filename buffer 184*0Sstevel@tonic-gate */ 185*0Sstevel@tonic-gate void 186*0Sstevel@tonic-gate fn_free(struct fn *fnp) 187*0Sstevel@tonic-gate { 188*0Sstevel@tonic-gate if (fnp) { 189*0Sstevel@tonic-gate if (fnp->fn_buf) 190*0Sstevel@tonic-gate FREE(fnp->fn_buf); 191*0Sstevel@tonic-gate FREE(fnp); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * fn_renew -- reset a filename buffer 197*0Sstevel@tonic-gate * 198*0Sstevel@tonic-gate * calling fn_renew(fnp, s) is the same as calling: 199*0Sstevel@tonic-gate * fn_free(fnp); 200*0Sstevel@tonic-gate * fn_new(s); 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate void 203*0Sstevel@tonic-gate fn_renew(struct fn *fnp, const char *s) 204*0Sstevel@tonic-gate { 205*0Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_wptr = fnp->fn_buf; 206*0Sstevel@tonic-gate fn_puts(fnp, s); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * fn_putc -- append a character to a filename 211*0Sstevel@tonic-gate * 212*0Sstevel@tonic-gate * this is the function that handles growing the filename buffer 213*0Sstevel@tonic-gate * automatically and calling err() if it overflows. 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate void 216*0Sstevel@tonic-gate fn_putc(struct fn *fnp, int c) 217*0Sstevel@tonic-gate { 218*0Sstevel@tonic-gate if (fnp->fn_wptr >= fnp->fn_buflast) { 219*0Sstevel@tonic-gate int buflen = fnp->fn_buflast + 1 - fnp->fn_buf; 220*0Sstevel@tonic-gate char *newbuf; 221*0Sstevel@tonic-gate char *src; 222*0Sstevel@tonic-gate char *dst; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* overflow, allocate more space or die if at FN_MAX */ 225*0Sstevel@tonic-gate if (buflen >= FN_MAX) 226*0Sstevel@tonic-gate err(0, "fn buffer overflow"); 227*0Sstevel@tonic-gate buflen += FN_INC; 228*0Sstevel@tonic-gate newbuf = MALLOC(buflen); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate /* copy string into new buffer */ 231*0Sstevel@tonic-gate src = fnp->fn_buf; 232*0Sstevel@tonic-gate dst = newbuf; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* just copy up to wptr, rest is history anyway */ 235*0Sstevel@tonic-gate while (src < fnp->fn_wptr) 236*0Sstevel@tonic-gate *dst++ = *src++; 237*0Sstevel@tonic-gate fnp->fn_rptr = &newbuf[fnp->fn_rptr - fnp->fn_buf]; 238*0Sstevel@tonic-gate FREE(fnp->fn_buf); 239*0Sstevel@tonic-gate fnp->fn_buf = newbuf; 240*0Sstevel@tonic-gate fnp->fn_buflast = &fnp->fn_buf[buflen - 1]; 241*0Sstevel@tonic-gate fnp->fn_wptr = dst; 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate *fnp->fn_wptr++ = c; 244*0Sstevel@tonic-gate *fnp->fn_wptr = '\0'; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * fn_puts -- append a string to a filename 249*0Sstevel@tonic-gate */ 250*0Sstevel@tonic-gate void 251*0Sstevel@tonic-gate fn_puts(struct fn *fnp, const char *s) 252*0Sstevel@tonic-gate { 253*0Sstevel@tonic-gate /* non-optimal, but simple! */ 254*0Sstevel@tonic-gate while (s && *s) 255*0Sstevel@tonic-gate fn_putc(fnp, *s++); 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * fn_putfn -- append a filename buffer to a filename 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate void 262*0Sstevel@tonic-gate fn_putfn(struct fn *fnp, struct fn *srcfnp) 263*0Sstevel@tonic-gate { 264*0Sstevel@tonic-gate int c; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate fn_rewind(srcfnp); 267*0Sstevel@tonic-gate while (c = fn_getc(srcfnp)) 268*0Sstevel@tonic-gate fn_putc(fnp, c); 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * fn_rewind -- reset the "read pointer" to the beginning of a filename 273*0Sstevel@tonic-gate */ 274*0Sstevel@tonic-gate void 275*0Sstevel@tonic-gate fn_rewind(struct fn *fnp) 276*0Sstevel@tonic-gate { 277*0Sstevel@tonic-gate fnp->fn_rptr = fnp->fn_buf; 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* 281*0Sstevel@tonic-gate * fn_getc -- "read" the next character of a filename 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate int 284*0Sstevel@tonic-gate fn_getc(struct fn *fnp) 285*0Sstevel@tonic-gate { 286*0Sstevel@tonic-gate if (fnp->fn_rptr > fnp->fn_buflast || *fnp->fn_rptr == '\0') 287*0Sstevel@tonic-gate return (0); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate return (*fnp->fn_rptr++); 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * fn_peekc -- "peek" at the next character of a filename 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate int 296*0Sstevel@tonic-gate fn_peekc(struct fn *fnp) 297*0Sstevel@tonic-gate { 298*0Sstevel@tonic-gate if (fnp->fn_rptr > fnp->fn_buflast || *fnp->fn_rptr == '\0') 299*0Sstevel@tonic-gate return (0); 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate return (*fnp->fn_rptr); 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * fn_s -- return a pointer to a null-terminated string containing the filename 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate char * 308*0Sstevel@tonic-gate fn_s(struct fn *fnp) 309*0Sstevel@tonic-gate { 310*0Sstevel@tonic-gate return (fnp->fn_buf); 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate /* 314*0Sstevel@tonic-gate * fn_list_new -- create a new list of filenames 315*0Sstevel@tonic-gate * 316*0Sstevel@tonic-gate * by convention, an empty list is represented by an allocated 317*0Sstevel@tonic-gate * struct fn_list which contains a NULL linked list, rather than 318*0Sstevel@tonic-gate * by a NULL fn_list pointer. in other words: 319*0Sstevel@tonic-gate * 320*0Sstevel@tonic-gate * struct fn_list *fnlp = some_func_returning_a_list(); 321*0Sstevel@tonic-gate * if (fn_list_empty(fnlp)) 322*0Sstevel@tonic-gate * ... 323*0Sstevel@tonic-gate * 324*0Sstevel@tonic-gate * is preferable to checking if the fnlp returned is NULL. 325*0Sstevel@tonic-gate */ 326*0Sstevel@tonic-gate struct fn_list * 327*0Sstevel@tonic-gate fn_list_new(const char * const *slist) 328*0Sstevel@tonic-gate { 329*0Sstevel@tonic-gate struct fn_list *fnlp = MALLOC(sizeof (struct fn_list)); 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate fnlp->fnl_first = fnlp->fnl_last = fnlp->fnl_rptr = NULL; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate while (slist && *slist) 334*0Sstevel@tonic-gate fn_list_adds(fnlp, *slist++); 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate return (fnlp); 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * fn_list_dup -- duplicate a list of filenames 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate struct fn_list * 343*0Sstevel@tonic-gate fn_list_dup(struct fn_list *fnlp) 344*0Sstevel@tonic-gate { 345*0Sstevel@tonic-gate struct fn_list *ret = fn_list_new(NULL); 346*0Sstevel@tonic-gate struct fn *fnp; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate fn_list_rewind(fnlp); 349*0Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 350*0Sstevel@tonic-gate fn_list_addfn(ret, fn_dup(fnp)); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate return (ret); 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate /* 356*0Sstevel@tonic-gate * fn_list_free -- free a list of filenames 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate void 359*0Sstevel@tonic-gate fn_list_free(struct fn_list *fnlp) 360*0Sstevel@tonic-gate { 361*0Sstevel@tonic-gate struct fn *fnp; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate fn_list_rewind(fnlp); 364*0Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 365*0Sstevel@tonic-gate fn_free(fnp); 366*0Sstevel@tonic-gate FREE(fnlp); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * fn_list_adds -- add a string to a list of filenames 371*0Sstevel@tonic-gate */ 372*0Sstevel@tonic-gate void 373*0Sstevel@tonic-gate fn_list_adds(struct fn_list *fnlp, const char *s) 374*0Sstevel@tonic-gate { 375*0Sstevel@tonic-gate fn_list_addfn(fnlp, fn_new(s)); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * fn_list_addfn -- add a filename (i.e. struct fn *) to a list of filenames 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate void 382*0Sstevel@tonic-gate fn_list_addfn(struct fn_list *fnlp, struct fn *fnp) 383*0Sstevel@tonic-gate { 384*0Sstevel@tonic-gate fnp->fn_next = NULL; 385*0Sstevel@tonic-gate if (fnlp->fnl_first == NULL) 386*0Sstevel@tonic-gate fnlp->fnl_first = fnlp->fnl_last = fnlp->fnl_rptr = fnp; 387*0Sstevel@tonic-gate else { 388*0Sstevel@tonic-gate fnlp->fnl_last->fn_next = fnp; 389*0Sstevel@tonic-gate fnlp->fnl_last = fnp; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate /* 394*0Sstevel@tonic-gate * fn_list_rewind -- reset the "read pointer" to the beginning of the list 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate void 397*0Sstevel@tonic-gate fn_list_rewind(struct fn_list *fnlp) 398*0Sstevel@tonic-gate { 399*0Sstevel@tonic-gate fnlp->fnl_rptr = fnlp->fnl_first; 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate /* 403*0Sstevel@tonic-gate * fn_list_next -- return the filename at the read pointer and advance it 404*0Sstevel@tonic-gate */ 405*0Sstevel@tonic-gate struct fn * 406*0Sstevel@tonic-gate fn_list_next(struct fn_list *fnlp) 407*0Sstevel@tonic-gate { 408*0Sstevel@tonic-gate struct fn *ret = fnlp->fnl_rptr; 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate if (fnlp->fnl_rptr == fnlp->fnl_last) 411*0Sstevel@tonic-gate fnlp->fnl_rptr = NULL; 412*0Sstevel@tonic-gate else if (fnlp->fnl_rptr != NULL) 413*0Sstevel@tonic-gate fnlp->fnl_rptr = fnlp->fnl_rptr->fn_next; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate return (ret); 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* 419*0Sstevel@tonic-gate * fn_list_addfn_list -- move filenames from fnlp2 to end of fnlp 420*0Sstevel@tonic-gate * 421*0Sstevel@tonic-gate * frees fnlp2 after moving all the filenames off of it. 422*0Sstevel@tonic-gate */ 423*0Sstevel@tonic-gate void 424*0Sstevel@tonic-gate fn_list_addfn_list(struct fn_list *fnlp, struct fn_list *fnlp2) 425*0Sstevel@tonic-gate { 426*0Sstevel@tonic-gate struct fn *fnp2 = fnlp2->fnl_first; 427*0Sstevel@tonic-gate struct fn *nextfnp2; 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate /* for each fn in the second list... */ 430*0Sstevel@tonic-gate while (fnp2) { 431*0Sstevel@tonic-gate if (fnp2 == fnlp2->fnl_last) 432*0Sstevel@tonic-gate nextfnp2 = NULL; 433*0Sstevel@tonic-gate else 434*0Sstevel@tonic-gate nextfnp2 = fnp2->fn_next; 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* append it to the first list */ 437*0Sstevel@tonic-gate fn_list_addfn(fnlp, fnp2); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate fnp2 = nextfnp2; 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate /* all the fn's were moved off the second list */ 442*0Sstevel@tonic-gate fnlp2->fnl_first = fnlp2->fnl_last = fnlp2->fnl_rptr = NULL; 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* done with the second list */ 445*0Sstevel@tonic-gate fn_list_free(fnlp2); 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate /* 449*0Sstevel@tonic-gate * fn_list_appendrange -- append a range of characters to each filename in list 450*0Sstevel@tonic-gate * 451*0Sstevel@tonic-gate * range of characters appended is the character at *s up to but not including 452*0Sstevel@tonic-gate * the character at *limit. NULL termination is not required. 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate void 455*0Sstevel@tonic-gate fn_list_appendrange(struct fn_list *fnlp, const char *s, const char *limit) 456*0Sstevel@tonic-gate { 457*0Sstevel@tonic-gate struct fn *fnp = fnlp->fnl_first; 458*0Sstevel@tonic-gate struct fn *nextfnp; 459*0Sstevel@tonic-gate const char *ptr; 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* for each fn in the list... */ 462*0Sstevel@tonic-gate while (fnp) { 463*0Sstevel@tonic-gate if (fnp == fnlp->fnl_last) 464*0Sstevel@tonic-gate nextfnp = NULL; 465*0Sstevel@tonic-gate else 466*0Sstevel@tonic-gate nextfnp = fnp->fn_next; 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate /* append the range */ 469*0Sstevel@tonic-gate for (ptr = s; ptr < limit; ptr++) 470*0Sstevel@tonic-gate fn_putc(fnp, *ptr); 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate fnp = nextfnp; 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate /* 477*0Sstevel@tonic-gate * fn_list_totalsize -- sum up all the st_size fields in the stat structs 478*0Sstevel@tonic-gate */ 479*0Sstevel@tonic-gate size_t 480*0Sstevel@tonic-gate fn_list_totalsize(struct fn_list *fnlp) 481*0Sstevel@tonic-gate { 482*0Sstevel@tonic-gate struct fn *fnp; 483*0Sstevel@tonic-gate size_t ret = 0; 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate fn_list_rewind(fnlp); 486*0Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 487*0Sstevel@tonic-gate ret += fnp->fn_stbuf.st_size; 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate return (ret); 490*0Sstevel@tonic-gate } 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate /* 493*0Sstevel@tonic-gate * fn_list_popoldest -- remove oldest file from list and return it 494*0Sstevel@tonic-gate * 495*0Sstevel@tonic-gate * this function uses the "n" values (set by fn_setn()) to determine 496*0Sstevel@tonic-gate * which file is oldest, or when there's a tie it turns to the modification 497*0Sstevel@tonic-gate * times in the stat structs, or when there's still a tie lexical sorting. 498*0Sstevel@tonic-gate */ 499*0Sstevel@tonic-gate struct fn * 500*0Sstevel@tonic-gate fn_list_popoldest(struct fn_list *fnlp) 501*0Sstevel@tonic-gate { 502*0Sstevel@tonic-gate struct fn *fnp; 503*0Sstevel@tonic-gate struct fn *ret = NULL; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate fn_list_rewind(fnlp); 506*0Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 507*0Sstevel@tonic-gate if (ret == NULL) 508*0Sstevel@tonic-gate ret = fnp; 509*0Sstevel@tonic-gate else if (fnp->fn_n > ret->fn_n || 510*0Sstevel@tonic-gate (fnp->fn_n == ret->fn_n && 511*0Sstevel@tonic-gate (fnp->fn_stbuf.st_mtime < ret->fn_stbuf.st_mtime || 512*0Sstevel@tonic-gate ((fnp->fn_stbuf.st_mtime == ret->fn_stbuf.st_mtime && 513*0Sstevel@tonic-gate strcmp(fnp->fn_buf, ret->fn_buf) > 0))))) 514*0Sstevel@tonic-gate ret = fnp; 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (ret == NULL) 517*0Sstevel@tonic-gate return (NULL); 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* oldest file is ret, remove it from list */ 520*0Sstevel@tonic-gate if (fnlp->fnl_first == ret) 521*0Sstevel@tonic-gate fnlp->fnl_first = ret->fn_next; 522*0Sstevel@tonic-gate else { 523*0Sstevel@tonic-gate fn_list_rewind(fnlp); 524*0Sstevel@tonic-gate while ((fnp = fn_list_next(fnlp)) != NULL) 525*0Sstevel@tonic-gate if (fnp->fn_next == ret) { 526*0Sstevel@tonic-gate fnp->fn_next = ret->fn_next; 527*0Sstevel@tonic-gate break; 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate ret->fn_next = NULL; 532*0Sstevel@tonic-gate return (ret); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* 536*0Sstevel@tonic-gate * fn_list_empty -- true if the list is empty 537*0Sstevel@tonic-gate */ 538*0Sstevel@tonic-gate boolean_t 539*0Sstevel@tonic-gate fn_list_empty(struct fn_list *fnlp) 540*0Sstevel@tonic-gate { 541*0Sstevel@tonic-gate return (fnlp->fnl_first == NULL); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* 545*0Sstevel@tonic-gate * fn_list_count -- return number of filenames in list 546*0Sstevel@tonic-gate */ 547*0Sstevel@tonic-gate int 548*0Sstevel@tonic-gate fn_list_count(struct fn_list *fnlp) 549*0Sstevel@tonic-gate { 550*0Sstevel@tonic-gate int ret = 0; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate /* 553*0Sstevel@tonic-gate * if this operation were more common, we'd cache the count 554*0Sstevel@tonic-gate * in the struct fn_list, but it isn't very common so we just 555*0Sstevel@tonic-gate * count 'em up here 556*0Sstevel@tonic-gate */ 557*0Sstevel@tonic-gate fn_list_rewind(fnlp); 558*0Sstevel@tonic-gate while (fn_list_next(fnlp) != NULL) 559*0Sstevel@tonic-gate ret++; 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate return (ret); 562*0Sstevel@tonic-gate } 563