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