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 DirErrno FileUtils::mkpath(const QDir &dir)
106 {
107  // We need to reset errno to prevent false positives
108  errno = 0;
109  if (!dir.mkpath("."))
110  {
111  int errnoval = errno;
112  if (errnoval != 0)
113  {
114  return DirErrno(dir.path(), errnoval, strerror(errnoval));
115  }
116  else
117  {
118  // Try to decipher if we have permissions.
119  // First we must find the bottom-most directory that does actually exist.
120  QString pathToBottomMostExisting = FileUtils::cdUpUntilExists(dir.path());
121  // If we've found a bottom-most directory that exists, we can check its permissions.
122  if (!pathToBottomMostExisting.isEmpty())
123  {
124  QFileInfo parentDir(pathToBottomMostExisting);
125  if (parentDir.exists() && !parentDir.isDir())
126  {
127  return DirErrno(dir.path(), DirErrno::CUSTOM_ERROR,
128  FileUtilsTr::parentPathIsNotADirectory(parentDir.filePath()));
129  }
130 
131  // BLOCK - keep this to absolute minimum
132  ++qt_ntfs_permission_lookup;
133  bool permissions = parentDir.isReadable()
134  && parentDir.isWritable()
135  && parentDir.isExecutable();
136  --qt_ntfs_permission_lookup;
137  // END OF BLOCK
138  if (!permissions)
139  {
140  return DirErrno(dir.path(), DirErrno::CUSTOM_ERROR,
141  FileUtilsTr::lackOfParentDirectoryPermissions(parentDir.filePath()));
142  }
143  }
144  // Just give up trying to deduce a correct error.
145  return DirErrno(dir.path(), DirErrno::CUSTOM_ERROR,
146  FileUtilsTr::cannotCreateDirectory());
147  }
148  }
149  return DirErrno();
150 }
151 
152 bool FileUtils::rmAllFiles(const QString &dirPath,
153  const QStringList &nameFilters)
154 {
155  QDirIterator it(dirPath, nameFilters, QDir::Files);
156  bool bAllSuccess = true;
157  while (it.hasNext())
158  {
159  QString path = it.next();
160  QFile f(path);
161  if (!f.remove())
162  {
163  bAllSuccess = false;
164  gLog << Log::tr("Failed to remove: %1").arg(path);
165  }
166  }
167  return bAllSuccess;
168 }
169 
170 #include "fileutils.moc"