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