1 /* @(#)xio.c	1.20 09/07/18 Copyright 2003-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)xio.c	1.20 09/07/18 Copyright 2003-2009 J. Schilling";
6 #endif
7 /*
8  *	EXtended I/O functions for cdrecord
9  *
10  *	Copyright (c) 2003-2009 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/mconfig.h>
27 #include <schily/unistd.h>
28 #include <schily/stdlib.h>
29 #include <schily/string.h>
30 #include <schily/standard.h>
31 #include <schily/fcntl.h>
32 #include <schily/io.h>				/* for setmode() prototype */
33 
34 #ifdef	VMS
35 #include <vms_init.h>
36 #define	open(n, p, m)	(open)((n), (p), (m), \
37 				"acc", acc_cb, &open_id)
38 #endif
39 
40 #include "xio.h"
41 
42 LOCAL xio_t	x_stdin = {
43 	NULL,		/* x_next	*/
44 	NULL,		/* x_name	*/
45 	0,		/* x_off	*/
46 	0,		/* x_startoff	*/
47 	STDIN_FILENO,	/* x_file	*/
48 	999,		/* x_refcnt	*/
49 	O_RDONLY,	/* x_oflag	*/
50 	0,		/* x_omode	*/
51 	0		/* x_xflags	*/
52 };
53 
54 LOCAL xio_t	*x_root = &x_stdin;
55 LOCAL xio_t	**x_tail = NULL;
56 
57 
58 LOCAL	xio_t	*xnewnode	__PR((char *name));
59 EXPORT	void	*xopen		__PR((char *name, int oflag, int mode,
60 								int xflags));
61 EXPORT	off_t	xmarkpos	__PR((void *vp));
62 EXPORT	int	xclose		__PR((void *vp));
63 
64 LOCAL xio_t *
xnewnode(name)65 xnewnode(name)
66 	char	*name;
67 {
68 	xio_t	*xp;
69 
70 	if ((xp = malloc(sizeof (xio_t))) == NULL)
71 		return ((xio_t *) NULL);
72 
73 	xp->x_next = (xio_t *) NULL;
74 	xp->x_name = strdup(name);
75 	if (xp->x_name == NULL) {
76 		free(xp);
77 		return ((xio_t *) NULL);
78 	}
79 	xp->x_off = 0;
80 	xp->x_startoff = (off_t)0;
81 	xp->x_file = -1;
82 	xp->x_refcnt = 1;
83 	xp->x_oflag = 0;
84 	xp->x_omode = 0;
85 	xp->x_xflags = 0;
86 	return (xp);
87 }
88 
89 EXPORT void *
xopen(name,oflag,mode,xflags)90 xopen(name, oflag, mode, xflags)
91 	char	*name;
92 	int	oflag;
93 	int	mode;
94 	int	xflags;
95 {
96 	int	f;
97 	xio_t	*xp;
98 	xio_t	*pp = x_root;
99 
100 	if (x_tail == NULL)
101 		x_tail = &x_stdin.x_next;
102 	if (name == NULL) {
103 		xp = &x_stdin;
104 		xp->x_refcnt++;
105 		if ((oflag & O_BINARY) != 0) {
106 			setmode(STDIN_FILENO, O_BINARY);
107 		}
108 		return (xp);
109 	}
110 	for (; pp; pp = pp->x_next) {
111 		if (pp->x_name == NULL)	/* stdin avoid core dump in strcmp() */
112 			continue;
113 		if ((strcmp(pp->x_name, name) == 0) &&
114 		    (pp->x_oflag == oflag) && (pp->x_omode == mode)) {
115 			break;
116 		}
117 	}
118 	if (pp) {
119 		pp->x_refcnt++;
120 		return ((void *)pp);
121 	}
122 	if ((f = open(name, oflag, mode)) < 0)
123 		return (NULL);
124 
125 	if ((xp = xnewnode(name)) == NULL) {
126 		close(f);
127 		return (NULL);
128 	}
129 	xp->x_file = f;
130 	xp->x_oflag = oflag;
131 	xp->x_omode = mode;
132 	xp->x_xflags = xflags & X_UFLAGS;
133 	*x_tail = xp;
134 	x_tail = &xp->x_next;
135 	return ((void *)xp);
136 }
137 
138 EXPORT off_t
xmarkpos(vp)139 xmarkpos(vp)
140 	void	*vp;
141 {
142 	xio_t	*xp = vp;
143 	off_t	off = (off_t)0;
144 
145 	if (xp == (xio_t *)NULL)
146 		return ((off_t)-1);
147 
148 	xp->x_startoff = off = lseek(xp->x_file, (off_t)0, SEEK_CUR);
149 	if (xp->x_startoff == (off_t)-1) {
150 		xp->x_startoff = (off_t)0;
151 		xp->x_xflags |= X_NOSEEK;
152 	}
153 	if (isatty(xp->x_file)) {
154 		off = (off_t)-1;
155 		xp->x_xflags |= X_NOSEEK;
156 	}
157 	return (off);
158 }
159 
160 EXPORT int
xclose(vp)161 xclose(vp)
162 	void	*vp;
163 {
164 	xio_t	*xp = vp;
165 	xio_t	*pp = x_root;
166 	int	ret = 0;
167 
168 	if (xp == &x_stdin)
169 		return (ret);
170 	if (x_tail == NULL)
171 		x_tail = &x_stdin.x_next;
172 
173 /*error("xclose(%p) refcnt = %d\n", vp, xp->x_refcnt);*/
174 	if (--xp->x_refcnt <= 0) {
175 		ret = close(xp->x_file);
176 		while (pp) {
177 			if (pp->x_next == xp)
178 				break;
179 			if (pp->x_next == NULL)
180 				break;
181 			pp = pp->x_next;
182 		}
183 		if (pp->x_next == xp) {
184 			if (x_tail == &xp->x_next)
185 				x_tail = &pp->x_next;
186 			pp->x_next = xp->x_next;
187 		}
188 
189 		free(xp->x_name);
190 		free(xp);
191 	} else if ((xp->x_xflags & (X_NOREWIND|X_NOSEEK)) == 0) {
192 		lseek(xp->x_file, xp->x_startoff, SEEK_SET);
193 	}
194 	return (ret);
195 }
196