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