fileutils.cpp
1 //------------------------------------------------------------------------------
2 // fileutils.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2012 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "fileutils.h"
24 
25 #include "ntfsperm.h"
26 #include "log.h"
27 #include <QCryptographicHash>
28 #include <QDirIterator>
29 #include <QFileInfo>
30 
31 class FileUtilsTr : public QObject
32 {
33  Q_OBJECT
34 
35 public:
36  static QString cannotCreateDirectory()
37  {
38  return tr("cannot create directory");
39  }
40 
41  static QString parentPathIsNotADirectory(const QString &path)
42  {
43  return tr("the parent path is not a directory: %1").arg(path);
44  }
45 
46  static QString lackOfParentDirectoryPermissions(const QString &to)
47  {
48  return tr("lack of necessary permissions to the parent directory: %1")
49  .arg(to);
50  }
51 
52 private:
53  FileUtilsTr() = delete;
54 };
55 
56 QByteArray FileUtils::md5(const QString &path)
57 {
58  QFile f(path);
59  if (f.open(QIODevice::ReadOnly))
60  {
61  QCryptographicHash hash(QCryptographicHash::Md5);
62  QByteArray chunk = f.read(1024 * 1024);
63  for (; !chunk.isEmpty(); chunk = f.read(1024 * 1024))
64  hash.addData(chunk);
65  f.close();
66  return hash.result();
67  }
68  return QByteArray();
69 }
70 
71 QString FileUtils::cdUpUntilExists(QString path)
72 {
73  static const int SANITY_LOOP_LIMIT = 1000;
74  QFileInfo fileInfo(QDir::cleanPath(path));
75  for (int i = 0; i < SANITY_LOOP_LIMIT; ++i)
76  {
77  if (fileInfo.filePath().endsWith("/.."))
78  return QString();
79  if (fileInfo.exists() || fileInfo.isRoot())
80  return fileInfo.filePath();
81  fileInfo = QFileInfo(QDir::cleanPath(fileInfo.filePath() + "/.."));
82  }
83  return QString();
84 }
85 
86 Qt::CaseSensitivity FileUtils::comparisonSensitivity()
87 {
88  #if defined(Q_OS_WIN32)
89  return Qt::CaseInsensitive;
90  #else
91  return Qt::CaseSensitive;
92  #endif
93 }
94 
95 bool FileUtils::containsPath(const QStringList &candidates, const QString &path)
96 {
97  for (const QString &candidate : candidates)
98  {
99  if (QFileInfo(candidate) == QFileInfo(path))
100  return true;
101  }
102  return false;
103 }
104 
105 QDir FileUtils::dirOrDir(const QString &preferred, const QString &fallback)
106 {
107  if (!preferred.isEmpty())
108  {
109  QDir dir(preferred);
110  if (dir.exists())
111  return dir;
112  }
113  return QDir(fallback);
114 }
115 
116 DirErrno FileUtils::mkpath(const QDir &dir)
117 {
118  // We need to reset errno to prevent false positives
119  errno = 0;
120  if (!dir.mkpath("."))
121  {
122  int errnoval = errno;
123  if (errnoval != 0)
124  {
125  return DirErrno(dir.path(), errnoval, strerror(errnoval));
126  }
127  else
128  {
129  // Try to decipher if we have permissions.
130  // First we must find the bottom-most directory that does actually exist.
131  QString pathToBottomMostExisting = FileUtils::cdUpUntilExists(dir.path());
132  // If we've found a bottom-most directory that exists, we can check its permissions.
133  if (!pathToBottomMostExisting.isEmpty())
134  {
135  QFileInfo parentDir(pathToBottomMostExisting);
136  if (parentDir.exists() && !parentDir.isDir())
137  {
138  return DirErrno(dir.path(), DirErrno::CUSTOM_ERROR,
139  FileUtilsTr::parentPathIsNotADirectory(parentDir.filePath()));
140  }
141 
142  // BLOCK - keep this to absolute minimum
143  ++qt_ntfs_permission_lookup;
144  bool permissions = parentDir.isReadable()
145  && parentDir.isWritable()
146  && parentDir.isExecutable();
147  --qt_ntfs_permission_lookup;
148  // END OF BLOCK
149  if (!permissions)
150  {
151  return DirErrno(dir.path(), DirErrno::CUSTOM_ERROR,
152  FileUtilsTr::lackOfParentDirectoryPermissions(parentDir.filePath()));
153  }
154  }
155  // Just give up trying to deduce a correct error.
156  return DirErrno(dir.path(), DirErrno::CUSTOM_ERROR,
157  FileUtilsTr::cannotCreateDirectory());
158  }
159  }
160  return DirErrno();
161 }
162 
163 bool FileUtils::rmAllFiles(const QString &dirPath,
164  const QStringList &nameFilters)
165 {
166  QDirIterator it(dirPath, nameFilters, QDir::Files);
167  bool bAllSuccess = true;
168  while (it.hasNext())
169  {
170  QString path = it.next();
171  QFile f(path);
172  if (!f.remove())
173  {
174  bAllSuccess = false;
175  gLog << Log::tr("Failed to remove: %1").arg(path);
176  }
177  }
178  return bAllSuccess;
179 }
180 
181 #include "fileutils.moc"