123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /* $TOG: FileUtils.c /main/8 1998/07/28 15:37:38 mgreess $ */
- /************************************<+>*************************************
- ****************************************************************************
- **
- ** File: FileUtils.c
- **
- ** Project: File locating
- **
- ** Description: Locates files (volumes) accessible via the
- ** known paths
- **
- ** NOTE: this file must remain free of Xt & Xm calls.
- **
- ** (c) Copyright 1993, 1994 Hewlett-Packard Company
- ** (c) Copyright 1993, 1994 International Business Machines Corp.
- ** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
- ** (c) Copyright 1993, 1994 Novell, Inc.
- ****************************************************************************
- ************************************<+>*************************************/
- /*
- * system includes
- */
- #include <errno.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <dirent.h>
- #include <sys/stat.h>
- #include <sys/param.h> /* MAXPATHLEN */
- #include <Dt/Help.h>
- /*
- * private includes
- */
- #include "bufioI.h" /* for AccessI.h */
- #include "Access.h" /* CompressPathname */
- #include "AccessI.h" /* ExpandPathname */
- #include "HelpP.h" /* for DtDEFAULT_xxx */
- #include "HelposI.h" /* for search path access */
- #include "StringFuncsI.h"
- #include "FileUtilsI.h"
- #include "Lock.h"
- /******** constants *********/
- #define LANG_C_STR "C"
- #define DIR_SLASH '/'
- #define EOS '\0'
- /******** types *********/
- /******** public global variables *********/
- const char * _DtHelpFileSuffixList[3] = {
- DtHelpSDL_VOL_SUFFIX,
- DtHelpCCDF_VOL_SUFFIX,
- NULL };
- /******** variables *********/
- #ifdef not_used
- static const char * PeriodStr = ".";
- #endif
- static const char * DirSlashStr = "/";
- static const char * PathSeparator = ":";
- static const _DtHelpCeDirStruct DefCacheDir = { NULL, ENOTDIR, 0, NULL };
- static _DtHelpCeDirStruct *CachedDirs = NULL;
- /******** functions *********/
- #define MyNewString(s) (NULL != s ? strdup((char *)s) : NULL)
- #define MyRealloc(p,s) (NULL != (p) ? realloc((char *)p,s) : malloc(s) )
- #define MyMalloc(s) malloc(s)
- /*****************************************************************************
- * Function: MyFree()
- *
- * locate the '.' of the filename extension, if present
- *
- *****************************************************************************/
- static void MyFree(char * ptr)
- {
- if(ptr) free(ptr);
- }
- #ifdef not_used
- /*****************************************************************************
- * Function: GetExtension()
- *
- * locate the '.' of the filename extension, if present
- *
- *****************************************************************************/
- static char * GetExtension(
- char * filename)
- {
- char * ext;
- if (_DtHelpCeStrrchr(filename,PeriodStr,MB_CUR_MAX,&ext) == 0 ) return ext;
- else return ""; /* do NOT return a NULL*/
- }
- /*****************************************************************************
- * Function: SpecialStrcmp()
- *
- * Tests the args for NULL pointers. If both are NULL or if
- * both aren't NULL and are the same string, then returns 0.
- * If one arg is NULL and other isn't, or if strings are
- * different, returns -1 or +1.
- *
- *****************************************************************************/
- static int SpecialStrcmp(
- const char * str1,
- const char * str2)
- {
- if(NULL == str1)
- {
- if(NULL == str2) return 0; /* str1 == str2 */
- return -1; /* str1 < str2 */
- }
- if(NULL == str2) return 1; /* str1 > str2 */
- return(strcmp(str1,str2)); /* str1 ? str2 */
- }
- #endif
- /************************************************************************
- * Function: _DtHelpFileTraceLinks (pathName)
- *
- * Purpose: Traces pathname through all symbolic links
- * until a real file is found or the link is
- * found to be invalid.
- *
- * Returns: True if file found at end of link, False if not
- *
- * Memory: pathName must point to a malloc'd string. The string
- * may be freed by the function and pathName assigned a pointer
- * to a different string specifying a different path to the same file.
- * If a file is found, foundPath is set to the same pointer
- * as pathName, otherwise it is set to NULL.
- ***********************************************************************/
- Boolean
- _DtHelpFileTraceLinks (
- char * * pPathName)
- {
- int result = 0;
- char curBuf;
- char * linkPath;
- char * filePath;
- char buf [2][MAXPATHLEN+2]; /* 2K+ bytes on stack */
- if ( NULL == *pPathName ) return False; /* RETURN */
- /* init */
- snprintf(buf[0], sizeof(buf[0]), "%s", *pPathName);
- linkPath = buf[0]; /* will be assigned to filePath below */
- curBuf = 1; /* next valid buf */
- /* find out if this path is a symbolic link */
- while ( result >= 0 )
- {
- /* exchange buffer ptrs and toggle index */
- filePath = linkPath;
- linkPath = buf[curBuf % 2];
- curBuf++;
- /* get the link info */
- result = readlink (filePath, linkPath, MAXPATHLEN);
- /* check for the result of the readlink call */
- if (result == -1)
- {
- /* if newPath is not a symbolic link, errno != EINVAL */
- if (errno != EINVAL)
- return False; /* RETURN */
- /* filePath is not a sym link ==> a real file or directory */
- /* so return filePath in caller-owned memory */
- if ( curBuf != 1 ) /* curBuf == 1 when pPathName is a file */
- {
- /*
- * pPathName had memory allocated before this function was called.
- * only increase the memory if needed.
- */
- if ( strlen (*pPathName) < strlen(filePath) )
- *pPathName = (char *)realloc((void *)*pPathName, (sizeof(char)
- * (strlen(filePath) +1)));
- strcpy(*pPathName, filePath);
- }
- /* printf("actual is: %s\n", filePath); ** DBG */
- return True; /* RETURN */
- } /* if an error */
- else
- { /* no error--handle the link */
- /* if the path is absolute, just take it as such */
- linkPath [result] = EOS; /* for safety */
- /* is path relative to current directory? */
- if ( linkPath[0] != DIR_SLASH )
- {
- char * slash = NULL;
- /* get last slash in the current file path */
- if(_DtHelpCeStrrchr(filePath,DirSlashStr,MB_CUR_MAX,&slash) == 0)
- { /* there is a path component in filePath; use it with linkPath */
- strcpy(++slash,linkPath);
- strcpy(linkPath,filePath); /* leave result in linkPath */
- }
- } /* if path is relative */
- /* printf("traced to: %s\n", linkPath); ** DBG */
- } /* if no error */
- } /* while result >= 0 */
- return False; /* RETURN */
- }
- /************************************************************************
- * Function: _DtHelpFileTraceToFile (pathName, accessMode, foundPath)
- *
- * Memory: pPathName must point to a malloc'd string. The string
- * may be freed by the function and pathName assigned a pointer
- * to a different string specifying a different path to the same file.
- * If a file is found, foundPath is set to the same pointer
- * as pathName, otherwise it is set to NULL.
- * Returns:
- * True: file found
- * False: file not found or error
- ***********************************************************************/
- Boolean
- _DtHelpFileTraceToFile (
- char * * pPathName,
- int accessMode,
- char * * pFoundPath)
- {
- struct stat status;
- char * pathName = *pPathName; /* avoid indirection */
- *pFoundPath = NULL;
- if ( pathName == NULL || pathName[0] == EOS )
- return False;
-
- /* if it's a file, trace its links */
- if ( access (pathName, accessMode) == 0
- && stat (pathName, &status) == 0
- && S_ISREG(status.st_mode) ) /* a file */
- {
- /* trace any links */
- if ( _DtHelpFileTraceLinks(pPathName) == False )
- {
- /* don't free pPathName here */
- return False; /* RETURN: no file */
- }
- pathName = *pPathName;
-
- /* find out if its an accessible file */
- if ( pathName != NULL
- && pathName[0] != EOS
- && access (pathName, accessMode) == 0
- && stat (pathName, &status) == 0
- && S_ISREG(status.st_mode)) /* a file */
- {
- /* point foundPath at the path */
- *pFoundPath = pathName;
- return True; /* RETURN: its a file */
- } /* if a valid path */
- } /* if a path */
- #if 0
- printf("Unknown file: %s\n", pathName);
- printf("Access: %d, stat: %d, IS_REG: %d, mode: %x\n",
- access (pathName, accessMode),
- stat (pathName, &status),
- S_ISREG(status.st_mode),
- status.st_mode);
- #endif
- /* its not a file */
- *pFoundPath = NULL;
- return False;
- }
- /******************************************************************************
- * Function: int _DtHelpFileGetSearchPaths ()
- *
- * Parameters:
- * paths: caller array size _DtHELP_FILE_NUM_PATHS in which
- * to store ptrs to the private path strings
- * searchHomeDir: boolean flag
- *
- * Memory:
- * the memory pointed to by the array is NOT owned by the
- * caller and should not be freed or modified
- *
- * Purpose: make the search paths available
- *
- *****************************************************************************/
- void _DtHelpFileGetSearchPaths(
- char * paths[],
- Boolean searchHomeDir)
- {
- static char * pathsSet[_DtHELP_FILE_NUM_PATHS];
- char tmpPath[MAXPATHLEN + 2];
- /* get user's home directory; is used in _DtHELP_FILE_USER_PATH as well */
- if (NULL == pathsSet[_DtHELP_FILE_HOME_PATH])
- {
- _DtHelpOSGetHomeDirName(tmpPath, sizeof(tmpPath));
- pathsSet[_DtHELP_FILE_HOME_PATH] = strdup(tmpPath);
- }
- if (searchHomeDir)
- paths[_DtHELP_FILE_HOME_PATH] = pathsSet[_DtHELP_FILE_HOME_PATH];
- else
- paths[_DtHELP_FILE_HOME_PATH] = NULL;
- /* generate the user path */
- if (NULL == pathsSet[_DtHELP_FILE_USER_PATH])
- pathsSet[_DtHELP_FILE_USER_PATH] = _DtHelpGetUserSearchPath();
- paths[_DtHELP_FILE_USER_PATH] = pathsSet[_DtHELP_FILE_USER_PATH];
- /* get the system search path */
- if (NULL == pathsSet[_DtHELP_FILE_SYS_PATH])
- pathsSet[_DtHELP_FILE_SYS_PATH] = _DtHelpGetSystemSearchPath();
- paths[_DtHELP_FILE_SYS_PATH] = pathsSet[_DtHELP_FILE_SYS_PATH];
- }
- /******************************************************************************
- * Function: char * _DtHelpFileLocate ()
- *
- * Parameters:
- * type: subdirectories to search (%T)
- * base: basename of the file
- * suffix: extension of the file to find (%S)
- * searchCurDir: boolean flag
- * accessMode: constant value from access(2)
- *
- * Returns: malloc'd path of the located file or NULL if none located
- *
- * errno Values:
- * EINVAL
- *
- * Purpose: Scans all paths of given type looking for a matching file
- * If file contains a valid absolute path, that is also
- * acceptable.
- *
- * FIX: merge _DtHelpFileLocate() and _DtHelpFileListScanPaths()
- *****************************************************************************/
- char * _DtHelpFileLocate (
- char * type,
- char * filespec,
- const char * suffixList[],
- Boolean searchCurDir,
- int accessMode)
- {
- char * loc;
- char * ptr;
- char * pathName;
- char * curPath;
- char * base;
- int curPathIndex;
- char * foundPath;
- const char empty = 0;
- const char * sufList[2];
- #define NUM_BUGS 1
- _DtSubstitutionRec bugFixSubs [NUM_BUGS];
- char * paths[_DtHELP_FILE_NUM_PATHS];
- char tmpPath[MAXPATHLEN + 2];
- const char * * pSuffix;
- char * eos = NULL;
- char * slash = NULL;
- /* test args */
- if (NULL == filespec) return NULL;
- /* init suffix list to empty if not specified */
- if (suffixList == NULL)
- {
- sufList[0] = ∅
- sufList[1] = NULL;
- suffixList = sufList; /* override initial argument setting */
- }
- /*** first look for file as specified ***/
- /* if filespec begins with . or .. then stop after the cwd path */
- if ( ( MB_CUR_MAX == 1
- || mblen(filespec, MB_CUR_MAX) == 1) /* 1st char is 1 byte */
- && *filespec == '/') /* and its a / */
- {
- /* _DtHelpFileTraceToFile() needs a malloc'd string */
- /* 10: leaves room for add'l suffixes */
- pathName = MyMalloc(sizeof(char) * (strlen(filespec)+10));
- pathName = strcpy(pathName,filespec);
- _DtHelpCeCompressPathname(pathName); /* compress out relative paths */
- if ( _DtHelpFileTraceToFile(&pathName,accessMode,&foundPath) )
- return foundPath; /* RETURN */
- /* test all suffixes */
- eos = pathName + strlen(pathName);
- for ( pSuffix = suffixList; NULL != *pSuffix; pSuffix++ )
- {
- strcpy(eos,(char *) *pSuffix);
- /*recall: _DtHelpFileTraceToFile() requires pathName to be malloc'd*/
- if ( _DtHelpFileTraceToFile(&pathName,accessMode,&foundPath) )
- return foundPath; /* RETURN: found */
- } /* for all suffixes */
- MyFree(pathName);
- }
- /*** second, check if its relative to the current directory ***/
- /* if filespec begins with . or .. then stop after the cwd path */
- if ( searchCurDir
- || ( MB_CUR_MAX == 1
- || mblen(filespec, MB_CUR_MAX) == 1) /* 1st char is 1 byte */
- && *filespec == '.') /* and its a . */
- { /* we're looking at a cwd-relative path; ignore others */
- /*** this is monstrously inefficient--but it shouldn't get called often ***/
- /* get user's current working directory */
- /* JET - CERT VU#575804 */
- if (getcwd(tmpPath, MAXPATHLEN - 1) == NULL) return NULL; /* RETURN: error */
-
- /* make path end in a slash */
- eos = tmpPath + strlen(tmpPath);
- _DtHelpCeStrrchr(tmpPath,DirSlashStr,MB_CUR_MAX,&slash);
- if ( slash != (eos - 1) ) { *eos++ = DIR_SLASH; *eos = EOS; }
- /* make a malloc'd copy of the path with room to grow */
- slash = filespec + strlen(filespec);
- pathName = malloc(sizeof(char) *
- ((eos-tmpPath) + (slash-filespec) + 50) ); /* 50: arbitrary */
- if (NULL == pathName) return NULL; /* RETURN: error */
- strcpy(pathName,tmpPath);
- /* cat on the relative path */
- strcat(pathName,filespec);
- /* compress out any relative paths */
- _DtHelpCeCompressPathname(pathName);
- /* see if we find the file now */
- /* recall: _DtHelpFileTraceToFile() requires pathName to be malloc'd */
- if ( _DtHelpFileTraceToFile(&pathName,accessMode,&foundPath) )
- return foundPath; /* RETURN: found */
- /* test all suffixes */
- eos = pathName + strlen(pathName);
- for ( pSuffix = suffixList; NULL != *pSuffix; pSuffix++ )
- {
- strcpy(eos,(char *) *pSuffix);
- /* recall: _DtHelpFileTraceToFile() requires pathName to be malloc'd */
- if ( _DtHelpFileTraceToFile(&pathName,accessMode,&foundPath) )
- return foundPath; /* RETURN: found */
- } /* for all suffixes */
- MyFree(pathName);
- return NULL; /* RETURN: error */
- } /* filespec is a relative path or search cur dir */
- /*** third look in search path directories ***/
- /* get the search paths */
- _DtHelpFileGetSearchPaths( paths, False );
- /*** prep variables to pass through the path search loop ***/
- /* we're not looking at a cwd-relative path and
- we know that 'filespec' isn't a valid path to a volume
- (from _DtHelpFileTraceToFile), so just pick off the
- basename of the spec */
- base = filespec;
- if ( _DtHelpCeStrrchr(filespec,DirSlashStr,MB_CUR_MAX,&ptr) == 0 )
- base = ++ptr; /* begin past the slash */
- /* Have to support %H explicitly */
- bugFixSubs[0].match = 'H';
- bugFixSubs[0].substitution = base;
- /* get the LANG value */
- loc = _DtHelpGetLocale();
- if (NULL == loc || EOS == loc[0]) loc = strdup(LANG_C_STR);
- /* outer loop is once for each path */
- foundPath = NULL;
- for ( curPathIndex = 0;
- curPathIndex < _DtHELP_FILE_NUM_PATHS && NULL == foundPath;
- curPathIndex++ )
- {
- curPath = paths[curPathIndex];
- if (NULL == curPath) continue; /* continue */
-
- /* look for the file in that path */
- if (NULL != curPath) do
- {
- /* look for next subpath separator and insert and EOS if found */
- if (_DtHelpCeStrchr(curPath,PathSeparator,MB_CUR_MAX,&ptr)==0)
- *ptr = EOS;
- /* compress that path */
- /* JET - CERT VU#575804 */
- strncpy(tmpPath, curPath, MAXPATHLEN);
- _DtHelpCeCompressPathname(tmpPath);
- /* test all suffixes */
- for ( pSuffix = suffixList, foundPath = NULL;
- NULL == foundPath && NULL != *pSuffix;
- pSuffix++ )
- {
- /* generate the (directory) path using all the variables and fix
- it up to remove the unwanted stuff involving the filename */
- pathName = _DtHelpCeExpandPathname (curPath, base, type,
- (char *) *pSuffix, loc, bugFixSubs, NUM_BUGS);
-
- if ( _DtHelpFileTraceToFile(&pathName,accessMode,&foundPath)==False
- && NULL != pathName)
- free(pathName);
- } /* for all suffixes */
-
- /* restore the subpath separator and advance past it */
- if (ptr) *ptr++ = *PathSeparator;
- curPath = ptr;
- } while (curPath && *curPath && NULL == foundPath);
- /* do while more subpaths */
- } /* for all paths */
- MyFree(loc);
- return foundPath;
- }
- /******************************************************************************
- * Function: int _DtHelpCeCheckAndCacheDir (char *dir)
- *
- * Parameters:
- * dir Specifies the directory to test.
- *
- * Returns: 0 if the directory exists.
- * ENOTDIR if the directory is invalid.
- *
- * Purpose: To check a directory only once and remember the result.
- *
- *****************************************************************************/
- int
- _DtHelpCeCheckAndCacheDir (char *dir)
- {
- int result = ENOTDIR;
- _DtHelpCeDirStruct *curDir = CachedDirs;
- _DtHelpCeDirStruct *prevDir = NULL;
- struct stat buf;
- _DtHelpProcessLock();
- if (dir == NULL || *dir == '\0')
- return ENOTDIR;
- /*
- * search the cached directories
- */
- while (curDir != NULL && strcmp(curDir->dir_name, dir))
- {
- prevDir = curDir;
- curDir = curDir->next_dir;
- }
- /*
- * was the directory found in the cache? If so, return the type.
- */
- if (curDir != NULL)
- result = curDir->type;
- else
- {
- /*
- * new directory - malloc room for this entry.
- */
- result = ENOMEM;
- curDir = (_DtHelpCeDirStruct *) malloc(sizeof(_DtHelpCeDirStruct));
- if (curDir != NULL)
- {
- /*
- * initialize the new entry. I.E. type starts out ENOTDIR.
- */
- *curDir = DefCacheDir;
- curDir->dir_name = strdup(dir);
- if (curDir->dir_name != NULL)
- {
- /*
- * put this entry in the list
- */
- if (prevDir != NULL)
- prevDir->next_dir = curDir;
- else
- CachedDirs = curDir;
- /*
- * is this a directory?
- */
- if (access(dir, R_OK) == 0 &&
- stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode))
- curDir->type = 0;
- /*
- * return the result of the tests.
- */
- result = curDir->type;
- }
- else
- free(curDir);
- }
- }
- /*
- * This should never happen, but just in case the directory
- * can't be cached, go ahead and check it anyway.
- */
- if (result == ENOMEM && access(dir, R_OK) == 0 &&
- stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode))
- result = 0;
- _DtHelpProcessUnlock();
- return result;
- }
- #ifdef not_done
- /******************************************************************************
- * Function: _DtHelpCeDirStruct *_DtHelpCeGetCachedDirs (void)
- *
- * Parameters: none.
- *
- * Returns: A pointer to the cached directories.
- *
- * Purpose: To allow access to the cached directories.
- *
- *****************************************************************************/
- _DtHelpCeDirStruct *
- _DtHelpCeGetCachedDirs (void)
- {
- return CachedDirs;
- }
- #endif /* not_done */
|