Postfix3.3.1
cleanup_body_edit.c
[詳解]
1 /*++
2 /* NAME
3 /* cleanup_body_edit 3
4 /* SUMMARY
5 /* edit body content
6 /* SYNOPSIS
7 /* #include "cleanup.h"
8 /*
9 /* int cleanup_body_edit_start(state)
10 /* CLEANUP_STATE *state;
11 /*
12 /* int cleanup_body_edit_write(state, type, buf)
13 /* CLEANUP_STATE *state;
14 /* int type;
15 /* VSTRING *buf;
16 /*
17 /* int cleanup_body_edit_finish(state)
18 /* CLEANUP_STATE *state;
19 /*
20 /* void cleanup_body_edit_free(state)
21 /* CLEANUP_STATE *state;
22 /* DESCRIPTION
23 /* This module maintains queue file regions with body content.
24 /* Regions are created on the fly, and can be reused multiple
25 /* times. This module must not be called until the queue file
26 /* is complete, and there must be no other read/write access
27 /* to the queue file between the cleanup_body_edit_start() and
28 /* cleanup_body_edit_finish() calls.
29 /*
30 /* cleanup_body_edit_start() performs initialization and sets
31 /* the queue file write pointer to the start of the first body
32 /* region.
33 /*
34 /* cleanup_body_edit_write() adds a queue file record to the
35 /* queue file. When the current body region fills up, some
36 /* unused region is reused, or a new region is created.
37 /*
38 /* cleanup_body_edit_finish() makes some final adjustments
39 /* after the last body content record is written.
40 /*
41 /* cleanup_body_edit_free() frees up memory that was allocated
42 /* by cleanup_body_edit_start() and cleanup_body_edit_write().
43 /*
44 /* Arguments:
45 /* .IP state
46 /* Queue file and message processing state. This state is updated
47 /* as records are processed and as errors happen.
48 /* .IP type
49 /* Record type.
50 /* .IP buf
51 /* Record content.
52 /* LICENSE
53 /* .ad
54 /* .fi
55 /* The Secure Mailer license must be distributed with this software.
56 /* AUTHOR(S)
57 /* Wietse Venema
58 /* IBM T.J. Watson Research
59 /* P.O. Box 704
60 /* Yorktown Heights, NY 10598, USA
61 /*
62 /* Wietse Venema
63 /* Google, Inc.
64 /* 111 8th Avenue
65 /* New York, NY 10011, USA
66 /*--*/
67 
68 /* System library. */
69 
70 #include <sys_defs.h>
71 
72 /* Utility library. */
73 
74 #include <msg.h>
75 #include <mymalloc.h>
76 #include <vstream.h>
77 #include <vstring.h>
78 
79 /* Global library. */
80 
81 #include <rec_type.h>
82 #include <record.h>
83 
84 /* Application-specific. */
85 
86 #include <cleanup.h>
87 
88 #define LEN(s) VSTRING_LEN(s)
89 
90 static int cleanup_body_edit_ptr_rec_len;
91 
92 /* cleanup_body_edit_start - rewrite body region pool */
93 
95 {
96  const char *myname = "cleanup_body_edit_start";
97  CLEANUP_REGION *curr_rp;
98 
99  /*
100  * Calculate the payload size sans body.
101  */
102  state->cont_length = state->body_offset - state->data_offset;
103 
104  /*
105  * One-time initialization.
106  */
107  if (state->body_regions == 0) {
108  REC_SPACE_NEED(REC_TYPE_PTR_PAYL_SIZE, cleanup_body_edit_ptr_rec_len);
109  cleanup_region_init(state);
110  }
111 
112  /*
113  * Return all body regions to the free pool.
114  */
115  cleanup_region_return(state, state->body_regions);
116 
117  /*
118  * Select the first region. XXX This will usually be the original body
119  * segment, but we must not count on that. Region assignments may change
120  * when header editing also uses queue file regions. XXX We don't really
121  * know if the first region will be large enough to hold the first body
122  * text record, but this problem is so rare that we will not complicate
123  * the code for it. If the first region is too small then we will simply
124  * waste it.
125  */
126  curr_rp = state->curr_body_region = state->body_regions =
127  cleanup_region_open(state, cleanup_body_edit_ptr_rec_len);
128 
129  /*
130  * Link the first body region to the last message header.
131  */
132  if (vstream_fseek(state->dst, state->append_hdr_pt_offset, SEEK_SET) < 0) {
133  msg_warn("%s: seek file %s: %m", myname, cleanup_path);
134  return (-1);
135  }
136  state->append_hdr_pt_target = curr_rp->start;
138  (long) state->append_hdr_pt_target);
139 
140  /*
141  * Move the file write pointer to the start of the current region.
142  */
143  if (vstream_ftell(state->dst) != curr_rp->start
144  && vstream_fseek(state->dst, curr_rp->start, SEEK_SET) < 0) {
145  msg_warn("%s: seek file %s: %m", myname, cleanup_path);
146  return (-1);
147  }
148  return (0);
149 }
150 
151 /* cleanup_body_edit_write - add record to body region pool */
152 
153 int cleanup_body_edit_write(CLEANUP_STATE *state, int rec_type,
154  VSTRING *buf)
155 {
156  const char *myname = "cleanup_body_edit_write";
157  CLEANUP_REGION *curr_rp = state->curr_body_region;
158  CLEANUP_REGION *next_rp;
159  off_t space_used;
160  ssize_t space_needed;
161  ssize_t rec_len;
162 
163  if (msg_verbose)
164  msg_info("%s: where %ld, buflen %ld region start %ld len %ld",
165  myname, (long) curr_rp->write_offs, (long) LEN(buf),
166  (long) curr_rp->start, (long) curr_rp->len);
167 
168  /*
169  * Switch to the next body region if we filled up the current one (we
170  * always append to an open-ended region). Besides space to write the
171  * specified record, we need to leave space for a final pointer record
172  * that will link this body region to the next region or to the content
173  * terminator record.
174  */
175  if (curr_rp->len > 0) {
176  space_used = curr_rp->write_offs - curr_rp->start;
177  REC_SPACE_NEED(LEN(buf), rec_len);
178  space_needed = rec_len + cleanup_body_edit_ptr_rec_len;
179  if (space_needed > curr_rp->len - space_used) {
180 
181  /*
182  * Update the payload size. Connect the filled up body region to
183  * its successor.
184  */
185  state->cont_length += space_used;
186  next_rp = cleanup_region_open(state, space_needed);
187  if (msg_verbose)
188  msg_info("%s: link %ld -> %ld", myname,
189  (long) curr_rp->write_offs, (long) next_rp->start);
191  (long) next_rp->start);
192  curr_rp->write_offs = vstream_ftell(state->dst);
193  cleanup_region_close(state, curr_rp);
194  curr_rp->next = next_rp;
195 
196  /*
197  * Select the new body region.
198  */
199  state->curr_body_region = curr_rp = next_rp;
200  if (vstream_fseek(state->dst, curr_rp->start, SEEK_SET) < 0) {
201  msg_warn("%s: seek file %s: %m", myname, cleanup_path);
202  return (-1);
203  }
204  }
205  }
206 
207  /*
208  * Finally, output the queue file record.
209  */
210  CLEANUP_OUT_BUF(state, REC_TYPE_NORM, buf);
211  curr_rp->write_offs = vstream_ftell(state->dst);
212 
213  return (0);
214 }
215 
216 /* cleanup_body_edit_finish - wrap up body region pool */
217 
219 {
220  CLEANUP_REGION *curr_rp = state->curr_body_region;
221 
222  /*
223  * Update the payload size.
224  */
225  state->cont_length += curr_rp->write_offs - curr_rp->start;
226 
227  /*
228  * Link the last body region to the content terminator record.
229  */
231  (long) state->xtra_offset);
232  curr_rp->write_offs = vstream_ftell(state->dst);
233  cleanup_region_close(state, curr_rp);
234 
235  return (CLEANUP_OUT_OK(state) ? 0 : -1);
236 }
int msg_verbose
Definition: msg.c:177
off_t body_offset
Definition: cleanup.h:77
off_t vstream_ftell(VSTREAM *stream)
Definition: vstream.c:1157
off_t start
Definition: cleanup.h:335
CLEANUP_REGION * cleanup_region_return(CLEANUP_STATE *, CLEANUP_REGION *)
#define REC_TYPE_PTR_PAYL_SIZE
Definition: rec_type.h:180
void cleanup_region_close(CLEANUP_STATE *, CLEANUP_REGION *)
int cleanup_body_edit_start(CLEANUP_STATE *state)
#define CLEANUP_OUT_BUF(s, t, b)
Definition: cleanup.h:236
CLEANUP_REGION * cleanup_region_open(CLEANUP_STATE *, ssize_t)
char * cleanup_path
Definition: cleanup_init.c:111
int cleanup_body_edit_finish(CLEANUP_STATE *state)
off_t xtra_offset
Definition: cleanup.h:78
void cleanup_region_init(CLEANUP_STATE *)
#define REC_TYPE_PTR_FORMAT
Definition: rec_type.h:179
off_t append_hdr_pt_offset
Definition: cleanup.h:84
#define REC_TYPE_PTR
Definition: rec_type.h:67
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define LEN(s)
struct CLEANUP_REGION * curr_body_region
Definition: cleanup.h:129
struct CLEANUP_REGION * body_regions
Definition: cleanup.h:128
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
VSTREAM * dst
Definition: cleanup.h:53
int cleanup_body_edit_write(CLEANUP_STATE *state, int rec_type, VSTRING *buf)
#define CLEANUP_OUT_OK(s)
Definition: cleanup.h:239
off_t cont_length
Definition: cleanup.h:79
#define REC_TYPE_NORM
Definition: rec_type.h:59
off_t append_hdr_pt_target
Definition: cleanup.h:85
struct CLEANUP_REGION * next
Definition: cleanup.h:338
int rec_fprintf(VSTREAM *stream, int type, const char *format,...)
Definition: record.c:391
off_t data_offset
Definition: cleanup.h:76
off_t write_offs
Definition: cleanup.h:337
#define REC_SPACE_NEED(buflen, reclen)
Definition: record.h:59
void msg_info(const char *fmt,...)
Definition: msg.c:199