1 /*
2 		    Low Level Interface Library
3 
4            Copyright 1983-2008 Green Hills Software,Inc.
5 
6  *  This program is the property of Green Hills Software, Inc,
7  *  its contents are proprietary information and no part of it
8  *  is to be disclosed to anyone except employees of Green Hills
9  *  Software, Inc., or as agreed in writing signed by the President
10  *  of Green Hills Software, Inc.
11 */
12 /* ind_trnc.c: NON-ANSI truncate() facility. Provided for FORTRAN support. */
13 
14 #include "indos.h"
15 #include "ind_io.h"
16 
17 #if !defined(ANYBSD) && !defined(ANYSYSV4)
18 
19 #if defined(__VXWORKS)
20 
21 #include <stdio.h>
22 #include <string.h>
23 
24 #else
25 
26 #ifndef L_tmpnam
27 #define L_tmpnam 32
28 #endif
29 
30 
31 #ifdef TMPNAMPREFIX
32 #   define L_TMPNAMEPREFIX 0
33 #elif defined(ANYUNIX)||defined(UNIXSYSCALLS)||defined(vms)||defined(__vms)
34 #   define TMPNAMPREFIX "gh_"
35 #   define L_TMPNAMEPREFIX 3
36 #else
37 #   define TMPNAMPREFIX "T"
38 #   define L_TMPNAMEPREFIX 1
39 #endif
40 
41 /* access is better everywhere */
42 #define USE_ACCESS
43 
44 #ifndef USE_ACESS
45 int stat(char *, struct stat *);
46 #endif
47 
tmpnam(char * s)48 static char *tmpnam(char *s) {
49 /******************************************************************************/
50 /*  This static tmpnam function is only needed for truncate, which is	      */
51 /*  only needed if the Green Hills Fortran Library is being used.	      */
52 /*  There is an exact copy of this function in the Green Hills C library.     */
53 /******************************************************************************/
54 #pragma ghs nowarning 1908
55     static const char hexmap[32]="0123456789abcdefghijklmnopqrstuv";
56 #pragma ghs endnowarning
57     int cnt = 0;
58     int chan, u=17;
59     char *p, *q;
60 #ifdef TMPNAMPREFIX
61 /*    if (sizeof(space) < (sizeof(TMPNAMPREFIX) + 8)) */
62 /*	return NULL; */
63 #elif defined(ANYUNIX)||defined(UNIXSYSCALLS)||defined(vms)||defined(__vms)
64 #else
65 #endif
66 #if L_tmpnam < L_TMPNAMEPREFIX + 8
67 #   error L_tmpnam too small
68 #endif
69 #if defined(ANYUNIX) || defined(UNIXSYSCALLS) || defined(MSW)
70     u = getpid();
71 #endif
72 /*    if ( s==NULL )	*/
73 /*	s=space;	*/
74     for (p = s, q = TMPNAMPREFIX; *q; )
75 	*p++ = *q++;
76 #if defined(ANYUNIX) || defined(UNIXSYSCALLS) || defined(MSW)
77     *p++ = hexmap[(u>>10) & 31];
78     *p++ = hexmap[(u>>5) & 31];
79     *p++ = hexmap[u & 31];
80 #endif
81 #ifndef USE_ACCESS
82     olderrno = __gh_get_errno();	/* access does not mess with errno */
83 #endif
84     do {
85 	char *qq = p;
86 	u = (++cnt & 0x0fffff);
87 	do {
88 	    *qq++ = hexmap[u & 31];
89 	    u >>= 5;
90 	} while (u);
91 	*qq = '\0';
92 #ifdef USE_ACESS
93 	chan = access(s, F_OK);
94 #else
95 	{
96 	struct stat st;
97 	chan = stat(s, &st);
98 	}
99 #endif
100     } while ( chan!=-1 );
101 #ifndef USE_ACCESS
102     __gh_set_errno(olderrno);
103 #endif
104 return(s);
105 }
106 
107 #endif /* defined(__VXWORKS) */
108 
109 /******************************************************************************/
110 /*  The Green Hills C Library does not use the truncate function, it is only  */
111 /*  needed if the Green Hills Fortran Library is being used.		      */
112 /*									      */
113 /*  int truncate(const char *path, int length);				      */
114 /*									      */
115 /*  If the file named "path" is longer than "length" bytes it is truncated    */
116 /*  to "length" bytes.							      */
117 /*									      */
118 /*  Return 0 if the named file is truncated or was previously less than	      */
119 /*  length bytes.  Return -1 if the file cannot be truncated, and set	      */
120 /*  errno appropriately.						      */
121 /*									      */
122 /*  REENTRANT								      */
123 /******************************************************************************/
124 
125 #define _0777 0x1ff
126 #if defined(__VXWORKS)
127 #define __CREAT_ARG O_WRONLY
128 #else
129 #define __CREAT_ARG _0777
130 #endif
131 
132 #define LBUFSIZ	1024
133 
truncate(const char * path,long length)134 int truncate(const char *path, long length)
135 {
136 /*
137    The following implementation copies the first "length" bytes of the file
138    named "path" to a temporary file, then it creates a new file with
139    the name "path" and copies the temporary file back into it.  At the end
140    the temporary file is deleted.  The prefered implementation is to shorten
141    the file without copying, but many operating systems lack such an operation.
142 */
143     char buf[LBUFSIZ];
144     char namebuff[L_tmpnam];
145     int inf, of;
146     int count = 0;
147     char *tmpname = tmpnam(namebuff);
148 
149 /* handle the two trivial cases efficiently:
150 	length is 0 and length is greater than or equal to actual size of file
151 */
152     if (length == 0) {
153 	if ((of = creat(path, __CREAT_ARG)) == -1)
154 	    return -1;
155 	close(of);
156 	return 0;
157     }
158 
159 #if !defined(CROSSUNIX) && \
160        (defined(ANYUNIX)||defined(UNIXSYSCALLS)||defined(MSW)||defined(__VXWORKS))
161     {
162     struct stat stat1;
163     if (stat((char *)path, &stat1) < 0)
164 	return -1;
165 
166     if (stat1.st_size != (unsigned long)-1 && length >= stat1.st_size)
167 	return 0;
168     }
169 #endif
170 
171     if ((inf = open(path, 0, 0)) == -1 || (of = creat(tmpname, __CREAT_ARG)) == -1)
172     {
173 	if (inf != -1)
174 	    close(inf);
175 	return(-1);
176     }
177     while (length > 0 && (count = read(inf, buf, LBUFSIZ)) > 0) {
178 	if (count > length)
179 	    count = length;
180 	if (count > write(of, buf, count)) {
181 	    count = -1;
182 	    break;
183 	}
184 	length -= count;
185     }
186     close(inf);
187     close(of);
188 
189     if (length == 0 && count >= 0) {
190 
191 	if (rename(tmpname, path) == 0) {
192 	    return(0);
193 	}
194 #if defined(vms) || defined(__vms)
195 	delete(path);
196 #elif defined (__VXWORKS)
197 	{
198 	    char *tmp_path = malloc (strlen(path) + 1);
199 	    if (tmp_path == NULL)
200 		return -1;
201 	    strcpy (tmp_path, path);
202 	    unlink(tmp_path);
203 	    free (tmp_path);
204 	}
205 #else
206 	unlink(path);
207 #endif
208 	if (rename(tmpname, path) == 0) {
209 	    return(0);
210 	}
211 
212 	if ((inf = open(tmpname, 0, 0)) == -1 || (of = creat(path, _0777)) == -1)
213 	{
214 	    if (inf != -1)
215 		close(inf);
216 	    return(-1);
217 	}
218 	while ((count = read(inf, buf, LBUFSIZ)) > 0)
219 	    if (count > write(of, buf, count)) {
220 		count = -1;
221 		break;
222 	    }
223 	close(inf);
224 	close(of);
225     }
226 #if defined(vms) || defined(__vms)
227     delete(tmpname);
228 #else
229     unlink(tmpname);
230 #endif
231     return(count);
232 }
233 
234 #else
235 
236 int _M_empty_file_illegal;
237 
238 #endif	/* ! ANYBSD */
239