KCoreAddons

kbackup.cpp
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 1999 Waldo Bastian <[email protected]>
5  SPDX-FileCopyrightText: 2006 Allen Winter <[email protected]>
6  SPDX-FileCopyrightText: 2006 Gregory S. Hayes <[email protected]>
7  SPDX-FileCopyrightText: 2006 Jaison Lee <[email protected]>
8  SPDX-FileCopyrightText: 2011 Romain Perier <[email protected]>
9 
10  SPDX-License-Identifier: LGPL-2.0-only
11 */
12 
13 #include "kbackup.h"
14 
15 #include <QDir>
16 #include <QFileInfo>
17 
18 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 75)
19 #include <QProcess>
20 #include <QStandardPaths>
21 #endif
22 
23 namespace KBackup
24 {
25 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 75)
26 bool backupFile(const QString &qFilename, const QString &backupDir)
27 {
28  return (simpleBackupFile(qFilename, backupDir, QStringLiteral("~")));
29 }
30 #endif
31 
32 bool simpleBackupFile(const QString &qFilename, const QString &backupDir, const QString &backupExtension)
33 {
34  QString backupFileName = qFilename + backupExtension;
35 
36  if (!backupDir.isEmpty()) {
37  QFileInfo fileInfo(qFilename);
38  backupFileName = backupDir + QLatin1Char('/') + fileInfo.fileName() + backupExtension;
39  }
40 
41  // qCDebug(KCOREADDONS_DEBUG) << "KBackup copying " << qFilename << " to " << backupFileName;
42  QFile::remove(backupFileName);
43  return QFile::copy(qFilename, backupFileName);
44 }
45 
46 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 75)
47 bool rcsBackupFile(const QString &qFilename, const QString &backupDir, const QString &backupMessage)
48 {
49  QFileInfo fileInfo(qFilename);
50 
51  QString qBackupFilename;
52  if (backupDir.isEmpty()) {
53  qBackupFilename = qFilename;
54  } else {
55  qBackupFilename = backupDir + fileInfo.fileName();
56  }
57  qBackupFilename += QLatin1String(",v");
58 
59  // If backupDir is specified, copy qFilename to the
60  // backupDir and perform the commit there, unlinking
61  // backupDir/qFilename when finished.
62  if (!backupDir.isEmpty()) {
63  if (!QFile::copy(qFilename, backupDir + fileInfo.fileName())) {
64  return false;
65  }
66  fileInfo.setFile(backupDir + QLatin1Char('/') + fileInfo.fileName());
67  }
68 
69  const QString cipath = QStandardPaths::findExecutable(QStringLiteral("ci"));
70  const QString copath = QStandardPaths::findExecutable(QStringLiteral("co"));
71  const QString rcspath = QStandardPaths::findExecutable(QStringLiteral("rcs"));
72  if (cipath.isEmpty() || copath.isEmpty() || rcspath.isEmpty()) {
73  return false;
74  }
75 
76  // Check in the file unlocked with 'ci'
77  QProcess ci;
78  if (!backupDir.isEmpty()) {
79  ci.setWorkingDirectory(backupDir);
80  }
81  ci.start(cipath, QStringList{QStringLiteral("-u"), fileInfo.filePath()});
82  if (!ci.waitForStarted()) {
83  return false;
84  }
85  ci.write(backupMessage.toLocal8Bit());
86  ci.write(".");
87  ci.closeWriteChannel();
88  if (!ci.waitForFinished()) {
89  return false;
90  }
91 
92  // Use 'rcs' to unset strict locking
93  QProcess rcs;
94  if (!backupDir.isEmpty()) {
95  rcs.setWorkingDirectory(backupDir);
96  }
97  rcs.start(rcspath, QStringList{QStringLiteral("-U"), qBackupFilename});
98  if (!rcs.waitForFinished()) {
99  return false;
100  }
101 
102  // Use 'co' to checkout the current revision and restore permissions
103  QProcess co;
104  if (!backupDir.isEmpty()) {
105  co.setWorkingDirectory(backupDir);
106  }
107  co.start(copath, QStringList{qBackupFilename});
108  if (!co.waitForFinished()) {
109  return false;
110  }
111 
112  if (!backupDir.isEmpty()) {
113  return QFile::remove(fileInfo.filePath());
114  } else {
115  return true;
116  }
117 }
118 #endif
119 
120 bool numberedBackupFile(const QString &qFilename, const QString &backupDir, const QString &backupExtension, const uint maxBackups)
121 {
122  QFileInfo fileInfo(qFilename);
123 
124  // The backup file name template.
125  QString sTemplate;
126  if (backupDir.isEmpty()) {
127  sTemplate = qFilename + QLatin1String(".%1") + backupExtension;
128  } else {
129  sTemplate = backupDir + QLatin1Char('/') + fileInfo.fileName() + QLatin1String(".%1") + backupExtension;
130  }
131 
132  // First, search backupDir for numbered backup files to remove.
133  // Remove all with number 'maxBackups' and greater.
134  QDir d = backupDir.isEmpty() ? fileInfo.dir() : backupDir;
136  const QStringList nameFilters = QStringList(fileInfo.fileName() + QLatin1String(".*") + backupExtension);
137  d.setNameFilters(nameFilters);
139 
140  uint maxBackupFound = 0;
141  const QFileInfoList infoList = d.entryInfoList();
142  for (const QFileInfo &fi : infoList) {
143  if (fi.fileName().endsWith(backupExtension)) {
144  // sTemp holds the file name, without the ending backupExtension
145  QString sTemp = fi.fileName();
146  sTemp.truncate(fi.fileName().length() - backupExtension.length());
147  // compute the backup number
148  int idex = sTemp.lastIndexOf(QLatin1Char('.'));
149  if (idex > 0) {
150  bool ok;
151  uint num = sTemp.midRef(idex + 1).toUInt(&ok);
152  if (ok) {
153  if (num >= maxBackups) {
154  QFile::remove(fi.filePath());
155  } else {
156  maxBackupFound = qMax(maxBackupFound, num);
157  }
158  }
159  }
160  }
161  }
162 
163  // Next, rename max-1 to max, max-2 to max-1, etc.
164  QString to = sTemplate.arg(maxBackupFound + 1);
165  for (int i = maxBackupFound; i > 0; i--) {
166  QString from = sTemplate.arg(i);
167  // qCDebug(KCOREADDONS_DEBUG) << "KBackup renaming " << from << " to " << to;
168  QFile::rename(from, to);
169  to = from;
170  }
171 
172  // Finally create most recent backup by copying the file to backup number 1.
173  // qCDebug(KCOREADDONS_DEBUG) << "KBackup copying " << qFilename << " to " << sTemplate.arg(1);
174  return QFile::copy(qFilename, sTemplate.arg(1));
175 }
176 
177 }
void truncate(int position)
void setNameFilters(const QStringList &nameFilters)
bool remove()
void setFile(const QString &file)
bool rename(const QString &newName)
QString findExecutable(const QString &executableName, const QStringList &paths)
bool rcsBackupFile(const QString &qFilename, const QString &backupDir, const QString &backupMessage)
Function to create an rcs backup file for a given filename.
Definition: kbackup.cpp:47
void setSorting(QDir::SortFlags sort)
bool copy(const QString &newName)
bool numberedBackupFile(const QString &qFilename, const QString &backupDir, const QString &backupExtension, const uint maxBackups)
Function to create a backup file for a given filename.
Definition: kbackup.cpp:120
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString filePath() const const
Provides utility functions for backup of files.
Definition: kbackup.cpp:23
void setFilter(QDir::Filters filters)
QString fileName() const const
QFileInfoList entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const const
bool isEmpty() const const
QDir dir() const const
QByteArray toLocal8Bit() const const
bool waitForStarted(int msecs)
void setWorkingDirectory(const QString &dir)
QStringRef midRef(int position, int n) const const
bool simpleBackupFile(const QString &qFilename, const QString &backupDir, const QString &backupExtension)
Function to create a backup file for a given filename.
Definition: kbackup.cpp:32
uint toUInt(bool *ok, int base) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
int length() const const
qint64 write(const char *data, qint64 maxSize)
void closeWriteChannel()
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
bool waitForFinished(int msecs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Apr 11 2021 23:01:47 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.