1/*	$NetBSD: store_fd.c,v 1.2 2017/01/28 21:31:49 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997 - 2004 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "krb5_locl.h"
37#include "store-int.h"
38
39typedef struct fd_storage {
40    int fd;
41} fd_storage;
42
43#define FD(S) (((fd_storage*)(S)->data)->fd)
44
45static ssize_t
46fd_fetch(krb5_storage * sp, void *data, size_t size)
47{
48    char *cbuf = (char *)data;
49    ssize_t count;
50    size_t rem = size;
51
52    /* similar pattern to net_read() to support pipes */
53    while (rem > 0) {
54	count = read (FD(sp), cbuf, rem);
55	if (count < 0) {
56	    if (errno == EINTR)
57		continue;
58	    else
59		return count;
60	} else if (count == 0) {
61	    return count;
62	}
63	cbuf += count;
64	rem -= count;
65    }
66    return size;
67}
68
69static ssize_t
70fd_store(krb5_storage * sp, const void *data, size_t size)
71{
72    const char *cbuf = (const char *)data;
73    ssize_t count;
74    size_t rem = size;
75
76    /* similar pattern to net_write() to support pipes */
77    while (rem > 0) {
78	count = write(FD(sp), cbuf, rem);
79	if (count < 0) {
80	    if (errno == EINTR)
81		continue;
82	    else
83		return count;
84	}
85	cbuf += count;
86	rem -= count;
87    }
88    return size;
89}
90
91static off_t
92fd_seek(krb5_storage * sp, off_t offset, int whence)
93{
94    return lseek(FD(sp), offset, whence);
95}
96
97static int
98fd_trunc(krb5_storage * sp, off_t offset)
99{
100    if (ftruncate(FD(sp), offset) == -1)
101	return errno;
102    return 0;
103}
104
105static int
106fd_sync(krb5_storage * sp)
107{
108    if (fsync(FD(sp)) == -1)
109	return errno;
110    return 0;
111}
112
113static void
114fd_free(krb5_storage * sp)
115{
116    int save_errno = errno;
117    if (close(FD(sp)) == 0)
118        errno = save_errno;
119}
120
121/**
122 *
123 *
124 * @return A krb5_storage on success, or NULL on out of memory error.
125 *
126 * @ingroup krb5_storage
127 *
128 * @sa krb5_storage_emem()
129 * @sa krb5_storage_from_mem()
130 * @sa krb5_storage_from_readonly_mem()
131 * @sa krb5_storage_from_data()
132 * @sa krb5_storage_from_socket()
133 */
134
135KRB5_LIB_FUNCTION krb5_storage * KRB5_LIB_CALL
136krb5_storage_from_fd(int fd_in)
137{
138    krb5_storage *sp;
139    int saved_errno;
140    int fd;
141
142#ifdef _MSC_VER
143    /*
144     * This function used to try to pass the input to
145     * _get_osfhandle() to test if the value is a HANDLE
146     * but this doesn't work because doing so throws an
147     * exception that will result in Watson being triggered
148     * to file a Windows Error Report.
149     */
150    fd = _dup(fd_in);
151#else
152    fd = dup(fd_in);
153#endif
154
155    if (fd < 0)
156	return NULL;
157
158    errno = ENOMEM;
159    sp = malloc(sizeof(krb5_storage));
160    if (sp == NULL) {
161	saved_errno = errno;
162	close(fd);
163	errno = saved_errno;
164	return NULL;
165    }
166
167    errno = ENOMEM;
168    sp->data = malloc(sizeof(fd_storage));
169    if (sp->data == NULL) {
170	saved_errno = errno;
171	close(fd);
172	free(sp);
173	errno = saved_errno;
174	return NULL;
175    }
176    sp->flags = 0;
177    sp->eof_code = HEIM_ERR_EOF;
178    FD(sp) = fd;
179    sp->fetch = fd_fetch;
180    sp->store = fd_store;
181    sp->seek = fd_seek;
182    sp->trunc = fd_trunc;
183    sp->fsync = fd_sync;
184    sp->free = fd_free;
185    sp->max_alloc = UINT_MAX/8;
186    return sp;
187}
188