1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2007 by Dominik Wenger
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 #include "rockboxinfo.h"
23 #include "rbsettings.h"
24 #include "systeminfo.h"
35 #if defined(Q_OS_WIN32)
40 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
41 #include <sys/statvfs.h>
44 // recursive function to delete a dir with files
45 bool Utils::recursiveRmdir( const QString
&dirName
)
47 QString dirN
= dirName
;
49 // make list of entries in directory
50 QStringList list
= dir
.entryList(QDir::AllEntries
| QDir::NoDotAndDotDot
);
52 QString curItem
, lstAt
;
53 for(int i
= 0; i
< list
.size(); i
++){ // loop through all items of list
54 QString name
= list
.at(i
);
55 curItem
= dirN
+ "/" + name
;
56 fileInfo
.setFile(curItem
);
57 if(fileInfo
.isDir()) // is directory
58 recursiveRmdir(curItem
); // call recRmdir() recursively for
59 // deleting subdirectory
61 QFile::remove(curItem
); // ok, delete file
64 return dir
.rmdir(dirN
); // delete empty dir and return if (now empty)
65 // dir-removing was successfull
69 //! @brief resolves the given path, ignoring case.
70 //! @param path absolute path to resolve.
71 //! @return returns exact casing of path, empty string if path not found.
72 QString
Utils::resolvePathCase(QString path
)
77 elems
= path
.split("/", QString::SkipEmptyParts
);
79 #if defined(Q_OS_WIN32)
80 // on windows we must make sure to start with the first entry (i.e. the
81 // drive letter) instead of a single / to make resolving work.
83 realpath
= elems
.at(0) + "/";
89 for(int i
= start
; i
< elems
.size(); i
++) {
91 = QDir(realpath
).entryList(QDir::AllEntries
|QDir::Hidden
|QDir::System
);
92 if(direlems
.contains(elems
.at(i
), Qt::CaseInsensitive
)) {
93 // need to filter using QRegExp as QStringList::filter(QString)
94 // matches any substring
95 QString expr
= QString("^" + elems
.at(i
) + "$");
96 QRegExp rx
= QRegExp(expr
, Qt::CaseInsensitive
);
97 QStringList a
= direlems
.filter(rx
);
101 if(!realpath
.endsWith("/"))
108 qDebug() << "[Utils] resolving path" << path
<< "->" << realpath
;
113 //! @brief figure the free disk space on a filesystem
114 //! @param path path on the filesystem to check
115 //! @return size in bytes
116 qulonglong
Utils::filesystemFree(QString path
)
118 return filesystemSize(path
, FilesystemFree
);
122 qulonglong
Utils::filesystemTotal(QString path
)
124 return filesystemSize(path
, FilesystemTotal
);
128 qulonglong
Utils::filesystemSize(QString path
, enum Utils::Size type
)
131 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
132 // the usage of statfs() is deprecated by the LSB so use statvfs().
136 ret
= statvfs(qPrintable(path
), &fs
);
139 if(type
== FilesystemFree
) {
140 size
= (qulonglong
)fs
.f_frsize
* (qulonglong
)fs
.f_bavail
;
142 if(type
== FilesystemTotal
) {
143 size
= (qulonglong
)fs
.f_frsize
* (qulonglong
)fs
.f_blocks
;
147 #if defined(Q_OS_WIN32)
149 ULARGE_INTEGER freeAvailBytes
;
150 ULARGE_INTEGER totalNumberBytes
;
152 ret
= GetDiskFreeSpaceExW((LPCTSTR
)path
.utf16(), &freeAvailBytes
,
153 &totalNumberBytes
, NULL
);
155 if(type
== FilesystemFree
) {
156 size
= freeAvailBytes
.QuadPart
;
158 if(type
== FilesystemTotal
) {
159 size
= totalNumberBytes
.QuadPart
;
163 qDebug() << "[Utils] Filesystem free:" << path
<< size
;
167 //! \brief searches for a Executable in the Environement Path
168 QString
Utils::findExecutable(QString name
)
172 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX) || defined(Q_OS_OPENBSD)
173 QStringList path
= QString(getenv("PATH")).split(":", QString::SkipEmptyParts
);
174 #elif defined(Q_OS_WIN)
175 QStringList path
= QString(getenv("PATH")).split(";", QString::SkipEmptyParts
);
177 qDebug() << "[Utils] system path:" << path
;
178 for(int i
= 0; i
< path
.size(); i
++)
180 QString executable
= QDir::fromNativeSeparators(path
.at(i
)) + "/" + name
;
181 #if defined(Q_OS_WIN)
182 executable
+= ".exe";
183 QStringList ex
= executable
.split("\"", QString::SkipEmptyParts
);
184 executable
= ex
.join("");
186 qDebug() << "[Utils] executable:" << executable
;
187 if(QFileInfo(executable
).isExecutable())
189 return QDir::toNativeSeparators(executable
);
196 /** @brief checks different Enviroment things. Ask if user wants to continue.
197 * @param permission if it should check for permission
198 * @return string with error messages if problems occurred, empty strings if none.
200 QString
Utils::checkEnvironment(bool permission
)
207 #if defined(Q_OS_WIN32)
208 if(System::userPermissions() != System::ADMIN
)
210 text
+= tr("<li>Permissions insufficient for bootloader "
211 "installation.\nAdministrator priviledges are necessary.</li>");
217 RockboxInfo
rbinfo(RbSettings::value(RbSettings::Mountpoint
).toString());
218 QString installed
= rbinfo
.target();
219 if(!installed
.isEmpty() && installed
!=
220 SystemInfo::value(SystemInfo::CurConfigureModel
).toString())
222 text
+= tr("<li>Target mismatch detected.\n"
223 "Installed target: %1, selected target: %2.</li>")
224 .arg(installed
, SystemInfo::value(SystemInfo::CurPlatformName
).toString());
225 // FIXME: replace installed by human-friendly name
229 return tr("Problem detected:") + "<ul>" + text
+ "</ul>";
233 /** @brief Compare two version strings.
234 * @param s1 first version string
235 * @param s2 second version string
236 * @return 0 if strings identical, 1 if second is newer, -1 if first.
238 int Utils::compareVersionStrings(QString s1
, QString s2
)
240 qDebug() << "[Utils] comparing version strings" << s1
<< "and" << s2
;
241 QString a
= s1
.trimmed();
242 QString b
= s2
.trimmed();
243 // if strings are identical return 0.
249 while(!a
.isEmpty() || !b
.isEmpty()) {
250 // trim all leading non-digits and non-dots (dots are removed afterwards)
251 a
.remove(QRegExp("^[^\\d\\.]*"));
252 b
.remove(QRegExp("^[^\\d\\.]*"));
254 // trim all trailing non-digits for conversion (QString::toInt()
255 // requires this). Copy strings first as replace() changes the string.
258 numa
.remove(QRegExp("\\D+.*$"));
259 numb
.remove(QRegExp("\\D+.*$"));
263 int vala
= numa
.toUInt(&ok1
);
264 int valb
= numb
.toUInt(&ok2
);
265 // if none of the numbers converted successfully we're at trailing garbage.
273 // if numbers mismatch we have a decision.
275 return (vala
> valb
) ? -1 : 1;
277 // trim leading digits.
278 a
.remove(QRegExp("^\\d*"));
279 b
.remove(QRegExp("^\\d*"));
281 // If only one of the following characters is a dot that one is
282 // "greater" then anything else. Make sure it's followed by a number,
283 // Otherwise it might be the end of the string or suffix. Do this
284 // before version addon characters check to avoid stopping too early.
285 bool adot
= a
.contains(QRegExp("^[a-zA-Z]*\\.[0-9]"));
286 bool bdot
= b
.contains(QRegExp("^[a-zA-Z]*\\.[0-9]"));
291 // if number is immediately followed by a character consider it as
292 // version addon (like 1.2.3b). In this case compare characters and end
293 // (version numbers like 1.2b.3 aren't handled).
296 if(a
.contains(QRegExp("^[a-zA-Z]")))
298 if(b
.contains(QRegExp("^[a-zA-Z]")))
301 return (ltra
< ltrb
) ? 1 : -1;
303 // both are identical or no addon characters, ignore.
304 // remove modifiers and following dot.
305 a
.remove(QRegExp("^[a-zA-Z]*\\."));
306 b
.remove(QRegExp("^[a-zA-Z]*\\."));
309 // no differences found.