/* ** Name: LOmkingpath - make INGRES location's area path ** ** Description: ** Makes missing subdirectories in a location's area path. ** ** Inputs: ** area "device" that the location is on ** what path to db, ckp, dmp, work, jnl ** loc set to full path of location ** ** Outputs: ** none ** ** Returns: ** LO_NULL_ARG area or what were NULL or empty ** LO_NO_SUCH required path component does not exist ** ** History: ** 03-dec-2003 (abbjo03) ** Created. */ STATUS LOmkingpath( char *area, /* "device" that the database is on */ char *what, /* path to db, ckp, dmp, work, or jnl */ LOCATION *loc) /* set to full path of location */ { STATUS status; char path[MAX_LOC+1]; i4 flags; LOINFORMATION info; /* check for legal arguments */ if (area == NULL || *area == EOS || STtrmwhite(area) == 0 || what == NULL || *what == EOS) return LO_NULL_ARG; LOdev_to_root(area, path); if ((status = LOfroms(PATH, path, loc)) != OK) return status; flags = LO_I_TYPE; if (LOinfo(loc, &flags, &info)) return LO_NO_SUCH; if ((flags & LO_I_TYPE) == 0 || info.li_type != LO_IS_DIR) return LO_NO_SUCH; LOfaddpath(loc, SystemLocationSubdirectory, loc); if ((status = LOfroms(PATH, path, loc)) != OK) return status; flags = LO_I_TYPE; if (LOinfo(loc, &flags, &info)) { if ((status = LOcreate(loc)) != OK) return status; } /* Set protections */ if (setperms(loc, PROT_SRWE_ORWE_G_WRE) != OK) return FAIL; LOfaddpath(loc, what, loc); if ((status = LOfroms(PATH, path, loc)) != OK) return status; flags = LO_I_TYPE; if (LOinfo(loc, &flags, &info)) { if ((status = LOcreate(loc)) != OK) return status; } if (setperms(loc, PROT_SRWE_ORWE_G_WRE) != OK) return FAIL; flags = LO_I_PERMS; if ((status = LOinfo(loc, &flags, &info)) == OK && (info.li_perms & LO_P_WRITE) == 0) status = LO_NO_PERM; return status; }
STATUS LOsize( register LOCATION *loc, register OFFSET_TYPE *loc_size) { LOINFORMATION info; STATUS status; i4 flags; /* We want size info only */ flags = LO_I_SIZE; /* Call LOinfo to get the info */ status = LOinfo(loc, &flags, &info); /* return the data and/or status */ if (status != OK) { return(status); } else if ((flags & LO_I_SIZE) == 0) { return (LO_CANT_TELL); } else { *loc_size = (OFFSET_TYPE) info.li_size; return (OK); } }
/*{ ** Name: NMwritesyms - write the symbol table list to file. ** ** Description: ** Write the symbol table list back out to the file. ** ** This duplicates the function in ingunset.c, but shouldn't be in ** compatlib because no one else has any business writing the file. ** ** Inputs: ** none. ** ** Output: ** none. ** ** Returns: ** OK Function completed normally. ** FAIL Function completed abnormally. ** ** History: ** 20-jul-87 (mmm) ** Updated to meet jupiter standards. ** 14-apr-89 (arana) ** When LOlast was added to update symbol table mod time, ** return value was saved off but not returned. ** 15-jul-93 (ed) ** adding <gl.h> after <compat.h> ** 29-sep-94 (cwaldman) ** Changed check of NMopensyms return value to compare against ** (FILE *)NULL (was NULL). ** Changed write routine to write into a temporary file first, ** check whether this file has been written OK, and rename ** temporary file to symbol.tbl if it is alright. This is part ** of the fix for bug 44445 (symbol.tbl disappears). There is ** still a slight chance of something going wrong during the ** rename, but in that case variables are at least preserved ** in symbol.tmp. ** 19-oct-94 (abowler) ** Minor correction to change above. Cal to SIopen should be ** passed address of location structure. (Didn't show up as ** a bug on su4_u42 !) ** 28-feb-95 (cwaldman) ** Amendment to change on 29 Sep. Part of the check whether ** the temporary symbol table had been written OK was to check ** the file size. The check would return the file size if ** check was OK and 0 otherwise. If a 0 was returned, the old ** symbol.tbl would not be replaced. This made it impossible ** to 'ingunset' the last variable in a symbol.tbl. Changed ** 'OK-check' to use -1 as error indicator. ** 02-jul-1996 (sweeney) ** Apply umask fix (bug #71890) from ingres63p ** 07-apr-2004 (somsa01) ** Added backup of symbol.tbl logic. */ STATUS NMwritesyms() { register SYM *sp; FILE *fp, *tfp = NULL; register i4 status = OK; register i4 closestat; char buf[ MAXLINE + NULL_NL_NULL ]; char tbuf[ MAXLINE + NULL_NL_NULL ]; i4 flagword, size, symcount = 0, bksymcount; STATUS retval; LOCATION t_loc; LOINFORMATION loinfo; bool perform_backup = TRUE; OFFSET_TYPE bk_size; /* ** ensure sensible umask for symbol.tmp, as it will become symbol.tbl */ PEsave(); PEumask("rw-r--"); if ((FILE *)NULL == (fp = NMopensyms( "r" ))) { PEreset(); return (NM_STOPN); } SIclose(fp); LOcopy(&NMSymloc, tbuf, &t_loc); if ( OK != LOfstfile("symbol.tmp", &t_loc) || OK != SIopen(&t_loc, "w", &tfp)) { return (NM_STOPN); } for ( sp = s_list; sp != NULL; sp = sp->s_next ) { (VOID) STpolycat( 3, sp->s_sym, "\t", sp->s_val, buf ); STmove( buf, ' ', MAXLINE, buf ); buf[ MAXLINE - 1 ] = '\n'; buf[ MAXLINE ] = '\0'; if ( OK != (status = SIputrec(buf, tfp))) break; symcount++; } /* Very interested in close status of file being written */ closestat = SIclose( tfp ); flagword = (LO_I_SIZE); size = (OK == LOinfo(&t_loc,&flagword,&loinfo) ? loinfo.li_size : -1); retval=(status != OK || closestat != OK || size == -1 ? NM_STAPP : OK); /* if file written ok update modification time */ if(retval == OK) { LOrename(&t_loc, &NMSymloc); LOlast(&NMSymloc, &NMtime); #if defined(su4_cmw) /* Now reset the old MAC label if any */ if (NM_got_label) { (void)setcmwlabel(NM_path, &NM_saved_label, SETCL_ALL); NM_got_label=0; } #endif /* ** If we have no backup to check against, just do it. Otherwise, ** make sure our new symbol table differs from the backup by at most ** one symbol before performing a backup. */ if (LOexist(&NMBakSymloc) == OK) { LOsize(&NMBakSymloc, &bk_size); bksymcount = (i4)(bk_size / (MAXLINE + 1)); if (bksymcount != symcount && bksymcount != symcount - 1 && bksymcount != symcount + 1) { perform_backup = FALSE; } } if (perform_backup) { if (SIopen(&NMBakSymloc, "w", &tfp) == OK) { for (sp = s_list; sp != NULL; sp = sp->s_next) { STpolycat(3, sp->s_sym, "\t", sp->s_val, buf); STmove(buf, ' ', MAXLINE, buf); buf[MAXLINE - 1] = '\n'; buf[MAXLINE] = '\0'; if ((status = SIputrec(buf, tfp)) != OK) break; } SIclose(tfp); } } } PEreset(); return (retval); }
/* ** Writes or erases a transaction log and displays a completion thermometer. ** ** 'context' must not be NULL, and defaults for element 0 & 1 of context ** must have been set. */ i4 write_transaction_log(bool create, PM_CONTEXT *context, char *log_dir[], char *log_file[], void (*message)(char *), void (*init_graph)(bool, i4), i4 graph_size, void (*update_graph)()) { # define LG_PAGE_SIZE 2048L # define LG_NUMBER_OF_PAGES 32L /* Number of pages to write at a time */ DI_IO dio[LG_MAX_FILE]; char buf[LG_PAGE_SIZE * LG_NUMBER_OF_PAGES]; char nodename[GL_MAXNAME]; i4 i, j, marker, count, num_logs; i4 num_pages, page, part_size, remainder, loop; CL_ERR_DESC err; char *string; LOCATION loc[LG_MAX_FILE]; char locbuf[MAX_LOC + 1]; char *path[LG_MAX_FILE]; i4 LOinfo_flag; LOINFORMATION loc_info; i8 size; CS_SCB scb; bool size_in_kbytes = FALSE; MEfill( sizeof( scb ), 0, ( PTR ) &scb ); ++graph_size; /* Prepare transaction for log LOCATION(s) */ for (num_logs = 0; num_logs < LG_MAX_FILE; num_logs++) { if (log_dir[num_logs] == 0) break; STcopy( log_dir[num_logs], locbuf ); LOfroms( PATH, locbuf, &loc[num_logs] ); LOfstfile( log_file[num_logs], &loc[num_logs] ); LOtos( &loc[num_logs], &path[num_logs] ); } /* get size (in bytes) of log file to be created or erased */ if( create ) { STATUS status; char *value; bool havevalue = FALSE; status = PMmGet( context, ERx( "$.$.rcp.file.kbytes" ), &value ); if ( status == OK ) { havevalue = TRUE; size_in_kbytes = TRUE; } if ( havevalue == FALSE ) { status = PMmGet( context, ERx( "$.$.rcp.file.size" ), &value ); if ( status == OK ) havevalue = TRUE; } if ( havevalue == FALSE ) { if ( message != NULL ) { char msg[ BIG_ENOUGH ]; STprintf( msg, ERx( "%s %s" ), PMmExpandRequest( context, ERx( "$.$.rcp.file.kbytes" ) ), "not found." ); message( msg ); } return( 0 ); } CVal8( value, &size ); } else { LOinfo_flag = LO_I_SIZE; size = 0; for (i = 0; i < num_logs; i++) { if ( LOinfo( &loc[i], &LOinfo_flag, &loc_info ) != OK ) { if ( message != NULL ) { char msg[ BIG_ENOUGH ]; STprintf( msg, "Unable to get size of transaction log:\n\n\t%s", path[i] ); (*message)( msg ); } return( 0 ); } else size += loc_info.li_size; if ((LOinfo_flag & LO_I_SIZE) == 0) break; } if ( (LOinfo_flag & LO_I_SIZE) == 0 || size == 0L) { STATUS status; char *value; bool havevalue = FALSE; status = PMmGet( context, ERx( "$.$.rcp.file.kbytes" ), &value ); if ( status == OK ) { havevalue = TRUE; size_in_kbytes = TRUE; } if ( havevalue == FALSE ) { status = PMmGet( context, ERx( "$.$.rcp.file.size" ), &value ); if ( status == OK ) havevalue = TRUE; } if ( havevalue == FALSE ) { if ( message != NULL ) { char msg[ BIG_ENOUGH ]; STprintf( msg, ERx( "%s %s." ), PMmExpandRequest( context, ERx( "$.$.rcp.file.kbytes" ) ), "not found." ); message( msg ); } return( 0 ); } CVal8( value, &size ); } } for (i = 0; i < num_logs; i++) { if ( create && LOexist( &loc[i] ) == OK ) { char msg[ BIG_ENOUGH ]; if ( message != NULL ) { STprintf( msg, "%s already exists.", path[i] ); (*message)( msg ); STprintf( msg, "To create a new transaction log, you must first delete all partitions of the old one." ); (*message)( msg ); } return( 0 ); } } if ( CSinitiate( (i4 *) NULL, (char ***) NULL, (CS_CB *) NULL ) != OK ) { if ( message != NULL ) message( "Unable to connect to shared memory" ); return( 0 ); } CSset_sid( &scb ); /* create DI file */ for (i = 0; i < num_logs; i++) { if ( create && DIcreate( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), (i4)LG_PAGE_SIZE, &err) != OK ) { char msg[ BIG_ENOUGH ]; if ( message != NULL ) { STprintf( msg, "Unable to create transaction log:\n\n\t%s", path[i] ); (*message)( msg ); } return( 0 ); } /* open DI file */ if ( DIopen( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), (i4)LG_PAGE_SIZE, DI_IO_WRITE, 0, &err) != OK ) { if ( message != NULL ) { char msg[ BIG_ENOUGH ]; STprintf( msg, "Unable to open transaction log:\n\n\t%s", path[i] ); (*message)( msg ); } return( 0 ); } } if ( size_in_kbytes == FALSE ) size = (size + 1023) / 1024; (*init_graph)( create, (i4) size ); num_pages = size / (LG_PAGE_SIZE/1024); part_size = num_pages / num_logs; /* Readjust num_pages to be a multiple of num_logs */ num_pages = part_size * num_logs; loop = part_size / LG_NUMBER_OF_PAGES; remainder = part_size % LG_NUMBER_OF_PAGES; marker = loop / graph_size; /* Fill buffer with zeroes */ MEfill( sizeof( buf ), 0 , buf); for (i = 0; i < num_logs; i++) { if ( create && DIalloc( &dio[i], part_size, &page, &err ) != OK ) { DIdelete( &dio[i], log_dir[i], (u_i4)STlength( log_dir[i] ), log_file[i], (u_i4)STlength( log_file[i] ), &err ); if ( message != NULL ) (*message)( "Unable to allocate space in transaction log file." ); return( 0 ); } } count = 0; for( j = 0; j < loop; j++ ) { i4 n = LG_NUMBER_OF_PAGES; i4 page_no = j * n; for (i = 0; i < num_logs; i++) { if ( DIwrite( &dio[i], &n, page_no, buf, &err ) != OK ) { DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), &err ); if ( message != NULL ) (*message)( "Unable to continue writing transaction log." ); return( 0 ); } } if ( j >= marker && j % marker == 0 && (f4) ((f4) j / (f4) loop) >= ((f4) count + 1) / graph_size ) { ++count; (*update_graph)(); SIflush( stdout ); } } if (remainder) { i4 page_no = loop * LG_NUMBER_OF_PAGES; for (i = 0; i < num_logs; i++) { if ( DIwrite( &dio[i], &remainder, page_no, buf, &err ) != OK ) { DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), &err ); if ( message != NULL ) (*message)( "Unable to continue writing transaction log." ); return( 0 ); } } } for (i = 0; i < num_logs; i++) { if ( DIforce( &dio[i], &err ) != OK ) { DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), &err ); if ( message != NULL ) (*message)( "Unable to force changes to transaction log." ); return( 0 ); } if ( create && DIflush( &dio[i], &err ) != OK ) { DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), &err ); if ( message != NULL ) (*message)( "Unable to flush transaction log to disk." ); return( 0 ); } if( DIclose( &dio[i], &err ) != OK) { DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]), log_file[i], (u_i4)STlength(log_file[i]), &err ); if ( message != NULL ) (*message)( "Unable to finish writing transaction log." ); return( 0 ); } } return( (i4) size ); }
/* ** Name: check_path ** ** Description: ** Function to test the specified path for: ** 1. Valid characters. ** 2. An existing or valid parent directory. ** 3. Write permissions for 2. ** ** Inputs: ** chkpath pointer to the path string for validation. ** eflags flags specifying the actions to be taken. ** ** Outputs: ** None. ** ** Returns: ** OK Path validation successful. ** !OK Path validation failed. ** ** History: ** 27-Jun-2005 (fanra01) ** Created. ** 11-Jul-2005 (fanra01) ** Return a more specific status code. */ static STATUS check_path( char* chkpath, int eflags ) { STATUS status = II_SUCCESSFUL; STATUS rc; int retcode = FAIL; LOCATION tloc; /* target location */ LOCATION wloc; /* working location */ LOCATION cloc; /* working location */ LOINFORMATION linfo; i4 info; char* temp = NULL; char* path = NULL; char* work = NULL; char* curr = NULL; char* d; char* p; char* f; char* e; char* v; char* s; while(TRUE) { /* ** Allocate working area up front. Saves declaring arrays on the ** stack. */ if ((temp = MEreqmem( 0, (MAX_LOC+1) * 8, TRUE, &status )) == NULL) { break; } /* ** Initialize working pointers with memory */ path = temp; work = temp + MAX_LOC + 1; curr = work + MAX_LOC + 1; d = curr + MAX_LOC + 1; p = d + MAX_LOC + 1; f = p + MAX_LOC + 1; e = f + MAX_LOC + 1; v = e + MAX_LOC + 1; /* ** Initialize a location structure with the specified path ** string. */ if ((eflags & (II_CHK_PATHCHAR | II_CHK_PATHDIR | II_CHK_PATHPERM)) && (LOfroms( PATH, chkpath, &tloc ) != OK)) { status = II_BAD_PATH; break; } /* ** Perform an illegal characters check, for all path tests. */ if ((eflags & (II_CHK_PATHCHAR | II_CHK_PATHDIR | II_CHK_PATHPERM)) && (check_path_chars( &tloc, &rc ))) { switch(rc) { case LO_BAD_DEVICE: status = II_BAD_PATH; break; case LO_NOT_PATH: case LO_NOT_FILE: default: status = II_INVAL_CHARS_IN_PATH; break; } break; } /* ** Duplicate the specified path location into a work location. */ LOcopy( &tloc, work, &wloc ); /* ** Create an empty location for the current working device, ** split the target path into components and ** create a location of the target device. */ if ((eflags & (II_CHK_PATHDIR | II_CHK_PATHPERM)) && ((status = LOfroms( PATH, curr, &cloc )) == OK) && ((status = LOdetail( &wloc, d, p, f, e, v )) == OK) && ((status = LOcompose( d, CURR_DIR, NULL, NULL, NULL, &cloc )) == OK)) { /* ** Save the current working directory */ LOsave(); /* ** Change working path to the target device */ status = LOchange( &cloc ); /* ** Starting with the whole path work backwards looking for ** a valid directory */ for (s=work, info=0; (status == OK) && (retcode != OK) && (s != NULL); ) { if ((status = LOfroms( PATH, p, &wloc )) != OK) { status = II_BAD_PATH; break; } /* ** Reset requested information flags for each iteration. */ info = (LO_I_TYPE | LO_I_PERMS); switch(retcode = LOinfo( &wloc, &info, &linfo )) { case OK: /* ** If the path or permission test is requested and ** type info is returned test for directory flag. */ if ((eflags & (II_CHK_PATHDIR | II_CHK_PATHPERM)) && ((info & LO_I_TYPE) == LO_I_TYPE)) status = (linfo.li_type == LO_IS_DIR) ? OK : II_PATH_NOT_DIR; /* ** If the permission test is requested and ** permissions are returned test the flags for read ** and write. */ if ((status == OK) && (eflags & II_CHK_PATHPERM)) { if (((info & LO_I_PERMS) == LO_I_PERMS) && (linfo.li_perms & (LO_P_READ|LO_P_WRITE)) == (LO_P_READ|LO_P_WRITE)) { /* ** Read and write permission */ break; } else { /* ** missing a permission */ status = II_PATH_CANNOT_WRITE; } } else { break; } case LO_NO_SUCH: /* ** Look backwards for the next path separator */ if((s = STrindex( p, PATH_SEPARATOR, 0 )) != NULL) { /* ** If separator found truncate the path ** otherwise the start of the path has ** been reached, update string to test the ** root directory. */ if (s != p) { *s = '\0'; } else { *(s+1) = '\0'; } } else { /* ** A root path character was included in the ** path that has been reached and still no ** installable area found. */ if (p && *p && *p == SLASH) { status = II_BAD_PATH; } else { /* ** A relative path was specified and no ** installable area has been found. ** Test the current working directory of the ** target device. */ if ((status = LOgt( p, &wloc )) == OK) { /* ** Reset temporary pointer to a work ** area to satisfy the loop condition. */ s = work; } } } break; default: status = II_BAD_PATH; break; } } break; } else { if (status != II_SUCCESSFUL) { status = II_BAD_PATH; } break; } } /* ** Free the working area */ if (temp != NULL) { MEfree( temp ); } return(status); }
/*{ ** Name: II_PrecheckInstallation - Pre-check installation environment ** ** Description: ** Verify that a machine environment will support the current release of ** Ingres. The following checks are made: **(E ** a. A minimum operating system version ** b. Other required software (currently none) ** c. Check the install path ** - exists ** - that user can write to it ** - does not have any disallowed characters (Windows only). **)E ** ** Inputs: ** response_file path to the Embedded Ingres response file. ** For more information concerning response file options ** please see the Ingres Embedded Edition User Guide. ** ** Outputs: ** error_msg Message text for status. If the message text exceeds ** MAX_IIERR_LEN then the message is truncated to ** MAX_IIERR_LEN. ** Unchanged if II_SUCCESSFUL is returned. ** ** Returns: ** II_SUCCESSFUL The environment test completed successfully ** II_NULL_PARAM The parameters passed are invalid ** II_NO_INSTALL_PATH Error reading response file or no II_SYSTEM entry ** II_CHARMAP_ERROR Error processing character mapping file ** II_GET_COMPUTER_FAIL Attempt to retrieve computer name failed ** II_INVALID_HOST Computer name contains illegal characters ** II_GET_HOST_FAILED Attempt to retrieve the network name failed ** II_INVALID_USER The username contains illegal characters ** II_UNMATCHED_NAME Computer name does not match network name ** II_OS_NOT_MIN_VERSION OS version does not meet the minimum requirement ** II_BAD_PATH The II_SYSTEM path is incorrectly formed ** II_INVAL_CHARS_IN_PATH The II_SYSTEM path contains illegal characters ** II_PATH_NOT_DIR The II_SYSTEM path is not a directory ** II_PATH_CANNOT_WRITE No write permission in the II_SYSTEM directory ** II_PATH_EXCEEDED Length of the path exceeds permitted maximum ** ** Example: ** # include "tngapi.h" ** ** # if defined(UNIX) ** II_CHAR reponsefile[] = {"./ingres.rsp"}; ** # else ** II_CHAR reponsefile[] = {".\\ingres.rsp"}; ** # endif ** II_INT4 status; ** II_CHAR error_msg[MAX_IIERR_LEN + 1] = { '\0' }; ** ** if ((status = II_PrecheckInstallation( responsefile, error_msg )) != ** II_SUCCESSFUL) ** { ** printf( "II_PrecheckInstallation failed - %s\n", error_msg ); ** } ** ** Side Effects: ** none ** ** History: ** 16-apr-2002 (abbjo03) ** Written. ** 11-Jul-2005 (fanra01) ** Add more specific status code from check_path_chars. */ int II_PrecheckInstallation( char *response_file, char *error_msg) { LOCATION loc; char buf[MAX_LOC]; char charmap[MAX_LOC+1]; LOINFORMATION loinfo; i4 flags; int result; CL_ERR_DESC clerr; if (!response_file || !error_msg) { result = II_NULL_PARAM; if (error_msg) II_GetErrorMessage(error_msgs[result], error_msg); return result; } if (!GetPrivateProfileString("Ingres Configuration", "II_SYSTEM", "", buf, sizeof(buf), response_file)) { result = II_NO_INSTALL_PATH; II_GetErrorMessage(error_msgs[result], error_msg); return result; } /* ** Get the charmap field from the response file. */ if (!GetPrivateProfileString("Ingres Configuration", II_CHARMAP, "", charmap, sizeof(charmap), response_file)) { result = II_NO_CHAR_MAP; II_GetErrorMessage(error_msgs[result], error_msg); return result; } /* ** Open and read the character map specified in the response file. ** This is a special installation character description file. */ #if defined(UNIX) if ((result = CMset_attr( charmap, &clerr )) != 0) #else if ((result = CMread_attr( II_CHARSET, charmap, &clerr )) != 0) #endif { result = II_CHARMAP_ERROR; II_GetErrorMessage( error_msgs[result], error_msg ); return(result); } if ((result = check_user()) != II_SUCCESSFUL) { II_GetErrorMessage( error_msgs[result], error_msg ); return(result); } if ((result = check_host()) != II_SUCCESSFUL) { II_GetErrorMessage( error_msgs[result], error_msg ); return(result); } if (check_platform( II_DEFARCH ) != OK) { result = II_OS_NOT_MIN_VERSION; II_GetErrorMessage(error_msgs[result], error_msg); return result; } if (LOfroms(PATH & FILENAME, buf, &loc) != OK) { result = II_BAD_PATH; II_GetErrorMessage(error_msgs[result], error_msg); return result; } flags = LO_I_TYPE | LO_I_PERMS; if (LOinfo(&loc, &flags, &loinfo) != OK) { result = II_BAD_PATH; II_GetErrorMessage(error_msgs[result], error_msg); return result; } if ((flags & LO_I_TYPE) == 0 || loinfo.li_type != LO_IS_DIR) { result = II_PATH_NOT_DIR; II_GetErrorMessage(error_msgs[result], error_msg); return result; } if ((flags & LO_I_PERMS) == 0 || (loinfo.li_perms & LO_P_WRITE) == 0) { result = II_PATH_CANNOT_WRITE; II_GetErrorMessage(error_msgs[result], error_msg); return result; } if (check_path_chars(&loc, &result)) { switch(result) { case LO_BAD_DEVICE: result = II_BAD_PATH; break; case LO_NOT_PATH: case LO_NOT_FILE: default: result = II_INVAL_CHARS_IN_PATH; break; } II_GetErrorMessage(error_msgs[result], error_msg); return result; } result = II_SUCCESSFUL; II_GetErrorMessage(error_msgs[result], error_msg); return result; }