Coverage Report

Created: 2026-06-15 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/gzcompressaction.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/rolling/gzcompressaction.h>
19
#include <apr_thread_proc.h>
20
#include <apr_strings.h>
21
#include <log4cxx/helpers/exception.h>
22
#include <log4cxx/helpers/transcoder.h>
23
#include <log4cxx/private/action_priv.h>
24
#include <log4cxx/helpers/loglog.h>
25
26
using namespace LOG4CXX_NS;
27
using namespace LOG4CXX_NS::rolling;
28
using namespace LOG4CXX_NS::helpers;
29
30
13
#define priv static_cast<GZCompressActionPrivate*>(m_priv.get())
31
32
struct GZCompressAction::GZCompressActionPrivate : public ActionPrivate
33
{
34
  GZCompressActionPrivate
35
    ( const File& toRename
36
    , const File& renameTo
37
    , bool deleteSource
38
    )
39
2
    : ActionPrivate{ LOG4CXX_STR("gzip") }
40
2
    , source(toRename)
41
2
    , destination(renameTo)
42
2
    , deleteSource(deleteSource)
43
2
    {}
44
45
  const File source;
46
  File destination;
47
  bool deleteSource;
48
  bool throwIOExceptionOnForkFailure = true;
49
};
50
51
IMPLEMENT_LOG4CXX_OBJECT(GZCompressAction)
52
53
GZCompressAction::GZCompressAction(const File& src,
54
  const File& dest,
55
  bool del)
56
2
  : Action(std::make_unique<GZCompressActionPrivate>(
57
2
        src, dest, del))
58
2
{
59
2
}
Unexecuted instantiation: log4cxx::rolling::GZCompressAction::GZCompressAction(log4cxx::File const&, log4cxx::File const&, bool)
log4cxx::rolling::GZCompressAction::GZCompressAction(log4cxx::File const&, log4cxx::File const&, bool)
Line
Count
Source
56
2
  : Action(std::make_unique<GZCompressActionPrivate>(
57
2
        src, dest, del))
58
2
{
59
2
}
60
61
2
GZCompressAction::~GZCompressAction() {}
62
63
bool GZCompressAction::execute( LOG4CXX_EXECUTE_ACTION_FORMAL_PARAMETERS ) const
64
2
{
65
2
  if (priv->source.exists())
66
2
  {
67
2
    helpers::Pool tempPool;
68
2
    apr_pool_t* aprpool = tempPool.getAPRPool();
69
2
    apr_procattr_t* attr;
70
2
    apr_status_t stat = apr_procattr_create(&attr, aprpool);
71
72
2
    if (stat != APR_SUCCESS)
73
0
    {
74
0
      throw IOException(stat);
75
0
    }
76
77
2
    stat = apr_procattr_io_set(attr, APR_NO_PIPE, APR_FULL_BLOCK, APR_FULL_BLOCK);
78
79
2
    if (stat != APR_SUCCESS)
80
0
    {
81
0
      throw IOException(stat);
82
0
    }
83
84
2
    stat = apr_procattr_cmdtype_set(attr, APR_PROGRAM_PATH);
85
86
2
    if (stat != APR_SUCCESS)
87
0
    {
88
0
      throw IOException(stat);
89
0
    }
90
91
    //
92
    //   set child process output to destination file
93
    //
94
2
    apr_file_t* child_out;
95
2
    apr_int32_t flags = APR_FOPEN_READ | APR_FOPEN_WRITE |
96
2
      APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE;
97
2
    stat = apr_file_open(&child_out, priv->destination.getAPRPath(), flags, APR_OS_DEFAULT, aprpool);
98
99
2
    if (stat != APR_SUCCESS)
100
0
    {
101
0
      throw IOException(priv->destination.getName(), stat);
102
0
    }
103
104
2
    stat =  apr_procattr_child_out_set(attr, child_out, NULL);
105
106
2
    if (stat != APR_SUCCESS)
107
0
    {
108
0
      throw IOException(stat);
109
0
    }
110
111
    //
112
    //   redirect the child's error stream to this processes' error stream
113
    //
114
2
    apr_file_t* child_err;
115
2
    stat = apr_file_open_stderr(&child_err, aprpool);
116
117
2
    if (stat == APR_SUCCESS)
118
2
    {
119
2
      stat =  apr_procattr_child_err_set(attr, child_err, NULL);
120
121
2
      if (stat != APR_SUCCESS)
122
0
      {
123
0
        throw IOException(stat);
124
0
      }
125
2
    }
126
127
2
    priv->destination.setAutoDelete(true);
128
129
2
    const char* args[4];
130
2
    int i = 0;
131
2
    args[i++] = "gzip";
132
2
    args[i++] = "-c";
133
2
    args[i++] = priv->source.getAPRPath();
134
2
    args[i++] = NULL;
135
136
2
    apr_proc_t pid;
137
2
    stat = apr_proc_create(&pid, "gzip", args, NULL, attr, aprpool);
138
139
2
    if (stat != APR_SUCCESS)
140
0
    {
141
0
      LogLog::warn(LOG4CXX_STR("Failed to fork gzip during log rotation; leaving log file uncompressed"));
142
0
      if (priv->throwIOExceptionOnForkFailure)
143
0
        throw IOException(LOG4CXX_STR("gzip"), stat);
144
      /* If we fail here (to create the gzip child process),
145
       * skip the compression and consider the rotation to be
146
       * otherwise successful. The caller has already rotated
147
       * the log file (`source` here refers to the
148
       * uncompressed, rotated path, and `destination` the
149
       * same path with `.gz` appended). Remove the empty
150
       * destination file and leave source as-is.
151
       */
152
0
      stat = apr_file_close(child_out);
153
0
      return true;
154
0
    }
155
156
2
    int exitCode = 0;
157
2
    apr_exit_why_e reason;
158
2
    apr_proc_wait(&pid, &exitCode, &reason, APR_WAIT);
159
2
    stat = apr_file_close(child_out);
160
161
2
    if (stat != APR_SUCCESS)
162
0
    {
163
0
      throw IOException(stat);
164
0
    }
165
166
2
    if (exitCode != 0)
167
1
    {
168
1
      throw SubProcessFailure(LOG4CXX_STR("gzip"), exitCode, reason);
169
1
    }
170
171
1
    priv->destination.setAutoDelete(false);
172
173
1
    if (priv->deleteSource)
174
1
    {
175
1
      priv->source.deleteFile();
176
1
    }
177
178
1
    return true;
179
2
  }
180
181
0
  return false;
182
2
}
183
184
2
void GZCompressAction::setThrowIOExceptionOnForkFailure(bool throwIO){
185
2
  priv->throwIOExceptionOnForkFailure = throwIO;
186
2
}
187