lldir_linux.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "lldir_linux.h"
00035 #include "llerror.h"
00036 #include "llrand.h"
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <unistd.h>
00040 #include <glob.h>
00041 #include <pwd.h>
00042 
00043 
00044 static std::string getCurrentUserHome(char* fallback)
00045 {
00046         const uid_t uid = getuid();
00047         struct passwd *pw;
00048         char *result_cstr = fallback;
00049         
00050         pw = getpwuid(uid);
00051         if ((pw != NULL) && (pw->pw_dir != NULL))
00052         {
00053                 result_cstr = (char*) pw->pw_dir;
00054         }
00055         else
00056         {
00057                 llinfos << "Couldn't detect home directory from passwd - trying $HOME" << llendl;
00058                 const char *const home_env = getenv("HOME");    /* Flawfinder: ignore */ 
00059                 if (home_env)
00060                 {
00061                         result_cstr = (char*) home_env;
00062                 }
00063                 else
00064                 {
00065                         llwarns << "Couldn't detect home directory!  Falling back to " << fallback << llendl;
00066                 }
00067         }
00068         
00069         return std::string(result_cstr);
00070 }
00071 
00072 
00073 LLDir_Linux::LLDir_Linux()
00074 {
00075         mDirDelimiter = "/";
00076         mCurrentDirIndex = -1;
00077         mCurrentDirCount = -1;
00078         mDirp = NULL;
00079 
00080         char tmp_str[LL_MAX_PATH];      /* Flawfinder: ignore */ 
00081         if (getcwd(tmp_str, LL_MAX_PATH) == NULL)
00082         {
00083                 strcpy(tmp_str, "/tmp");
00084                 llwarns << "Could not get current directory; changing to "
00085                                 << tmp_str << llendl;
00086                 if (chdir(tmp_str) == -1)
00087                 {
00088                         llerrs << "Could not change directory to " << tmp_str << llendl;
00089                 }
00090         }
00091 
00092         mExecutableFilename = "";
00093         mExecutablePathAndName = "";
00094         mExecutableDir = tmp_str;
00095         mWorkingDir = tmp_str;
00096         mAppRODataDir = tmp_str;
00097         mOSUserDir = getCurrentUserHome(tmp_str);
00098         mOSUserAppDir = "";
00099         mLindenUserDir = tmp_str;
00100 
00101         char path [32]; /* Flawfinder: ignore */ 
00102 
00103         // *NOTE: /proc/%d/exe doesn't work on FreeBSD. But that's ok,
00104         // because this is the linux implementation.
00105 
00106         snprintf (path, sizeof(path), "/proc/%d/exe", (int) getpid ()); 
00107         int rc = readlink (path, tmp_str, sizeof (tmp_str)-1);  /* Flawfinder: ignore */ 
00108         if ( (rc != -1) && (rc <= ((int) sizeof (tmp_str)-1)) )
00109         {
00110                 tmp_str[rc] = '\0'; //readlink() doesn't 0-terminate the buffer
00111                 mExecutablePathAndName = tmp_str;
00112                 char *path_end;
00113                 if ((path_end = strrchr(tmp_str,'/')))
00114                 {
00115                         *path_end = '\0';
00116                         mExecutableDir = tmp_str;
00117                         mWorkingDir = tmp_str;
00118                         mExecutableFilename = path_end+1;
00119                 }
00120                 else
00121                 {
00122                         mExecutableFilename = tmp_str;
00123                 }
00124         }
00125 
00126         // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something.
00127         mTempDir = "/tmp";
00128 }
00129 
00130 LLDir_Linux::~LLDir_Linux()
00131 {
00132 }
00133 
00134 // Implementation
00135 
00136 
00137 void LLDir_Linux::initAppDirs(const std::string &app_name)
00138 {
00139         mAppName = app_name;
00140 
00141         LLString upper_app_name(app_name);
00142         LLString::toUpper(upper_app_name);
00143 
00144         char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str());    /* Flawfinder: ignore */ 
00145         if (app_home_env)
00146         {
00147                 // user has specified own userappdir i.e. $SECONDLIFE_USER_DIR
00148                 mOSUserAppDir = app_home_env;
00149         }
00150         else
00151         {
00152                 // traditionally on unixoids, MyApp gets ~/.myapp dir for data
00153                 mOSUserAppDir = mOSUserDir;
00154                 mOSUserAppDir += "/";
00155                 mOSUserAppDir += ".";
00156                 LLString lower_app_name(app_name);
00157                 LLString::toLower(lower_app_name);
00158                 mOSUserAppDir += lower_app_name;
00159         }
00160 
00161         // create any directories we expect to write to.
00162 
00163         int res = LLFile::mkdir(mOSUserAppDir.c_str());
00164         if (res == -1)
00165         {
00166                 if (errno != EEXIST)
00167                 {
00168                         llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl;
00169                         llwarns << "Default to base dir" << mOSUserDir << llendl;
00170                         mOSUserAppDir = mOSUserDir;
00171                 }
00172         }
00173 
00174         res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"").c_str());
00175         if (res == -1)
00176         {
00177                 if (errno != EEXIST)
00178                 {
00179                         llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl;
00180                 }
00181         }
00182         
00183         res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"").c_str());
00184         if (res == -1)
00185         {
00186                 if (errno != EEXIST)
00187                 {
00188                         llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl;
00189                 }
00190         }
00191         
00192         res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"").c_str());
00193         if (res == -1)
00194         {
00195                 if (errno != EEXIST)
00196                 {
00197                         llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl;
00198                 }
00199         }
00200         
00201         res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"").c_str());
00202         if (res == -1)
00203         {
00204                 if (errno != EEXIST)
00205                 {
00206                         llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl;
00207                 }
00208         }
00209 
00210         mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
00211 }
00212 
00213 U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &mask)
00214 {
00215         U32 file_count = 0;
00216         glob_t g;
00217 
00218         std::string tmp_str;
00219         tmp_str = dirname;
00220         tmp_str += mask;
00221         
00222         if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
00223         {
00224                 file_count = g.gl_pathc;
00225 
00226                 globfree(&g);
00227         }
00228 
00229         return (file_count);
00230 }
00231 
00232 // get the next file in the directory
00233 // automatically wrap if we've hit the end
00234 BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
00235 {
00236         glob_t g;
00237         BOOL result = FALSE;
00238         fname = "";
00239         
00240         if(!(dirname == mCurrentDir))
00241         {
00242                 // different dir specified, close old search
00243                 mCurrentDirIndex = -1;
00244                 mCurrentDirCount = -1;
00245                 mCurrentDir = dirname;
00246         }
00247         
00248         std::string tmp_str;
00249         tmp_str = dirname;
00250         tmp_str += mask;
00251 
00252         if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
00253         {
00254                 if(g.gl_pathc > 0)
00255                 {
00256                         if((int)g.gl_pathc != mCurrentDirCount)
00257                         {
00258                                 // Number of matches has changed since the last search, meaning a file has been added or deleted.
00259                                 // Reset the index.
00260                                 mCurrentDirIndex = -1;
00261                                 mCurrentDirCount = g.gl_pathc;
00262                         }
00263         
00264                         mCurrentDirIndex++;
00265         
00266                         if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
00267                         {
00268                                 mCurrentDirIndex = 0;
00269                         }
00270                         
00271                         if(mCurrentDirIndex < (int)g.gl_pathc)
00272                         {
00273 //                              llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
00274 
00275                                 // The API wants just the filename, not the full path.
00276                                 //fname = g.gl_pathv[mCurrentDirIndex];
00277 
00278                                 char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
00279                                 
00280                                 if(s == NULL)
00281                                         s = g.gl_pathv[mCurrentDirIndex];
00282                                 else if(s[0] == '/')
00283                                         s++;
00284                                         
00285                                 fname = s;
00286                                 
00287                                 result = TRUE;
00288                         }
00289                 }
00290                 
00291                 globfree(&g);
00292         }
00293         
00294         return(result);
00295 }
00296 
00297 
00298 // get a random file in the directory
00299 // automatically wrap if we've hit the end
00300 void LLDir_Linux::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
00301 {
00302         S32 num_files;
00303         S32 which_file;
00304         DIR *dirp;
00305         dirent *entryp = NULL;
00306 
00307         fname = "";
00308 
00309         num_files = countFilesInDir(dirname,mask);
00310         if (!num_files)
00311         {
00312                 return;
00313         }
00314 
00315         which_file = ll_rand(num_files);
00316 
00317 //      llinfos << "Random select file #" << which_file << llendl;
00318 
00319     // which_file now indicates the (zero-based) index to which file to play
00320         
00321         if (!((dirp = opendir(dirname.c_str()))))
00322         {
00323                 while (which_file--)
00324                 {
00325                         if (!((entryp = readdir(dirp))))
00326                         {
00327                                 return;
00328                         }
00329                 }                  
00330 
00331                 if ((!which_file) && entryp)
00332                 {
00333                         fname = entryp->d_name;
00334                 }
00335                 
00336                 closedir(dirp);
00337         }
00338 }
00339 
00340 std::string LLDir_Linux::getCurPath()
00341 {
00342         char tmp_str[LL_MAX_PATH];      /* Flawfinder: ignore */ 
00343         if (getcwd(tmp_str, LL_MAX_PATH) == NULL)
00344         {
00345                 llwarns << "Could not get current directory" << llendl;
00346                 tmp_str[0] = '\0';
00347         }
00348         return tmp_str;
00349 }
00350 
00351 
00352 BOOL LLDir_Linux::fileExists(const std::string &filename)
00353 {
00354         struct stat stat_data;
00355         // Check the age of the file
00356         // Now, we see if the files we've gathered are recent...
00357         int res = stat(filename.c_str(), &stat_data);
00358         if (!res)
00359         {
00360                 return TRUE;
00361         }
00362         else
00363         {
00364                 return FALSE;
00365         }
00366 }
00367 

Generated on Thu Jul 1 06:08:24 2010 for Second Life Viewer by  doxygen 1.4.7