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