File: UndoableUnlink.cc

package info (click to toggle)
rdfind 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 648 kB
  • sloc: cpp: 1,670; sh: 1,622; makefile: 32
file content (89 lines) | stat: -rw-r--r-- 2,330 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
   copyright 2018 Paul Dreik
   Distributed under GPL v 2.0 or later, at your option.
   See LICENSE for further details.
*/

#include "config.h"

// std
#include <iostream>
#include <stdexcept>

// os
#include <unistd.h> //for unlink etc.

// project
#include "EasyRandom.hh"
#include "UndoableUnlink.hh"

UndoableUnlink::UndoableUnlink(const std::string& filename)
  : m_filename(filename)
{
  // make a random filename, to avoid getting ENAMETOOLONG
  // we try to replace the existing filename, instead of appending to it.
  // this will fail if the directory name is really long, but there is not
  // much to do about that without going into parsing mount points etc.
  const auto last_sep = m_filename.find_last_of('/');
  if (last_sep == std::string::npos) {
    // bare filename - replace it.
    m_tempfilename = EasyRandom().makeRandomFileString();
  } else {
    // found. keep the directory, switch out the filename.
    m_tempfilename =
      m_filename.substr(0, last_sep + 1) + EasyRandom().makeRandomFileString();
  }

  // move the file to a temporary name
  if (0 != rename(m_filename.c_str(), m_tempfilename.c_str())) {
    // failed rename.
    std::cerr << "Failed moving " + m_filename + " to a temporary file\n";
    m_state = state::FAILED_MOVE_TO_TEMPORARY;
  } else {
    m_state = state::MOVED_TO_TEMPORARY;
  }
}

int
UndoableUnlink::undo()
{
  if (m_state != state::MOVED_TO_TEMPORARY) {
    throw std::runtime_error(
      "api misuse - calling undo() now is a programming error");
  }

  if (0 != rename(m_tempfilename.c_str(), m_filename.c_str())) {
    // failed rename.
    m_state = state::FAILED_UNDO;
    std::cerr << "Failed moving file from temporary back to " + m_filename +
                   '\n';
    return 1;
  }

  m_state = state::UNDONE;
  return 0;
}

int
UndoableUnlink::unlink()
{
  if (m_state != state::MOVED_TO_TEMPORARY) {
    throw std::runtime_error(
      "api misuse - calling unlink() now is a programming error");
  }
  if (0 != ::unlink(m_tempfilename.c_str())) {
    std::cerr << "Failed unlinking temporary file made from " + m_filename +
                   '\n';
    m_state = state::FAILED_UNLINK;
    return 1;
  }
  m_state = state::UNLINKED;
  return 0;
}

UndoableUnlink::~UndoableUnlink()
{
  if (m_state == state::MOVED_TO_TEMPORARY) {
    undo();
  }
}