• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeutils API Reference
  • KDE Home
  • Contact Us
 

ark

  • sources
  • kde-4.14
  • kdeutils
  • ark
  • plugins
  • karchiveplugin
karchiveplugin.cpp
Go to the documentation of this file.
1 /*
2  * ark -- archiver for the KDE project
3  *
4  * Copyright (C) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  */
21 #include "karchiveplugin.h"
22 #include "kerfuffle/queries.h"
23 
24 #include <KZip>
25 #include <KTar>
26 #include <KMimeType>
27 #include <KDebug>
28 #include <KLocale>
29 #include <QDir>
30 
31 #include <QFileInfo>
32 #include <QSet>
33 
34 KArchiveInterface::KArchiveInterface(QObject *parent, const QVariantList &args)
35  : ReadWriteArchiveInterface(parent, args), m_archive(0)
36 {
37  kDebug();
38 }
39 
40 KArchiveInterface::~KArchiveInterface()
41 {
42  delete m_archive;
43  m_archive = 0;
44 }
45 
46 KArchive *KArchiveInterface::archive()
47 {
48  if (m_archive == 0) {
49  KMimeType::Ptr mimeType = KMimeType::findByPath(filename());
50 
51  if (mimeType->is(QLatin1String("application/zip"))) {
52  m_archive = new KZip(filename());
53  } else {
54  m_archive = new KTar(filename());
55  }
56 
57  }
58  return m_archive;
59 }
60 
61 bool KArchiveInterface::list()
62 {
63  kDebug();
64  if (!archive()->isOpen() && !archive()->open(QIODevice::ReadOnly)) {
65  emit error(i18nc("@info", "Could not open the archive <filename>%1</filename> for reading", filename()));
66  return false;
67  } else {
68  return browseArchive(archive());
69  }
70 }
71 
72 void KArchiveInterface::getAllEntries(const KArchiveDirectory *dir, const QString &prefix, QList< QVariant > &list)
73 {
74  foreach(const QString &entryName, dir->entries()) {
75  const KArchiveEntry *entry = dir->entry(entryName);
76  if (entry->isDirectory()) {
77  QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName;
78  getAllEntries(static_cast<const KArchiveDirectory*>(entry), newPrefix, list);
79  }
80  else {
81  list.append(prefix + QLatin1Char('/') + entryName);
82  }
83  }
84 }
85 
86 bool KArchiveInterface::copyFiles(const QList<QVariant> &files, const QString &destinationDirectory, ExtractionOptions options)
87 {
88  const bool preservePaths = options.value(QLatin1String("PreservePaths")).toBool();
89  const KArchiveDirectory *dir = archive()->directory();
90 
91  if (!archive()->isOpen() && !archive()->open(QIODevice::ReadOnly)) {
92  emit error(i18nc("@info", "Could not open the archive <filename>%1</filename> for reading", filename()));
93  return false;
94  }
95 
96  QList<QVariant> extrFiles = files;
97  if (extrFiles.isEmpty()) { // All files should be extracted
98  getAllEntries(dir, QString(), extrFiles);
99  }
100 
101  bool overwriteAllSelected = false;
102  bool autoSkipSelected = false;
103  QSet<QString> dirCache;
104  foreach(const QVariant &file, extrFiles) {
105  QString realDestination = destinationDirectory;
106  const KArchiveEntry *archiveEntry = dir->entry(file.toString());
107  if (!archiveEntry) {
108  emit error(i18nc("@info", "File <filename>%1</filename> not found in the archive" , file.toString()));
109  return false;
110  }
111 
112  if (preservePaths) {
113  QFileInfo fi(file.toString());
114  QDir dest(destinationDirectory);
115  QString filepath = archiveEntry->isDirectory() ? fi.filePath() : fi.path();
116  if (!dirCache.contains(filepath)) {
117  if (!dest.mkpath(filepath)) {
118  emit error(i18nc("@info", "Error creating directory <filename>%1</filename>", filepath));
119  return false;
120  }
121  dirCache << filepath;
122  }
123  realDestination = dest.absolutePath() + QLatin1Char('/') + filepath;
124  }
125 
126  // TODO: handle errors, copyTo fails silently
127  if (!archiveEntry->isDirectory()) { // We don't need to do anything about directories
128  if (QFile::exists(realDestination + QLatin1Char('/') + archiveEntry->name()) && !overwriteAllSelected) {
129  if (autoSkipSelected) {
130  continue;
131  }
132 
133  int response = handleFileExistsMessage(realDestination, archiveEntry->name());
134 
135  if (response == OverwriteCancel) {
136  break;
137  }
138  if (response == OverwriteYes || response == OverwriteAll) {
139  static_cast<const KArchiveFile*>(archiveEntry)->copyTo(realDestination);
140  if (response == OverwriteAll) {
141  overwriteAllSelected = true;
142  }
143  }
144  if (response == OverwriteAutoSkip) {
145  autoSkipSelected = true;
146  }
147  }
148  else {
149  static_cast<const KArchiveFile*>(archiveEntry)->copyTo(realDestination);
150  }
151  }
152  }
153 
154  return true;
155 }
156 
157 int KArchiveInterface::handleFileExistsMessage(const QString &dir, const QString &fileName)
158 {
159  Kerfuffle::OverwriteQuery query(dir + QLatin1Char('/') + fileName);
160  query.setNoRenameMode(true);
161  emit userQuery(&query);
162  query.waitForResponse();
163 
164  if (query.responseOverwrite()) {
165  return OverwriteYes;
166  } else if (query.responseSkip()) {
167  return OverwriteSkip;
168  } else if (query.responseOverwriteAll()) {
169  return OverwriteAll;
170  } else if (query.responseAutoSkip()) {
171  return OverwriteAutoSkip;
172  }
173 
174  return OverwriteCancel;
175 }
176 
177 bool KArchiveInterface::browseArchive(KArchive *archive)
178 {
179  return processDir(archive->directory());
180 }
181 
182 bool KArchiveInterface::processDir(const KArchiveDirectory *dir, const QString & prefix)
183 {
184  foreach(const QString& entryName, dir->entries()) {
185  const KArchiveEntry *entry = dir->entry(entryName);
186  createEntryFor(entry, prefix);
187  if (entry->isDirectory()) {
188  QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName;
189  processDir(static_cast<const KArchiveDirectory*>(entry), newPrefix);
190  }
191  }
192  return true;
193 }
194 
195 void KArchiveInterface::createEntryFor(const KArchiveEntry *aentry, const QString& prefix)
196 {
197  ArchiveEntry e;
198  QString fileName = prefix.isEmpty() ? aentry->name() : prefix + QLatin1Char('/') + aentry->name();
199 
200  if (aentry->isDirectory() && !fileName.endsWith(QLatin1Char('/')))
201  fileName += QLatin1Char('/');
202 
203  e[ FileName ] = fileName;
204  e[ InternalID ] = e[ FileName ];
205  e[ Permissions ] = permissionsString(aentry->permissions());
206  e[ Owner ] = aentry->user();
207  e[ Group ] = aentry->group();
208  e[ IsDirectory ] = aentry->isDirectory();
209  e[ Timestamp ] = aentry->datetime();
210  if (!aentry->symLinkTarget().isEmpty()) {
211  e[ Link ] = aentry->symLinkTarget();
212  }
213  if (aentry->isFile()) {
214  e[ Size ] = static_cast<const KArchiveFile*>(aentry)->size();
215  }
216  else {
217  e[ Size ] = 0;
218  }
219  emit entry(e);
220 }
221 
222 bool KArchiveInterface::addFiles(const QStringList &files, const Kerfuffle::CompressionOptions &options)
223 {
224  Q_UNUSED(options)
225  kDebug() << "Starting...";
226 // delete m_archive;
227 // m_archive = 0;
228  if (archive()->isOpen()) {
229  archive()->close();
230  }
231  if (!archive()->open(QIODevice::ReadWrite)) {
232  emit error(i18nc("@info", "Could not open the archive <filename>%1</filename> for writing.", filename()));
233  return false;
234  }
235 
236  kDebug() << "Archive opened for writing...";
237  kDebug() << "Will add " << files.count() << " files";
238  foreach(const QString &path, files) {
239  kDebug() << "Adding " << path;
240  QFileInfo fi(path);
241  Q_ASSERT(fi.exists());
242 
243  if (fi.isDir()) {
244  if (archive()->addLocalDirectory(path, fi.fileName())) {
245  const KArchiveEntry *entry = archive()->directory()->entry(fi.fileName());
246  createEntryFor(entry, QString());
247  processDir((KArchiveDirectory*) archive()->directory()->entry(fi.fileName()), fi.fileName());
248  } else {
249  emit error(i18nc("@info", "Could not add the directory <filename>%1</filename> to the archive", path));
250  return false;
251  }
252  } else {
253  if (archive()->addLocalFile(path, fi.fileName())) {
254  const KArchiveEntry *entry = archive()->directory()->entry(fi.fileName());
255  createEntryFor(entry, QString());
256  } else {
257  emit error(i18nc("@info", "Could not add the file <filename>%1</filename> to the archive.", path));
258  return false;
259  }
260  }
261  }
262  kDebug() << "Closing the archive";
263  archive()->close();
264  kDebug() << "Done";
265  return true;
266 }
267 
268 bool KArchiveInterface::deleteFiles(const QList<QVariant> & files)
269 {
270  Q_UNUSED(files)
271  return false;
272 }
273 
274 // Borrowed and adapted from KFileItemPrivate::parsePermissions.
275 QString KArchiveInterface::permissionsString(mode_t perm)
276 {
277  static char buffer[ 12 ];
278 
279  char uxbit,gxbit,oxbit;
280 
281  if ( (perm & (S_IXUSR|S_ISUID)) == (S_IXUSR|S_ISUID) )
282  uxbit = 's';
283  else if ( (perm & (S_IXUSR|S_ISUID)) == S_ISUID )
284  uxbit = 'S';
285  else if ( (perm & (S_IXUSR|S_ISUID)) == S_IXUSR )
286  uxbit = 'x';
287  else
288  uxbit = '-';
289 
290  if ( (perm & (S_IXGRP|S_ISGID)) == (S_IXGRP|S_ISGID) )
291  gxbit = 's';
292  else if ( (perm & (S_IXGRP|S_ISGID)) == S_ISGID )
293  gxbit = 'S';
294  else if ( (perm & (S_IXGRP|S_ISGID)) == S_IXGRP )
295  gxbit = 'x';
296  else
297  gxbit = '-';
298 
299  if ( (perm & (S_IXOTH|S_ISVTX)) == (S_IXOTH|S_ISVTX) )
300  oxbit = 't';
301  else if ( (perm & (S_IXOTH|S_ISVTX)) == S_ISVTX )
302  oxbit = 'T';
303  else if ( (perm & (S_IXOTH|S_ISVTX)) == S_IXOTH )
304  oxbit = 'x';
305  else
306  oxbit = '-';
307 
308  // Include the type in the first char like kde3 did; people are more used to seeing it,
309  // even though it's not really part of the permissions per se.
310  if (S_ISDIR(perm))
311  buffer[0] = 'd';
312  else if (S_ISLNK(perm))
313  buffer[0] = 'l';
314  else
315  buffer[0] = '-';
316 
317  buffer[1] = ((( perm & S_IRUSR ) == S_IRUSR ) ? 'r' : '-' );
318  buffer[2] = ((( perm & S_IWUSR ) == S_IWUSR ) ? 'w' : '-' );
319  buffer[3] = uxbit;
320  buffer[4] = ((( perm & S_IRGRP ) == S_IRGRP ) ? 'r' : '-' );
321  buffer[5] = ((( perm & S_IWGRP ) == S_IWGRP ) ? 'w' : '-' );
322  buffer[6] = gxbit;
323  buffer[7] = ((( perm & S_IROTH ) == S_IROTH ) ? 'r' : '-' );
324  buffer[8] = ((( perm & S_IWOTH ) == S_IWOTH ) ? 'w' : '-' );
325  buffer[9] = oxbit;
326  buffer[10] = 0;
327 
328  return QString::fromLatin1(buffer);
329 }
330 
331 KERFUFFLE_EXPORT_PLUGIN(KArchiveInterface)
Kerfuffle::Owner
The user the entry belongs to.
Definition: archive.h:62
KArchiveInterface::~KArchiveInterface
~KArchiveInterface()
Definition: karchiveplugin.cpp:40
Kerfuffle::IsDirectory
The entry is a directory.
Definition: archive.h:72
Kerfuffle::ReadOnlyArchiveInterface::userQuery
void userQuery(Query *query)
Kerfuffle::ReadOnlyArchiveInterface::filename
QString filename() const
Returns the filename of the archive currently being handled.
Definition: archiveinterface.cpp:48
KArchiveInterface::deleteFiles
bool deleteFiles(const QList< QVariant > &files)
Definition: karchiveplugin.cpp:268
queries.h
QFile::exists
bool exists() const
karchiveplugin.h
Kerfuffle::Link
The entry is a symbolic link.
Definition: archive.h:66
Kerfuffle::ReadOnlyArchiveInterface::entry
void entry(const ArchiveEntry &archiveEntry)
QList::count
int count(const T &value) const
Kerfuffle::ArchiveEntry
QHash< int, QVariant > ArchiveEntry
Definition: archive.h:78
QList::append
void append(const T &value)
Kerfuffle::ReadWriteArchiveInterface
Definition: archiveinterface.h:121
QHash
QFileInfo::isDir
bool isDir() const
QFileInfo::fileName
QString fileName() const
QObject
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
KArchiveInterface::list
bool list()
List archive contents.
Definition: karchiveplugin.cpp:61
QSet
QString
QList
Kerfuffle::Timestamp
The timestamp for the current entry.
Definition: archive.h:71
QStringList
Kerfuffle::FileName
The entry's file name.
Definition: archive.h:59
Kerfuffle::ReadOnlyArchiveInterface::open
virtual bool open()
Definition: archiveinterface.cpp:58
QFileInfo
QHash::value
const T value(const Key &key) const
QFileInfo::exists
bool exists() const
QLatin1Char
QSet::contains
bool contains(const T &value) const
QDir
Kerfuffle::Permissions
The entry's permissions.
Definition: archive.h:61
KArchiveInterface
Definition: karchiveplugin.h:31
KArchiveInterface::KArchiveInterface
KArchiveInterface(QObject *parent=0, const QVariantList &args=QVariantList())
Definition: karchiveplugin.cpp:34
QLatin1String
Kerfuffle::ReadOnlyArchiveInterface::error
void error(const QString &message, const QString &details=QString())
Kerfuffle::Size
The entry's original size.
Definition: archive.h:64
KArchiveInterface::addFiles
bool addFiles(const QStringList &files, const CompressionOptions &options)
Definition: karchiveplugin.cpp:222
Kerfuffle::OverwriteQuery
Definition: queries.h:77
QString::fromLatin1
QString fromLatin1(const char *str, int size)
KERFUFFLE_EXPORT_PLUGIN
#define KERFUFFLE_EXPORT_PLUGIN(p)
Definition: kerfuffle_export.h:49
Kerfuffle::Group
The user group the entry belongs to.
Definition: archive.h:63
Kerfuffle::InternalID
The entry's ID for Ark's internal manipulation.
Definition: archive.h:60
KArchiveInterface::copyFiles
bool copyFiles(const QList< QVariant > &files, const QString &destinationDirectory, ExtractionOptions options)
Extract files from archive.
Definition: karchiveplugin.cpp:86
QVariant::toString
QString toString() const
QVariant
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:42:37 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

ark

Skip menu "ark"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeutils API Reference

Skip menu "kdeutils API Reference"
  • ark
  • filelight
  • kcalc
  • kcharselect
  • kdf
  • kfloppy
  • kgpg
  • ktimer
  • kwallet
  • sweeper

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal