/src/ogre/OgreMain/src/GLX/OgreFileSystemLayer.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreFileSystemLayer.h" |
29 | | #include <errno.h> |
30 | | #include <unistd.h> |
31 | | #include <sys/types.h> |
32 | | #include <sys/stat.h> |
33 | | #include <pwd.h> |
34 | | #include <dlfcn.h> |
35 | | |
36 | | namespace Ogre |
37 | | { |
38 | | namespace { |
39 | | /** Get actual file pointed to by symlink */ |
40 | | const Ogre::String resolveSymlink(const Ogre::String& symlink) |
41 | 0 | { |
42 | 0 | ssize_t bufsize = 256; |
43 | 0 | char* resolved = 0; |
44 | 0 | do |
45 | 0 | { |
46 | 0 | char* buf = OGRE_ALLOC_T(char, bufsize, Ogre::MEMCATEGORY_GENERAL); |
47 | 0 | ssize_t retval = readlink(symlink.c_str(), buf, bufsize); |
48 | 0 | if (retval == -1) |
49 | 0 | { |
50 | 0 | OGRE_FREE(buf, Ogre::MEMCATEGORY_GENERAL); |
51 | 0 | break; |
52 | 0 | } |
53 | | |
54 | 0 | if (retval < bufsize) |
55 | 0 | { |
56 | | // operation was successful. |
57 | | // readlink does not guarantee to 0-terminate, so do this manually |
58 | 0 | buf[retval] = '\0'; |
59 | 0 | resolved = buf; |
60 | 0 | } |
61 | 0 | else |
62 | 0 | { |
63 | | // buffer was too small, grow buffer and try again |
64 | 0 | OGRE_FREE(buf, Ogre::MEMCATEGORY_GENERAL); |
65 | 0 | bufsize <<= 1; |
66 | 0 | } |
67 | 0 | } while (!resolved); |
68 | |
|
69 | 0 | if (resolved) |
70 | 0 | { |
71 | 0 | Ogre::String result (resolved); |
72 | 0 | OGRE_FREE(resolved, Ogre::MEMCATEGORY_GENERAL); |
73 | 0 | return result; |
74 | 0 | } |
75 | 0 | else |
76 | 0 | return ""; |
77 | 0 | } |
78 | | } |
79 | | |
80 | | String FileSystemLayer::resolveBundlePath(String path) |
81 | 0 | { |
82 | | // With Ubuntu snaps absolute paths are relative to the snap package. |
83 | 0 | char* env_SNAP = getenv("SNAP"); |
84 | 0 | if (env_SNAP && !path.empty() && path[0] == '/' && // only adjust absolute dirs |
85 | 0 | !StringUtil::startsWith(path, "/snap")) // not a snap path already |
86 | 0 | path = env_SNAP + path; |
87 | |
|
88 | 0 | return path; |
89 | 0 | } |
90 | | //--------------------------------------------------------------------- |
91 | | void FileSystemLayer::getConfigPaths() |
92 | 0 | { |
93 | | // try to determine the application's path: |
94 | | // recent systems should provide the executable path via the /proc system |
95 | 0 | Ogre::String appPath = resolveSymlink("/proc/self/exe"); |
96 | 0 | if (appPath.empty()) |
97 | 0 | { |
98 | | // if /proc/self/exe isn't available, try it via the program's pid |
99 | 0 | pid_t pid = getpid(); |
100 | 0 | char proc[64]; |
101 | 0 | int retval = snprintf(proc, sizeof(proc), "/proc/%llu/exe", (unsigned long long) pid); |
102 | 0 | if (retval > 0 && retval < (long)sizeof(proc)) |
103 | 0 | appPath = resolveSymlink(proc); |
104 | 0 | } |
105 | |
|
106 | 0 | if (!appPath.empty()) |
107 | 0 | { |
108 | | // we need to strip the executable name from the path |
109 | 0 | Ogre::String::size_type pos = appPath.rfind('/'); |
110 | 0 | if (pos != Ogre::String::npos) |
111 | 0 | appPath.erase(pos); |
112 | | |
113 | | // use application path as first config search path |
114 | 0 | mConfigPaths.push_back(appPath + '/'); |
115 | 0 | } |
116 | |
|
117 | 0 | Dl_info info; |
118 | 0 | if (dladdr((const void*)resolveSymlink, &info)) |
119 | 0 | { |
120 | 0 | String base(info.dli_fname); |
121 | | // need to strip the module filename from the path |
122 | 0 | String::size_type pos = base.rfind('/'); |
123 | 0 | if (pos != String::npos) |
124 | 0 | base.erase(pos); |
125 | |
|
126 | 0 | String dirname = StringUtil::format("OGRE-%d.%d/", OGRE_VERSION_MAJOR, OGRE_VERSION_MINOR); |
127 | | // search inside ../share/OGRE-X.Y |
128 | 0 | mConfigPaths.push_back(StringUtil::normalizeFilePath(base + "/../share/"+dirname, false)); |
129 | | // then look relative to PIP structure |
130 | 0 | mConfigPaths.push_back(StringUtil::normalizeFilePath(base+"/../../../../share/"+dirname)); |
131 | 0 | } |
132 | | |
133 | | // then try system wide /etc |
134 | 0 | mConfigPaths.push_back("/etc/OGRE/"); |
135 | 0 | } |
136 | | //--------------------------------------------------------------------- |
137 | | void FileSystemLayer::prepareUserHome(const Ogre::String& subdir) |
138 | 0 | { |
139 | 0 | char* xdg_cache = getenv("XDG_CACHE_HOME"); |
140 | |
|
141 | 0 | if(xdg_cache) { |
142 | 0 | mHomePath = xdg_cache; |
143 | 0 | mHomePath.append("/"); |
144 | 0 | } else { |
145 | 0 | struct passwd* pwd = getpwuid(getuid()); |
146 | 0 | if (pwd) |
147 | 0 | { |
148 | 0 | mHomePath = pwd->pw_dir; |
149 | 0 | } |
150 | 0 | else |
151 | 0 | { |
152 | | // try the $HOME environment variable |
153 | 0 | mHomePath = getenv("HOME"); |
154 | 0 | } |
155 | |
|
156 | 0 | if(!mHomePath.empty()) { |
157 | 0 | mHomePath.append("/.cache/"); |
158 | 0 | } |
159 | 0 | } |
160 | |
|
161 | 0 | if (!mHomePath.empty()) |
162 | 0 | { |
163 | | // create the given subdir |
164 | 0 | mHomePath.append(subdir + '/'); |
165 | 0 | if (mkdir(mHomePath.c_str(), 0755) != 0 && errno != EEXIST) |
166 | 0 | { |
167 | | // can't create dir |
168 | 0 | mHomePath.clear(); |
169 | 0 | } |
170 | 0 | } |
171 | |
|
172 | 0 | if (mHomePath.empty()) |
173 | 0 | { |
174 | | // couldn't create dir in home directory, fall back to cwd |
175 | 0 | mHomePath = "./"; |
176 | 0 | } |
177 | 0 | } |
178 | | //--------------------------------------------------------------------- |
179 | | bool FileSystemLayer::fileExists(const Ogre::String& path) |
180 | 0 | { |
181 | 0 | return access(path.c_str(), R_OK) == 0; |
182 | 0 | } |
183 | | //--------------------------------------------------------------------- |
184 | | bool FileSystemLayer::createDirectory(const Ogre::String& path) |
185 | 0 | { |
186 | 0 | return !mkdir(path.c_str(), 0755) || errno == EEXIST; |
187 | 0 | } |
188 | | //--------------------------------------------------------------------- |
189 | | bool FileSystemLayer::removeDirectory(const Ogre::String& path) |
190 | 0 | { |
191 | 0 | return !rmdir(path.c_str()) || errno == ENOENT; |
192 | 0 | } |
193 | | //--------------------------------------------------------------------- |
194 | | bool FileSystemLayer::removeFile(const Ogre::String& path) |
195 | 0 | { |
196 | 0 | return !unlink(path.c_str()) || errno == ENOENT; |
197 | 0 | } |
198 | | //--------------------------------------------------------------------- |
199 | | bool FileSystemLayer::renameFile(const Ogre::String& oldname, const Ogre::String& newname) |
200 | 0 | { |
201 | 0 | return !rename(oldname.c_str(), newname.c_str()); |
202 | 0 | } |
203 | | } |