diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llvfs/lldir_linux.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llvfs/lldir_linux.cpp | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/linden/indra/llvfs/lldir_linux.cpp b/linden/indra/llvfs/lldir_linux.cpp new file mode 100644 index 0000000..8557901 --- /dev/null +++ b/linden/indra/llvfs/lldir_linux.cpp | |||
@@ -0,0 +1,350 @@ | |||
1 | /** | ||
2 | * @file lldir_linux.cpp | ||
3 | * @brief Implementation of directory utilities for linux | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "lldir_linux.h" | ||
31 | #include "llerror.h" | ||
32 | #include "llrand.h" // for gLindenLabRandomNumber | ||
33 | #include <sys/types.h> | ||
34 | #include <sys/stat.h> | ||
35 | #include <unistd.h> | ||
36 | #include <glob.h> | ||
37 | #include <pwd.h> | ||
38 | |||
39 | |||
40 | static std::string getCurrentUserHome(char* fallback) | ||
41 | { | ||
42 | const uid_t uid = getuid(); | ||
43 | struct passwd *pw; | ||
44 | char *result_cstr = fallback; | ||
45 | |||
46 | pw = getpwuid(uid); | ||
47 | if ((pw != NULL) && (pw->pw_dir != NULL)) | ||
48 | { | ||
49 | result_cstr = (char*) pw->pw_dir; | ||
50 | } | ||
51 | else | ||
52 | { | ||
53 | llinfos << "Couldn't detect home directory from passwd - trying $HOME" << llendl; | ||
54 | const char *const home_env = getenv("HOME"); | ||
55 | if (home_env) | ||
56 | { | ||
57 | result_cstr = (char*) home_env; | ||
58 | } | ||
59 | else | ||
60 | { | ||
61 | llwarns << "Couldn't detect home directory! Falling back to " << fallback << llendl; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | return std::string(result_cstr); | ||
66 | } | ||
67 | |||
68 | |||
69 | LLDir_Linux::LLDir_Linux() | ||
70 | { | ||
71 | mDirDelimiter = "/"; | ||
72 | mCurrentDirIndex = -1; | ||
73 | mCurrentDirCount = -1; | ||
74 | mDirp = NULL; | ||
75 | |||
76 | char tmp_str[LL_MAX_PATH]; | ||
77 | getcwd(tmp_str, LL_MAX_PATH); | ||
78 | |||
79 | mExecutableFilename = ""; | ||
80 | mExecutablePathAndName = ""; | ||
81 | mExecutableDir = tmp_str; | ||
82 | mWorkingDir = tmp_str; | ||
83 | mAppRODataDir = tmp_str; | ||
84 | mOSUserDir = getCurrentUserHome(tmp_str); | ||
85 | mOSUserAppDir = ""; | ||
86 | mLindenUserDir = tmp_str; | ||
87 | |||
88 | char path [32]; | ||
89 | |||
90 | // *NOTE: /proc/%d/exe doesn't work on FreeBSD. But that's ok, | ||
91 | // because this is the linux implementation. | ||
92 | |||
93 | sprintf (path, "/proc/%d/exe", (int) getpid ()); | ||
94 | int rc = readlink (path, tmp_str, sizeof (tmp_str)-1); | ||
95 | if ( (rc != -1) && (rc <= ((int) sizeof (tmp_str)-1)) ) | ||
96 | { | ||
97 | tmp_str[rc] = '\0'; //readlink() doesn't 0-terminate the buffer | ||
98 | mExecutablePathAndName = tmp_str; | ||
99 | char *path_end; | ||
100 | if ((path_end = strrchr(tmp_str,'/'))) | ||
101 | { | ||
102 | *path_end = '\0'; | ||
103 | mExecutableDir = tmp_str; | ||
104 | mWorkingDir = tmp_str; | ||
105 | mExecutableFilename = path_end+1; | ||
106 | } | ||
107 | else | ||
108 | { | ||
109 | mExecutableFilename = tmp_str; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. | ||
114 | mTempDir = "/tmp"; | ||
115 | } | ||
116 | |||
117 | LLDir_Linux::~LLDir_Linux() | ||
118 | { | ||
119 | } | ||
120 | |||
121 | // Implementation | ||
122 | |||
123 | |||
124 | void LLDir_Linux::initAppDirs(const std::string &app_name) | ||
125 | { | ||
126 | mAppName = app_name; | ||
127 | |||
128 | LLString upper_app_name(app_name); | ||
129 | LLString::toUpper(upper_app_name); | ||
130 | |||
131 | char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); | ||
132 | if (app_home_env) | ||
133 | { | ||
134 | // user has specified own userappdir i.e. $SECONDLIFE_USER_DIR | ||
135 | mOSUserAppDir = app_home_env; | ||
136 | } | ||
137 | else | ||
138 | { | ||
139 | // traditionally on unixoids, MyApp gets ~/.myapp dir for data | ||
140 | mOSUserAppDir = mOSUserDir; | ||
141 | mOSUserAppDir += "/"; | ||
142 | mOSUserAppDir += "."; | ||
143 | LLString lower_app_name(app_name); | ||
144 | LLString::toLower(lower_app_name); | ||
145 | mOSUserAppDir += lower_app_name; | ||
146 | } | ||
147 | |||
148 | // create any directories we expect to write to. | ||
149 | |||
150 | int res = LLFile::mkdir(mOSUserAppDir.c_str()); | ||
151 | if (res == -1) | ||
152 | { | ||
153 | if (errno != EEXIST) | ||
154 | { | ||
155 | llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl; | ||
156 | llwarns << "Default to base dir" << mOSUserDir << llendl; | ||
157 | mOSUserAppDir = mOSUserDir; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"").c_str()); | ||
162 | if (res == -1) | ||
163 | { | ||
164 | if (errno != EEXIST) | ||
165 | { | ||
166 | llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"").c_str()); | ||
171 | if (res == -1) | ||
172 | { | ||
173 | if (errno != EEXIST) | ||
174 | { | ||
175 | llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"").c_str()); | ||
180 | if (res == -1) | ||
181 | { | ||
182 | if (errno != EEXIST) | ||
183 | { | ||
184 | llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"").c_str()); | ||
189 | if (res == -1) | ||
190 | { | ||
191 | if (errno != EEXIST) | ||
192 | { | ||
193 | llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); | ||
198 | } | ||
199 | |||
200 | U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &mask) | ||
201 | { | ||
202 | U32 file_count = 0; | ||
203 | glob_t g; | ||
204 | |||
205 | std::string tmp_str; | ||
206 | tmp_str = dirname; | ||
207 | tmp_str += mask; | ||
208 | |||
209 | if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) | ||
210 | { | ||
211 | file_count = g.gl_pathc; | ||
212 | |||
213 | globfree(&g); | ||
214 | } | ||
215 | |||
216 | return (file_count); | ||
217 | } | ||
218 | |||
219 | // get the next file in the directory | ||
220 | // automatically wrap if we've hit the end | ||
221 | BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) | ||
222 | { | ||
223 | glob_t g; | ||
224 | BOOL result = FALSE; | ||
225 | fname = ""; | ||
226 | |||
227 | if(!(dirname == mCurrentDir)) | ||
228 | { | ||
229 | // different dir specified, close old search | ||
230 | mCurrentDirIndex = -1; | ||
231 | mCurrentDirCount = -1; | ||
232 | mCurrentDir = dirname; | ||
233 | } | ||
234 | |||
235 | std::string tmp_str; | ||
236 | tmp_str = dirname; | ||
237 | tmp_str += mask; | ||
238 | |||
239 | if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) | ||
240 | { | ||
241 | if(g.gl_pathc > 0) | ||
242 | { | ||
243 | if((int)g.gl_pathc != mCurrentDirCount) | ||
244 | { | ||
245 | // Number of matches has changed since the last search, meaning a file has been added or deleted. | ||
246 | // Reset the index. | ||
247 | mCurrentDirIndex = -1; | ||
248 | mCurrentDirCount = g.gl_pathc; | ||
249 | } | ||
250 | |||
251 | mCurrentDirIndex++; | ||
252 | |||
253 | if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap) | ||
254 | { | ||
255 | mCurrentDirIndex = 0; | ||
256 | } | ||
257 | |||
258 | if(mCurrentDirIndex < (int)g.gl_pathc) | ||
259 | { | ||
260 | // llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; | ||
261 | |||
262 | // The API wants just the filename, not the full path. | ||
263 | //fname = g.gl_pathv[mCurrentDirIndex]; | ||
264 | |||
265 | char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); | ||
266 | |||
267 | if(s == NULL) | ||
268 | s = g.gl_pathv[mCurrentDirIndex]; | ||
269 | else if(s[0] == '/') | ||
270 | s++; | ||
271 | |||
272 | fname = s; | ||
273 | |||
274 | result = TRUE; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | globfree(&g); | ||
279 | } | ||
280 | |||
281 | return(result); | ||
282 | } | ||
283 | |||
284 | |||
285 | // get a random file in the directory | ||
286 | // automatically wrap if we've hit the end | ||
287 | void LLDir_Linux::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) | ||
288 | { | ||
289 | U32 num_files; | ||
290 | U32 which_file; | ||
291 | DIR *dirp; | ||
292 | dirent *entryp = NULL; | ||
293 | |||
294 | fname = ""; | ||
295 | |||
296 | num_files = countFilesInDir(dirname,mask); | ||
297 | if (!num_files) | ||
298 | { | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | which_file = gLindenLabRandomNumber.llrand() % num_files; | ||
303 | |||
304 | // llinfos << "Random select file #" << which_file << llendl; | ||
305 | |||
306 | // which_file now indicates the (zero-based) index to which file to play | ||
307 | |||
308 | if (!((dirp = opendir(dirname.c_str())))) | ||
309 | { | ||
310 | while (which_file--) | ||
311 | { | ||
312 | if (!((entryp = readdir(dirp)))) | ||
313 | { | ||
314 | return; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | if ((!which_file) && entryp) | ||
319 | { | ||
320 | fname = entryp->d_name; | ||
321 | } | ||
322 | |||
323 | closedir(dirp); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | std::string LLDir_Linux::getCurPath() | ||
328 | { | ||
329 | char tmp_str[LL_MAX_PATH]; | ||
330 | getcwd(tmp_str, LL_MAX_PATH); | ||
331 | return tmp_str; | ||
332 | } | ||
333 | |||
334 | |||
335 | BOOL LLDir_Linux::fileExists(const std::string &filename) | ||
336 | { | ||
337 | struct stat stat_data; | ||
338 | // Check the age of the file | ||
339 | // Now, we see if the files we've gathered are recent... | ||
340 | int res = stat(filename.c_str(), &stat_data); | ||
341 | if (!res) | ||
342 | { | ||
343 | return TRUE; | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | return FALSE; | ||
348 | } | ||
349 | } | ||
350 | |||