1 /* 2 * Copyright (c) 2000-2002, 2004, 2005 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * By using this file, you agree to the terms and conditions set 11 * forth in the LICENSE file which can be found at the top level of 12 * the sendmail distribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include <sm/gen.h> 18 SM_IDSTR(id, "@(#)$Id: strio.c,v 1.44 2005/06/09 21:40:19 ca Exp $") 19 #include <stdlib.h> 20 #include <unistd.h> 21 #include <fcntl.h> 22 #include <string.h> 23 #include <errno.h> 24 #include <sm/rpool.h> 25 #include <sm/io.h> 26 #include <sm/heap.h> 27 #include <sm/conf.h> 28 #include "local.h" 29 30 static int sm_strsetmode __P((SM_FILE_T*, const int *)); 31 static int sm_strgetmode __P((SM_FILE_T*, int *)); 32 33 /* 34 ** Cookie structure for the "strio" file type 35 */ 36 37 struct sm_str_obj 38 { 39 char *strio_base; 40 char *strio_end; 41 size_t strio_size; 42 size_t strio_offset; 43 int strio_flags; 44 const void *strio_rpool; 45 }; 46 47 typedef struct sm_str_obj SM_STR_OBJ_T; 48 49 /* 50 ** SM_STRGROW -- increase storage space for string 51 ** 52 ** Parameters: 53 ** s -- current cookie 54 ** size -- new storage size request 55 ** 56 ** Returns: 57 ** true iff successful. 58 */ 59 60 static bool sm_strgrow __P((SM_STR_OBJ_T *, size_t)); 61 62 static bool 63 sm_strgrow(s, size) 64 SM_STR_OBJ_T *s; 65 size_t size; 66 { 67 register void *p; 68 69 if (s->strio_size >= size) 70 return true; 71 p = sm_realloc(s->strio_base, size); 72 if (p == NULL) 73 return false; 74 s->strio_base = p; 75 s->strio_end = s->strio_base + size; 76 s->strio_size = size; 77 return true; 78 } 79 80 /* 81 ** SM_STRREAD -- read a portion of the string 82 ** 83 ** Parameters: 84 ** fp -- the file pointer 85 ** buf -- location to place read data 86 ** n -- number of bytes to read 87 ** 88 ** Returns: 89 ** Failure: -1 and sets errno 90 ** Success: >=0, number of bytes read 91 */ 92 93 ssize_t 94 sm_strread(fp, buf, n) 95 SM_FILE_T *fp; 96 char *buf; 97 size_t n; 98 { 99 register SM_STR_OBJ_T *s = fp->f_cookie; 100 int len; 101 102 if (!(s->strio_flags & SMRD) && !(s->strio_flags & SMRW)) 103 { 104 errno = EBADF; 105 return -1; 106 } 107 len = SM_MIN(s->strio_size - s->strio_offset, n); 108 (void) memmove(buf, s->strio_base + s->strio_offset, len); 109 s->strio_offset += len; 110 return len; 111 } 112 113 /* 114 ** SM_STRWRITE -- write a portion of the string 115 ** 116 ** Parameters: 117 ** fp -- the file pointer 118 ** buf -- location of data for writing 119 ** n -- number of bytes to write 120 ** 121 ** Returns: 122 ** Failure: -1 and sets errno 123 ** Success: >=0, number of bytes written 124 */ 125 126 ssize_t 127 sm_strwrite(fp, buf, n) 128 SM_FILE_T *fp; 129 char const *buf; 130 size_t n; 131 { 132 register SM_STR_OBJ_T *s = fp->f_cookie; 133 134 if (!(s->strio_flags & SMWR) && !(s->strio_flags & SMRW)) 135 { 136 errno = EBADF; 137 return -1; 138 } 139 if (n + s->strio_offset > s->strio_size) 140 { 141 if (!sm_strgrow(s, n + s->strio_offset)) 142 return 0; 143 } 144 (void) memmove(s->strio_base + s->strio_offset, buf, n); 145 s->strio_offset += n; 146 return n; 147 } 148 149 /* 150 ** SM_STRSEEK -- position the offset pointer for the string 151 ** 152 ** Only SM_IO_SEEK_SET, SM_IO_SEEK_CUR and SM_IO_SEEK_END are valid 153 ** values for whence. 154 ** 155 ** Parameters: 156 ** fp -- the file pointer 157 ** offset -- number of bytes offset from "base" 158 ** whence -- determines "base" for 'offset' 159 ** 160 ** Returns: 161 ** Failure: -1 and sets errno 162 ** Success: >=0, number of bytes read 163 */ 164 165 off_t 166 sm_strseek(fp, offset, whence) 167 SM_FILE_T *fp; 168 off_t offset; 169 int whence; 170 { 171 register off_t ret; 172 register SM_STR_OBJ_T *s = fp->f_cookie; 173 174 reseek: 175 switch (whence) 176 { 177 case SM_IO_SEEK_SET: 178 ret = offset; 179 break; 180 case SM_IO_SEEK_CUR: 181 ret = s->strio_offset + offset; 182 break; 183 case SM_IO_SEEK_END: 184 ret = s->strio_size; 185 break; 186 default: 187 errno = EINVAL; 188 return -1; 189 } 190 if (ret < 0 || ret > (off_t)(size_t)(-1)) /* XXX ugly */ 191 return -1; 192 if ((size_t) ret > s->strio_size) 193 { 194 if (sm_strgrow(s, (size_t)ret)) 195 goto reseek; 196 197 /* errno set by sm_strgrow */ 198 return -1; 199 } 200 s->strio_offset = (size_t) ret; 201 return ret; 202 } 203 204 /* 205 ** SM_STROPEN -- open a string file type 206 ** 207 ** Parameters: 208 ** fp -- file pointer open to be associated with 209 ** info -- initial contents (NULL for none) 210 ** flags -- flags for methods of access (was mode) 211 ** rpool -- resource pool to use memory from (if applicable) 212 ** 213 ** Results: 214 ** Success: 0 (zero) 215 ** Failure: -1 and sets errno 216 */ 217 218 int 219 sm_stropen(fp, info, flags, rpool) 220 SM_FILE_T *fp; 221 const void *info; 222 int flags; 223 const void *rpool; 224 { 225 register SM_STR_OBJ_T *s; 226 227 #if SM_RPOOL 228 s = sm_rpool_malloc_x(rpool, sizeof(SM_STR_OBJ_T)); 229 #else /* SM_RPOOL */ 230 s = sm_malloc(sizeof(SM_STR_OBJ_T)); 231 if (s == NULL) 232 return -1; 233 #endif /* SM_RPOOL */ 234 235 fp->f_cookie = s; 236 s->strio_rpool = rpool; 237 s->strio_offset = 0; 238 s->strio_size = 0; 239 s->strio_base = NULL; 240 s->strio_end = 0; 241 242 switch (flags) 243 { 244 case SM_IO_RDWR: 245 s->strio_flags = SMRW; 246 break; 247 case SM_IO_RDONLY: 248 s->strio_flags = SMRD; 249 break; 250 case SM_IO_WRONLY: 251 s->strio_flags = SMWR; 252 break; 253 case SM_IO_APPEND: 254 if (s->strio_rpool == NULL) 255 sm_free(s); 256 errno = EINVAL; 257 return -1; 258 default: 259 if (s->strio_rpool == NULL) 260 sm_free(s); 261 errno = EINVAL; 262 return -1; 263 } 264 265 if (info != NULL) 266 { 267 s->strio_base = sm_strdup_x(info); 268 if (s->strio_base == NULL) 269 { 270 int save_errno = errno; 271 272 if (s->strio_rpool == NULL) 273 sm_free(s); 274 errno = save_errno; 275 return -1; 276 } 277 s->strio_size = strlen(info); 278 s->strio_end = s->strio_base + s->strio_size; 279 } 280 return 0; 281 } 282 283 /* 284 ** SM_STRCLOSE -- close the string file type and free resources 285 ** 286 ** Parameters: 287 ** fp -- file pointer 288 ** 289 ** Results: 290 ** Success: 0 (zero) 291 */ 292 293 int 294 sm_strclose(fp) 295 SM_FILE_T *fp; 296 { 297 SM_STR_OBJ_T *s = fp->f_cookie; 298 299 #if !SM_RPOOL 300 sm_free(s->strio_base); 301 s->strio_base = NULL; 302 #endif /* !SM_RPOOL */ 303 return 0; 304 } 305 306 /* 307 ** SM_STRSETMODE -- set mode info for the file 308 ** 309 ** Note: changing the mode can be a safe way to have the "parent" 310 ** set up a string that the "child" is not to modify 311 ** 312 ** Parameters: 313 ** fp -- the file pointer 314 ** mode -- location of new mode to set 315 ** 316 ** Results: 317 ** Success: 0 (zero) 318 ** Failure: -1 and sets errno 319 */ 320 321 static int 322 sm_strsetmode(fp, mode) 323 SM_FILE_T *fp; 324 const int *mode; 325 { 326 register SM_STR_OBJ_T *s = fp->f_cookie; 327 int flags; 328 329 switch (*mode) 330 { 331 case SM_IO_RDWR: 332 flags = SMRW; 333 break; 334 case SM_IO_RDONLY: 335 flags = SMRD; 336 break; 337 case SM_IO_WRONLY: 338 flags = SMWR; 339 break; 340 case SM_IO_APPEND: 341 errno = EINVAL; 342 return -1; 343 default: 344 errno = EINVAL; 345 return -1; 346 } 347 s->strio_flags &= ~SMMODEMASK; 348 s->strio_flags |= flags; 349 return 0; 350 } 351 352 /* 353 ** SM_STRGETMODE -- get mode info for the file 354 ** 355 ** Parameters: 356 ** fp -- the file pointer 357 ** mode -- location to store current mode 358 ** 359 ** Results: 360 ** Success: 0 (zero) 361 ** Failure: -1 and sets errno 362 */ 363 364 static int 365 sm_strgetmode(fp, mode) 366 SM_FILE_T *fp; 367 int *mode; 368 { 369 register SM_STR_OBJ_T *s = fp->f_cookie; 370 371 switch (s->strio_flags & SMMODEMASK) 372 { 373 case SMRW: 374 *mode = SM_IO_RDWR; 375 break; 376 case SMRD: 377 *mode = SM_IO_RDONLY; 378 break; 379 case SMWR: 380 *mode = SM_IO_WRONLY; 381 break; 382 default: 383 errno = EINVAL; 384 return -1; 385 } 386 return 0; 387 } 388 389 /* 390 ** SM_STRSETINFO -- set info for the file 391 ** 392 ** Currently only SM_IO_WHAT_MODE is supported for 'what'. 393 ** 394 ** Parameters: 395 ** fp -- the file pointer 396 ** what -- type of information to set 397 ** valp -- location to data for doing set 398 ** 399 ** Results: 400 ** Failure: -1 and sets errno 401 ** Success: sm_strsetmode() return [0 (zero)] 402 */ 403 404 int 405 sm_strsetinfo(fp, what, valp) 406 SM_FILE_T *fp; 407 int what; 408 void *valp; 409 { 410 switch(what) 411 { 412 case SM_IO_WHAT_MODE: 413 return sm_strsetmode(fp, (int *) valp); 414 default: 415 errno = EINVAL; 416 return -1; 417 } 418 } 419 420 /* 421 ** SM_STRGETINFO -- get info for the file 422 ** 423 ** Currently only SM_IO_WHAT_MODE is supported for 'what'. 424 ** 425 ** Parameters: 426 ** fp -- the file pointer 427 ** what -- type of information requested 428 ** valp -- location to return information in 429 ** 430 ** Results: 431 ** Failure: -1 and sets errno 432 ** Success: sm_strgetmode() return [0 (zero)] 433 */ 434 435 int 436 sm_strgetinfo(fp, what, valp) 437 SM_FILE_T *fp; 438 int what; 439 void *valp; 440 { 441 switch(what) 442 { 443 case SM_IO_WHAT_MODE: 444 return sm_strgetmode(fp, (int *) valp); 445 default: 446 errno = EINVAL; 447 return -1; 448 } 449 } 450 451 /* 452 ** SM_STRIO_INIT -- initializes a write-only string type 453 ** 454 ** Original comments below. This function does not appear to be used anywhere. 455 ** The same functionality can be done by changing the mode of the file. 456 ** ------------ 457 ** sm_strio_init initializes an SM_FILE_T structure as a write-only file 458 ** that writes into the specified buffer: 459 ** - Use sm_io_putc, sm_io_fprintf, etc, to write into the buffer. 460 ** Attempts to write more than size-1 characters into the buffer will fail 461 ** silently (no error is reported). 462 ** - Use sm_io_fflush to nul terminate the string in the buffer 463 ** (the write pointer is not advanced). 464 ** No memory is allocated either by sm_strio_init or by sm_io_{putc,write} etc. 465 ** 466 ** Parameters: 467 ** fp -- file pointer 468 ** buf -- memory location for stored data 469 ** size -- size of 'buf' 470 ** 471 ** Results: 472 ** none. 473 */ 474 475 void 476 sm_strio_init(fp, buf, size) 477 SM_FILE_T *fp; 478 char *buf; 479 size_t size; 480 { 481 fp->sm_magic = SmFileMagic; 482 fp->f_flags = SMWR | SMSTR; 483 fp->f_file = -1; 484 fp->f_bf.smb_base = fp->f_p = (unsigned char *) buf; 485 fp->f_bf.smb_size = fp->f_w = (size ? size - 1 : 0); 486 fp->f_lbfsize = 0; 487 fp->f_r = 0; 488 fp->f_read = NULL; 489 fp->f_seek = NULL; 490 fp->f_getinfo = NULL; 491 fp->f_setinfo = NULL; 492 } 493