1*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
2*7c478bd9Sstevel@tonic-gate /*
3*7c478bd9Sstevel@tonic-gate  * prof_file.c ---- routines that manipulate an individual profile file.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #include <autoconf.h>
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate #include <stdio.h>
9*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H
10*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
11*7c478bd9Sstevel@tonic-gate #endif
12*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UNISTD_H
13*7c478bd9Sstevel@tonic-gate #include <unistd.h>
14*7c478bd9Sstevel@tonic-gate #endif
15*7c478bd9Sstevel@tonic-gate #include <string.h>
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include "prof_int.h"
18*7c478bd9Sstevel@tonic-gate 
19*7c478bd9Sstevel@tonic-gate #ifndef NO_SYS_TYPES_H
20*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
21*7c478bd9Sstevel@tonic-gate #endif
22*7c478bd9Sstevel@tonic-gate #ifndef NO_SYS_STAT_H
23*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
24*7c478bd9Sstevel@tonic-gate #endif
25*7c478bd9Sstevel@tonic-gate #include <errno.h>
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #if defined(_MSDOS) || defined(_WIN32)
29*7c478bd9Sstevel@tonic-gate #include <io.h>
30*7c478bd9Sstevel@tonic-gate #define HAVE_STAT
31*7c478bd9Sstevel@tonic-gate #define stat _stat
32*7c478bd9Sstevel@tonic-gate #endif
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #ifndef PROFILE_USES_PATHS
35*7c478bd9Sstevel@tonic-gate #include <FSp_fopen.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate static OSErr GetMacOSTempFilespec (
38*7c478bd9Sstevel@tonic-gate 	const	FSSpec*	inFilespec,
39*7c478bd9Sstevel@tonic-gate 			FSSpec*	outFilespec);
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #endif
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate static int rw_access(filespec)
44*7c478bd9Sstevel@tonic-gate 	profile_filespec_t filespec;
45*7c478bd9Sstevel@tonic-gate {
46*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ACCESS
47*7c478bd9Sstevel@tonic-gate 	if (access(filespec, W_OK) == 0)
48*7c478bd9Sstevel@tonic-gate 		return 1;
49*7c478bd9Sstevel@tonic-gate 	else
50*7c478bd9Sstevel@tonic-gate 		return 0;
51*7c478bd9Sstevel@tonic-gate #else
52*7c478bd9Sstevel@tonic-gate 	/*
53*7c478bd9Sstevel@tonic-gate 	 * We're on a substandard OS that doesn't support access.  So
54*7c478bd9Sstevel@tonic-gate 	 * we kludge a test using stdio routines, and hope fopen
55*7c478bd9Sstevel@tonic-gate 	 * checks the r/w permissions.
56*7c478bd9Sstevel@tonic-gate 	 */
57*7c478bd9Sstevel@tonic-gate 	FILE	*f;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #ifdef PROFILE_USES_PATHS
60*7c478bd9Sstevel@tonic-gate 	f = fopen(filespec, "r+");
61*7c478bd9Sstevel@tonic-gate #else
62*7c478bd9Sstevel@tonic-gate 	f = FSp_fopen(&filespec, "r+");
63*7c478bd9Sstevel@tonic-gate #endif
64*7c478bd9Sstevel@tonic-gate 	if (f) {
65*7c478bd9Sstevel@tonic-gate 		fclose(f);
66*7c478bd9Sstevel@tonic-gate 		return 1;
67*7c478bd9Sstevel@tonic-gate 	}
68*7c478bd9Sstevel@tonic-gate 	return 0;
69*7c478bd9Sstevel@tonic-gate #endif
70*7c478bd9Sstevel@tonic-gate }
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate errcode_t profile_open_file(filespec, ret_prof)
73*7c478bd9Sstevel@tonic-gate 	const_profile_filespec_t filespec;
74*7c478bd9Sstevel@tonic-gate 	prf_file_t *ret_prof;
75*7c478bd9Sstevel@tonic-gate {
76*7c478bd9Sstevel@tonic-gate 	prf_file_t	prf;
77*7c478bd9Sstevel@tonic-gate 	errcode_t	retval;
78*7c478bd9Sstevel@tonic-gate 	char		*home_env = 0;
79*7c478bd9Sstevel@tonic-gate 	int		len;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	prf = (prf_file_t) malloc(sizeof(struct _prf_file_t));
82*7c478bd9Sstevel@tonic-gate 	if (!prf)
83*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
84*7c478bd9Sstevel@tonic-gate 	memset(prf, 0, sizeof(struct _prf_file_t));
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #ifndef macintosh
87*7c478bd9Sstevel@tonic-gate 	len = strlen(filespec)+1;
88*7c478bd9Sstevel@tonic-gate 	if (filespec[0] == '~' && filespec[1] == '/') {
89*7c478bd9Sstevel@tonic-gate 		home_env = getenv("HOME");
90*7c478bd9Sstevel@tonic-gate 		if (home_env)
91*7c478bd9Sstevel@tonic-gate 			len += strlen(home_env);
92*7c478bd9Sstevel@tonic-gate 	}
93*7c478bd9Sstevel@tonic-gate 	prf->filespec = (char *) malloc(len);
94*7c478bd9Sstevel@tonic-gate 	if (!prf->filespec) {
95*7c478bd9Sstevel@tonic-gate 		free(prf);
96*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
97*7c478bd9Sstevel@tonic-gate 	}
98*7c478bd9Sstevel@tonic-gate 	if (home_env) {
99*7c478bd9Sstevel@tonic-gate 		strcpy(prf->filespec, home_env);
100*7c478bd9Sstevel@tonic-gate 		strcat(prf->filespec, filespec+1);
101*7c478bd9Sstevel@tonic-gate 	} else
102*7c478bd9Sstevel@tonic-gate 		strcpy(prf->filespec, filespec);
103*7c478bd9Sstevel@tonic-gate 	prf->magic = PROF_MAGIC_FILE;
104*7c478bd9Sstevel@tonic-gate #else
105*7c478bd9Sstevel@tonic-gate 	prf->filespec = filespec;
106*7c478bd9Sstevel@tonic-gate 	prf->magic = PROF_MAGIC_FILE;
107*7c478bd9Sstevel@tonic-gate #endif
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	retval = profile_update_file(prf);
110*7c478bd9Sstevel@tonic-gate 	if (retval) {
111*7c478bd9Sstevel@tonic-gate 		profile_close_file(prf);
112*7c478bd9Sstevel@tonic-gate 		return retval;
113*7c478bd9Sstevel@tonic-gate 	}
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 	*ret_prof = prf;
116*7c478bd9Sstevel@tonic-gate 	return 0;
117*7c478bd9Sstevel@tonic-gate }
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate errcode_t profile_update_file(prf)
120*7c478bd9Sstevel@tonic-gate 	prf_file_t prf;
121*7c478bd9Sstevel@tonic-gate {
122*7c478bd9Sstevel@tonic-gate 	errcode_t retval;
123*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT
124*7c478bd9Sstevel@tonic-gate 	struct stat st;
125*7c478bd9Sstevel@tonic-gate #endif
126*7c478bd9Sstevel@tonic-gate 	FILE *f;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT
129*7c478bd9Sstevel@tonic-gate 	if (stat(prf->filespec, &st))
130*7c478bd9Sstevel@tonic-gate 		return errno;
131*7c478bd9Sstevel@tonic-gate 	if (st.st_mtime == prf->timestamp)
132*7c478bd9Sstevel@tonic-gate 		return 0;
133*7c478bd9Sstevel@tonic-gate 	if (prf->root) {
134*7c478bd9Sstevel@tonic-gate 		profile_free_node(prf->root);
135*7c478bd9Sstevel@tonic-gate 		prf->root = 0;
136*7c478bd9Sstevel@tonic-gate 	}
137*7c478bd9Sstevel@tonic-gate 	if (prf->comment) {
138*7c478bd9Sstevel@tonic-gate 		free(prf->comment);
139*7c478bd9Sstevel@tonic-gate 		prf->comment = 0;
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate #else
142*7c478bd9Sstevel@tonic-gate 	/*
143*7c478bd9Sstevel@tonic-gate 	 * If we don't have the stat() call, assume that our in-core
144*7c478bd9Sstevel@tonic-gate 	 * memory image is correct.  That is, we won't reread the
145*7c478bd9Sstevel@tonic-gate 	 * profile file if it changes.
146*7c478bd9Sstevel@tonic-gate 	 */
147*7c478bd9Sstevel@tonic-gate 	if (prf->root)
148*7c478bd9Sstevel@tonic-gate 		return 0;
149*7c478bd9Sstevel@tonic-gate #endif
150*7c478bd9Sstevel@tonic-gate 	errno = 0;
151*7c478bd9Sstevel@tonic-gate #ifdef PROFILE_USES_PATHS
152*7c478bd9Sstevel@tonic-gate 	f = fopen(prf->filespec, "r");
153*7c478bd9Sstevel@tonic-gate #else
154*7c478bd9Sstevel@tonic-gate 	f = FSp_fopen (&prf->filespec, "r");
155*7c478bd9Sstevel@tonic-gate #endif
156*7c478bd9Sstevel@tonic-gate 	if (f == NULL) {
157*7c478bd9Sstevel@tonic-gate 		retval = errno;
158*7c478bd9Sstevel@tonic-gate 		if (retval == 0)
159*7c478bd9Sstevel@tonic-gate 			retval = ENOENT;
160*7c478bd9Sstevel@tonic-gate 		return retval;
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 	prf->upd_serial++;
163*7c478bd9Sstevel@tonic-gate 	prf->flags = 0;
164*7c478bd9Sstevel@tonic-gate 	if (rw_access(prf->filespec))
165*7c478bd9Sstevel@tonic-gate 		prf->flags |= PROFILE_FILE_RW;
166*7c478bd9Sstevel@tonic-gate 	retval = profile_parse_file(f, &prf->root);
167*7c478bd9Sstevel@tonic-gate 	fclose(f);
168*7c478bd9Sstevel@tonic-gate 	if (retval)
169*7c478bd9Sstevel@tonic-gate 		return retval;
170*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT
171*7c478bd9Sstevel@tonic-gate 	prf->timestamp = st.st_mtime;
172*7c478bd9Sstevel@tonic-gate #endif
173*7c478bd9Sstevel@tonic-gate 	return 0;
174*7c478bd9Sstevel@tonic-gate }
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate #ifndef PROFILE_USES_PATHS
177*7c478bd9Sstevel@tonic-gate OSErr GetMacOSTempFilespec (
178*7c478bd9Sstevel@tonic-gate 	const	FSSpec*	inFileSpec,
179*7c478bd9Sstevel@tonic-gate 			FSSpec*	outFileSpec)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	OSErr	err;
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	err = FindFolder (inFileSpec -> vRefNum, kTemporaryFolderType,
184*7c478bd9Sstevel@tonic-gate 		kCreateFolder, &(outFileSpec -> vRefNum), &(outFileSpec -> parID));
185*7c478bd9Sstevel@tonic-gate 	if (err != noErr)
186*7c478bd9Sstevel@tonic-gate 		return err;
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	BlockMoveData (&(inFileSpec -> name), &(outFileSpec -> name), StrLength (inFileSpec -> name) + 1);
189*7c478bd9Sstevel@tonic-gate 	return noErr;
190*7c478bd9Sstevel@tonic-gate }
191*7c478bd9Sstevel@tonic-gate #endif
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate errcode_t profile_flush_file(prf)
195*7c478bd9Sstevel@tonic-gate 	prf_file_t prf;
196*7c478bd9Sstevel@tonic-gate {
197*7c478bd9Sstevel@tonic-gate 	FILE		*f;
198*7c478bd9Sstevel@tonic-gate 	profile_filespec_t new_file;
199*7c478bd9Sstevel@tonic-gate 	profile_filespec_t old_file;
200*7c478bd9Sstevel@tonic-gate 	errcode_t	retval = 0;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	if (!prf || prf->magic != PROF_MAGIC_FILE)
203*7c478bd9Sstevel@tonic-gate 		return PROF_MAGIC_FILE;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	if ((prf->flags & PROFILE_FILE_DIRTY) == 0)
206*7c478bd9Sstevel@tonic-gate 		return 0;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	retval = ENOMEM;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate #ifdef PROFILE_USES_PATHS
211*7c478bd9Sstevel@tonic-gate 	new_file = old_file = 0;
212*7c478bd9Sstevel@tonic-gate 	new_file = (char *) malloc(strlen(prf->filespec) + 5);
213*7c478bd9Sstevel@tonic-gate 	if (!new_file)
214*7c478bd9Sstevel@tonic-gate 		goto errout;
215*7c478bd9Sstevel@tonic-gate 	old_file = (char *) malloc(strlen(prf->filespec) + 5);
216*7c478bd9Sstevel@tonic-gate 	if (!old_file)
217*7c478bd9Sstevel@tonic-gate 		goto errout;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	sprintf(new_file, "%s.$$$", prf->filespec);
220*7c478bd9Sstevel@tonic-gate 	sprintf(old_file, "%s.bak", prf->filespec);
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	errno = 0;
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	f = fopen(new_file, "w");
225*7c478bd9Sstevel@tonic-gate #else
226*7c478bd9Sstevel@tonic-gate 	/* On MacOS, we do this by writing to a new file and then atomically
227*7c478bd9Sstevel@tonic-gate 	swapping the files with a file system call */
228*7c478bd9Sstevel@tonic-gate 	GetMacOSTempFilespec (&prf->filespec, &new_file);
229*7c478bd9Sstevel@tonic-gate 	f = FSp_fopen (&new_file, "w");
230*7c478bd9Sstevel@tonic-gate #endif
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if (!f) {
233*7c478bd9Sstevel@tonic-gate 		retval = errno;
234*7c478bd9Sstevel@tonic-gate 		if (retval == 0)
235*7c478bd9Sstevel@tonic-gate 			retval = PROF_FAIL_OPEN;
236*7c478bd9Sstevel@tonic-gate 		goto errout;
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	profile_write_tree_file(prf->root, f);
240*7c478bd9Sstevel@tonic-gate 	if (fclose(f) != 0) {
241*7c478bd9Sstevel@tonic-gate 		retval = errno;
242*7c478bd9Sstevel@tonic-gate 		goto errout;
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate #ifdef PROFILE_USES_PATHS
246*7c478bd9Sstevel@tonic-gate 	unlink(old_file);
247*7c478bd9Sstevel@tonic-gate 	if (rename(prf->filespec, old_file)) {
248*7c478bd9Sstevel@tonic-gate 		retval = errno;
249*7c478bd9Sstevel@tonic-gate 		goto errout;
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	if (rename(new_file, prf->filespec)) {
252*7c478bd9Sstevel@tonic-gate 		retval = errno;
253*7c478bd9Sstevel@tonic-gate 		rename(old_file, prf->filespec); /* back out... */
254*7c478bd9Sstevel@tonic-gate 		goto errout;
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate #else
257*7c478bd9Sstevel@tonic-gate 	{
258*7c478bd9Sstevel@tonic-gate 		OSErr err = FSpExchangeFiles (&prf->filespec, &new_file);
259*7c478bd9Sstevel@tonic-gate 		if (err != noErr) {
260*7c478bd9Sstevel@tonic-gate 			retval = ENFILE;
261*7c478bd9Sstevel@tonic-gate 			goto errout;
262*7c478bd9Sstevel@tonic-gate 		}
263*7c478bd9Sstevel@tonic-gate 		FSpDelete (&new_file);
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate #endif
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	prf->flags = 0;
269*7c478bd9Sstevel@tonic-gate 	if (rw_access(prf->filespec))
270*7c478bd9Sstevel@tonic-gate 		prf->flags |= PROFILE_FILE_RW;
271*7c478bd9Sstevel@tonic-gate 	retval = 0;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate errout:
274*7c478bd9Sstevel@tonic-gate #ifdef PROFILE_USES_PATHS
275*7c478bd9Sstevel@tonic-gate 	if (new_file)
276*7c478bd9Sstevel@tonic-gate 		free(new_file);
277*7c478bd9Sstevel@tonic-gate 	if (old_file)
278*7c478bd9Sstevel@tonic-gate 		free(old_file);
279*7c478bd9Sstevel@tonic-gate #endif
280*7c478bd9Sstevel@tonic-gate 	return retval;
281*7c478bd9Sstevel@tonic-gate }
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate void profile_free_file(prf)
285*7c478bd9Sstevel@tonic-gate 	prf_file_t prf;
286*7c478bd9Sstevel@tonic-gate {
287*7c478bd9Sstevel@tonic-gate #ifdef PROFILE_USES_PATHS
288*7c478bd9Sstevel@tonic-gate 	if (prf->filespec)
289*7c478bd9Sstevel@tonic-gate 		free(prf->filespec);
290*7c478bd9Sstevel@tonic-gate #endif
291*7c478bd9Sstevel@tonic-gate 	if (prf->root)
292*7c478bd9Sstevel@tonic-gate 		profile_free_node(prf->root);
293*7c478bd9Sstevel@tonic-gate 	if (prf->comment)
294*7c478bd9Sstevel@tonic-gate 		free(prf->comment);
295*7c478bd9Sstevel@tonic-gate 	prf->magic = 0;
296*7c478bd9Sstevel@tonic-gate 	free(prf);
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	return;
299*7c478bd9Sstevel@tonic-gate }
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate errcode_t profile_close_file(prf)
302*7c478bd9Sstevel@tonic-gate 	prf_file_t prf;
303*7c478bd9Sstevel@tonic-gate {
304*7c478bd9Sstevel@tonic-gate 	errcode_t	retval;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	retval = profile_flush_file(prf);
307*7c478bd9Sstevel@tonic-gate 	if (retval)
308*7c478bd9Sstevel@tonic-gate 		return retval;
309*7c478bd9Sstevel@tonic-gate 	profile_free_file(prf);
310*7c478bd9Sstevel@tonic-gate 	return 0;
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate 
313