File: temp_file.cpp

package info (click to toggle)
videolink 1.0-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 368 kB
  • ctags: 502
  • sloc: cpp: 3,210; ansic: 880; makefile: 121
file content (114 lines) | stat: -rw-r--r-- 2,751 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2005-6 Ben Hutchings <ben@decadent.org.uk>.
// See the file "COPYING" for licence details.

#include "temp_file.hpp"

#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <vector>

#include <fcntl.h>
#include <unistd.h>

#include <glibmm/fileutils.h>
#include <glibmm/miscutils.h>

namespace
{
    bool try_rmdir_recursive(const std::string & dir_name)
    {
	Glib::Dir dir(dir_name);
	bool empty = true;

	for (Glib::Dir::iterator it = dir.begin(), end = dir.end();
	     it != end;
	     ++it)
	{
	    std::string full_name(Glib::build_filename(dir_name, *it));
	    if (!(Glib::file_test(full_name, Glib::FILE_TEST_IS_DIR)
		  ? try_rmdir_recursive(full_name)
		  : (unlink(full_name.c_str()) == 0 || errno == ENOENT)))
		empty = false;
	}

	return empty && (rmdir(dir_name.c_str()) == 0 || errno == ENOENT);
    }

    bool do_keep_all = false;
}

temp_file::temp_file(const std::string & base_name)
{
    fd_ = Glib::file_open_tmp(name_, base_name);
    assert(fd_ >= 0);

    // Workaround bug in glibc <2.2 that may cause the file to be
    // created with lax permissions.
#   ifdef __GLIBC__
#   if !__GLIBC_PREREQ(2, 2)
    if (fchmod(fd_, S_IREAD|S_IWRITE) != 0 || ftruncate(fd_, 0) != 0)
    {
	close(fd_);
	throw std::runtime_error(std::strerror(errno));
    }
#   endif
#   endif
}

temp_file::~temp_file()
{
    close();

    if (!do_keep_all)
    {
	// Don't assert that this is successful.  The file could have
	// been removed by another process.
	unlink(name_.c_str());
    }
}

void temp_file::close()
{
    if (fd_ >= 0)
    {
	int result = ::close(fd_);
	assert(result == 0);
	fd_ = -1;
    }
}

void temp_file::keep_all(bool keep)
{
    do_keep_all = keep;
}

temp_dir::temp_dir(const std::string & base_name)
{
    std::string tmp_dir_name(Glib::get_tmp_dir());
    std::vector<char> template_name;
    template_name.reserve(tmp_dir_name.size() + 1 + base_name.size() + 6 + 1);
    name_.reserve(tmp_dir_name.size() + 1 + base_name.size() + 6);
    template_name.assign(tmp_dir_name.begin(), tmp_dir_name.end());
    template_name.insert(template_name.end(), '/');
    template_name.insert(template_name.end(),
			 base_name.begin(), base_name.end());
    template_name.insert(template_name.end(), 6, 'X');
    template_name.insert(template_name.end(), '\0');
    if (mkdtemp(&template_name[0]))
	name_.assign(template_name.begin(), template_name.end() - 1);
    else
	throw std::runtime_error(
	    std::string("mkdtemp: ").append(std::strerror(errno)));
}

temp_dir::~temp_dir()
{
    if (!do_keep_all && !try_rmdir_recursive(name_))
	std::cerr << "Warning: failed to remove temporary directory "
		  << name_ << "\n";
}