Show the total size of the volume along with the free space.
[kugel-rb.git] / rbutil / rbutilqt / base / utils.cpp
blob1a8607b8e294859251318fbab108f8ba3f9debeb
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
9 * Copyright (C) 2007 by Dominik Wenger
10 * $Id$
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 ****************************************************************************/
20 #include "utils.h"
21 #include "rockboxinfo.h"
22 #include "system.h"
23 #include "rbsettings.h"
24 #include "systeminfo.h"
26 #ifdef UNICODE
27 #define _UNICODE
28 #endif
30 #include <QtCore>
31 #include <QDebug>
32 #include <cstdlib>
33 #include <stdio.h>
35 #if defined(Q_OS_WIN32)
36 #include <windows.h>
37 #include <tchar.h>
38 #include <winioctl.h>
39 #endif
40 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
41 #include <sys/statvfs.h>
42 #endif
44 // recursive function to delete a dir with files
45 bool Utils::recursiveRmdir( const QString &dirName )
47 QString dirN = dirName;
48 QDir dir(dirN);
49 // make list of entries in directory
50 QStringList list = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
51 QFileInfo fileInfo;
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
60 else // is file
61 QFile::remove(curItem); // ok, delete file
63 dir.cdUp();
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)
74 QStringList elems;
75 QString realpath;
77 elems = path.split("/", QString::SkipEmptyParts);
78 int start;
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.
82 start = 1;
83 realpath = elems.at(0) + "/";
84 #else
85 start = 0;
86 realpath = "/";
87 #endif
89 for(int i = start; i < elems.size(); i++) {
90 QStringList direlems
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);
99 if(a.size() != 1)
100 return QString("");
101 if(!realpath.endsWith("/"))
102 realpath += "/";
103 realpath += a.at(0);
105 else
106 return QString("");
108 qDebug() << "[Utils] resolving path" << path << "->" << realpath;
109 return 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)
130 qlonglong size = 0;
131 #if defined(Q_OS_LINUX) || defined(Q_OS_MACX)
132 // the usage of statfs() is deprecated by the LSB so use statvfs().
133 struct statvfs fs;
134 int ret;
136 ret = statvfs(qPrintable(path), &fs);
138 if(ret == 0) {
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;
146 #endif
147 #if defined(Q_OS_WIN32)
148 BOOL ret;
149 ULARGE_INTEGER freeAvailBytes;
150 ULARGE_INTEGER totalNumberBytes;
152 ret = GetDiskFreeSpaceExW((LPCTSTR)path.utf16(), &freeAvailBytes,
153 &totalNumberBytes, NULL);
154 if(ret) {
155 if(type == FilesystemFree) {
156 size = freeAvailBytes.QuadPart;
158 if(type == FilesystemTotal) {
159 size = totalNumberBytes.QuadPart;
162 #endif
163 qDebug() << "[Utils] Filesystem free:" << path << size;
164 return size;
167 //! \brief searches for a Executable in the Environement Path
168 QString Utils::findExecutable(QString name)
170 QString exepath;
171 //try autodetect tts
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);
176 #endif
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("");
185 #endif
186 qDebug() << "[Utils] executable:" << executable;
187 if(QFileInfo(executable).isExecutable())
189 return QDir::toNativeSeparators(executable);
192 return "";
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)
202 QString text = "";
204 // check permission
205 if(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>");
213 #endif
216 // Check TargetId
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
228 if(!text.isEmpty())
229 return tr("Problem detected:") + "<ul>" + text + "</ul>";
230 else
231 return text;
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.
244 if(a.isEmpty())
245 return 1;
246 if(b.isEmpty())
247 return -1;
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.
256 QString numa = a;
257 QString numb = b;
258 numa.remove(QRegExp("\\D+.*$"));
259 numb.remove(QRegExp("\\D+.*$"));
261 // convert to number
262 bool ok1, ok2;
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.
266 if(!ok1 && !ok2)
267 break;
268 if(!ok1)
269 return 1;
270 if(!ok2)
271 return -1;
273 // if numbers mismatch we have a decision.
274 if(vala != valb)
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]"));
287 if(adot && !bdot)
288 return -1;
289 if(!adot && bdot)
290 return 1;
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).
294 QChar ltra;
295 QChar ltrb;
296 if(a.contains(QRegExp("^[a-zA-Z]")))
297 ltra = a.at(0);
298 if(b.contains(QRegExp("^[a-zA-Z]")))
299 ltrb = b.at(0);
300 if(ltra != ltrb)
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.
310 return 0;