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