summaryrefslogtreecommitdiff
path: root/indra/llcommon/lltempredirect.cpp
blob: ee7923e8ca23d0b49a94d449526a3623d4b6d921 (plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
 * @file   lltempredirect.cpp
 * @author Nat Goodspeed
 * @date   2019-10-31
 * @brief  Implementation for lltempredirect.
 *
 * $LicenseInfo:firstyear=2019&license=viewerlgpl$
 * Copyright (c) 2019, Linden Research, Inc.
 * $/LicenseInfo$
 */

// Precompiled header
#include "linden_common.h"
// associated header
#include "lltempredirect.h"
// STL headers
// std headers
#if !LL_WINDOWS
# include <unistd.h>
#else
# include <io.h>
#endif // !LL_WINDOWS
// external library headers
// other Linden headers

/*****************************************************************************
*   llfd
*****************************************************************************/
// We could restate the implementation of each of llfd::close(), etc., but
// this is way more succinct.
#if LL_WINDOWS
#define fhclose  _close
#define fhdup    _dup
#define fhdup2   _dup2
#define fhfdopen _fdopen
#define fhfileno _fileno
#else
#define fhclose  ::close
#define fhdup    ::dup
#define fhdup2   ::dup2
#define fhfdopen ::fdopen
#define fhfileno ::fileno
#endif

int llfd::close(int fd)
{
    return fhclose(fd);
}

int llfd::dup(int target)
{
    return fhdup(target);
}

int llfd::dup2(int target, int reference)
{
    return fhdup2(target, reference);
}

FILE* llfd::open(int fd, const char* mode)
{
    return fhfdopen(fd, mode);
}

int llfd::fileno(FILE* stream)
{
    return fhfileno(stream);
}

/*****************************************************************************
*   LLTempRedirect
*****************************************************************************/
LLTempRedirect::LLTempRedirect():
    mOrigTarget(-1),                // -1 is an invalid file descriptor
    mReference(-1)
{}

LLTempRedirect::LLTempRedirect(FILE* target, FILE* reference):
    LLTempRedirect((target?    fhfileno(target)    : -1),
                   (reference? fhfileno(reference) : -1))
{}

LLTempRedirect::LLTempRedirect(int target, int reference):
    // capture a duplicate file descriptor for the file originally targeted by
    // 'reference'
    mOrigTarget((reference >= 0)? fhdup(reference) : -1),
    mReference(reference)
{
    if (target >= 0 && reference >= 0)
    {
        // As promised, force 'reference' to refer to 'target'. This first
        // implicitly closes 'reference', which is why we first capture a
        // duplicate so the original target file stays open.
        fhdup2(target, reference);
    }
}

LLTempRedirect::LLTempRedirect(LLTempRedirect&& other)
{
    mOrigTarget = other.mOrigTarget;
    mReference  = other.mReference;
    // other LLTempRedirect must be in moved-from state so its destructor
    // won't repeat the same operations as ours!
    other.mOrigTarget = -1;
    other.mReference  = -1;
}

LLTempRedirect::~LLTempRedirect()
{
    reset();
}

void LLTempRedirect::reset()
{
    // If this instance was default-constructed (or constructed with an
    // invalid file descriptor), skip the following.
    if (mOrigTarget >= 0)
    {
        // Restore mReference to point to mOrigTarget. This implicitly closes
        // the duplicate created by our constructor of its 'target' file
        // descriptor.
        fhdup2(mOrigTarget, mReference);
        // mOrigTarget has served its purpose
        fhclose(mOrigTarget);
    }
    // assign these because reset() is also responsible for a "moved from"
    // instance
    mOrigTarget = -1;
    mReference  = -1;
}

LLTempRedirect& LLTempRedirect::operator=(LLTempRedirect&& other)
{
    reset();
    std::swap(mOrigTarget, other.mOrigTarget);
    std::swap(mReference,  other.mReference);
    return *this;
}