1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfhdr.h"
23
24/*	Change the file descriptor
25**
26**	Written by Kiem-Phong Vo.
27*/
28
29#if __STD_C
30static int _sfdup(int fd, int newfd)
31#else
32static int _sfdup(fd,newfd)
33int	fd;
34int	newfd;
35#endif
36{
37	reg int	dupfd;
38
39#ifdef F_DUPFD	/* the simple case */
40	while((dupfd = sysfcntlf(fd,F_DUPFD,newfd)) < 0 && errno == EINTR)
41		errno = 0;
42	return dupfd;
43
44#else	/* do it the hard way */
45	if((dupfd = sysdupf(fd)) < 0 || dupfd >= newfd)
46		return dupfd;
47
48	/* dup() succeeded but didn't get the right number, recurse */
49	newfd = _sfdup(fd,newfd);
50
51	/* close the one that didn't match */
52	CLOSE(dupfd);
53
54	return newfd;
55#endif
56}
57
58#if __STD_C
59int sfsetfd(Sfio_t* f, int newfd)
60#else
61int sfsetfd(f,newfd)
62Sfio_t	*f;
63int	newfd;
64#endif
65{
66	reg int		oldfd;
67	SFMTXDECL(f);
68
69	SFMTXENTER(f, -1);
70
71	if(f->flags&SF_STRING)
72		SFMTXRETURN(f, -1);
73
74	if((f->mode&SF_INIT) && f->file < 0)
75	{	/* restoring file descriptor after a previous freeze */
76		if(newfd < 0)
77			SFMTXRETURN(f, -1);
78	}
79	else
80	{	/* change file descriptor */
81		if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
82			SFMTXRETURN(f, -1);
83		SFLOCK(f,0);
84
85		oldfd = f->file;
86		if(oldfd >= 0)
87		{	if(newfd >= 0)
88			{	if((newfd = _sfdup(oldfd,newfd)) < 0)
89				{	SFOPEN(f,0);
90					SFMTXRETURN(f, -1);
91				}
92				CLOSE(oldfd);
93			}
94			else
95			{	/* sync stream if necessary */
96				if(((f->mode&SF_WRITE) && f->next > f->data) ||
97				   (f->mode&SF_READ) || f->disc == _Sfudisc)
98				{	if(SFSYNC(f) < 0)
99					{	SFOPEN(f,0);
100						SFMTXRETURN(f, -1);
101					}
102				}
103
104				if(((f->mode&SF_WRITE) && f->next > f->data) ||
105				   ((f->mode&SF_READ) && f->extent < 0 &&
106				    f->next < f->endb) )
107				{	SFOPEN(f,0);
108					SFMTXRETURN(f, -1);
109				}
110
111#ifdef MAP_TYPE
112				if((f->bits&SF_MMAP) && f->data)
113				{	SFMUNMAP(f,f->data,f->endb-f->data);
114					f->data = NIL(uchar*);
115				}
116#endif
117
118				/* make stream appears uninitialized */
119				f->endb = f->endr = f->endw = f->data;
120				f->extent = f->here = 0;
121				f->mode = (f->mode&SF_RDWR)|SF_INIT;
122				f->bits &= ~SF_NULL;	/* off /dev/null handling */
123			}
124		}
125
126		SFOPEN(f,0);
127	}
128
129	/* notify changes */
130	if(_Sfnotify)
131		(*_Sfnotify)(f, SF_SETFD, (void*)((long)newfd));
132
133	f->file = newfd;
134
135	SFMTXRETURN(f,newfd);
136}
137